1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 John E. Davis
3  * This file is part of JED editor library source.
4  *
5  * You may distribute this file under the terms the GNU General Public
6  * License.  See the file COPYING for more information.
7  */
8 
9 #include "config.h"
10 #include "jed-feat.h"
11 /*{{{ Include Files */
12 
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "buffer.h"
17 #include "ins.h"
18 #include "line.h"
19 #include "paste.h"
20 #include "screen.h"
21 #include "misc.h"
22 #include "cmds.h"
23 
24 /*}}}*/
25 
26 /* SLang user object be larger than 128 */
27 #define JED_MARK_TYPE 128
28 
29 Buffer *Paste_Buffer;
30 static Buffer *Rectangle_Buffer;
31 
32 /* This is used by the narrow command so that multiple windows are
33  * handled properly. The assumption is that we are dealing with a canonical
34  * region */
35 
touch_windows(void)36 static void touch_windows(void) /*{{{*/
37 {
38    Window_Type *w;
39    Line *l;
40    unsigned int n;
41 
42    w = JWindow;
43    JWindow = JWindow->next;
44    while (JWindow != w)
45      {
46 	if (CBuf == JWindow->buffer)
47 	  {
48 	     /* The mark is set with line at top of buffer */
49 	     l = CBuf->marks->line;
50 	     n = CBuf->marks->n;
51 	     while ((l != NULL) && (l != JWindow->mark.line)) l = l->next, n++;
52 	     if (l == NULL)
53 	       jed_init_mark (&JWindow->mark, 0);
54 	     touch_window();
55 	  }
56 	JWindow = JWindow->next;
57      }
58    jed_pop_mark(0);
59 }
60 
61 /*}}}*/
62 
63 #if 0
64 static int line_in_buffer(Line *line) /*{{{*/
65 {
66    Line *l;
67 
68    l = CBuf->beg;
69    while (l != NULL) if (l == line) return(1); else l = l->next;
70    return(0);
71 }
72 
73 /*}}}*/
74 #endif
75 
76 /*{{{ Spot/Mark Functions */
77 
jed_copy_mark(Mark * dest,Mark * src)78 void jed_copy_mark (Mark *dest, Mark *src)
79 {
80    *dest = *src;
81    dest->next = NULL;
82 }
83 
jed_init_mark(Mark * m,unsigned int flags)84 void jed_init_mark (Mark *m, unsigned int flags) /*{{{*/
85 {
86    m->line = CLine;
87    m->point = Point;
88    m->n = LineNum + CBuf->nup;
89    m->flags = flags;
90    /* m->next = NULL; */
91 }
92 
93 /*}}}*/
94 
jed_init_mark_for_buffer(Mark * m,Buffer * b,unsigned int flags)95 void jed_init_mark_for_buffer (Mark *m, Buffer *b, unsigned int flags) /*{{{*/
96 {
97    m->line = b->line;
98    m->point = b->point;
99    m->n = b->linenum + b->nup;
100    m->flags = flags;
101    /* m->next = NULL; */
102 }
103 
104 /*}}}*/
105 #if 0
106 int jed_init_mark_for_line (Mark *m, Line *l, unsigned int flags) /*{{{*/
107 {
108    Line *ll;
109    unsigned int n;
110 
111    n = 1;
112    ll = CBuf->beg;
113    while ((ll != NULL) && (ll != l))
114      {
115 	ll = ll->next;
116 	n++;
117      }
118    if (ll == NULL)
119      return -1;
120 
121    m->line = l;
122    m->point = 0;
123    m->n = n + CBuf->nup;
124    m->flags = flags;
125    /* m->next = NULL; */
126    return 0;
127 }
128 
129 /*}}}*/
130 #endif
131 #if JED_HAS_SAVE_NARROW
create_mark(unsigned int flags)132 static Mark *create_mark (unsigned int flags) /*{{{*/
133 {
134    Mark *m;
135 
136    if (NULL == (m = (Mark *) jed_malloc0 (sizeof(Mark))))
137      exit_error("create-mark: malloc error", 0);
138 
139    jed_init_mark (m, flags);
140 
141    return m;
142 }
143 
144 /*}}}*/
145 #endif
146 /* with prefix argument, pop marks */
set_mark_cmd(void)147 int set_mark_cmd (void) /*{{{*/
148 {
149    Mark *m;
150    if (Repeat_Factor != NULL)
151      {
152 	while (CBuf->marks != NULL) jed_pop_mark(0);
153 	Repeat_Factor = NULL;
154 	return(1);
155      }
156 
157    if (CBuf->marks == NULL)
158      {
159 	jed_push_mark ();
160      }
161 
162    m = CBuf->marks;
163 
164    jed_init_mark (m, m->flags);
165 
166    if ((m->flags & VISIBLE_MARK) == 0)
167      {
168 	m->flags |= VISIBLE_MARK;
169 	CBuf->vis_marks++;
170      }
171 
172    /* if (m != CBuf->marks) m->next = CBuf->marks;
173     CBuf->marks = m; */
174    if (Last_Key_Function == (FVOID_STAR) set_mark_cmd) message("Mark Set.");
175    return(1);
176 }
177 
178 /*}}}*/
179 
allocate_mark(Jed_Mark_Array_Type ** ap,Mark ** mp,unsigned int flags)180 static Mark *allocate_mark (Jed_Mark_Array_Type **ap, Mark **mp, unsigned int flags) /*{{{*/
181 {
182    Jed_Mark_Array_Type *a, *b;
183    Mark *m;
184 
185    a = *ap;
186    if ((a == NULL)
187        || (a->num_marks == JED_MAX_MARK_ARRAY_SIZE))
188      {
189 	if (NULL == (b = (Jed_Mark_Array_Type *) jed_malloc0 (sizeof(Jed_Mark_Array_Type))))
190 	  {
191 	     exit_error("allocate_mark: malloc error", 0);
192 	  }
193 	b->next = a;
194 	a = b;
195 	*ap = a;
196      }
197 
198    m = &a->marks[a->num_marks];
199    jed_init_mark (m, flags);
200 
201    a->num_marks += 1;
202    m->next = *mp;
203    *mp = m;
204    return m;
205 }
206 
207 /*}}}*/
208 
deallocate_mark(Jed_Mark_Array_Type ** ap,Mark ** mp)209 static void deallocate_mark (Jed_Mark_Array_Type **ap, Mark **mp) /*{{{*/
210 {
211    Jed_Mark_Array_Type *a;
212    Mark *m;
213 
214    m = *mp;
215    *mp = m->next;
216 
217    a = *ap;
218    a->num_marks -= 1;
219 
220    if (a->num_marks == 0)
221      {
222 	*ap = a->next;
223 	SLfree ((char *)a);
224      }
225 }
226 
227 /*}}}*/
228 
push_spot()229 int push_spot() /*{{{*/
230 {
231    (void) allocate_mark (&CBuf->spot_array, &CBuf->spots, 0);
232    return 1;
233 }
234 
235 /*}}}*/
236 
jed_push_mark()237 int jed_push_mark() /*{{{*/
238 {
239    (void) allocate_mark (&CBuf->mark_array, &CBuf->marks, 0);
240    return 1;
241 }
242 
243 /*}}}*/
244 
jed_goto_mark(Mark * m)245 int jed_goto_mark(Mark *m) /*{{{*/
246 {
247    Line *l;
248    int ret = -1;
249 
250    l = m->line;
251    LineNum = m->n;
252 
253    if (LineNum <= CBuf->nup) bob();
254    else if (LineNum > CBuf->nup + Max_LineNum) eob();
255    else
256      {
257 	CLine = l;
258 	Point = m->point;
259 	LineNum -= CBuf->nup;
260 	ret = 0;
261      }
262    return ret;
263 }
264 
265 /*}}}*/
266 
jed_pop_mark(int go)267 int jed_pop_mark (int go) /*{{{*/
268 {
269    Mark *m;
270 
271    m = CBuf->marks;
272    if (m == NULL) return(0);
273 
274    if (go) jed_goto_mark(m);
275    if (m->flags & VISIBLE_MARK_MASK)
276      {
277 	CBuf->vis_marks--;
278 	/* touch screen since region may be highlighted */
279 	if (CBuf->vis_marks == 0) touch_screen();
280      }
281 
282    deallocate_mark (&CBuf->mark_array, &CBuf->marks);
283 
284    return 1;
285 }
286 
287 /*}}}*/
288 
mark_spot()289 int mark_spot() /*{{{*/
290 {
291     push_spot();
292     message("Spot Marked.");
293     return(1);
294 }
295 
296 /*}}}*/
297 
pop_spot_go(int go)298 static int pop_spot_go (int go) /*{{{*/
299 {
300    Mark *m;
301 
302    m = CBuf->spots;
303    if (m == NULL) return(0);
304 
305    if (go) jed_goto_mark (m);
306 
307    deallocate_mark (&CBuf->spot_array, &CBuf->spots);
308    return 1;
309 }
310 
311 /*}}}*/
312 
pop_spot()313 int pop_spot () /*{{{*/
314 {
315    return pop_spot_go (1);
316 }
317 
318 /*}}}*/
319 
exchange_point_mark(void)320 int exchange_point_mark(void) /*{{{*/
321 {
322    Line *save_line;
323    int save_point;
324    unsigned int save_n;
325    Mark *m;
326 
327    if ((m = CBuf->marks) == NULL) return(0);
328 
329    save_point = Point;
330    save_line = CLine;
331    save_n = LineNum + CBuf->nup;
332 
333    jed_goto_mark (m);
334 
335    m->point = save_point; m->line = save_line; m->n = save_n;
336    return(1);
337 }
338 
339 /*}}}*/
340 
341 /*}}}*/
342 
343 /*{{{ Narrow/Widen/Region Functions */
344 
345  /*returns 0 if the mark is not set and gives error.  Exchanges point and mark
346   * to produce valid region.  A valid region is one with mark
347   * earlier in the buffer than point.  Always call this if using a region
348   * which reqires point > mark.  Also, push spot first then pop at end.
349   */
check_region(int * push)350 int check_region(int *push) /*{{{*/
351 {
352    register Line *beg, *tthis = CLine;
353    int pbeg;
354 
355    if (CBuf->marks == NULL)
356      {
357 	msg_error("No region defined");
358 	return(0);
359      }
360 
361    if (*push) push_spot();
362    beg = CBuf->marks->line;
363    pbeg = CBuf->marks->point;
364 
365    if (beg == CLine)
366      {
367 	if (pbeg <= Point) return(1);
368      }
369 
370    else
371      {
372 	while((beg != NULL) && (beg != tthis)) beg = beg->next;
373 	if (beg == tthis) return(1);
374      }
375 
376    exchange_point_mark();
377    return(1);
378 }
379 
380 /*}}}*/
381 
widen_buffer_lines(Buffer * b)382 static int widen_buffer_lines (Buffer *b) /*{{{*/
383 {
384    Narrow_Type *n;
385    Buffer *save = CBuf;
386 
387    if (NULL == (n = b->narrow)) return(0);
388 
389    /* make sure buffer ends in final newline */
390 
391    switch_to_buffer(b);
392    push_spot();
393    eob();
394    if ((n->end != NULL)
395        && (0 == LINE_HAS_NEWLINE (CLine)))
396      {
397 	/* This is a hack to avoid messing with the lock file. Yuk. */
398 	unsigned int flags = CBuf->flags;
399 	CBuf->flags &= ~(READ_ONLY);
400 	CBuf->flags |= BUFFER_NON_LOCKING;
401 	(void) _jed_ins_byte ('\n');
402 	CBuf->flags = flags;  /* jed_set_buffer_flags (CBuf, flags); */
403      }
404 
405    pop_spot();
406 
407    if (n->end != NULL) n->end->prev = b->end;
408    if (n->beg != NULL) n->beg->next = b->beg;
409    b->end->next = n->end;
410    b->beg->prev = n->beg;
411    b->beg = n->beg1;
412    if (n->end != NULL) b->end = n->end1;
413 
414    Max_LineNum += n->ndown + n->nup;
415    LineNum += n->nup;
416 
417    /* adjust absolute offsets */
418    b->nup -= n->nup;
419    b->ndown -= n->ndown;
420    b->narrow = n->next;
421 
422    /* mark_undo_boundary (b); */
423 
424    SLfree ((char *)n);
425    switch_to_buffer(save);
426    return(1);
427 }
428 
429 /*}}}*/
430 
widen_buffer(Buffer * b)431 int widen_buffer (Buffer *b) /*{{{*/
432 {
433    unsigned int flags;
434 #if JED_HAS_LINE_ATTRIBUTES
435    unsigned int line_flags;
436 #endif
437    Buffer *save;
438 
439    if (b->narrow == NULL) return 0;
440 
441    if (b->narrow->is_region == 0)
442      return widen_buffer_lines (b);
443 
444    flags = b->flags;
445    b->flags &= ~(READ_ONLY);
446 
447    /* A hack to avoid locking file */
448    b->flags |= BUFFER_NON_LOCKING;
449 
450    save = CBuf;
451    if (b != CBuf) switch_to_buffer (b);
452    push_spot ();
453    bob ();
454    push_spot ();
455    eob ();
456    widen_buffer_lines (CBuf);
457 
458 #if JED_HAS_LINE_ATTRIBUTES
459    line_flags = CLine->flags;
460    CLine->flags &= ~JED_LINE_IS_READONLY;
461 #endif
462    (void) jed_del_wchar ();
463 #if JED_HAS_LINE_ATTRIBUTES
464    CLine->flags = line_flags;
465 #endif
466 
467    pop_spot ();
468    (void) jed_up (1);
469 #if JED_HAS_LINE_ATTRIBUTES
470    line_flags = CLine->flags;
471    CLine->flags &= ~JED_LINE_IS_READONLY;
472 #endif
473    (void) jed_del_wchar ();
474 #if JED_HAS_LINE_ATTRIBUTES
475    CLine->flags = line_flags;
476 #endif
477    /* mark_undo_boundary (b); */
478 
479    pop_spot ();
480    if (save != CBuf) switch_to_buffer (save);
481 
482    b->flags = flags;
483    return 1;
484 }
485 
486 /*}}}*/
487 
narrow_to_region(void)488 int narrow_to_region (void) /*{{{*/
489 {
490    int pnt;
491    Line *line;
492    unsigned int flags;
493 #if JED_HAS_LINE_ATTRIBUTES
494    unsigned int line_flags;
495 #endif
496 
497    if (0 == check_region (&Number_One))/* spot pushed */
498      return 0;
499 
500    /* unmark_undo_boundary (CBuf); */
501 
502    flags = CBuf->flags;
503    CBuf->flags &= ~(READ_ONLY);
504    /* A hack to avoid locking file */
505    CBuf->flags |= BUFFER_NON_LOCKING;
506 
507    push_spot ();
508 
509    line = CLine;
510    pnt = Point;
511 
512    jed_pop_mark (1);
513    /* Special case if region is empty */
514    if ((CLine == line) && (pnt == Point))
515      {
516 	pop_spot ();
517 	pop_spot ();
518 
519 #if JED_HAS_LINE_ATTRIBUTES
520 	line_flags = CLine->flags;
521 	CLine->flags &= ~JED_LINE_IS_READONLY;
522 #endif
523 
524 	(void) jed_insert_newline ();
525 
526 #if JED_HAS_LINE_ATTRIBUTES
527 	if (CLine->prev != NULL) CLine->prev->flags = line_flags;
528 #endif
529 
530 	jed_push_mark ();
531 
532 	(void) jed_insert_newline ();
533 
534 #if JED_HAS_LINE_ATTRIBUTES
535 	CLine->flags = line_flags;
536 #endif
537 	(void) jed_up (1);
538 
539 #if JED_HAS_LINE_ATTRIBUTES
540 	CLine->flags = line_flags;
541 #endif
542 
543 	if (narrow_to_lines ())
544 	  CBuf->narrow->is_region = 1;
545      }
546    else
547      {
548 #if JED_HAS_LINE_ATTRIBUTES
549 	line_flags = CLine->flags;
550 	CLine->flags &= ~JED_LINE_IS_READONLY;
551 #endif
552 	jed_insert_newline ();
553 #if JED_HAS_LINE_ATTRIBUTES
554 	CLine->flags = line_flags;
555 	if (CLine->prev != NULL) CLine->prev->flags = line_flags;
556 #endif
557 
558 	jed_push_mark ();
559 	pop_spot ();
560 
561 #if JED_HAS_LINE_ATTRIBUTES
562 	line_flags = CLine->flags;
563 	CLine->flags &= ~JED_LINE_IS_READONLY;
564 #endif
565 	jed_insert_newline ();
566 #if JED_HAS_LINE_ATTRIBUTES
567 	CLine->flags = line_flags;
568 #endif
569 	jed_up (1);
570 
571 #if JED_HAS_LINE_ATTRIBUTES
572 	CLine->flags = line_flags;
573 #endif
574 	if (narrow_to_lines ())
575 	  CBuf->narrow->is_region = 1;
576 
577 	pop_spot ();
578      }
579 
580    /* mark_undo_boundary (CBuf); */
581    CBuf->flags = flags;
582    return 1;
583 }
584 
585 /*}}}*/
586 
widen(void)587 int widen (void) /*{{{*/
588 {
589    if (CBuf->narrow == NULL)
590      return 0;
591 
592    if (CBuf->narrow->is_region == 0)
593      return widen_buffer_lines (CBuf);
594 
595    return widen_buffer (CBuf);
596 }
597 
598 /*}}}*/
599 
widen_region(void)600 int widen_region (void) /*{{{*/
601 {
602    return widen ();
603 }
604 
605 /*}}}*/
606 
607 /* not really a region of points but a region of lines. */
narrow_to_lines()608 int narrow_to_lines () /*{{{*/
609 {
610    Line *beg;
611    Narrow_Type *nt;
612 
613    if (NULL == (nt = (Narrow_Type *) jed_malloc0 (sizeof(Narrow_Type))))
614      return 0;
615 
616    if (!check_region(&Number_One)) return(0);       /* spot pushed */
617 
618    /* unmark_undo_boundary (CBuf); */
619 
620    push_spot();
621    jed_pop_mark(1);
622    jed_push_mark();			       /* popped and used in touch_windows! */
623    beg = CLine;
624    nt->nup = LineNum - 1;
625 
626    pop_spot();  /* eor now */
627 
628    nt->ndown = Max_LineNum - LineNum;
629 
630    Max_LineNum = LineNum = LineNum - nt->nup;
631    CBuf->nup += nt->nup;
632    CBuf->ndown += nt->ndown;
633 
634 
635    nt->next = CBuf->narrow;
636    CBuf->narrow = nt;
637    nt->beg = beg->prev;
638    nt->end = CLine->next;
639    nt->beg1 = CBuf->beg;
640    nt->end1 = CBuf->end;
641 
642    nt->is_region = 0;
643    CBuf->beg = beg;
644    CBuf->end = CLine;
645    beg->prev = NULL;
646    CLine->next = NULL;
647 
648    if (CLine->len && (CLine->data[CLine->len - 1] == '\n'))
649      {
650 	/* I do not think that this will affect undo. */
651 	CLine->len--;
652      }
653 
654    pop_spot();
655    touch_windows();
656    return(1);
657 }
658 
659 /*}}}*/
660 
661 /*}}}*/
662 
663 /*{{{ Pastebuffer, Delete Region functions */
664 
yank()665 int yank() /*{{{*/
666 {
667    CHECK_READ_ONLY
668     if (Paste_Buffer == NULL) return(0);
669     insert_buffer(Paste_Buffer);
670     return(1);
671 }
672 
673 /*}}}*/
674 
copy_region_to_buffer(Buffer * b)675 int copy_region_to_buffer(Buffer *b) /*{{{*/
676 {
677    int first_point, last_point, n;
678    Line *first, *last;
679    Buffer *save_buf;
680 
681    if (b->flags & READ_ONLY)
682      {
683 	msg_error(Read_Only_Error);
684 	return (0);
685      }
686 
687    if (!check_region(&Number_One)) return(0);  /* spot pushed */
688    last = CLine;
689    last_point = Point;
690 
691    jed_pop_mark(1);
692    if (b == CBuf)
693      {
694 	msg_error("A buffer cannot be inserted upon itself.");
695 	pop_spot();
696 	return(0);
697      }
698 
699    first = CLine;
700    first_point = Point;
701 
702    save_buf = CBuf;
703    switch_to_buffer(b);
704 
705    /* go through standard routines for undo comapatability */
706    Suspend_Screen_Update = 1;
707    if (first == last)
708      {
709 	n = last_point - first_point;
710 	if (save_buf == MiniBuffer)
711 	  {
712 	     (void) jed_insert_nbytes (first->data + first_point, n);
713 	  }
714 	else (void) jed_quick_insert (first->data + first_point, n);
715      }
716    else
717      {
718 	n = first->len - first_point;
719 	if (-1 == jed_quick_insert(first->data + first_point, n))
720 	  goto the_return;
721 
722 	while (first = first->next, first != last)
723 	  {
724 	     if (-1 == jed_quick_insert (first->data, first->len))
725 	       goto the_return;
726 	  }
727 	(void) jed_quick_insert(first->data, last_point);
728      }
729 
730    the_return:
731    switch_to_buffer(save_buf);
732    pop_spot();
733    return(1);
734 }
735 
736 /*}}}*/
737 
copy_to_pastebuffer()738 int copy_to_pastebuffer() /*{{{*/
739 {
740    /* delete paste buffer */
741    if (Paste_Buffer != NULL) delete_buffer(Paste_Buffer);
742    Paste_Buffer = make_buffer (" <paste>", NULL, NULL);
743 
744    copy_region_to_buffer(Paste_Buffer);
745    return(0);
746 }
747 
748 /*}}}*/
749 
jed_check_readonly_region(void)750 static int jed_check_readonly_region (void)
751 {
752    int beg_point, end_point;
753    Line *beg, *end;
754 
755    if (CBuf->flags & READ_ONLY)
756      {
757 	msg_error(Read_Only_Error);
758 	return -1;
759      }
760 
761    if (!check_region(&Number_Zero))
762      return -1;
763 
764    end = CLine; end_point = Point;
765    (void) exchange_point_mark ();
766    beg = CLine; beg_point = Point;
767    (void) exchange_point_mark ();
768 
769    while (1)
770      {
771 	if (beg->flags & JED_LINE_IS_READONLY)
772 	  {
773 	     if ((beg == end)
774 		 && (end_point == 0)
775 		 && (beg_point == 0))
776 	       return 0;
777 
778 	     msg_error (Line_Read_Only_Error);
779 	     return -1;
780 	  }
781 	if (beg == end)
782 	  break;
783 
784 	beg = beg->next;
785      }
786    return 0;
787 }
788 
789 
delete_region(void)790 int delete_region (void) /*{{{*/
791 {
792    int beg_point, end_point;
793    Line *beg, *end;
794 
795    if (0 != jed_check_readonly_region ())
796      return -1;
797 
798    /* make this go through standard ins/del routines to ensure undo */
799 
800    end = CLine; end_point = Point;
801    push_spot();
802    jed_pop_mark(1);
803    beg = CLine; beg_point = Point;
804    pop_spot();
805 
806    if (end != beg)
807      {
808 	bol ();
809 
810 	if (-1 == jed_del_nbytes (end_point))
811 	  return -1;
812 
813 	/* go back because we do not want to mess with Line structures
814 	   changing on us --- shouldn't happen anyway */
815 
816 	while (jed_up (1) && (CLine != beg))
817 	  {
818 	     bol ();
819 	     if (-1 == jed_del_through_eol ())
820 	       return -1;
821 	  }
822 	end_point = CLine->len;	       /* include \n */
823      }
824 
825    jed_set_point (beg_point);
826    (void) jed_generic_del_nbytes (end_point - Point);
827    return 1;
828 }
829 
830 /*}}}*/
831 
kill_region()832 int kill_region() /*{{{*/
833 {
834    if (-1 == jed_check_readonly_region ())
835      return -1;
836 
837    /* need two marks for this one */
838    push_spot();
839    if (!jed_pop_mark(1))
840      {
841 	check_region(&Number_Zero);
842 	pop_spot();
843 	return(0);
844      }
845    jed_push_mark();
846    jed_push_mark();
847    pop_spot();
848 
849    copy_to_pastebuffer();
850    delete_region();
851    return(1);
852 }
853 
854 /*}}}*/
855 
856 /*}}}*/
857 
858 /*{{{ Rectangle Functions */
859 
860 static char *Rect_Error = "Rectangle has 0 width.";
insert_rectangle()861 int insert_rectangle() /*{{{*/
862 {
863    int c1;
864    Line *rline;
865 
866    CHECK_READ_ONLY
867    if (0 == buffer_exists (Rectangle_Buffer))
868      {
869 	Rectangle_Buffer = NULL;
870 	return 0;
871      }
872 
873    Suspend_Screen_Update = 1;
874    c1 = calculate_column();
875    rline = Rectangle_Buffer->beg;
876    if (rline != NULL) while (1)
877      {
878 	goto_column(&c1);
879 	if (-1 == jed_quick_insert (rline->data, rline->len))
880 	  return -1;
881 
882 	rline = rline->next;
883 	if (rline == NULL) break;
884 	if (0 == jed_down (1))
885 	  {
886 	     eol();
887 	     jed_insert_newline();
888 	  }
889      }
890    return(1);
891 }
892 
893 /*}}}*/
894 
open_rectangle()895 int open_rectangle() /*{{{*/
896 {
897    int c1, n, c2, tmpm;
898    Line *save_line;
899 
900    CHECK_READ_ONLY
901    if (!check_region(&Number_One)) return(0); /* push_spot(); performed */
902 
903    c1 = calculate_column();
904    save_line = CLine;
905    tmpm = 1; jed_pop_mark(1);
906    c2 = calculate_column();
907    n = c2 - c1;
908    if (n < 0)
909      {
910 	n = -n;
911 	c1 = c2;
912      }
913 
914    Suspend_Screen_Update = 1;
915    while(1)
916      {
917 	goto_column(&c1);
918 	if (-1 == jed_insert_wchar_n_times(' ', n))
919 	  break;
920 	if (CLine == save_line) break;
921 	(void) jed_down (1);
922      }
923    pop_spot();
924 
925    return(1);
926 }
927 
928 /*}}}*/
929 
930 /* MB Safe */
copy_or_kill_rectangle(int kill)931 static int copy_or_kill_rectangle (int kill) /*{{{*/
932 {
933    Line *save_line, *line, *beg;
934    int c1, c2, dc, tmp;
935 
936    if (!check_region(&Number_One)) return(0);       /* spot pushed */
937    /* delete Rectangle buffer */
938    if (Rectangle_Buffer != NULL) delete_buffer(Rectangle_Buffer);
939 
940    Rectangle_Buffer = make_buffer (" <rect>", NULL, NULL);
941    c2 = calculate_column();
942    save_line = CLine;
943 
944    jed_pop_mark(1);
945    c1 = calculate_column();
946    if (c1 == c2)
947      {
948 	msg_error(Rect_Error);
949 	pop_spot();
950 	return(0);
951      }
952    if (c1 > c2)
953      {
954 	tmp = c1;
955 	c1 = c2;
956 	c2 = tmp;
957 	goto_column(&c1);
958      }
959 
960    dc = c2 - c1;
961 
962    /* go through the region copying rectanglar blocks to Rectanglebuffer */
963 
964    line = beg = NULL;
965    while (1)
966      {
967 	int col2, col1;
968 	unsigned int len, len1;
969 	unsigned int nspaces;
970 	unsigned int nbytes;
971 	unsigned char *p1, *p2;
972 
973 	col1 = goto_column1 (&c1);
974 	p1 = CLine->data + Point;
975 
976 	if (col1 == c1)
977 	  {
978 	     col2 = goto_column1(&c2);
979 	     p2 = CLine->data + Point;
980 	  }
981 	else
982 	  {
983 	     col2 = col1;
984 	     p2 = p1;
985 	  }
986 
987 	nspaces = (unsigned int) (dc - (col2 - col1));
988 	nbytes = (unsigned int) (p2 - p1);
989 	len1 = len = nbytes + nspaces;
990 
991 	/* Need to allocate at least 2 bytes, since a single byte is a
992 	 * signature of a line with a single character whose value is a
993 	 * newline character.  See make_line1 for details.
994 	 */
995 	if (len <= 1)
996 	  len1++;
997 
998 	if (beg == NULL)
999 	  {
1000 	     beg = line = make_line1 (len1);
1001 	     beg->prev = NULL;
1002 	  }
1003 	else
1004 	  {
1005 	     line->next = make_line1 (len1);
1006 	     line->next->prev = line;
1007 	     line = line->next;
1008 	  }
1009 	line->len = len;
1010 
1011 	memcpy ((char *) line->data, (char *) p1, nbytes);
1012 	memset ((char *) line->data + nbytes, ' ', nspaces);
1013 
1014 	if (kill && (nbytes != 0))
1015 	  {
1016 	     jed_position_point (p1);
1017 	     if (-1 == jed_del_nbytes (nbytes))
1018 	       break;
1019 	  }
1020 
1021 	 if (CLine == save_line) break;
1022 	 (void) jed_down(1);
1023       }
1024 
1025     line->next = NULL;
1026 
1027     Rectangle_Buffer->line = Rectangle_Buffer->beg = beg;
1028     Rectangle_Buffer->end = line;
1029     Rectangle_Buffer->point = 0;
1030 
1031     pop_spot();
1032     return(0);
1033 }
1034 
1035 /*}}}*/
1036 
copy_rectangle(void)1037 int copy_rectangle (void)
1038 {
1039    return copy_or_kill_rectangle (0);
1040 }
1041 
kill_rectangle(void)1042 int kill_rectangle (void)
1043 {
1044    return copy_or_kill_rectangle (1);
1045 }
1046 
blank_rectangle(void)1047 int blank_rectangle (void) /*{{{*/
1048 {
1049    int c1, c2;
1050    Line *save_line;
1051    int ncols;
1052 
1053    CHECK_READ_ONLY
1054    if (!check_region(&Number_One)) return(0); /* push_spot(); performed */
1055 
1056    c1 = calculate_column();
1057    save_line = CLine;
1058    jed_pop_mark(1);
1059    c2 = calculate_column();
1060    if (c1 > c2)
1061      {
1062 	int tmp = c1;
1063 	c1 = c2;
1064 	c2 = tmp;
1065      }
1066    ncols = c2 - c1;
1067 
1068    Suspend_Screen_Update = 1;
1069    while(1)
1070      {
1071 	int pnt;
1072 
1073 	goto_column (&c2);
1074 	pnt = Point;
1075 	goto_column (&c1);
1076 
1077 	if (-1 == jed_del_nbytes (pnt - Point))
1078 	  break;
1079 
1080 	if (-1 == jed_insert_wchar_n_times( ' ', ncols))
1081 	  break;
1082 
1083 	if (CLine == save_line) break;
1084 	(void) jed_down (1);
1085      }
1086    pop_spot();
1087    return(1);
1088 }
1089 
1090 /*}}}*/
1091 
1092 /*}}}*/
1093 
1094 /*{{{ User Mark Functions */
1095 
1096 typedef struct /*{{{*/
1097 {
1098    Mark m;			       /* MUST be the first */
1099    Buffer *b;
1100 }
1101 
1102 /*}}}*/
1103 User_Mark_Type;
1104 
free_user_mark(SLtype type,VOID_STAR um_alias)1105 static void free_user_mark (SLtype type, VOID_STAR um_alias) /*{{{*/
1106 {
1107    Mark *m, *m1;
1108    Buffer *b;
1109    User_Mark_Type *um;
1110 
1111    (void) type;
1112    um = (User_Mark_Type *) um_alias;
1113    m1 = &um->m;
1114 
1115    /* The mark is only valid if the buffer that it was created for still
1116     * exists.
1117     */
1118    if ((m1->flags & MARK_INVALID) == 0)
1119      {
1120 	/* Unlink the mark from the chain. */
1121 	b = um->b;
1122 	m = b->user_marks;
1123 #if JED_HAS_LINE_MARKS
1124 	if (m1->flags & JED_LINE_MARK)
1125 	  touch_screen ();
1126 #endif
1127 	if (m == m1)	b->user_marks = m1->next;
1128 	else
1129 	  {
1130 	     while (m->next != m1) m = m->next;
1131 	     m->next = m1->next;
1132 	  }
1133      }
1134 
1135    SLfree ((char *)um);
1136 }
1137 
1138 /*}}}*/
1139 
free_user_marks(Buffer * b)1140 void free_user_marks (Buffer *b) /*{{{*/
1141 {
1142    Mark *m = b->user_marks;
1143 
1144    while (m != NULL)
1145      {
1146 	m->flags |= MARK_INVALID;
1147 	m = m->next;
1148      }
1149 }
1150 
1151 /*}}}*/
1152 
mark_valid(Mark * m)1153 static int mark_valid (Mark *m) /*{{{*/
1154 {
1155    if (m->flags & MARK_INVALID)
1156      {
1157 	msg_error ("Mark is invalid.");
1158 	return 0;
1159      }
1160    return 1;
1161 }
1162 
1163 /*}}}*/
1164 
pop_valid_user_mark(User_Mark_Type ** ump)1165 static SLang_MMT_Type *pop_valid_user_mark (User_Mark_Type **ump)
1166 {
1167    SLang_MMT_Type *mmt;
1168    User_Mark_Type *um;
1169 
1170    *ump = NULL;
1171 
1172    if (NULL == (mmt = SLang_pop_mmt (JED_MARK_TYPE)))
1173      return NULL;
1174 
1175    um = (User_Mark_Type *) SLang_object_from_mmt (mmt);
1176 
1177    if (0 == mark_valid (&um->m))
1178      {
1179 	SLang_free_mmt (mmt);
1180 	return NULL;
1181      }
1182 
1183    *ump = um;
1184    return mmt;
1185 }
1186 
1187 
1188 
jed_move_user_object_mark(SLang_MMT_Type * mmt)1189 int jed_move_user_object_mark (SLang_MMT_Type *mmt) /*{{{*/
1190 {
1191    User_Mark_Type *um;
1192    Mark *m;
1193 
1194    um = (User_Mark_Type *) SLang_object_from_mmt (mmt);
1195    m = &um->m;
1196 
1197    if (!mark_valid (m)) return 0;
1198 
1199    if (CBuf != um->b)
1200      {
1201 	msg_error ("Mark not in buffer.");
1202 	return 0;
1203      }
1204 
1205 
1206    m->line = CLine;
1207    m->point = Point;
1208    m->n = LineNum + CBuf->nup;
1209    return 1;
1210 }
1211 
1212 /*}}}*/
1213 
move_user_mark(void)1214 void move_user_mark (void) /*{{{*/
1215 {
1216    SLang_MMT_Type *mmt;
1217 
1218    if (NULL == (mmt = SLang_pop_mmt (JED_MARK_TYPE)))
1219      return;
1220 
1221    (void) jed_move_user_object_mark (mmt);
1222    SLang_free_mmt (mmt);
1223 }
1224 
1225 /*}}}*/
1226 
x_user_mark_fun(int (* xfun)(Mark *))1227 static int x_user_mark_fun (int (*xfun)(Mark *)) /*{{{*/
1228 {
1229    SLang_MMT_Type *mmt;
1230    User_Mark_Type *um;
1231    int ret = -1;
1232 
1233    if (NULL == (mmt = pop_valid_user_mark (&um)))
1234      return -1;
1235 
1236    if (CBuf != um->b) msg_error ("Mark not in buffer.");
1237    else
1238      ret = (*xfun) (&um->m);
1239 
1240    SLang_free_mmt (mmt);
1241    return ret;
1242 }
1243 
1244 /*}}}*/
1245 
1246 /* It is up to calling routine to ensure that mark is in buffer. */
is_mark_in_narrow(Mark * m)1247 static int is_mark_in_narrow (Mark *m)
1248 {
1249    return ((m->n > CBuf->nup)
1250 	   && (m->n <= CBuf->nup + Max_LineNum));
1251 }
1252 
jed_is_user_mark_in_narrow(void)1253 int jed_is_user_mark_in_narrow (void)
1254 {
1255    return x_user_mark_fun (is_mark_in_narrow);
1256 }
1257 
goto_user_mark(void)1258 void goto_user_mark (void)
1259 {
1260    (void) x_user_mark_fun (jed_goto_mark);
1261 }
1262 
jed_make_user_object_mark(void)1263 SLang_MMT_Type *jed_make_user_object_mark (void) /*{{{*/
1264 {
1265    User_Mark_Type *um;
1266    SLang_MMT_Type *mmt;
1267    Mark *m;
1268 
1269    if (NULL == (um = (User_Mark_Type *) jed_malloc0 (sizeof(User_Mark_Type))))
1270      return NULL;
1271 
1272    if (NULL == (mmt = SLang_create_mmt (JED_MARK_TYPE, (VOID_STAR) um)))
1273      {
1274 	SLfree ((char *) um);
1275 	return NULL;
1276      }
1277 
1278    m = &um->m;
1279 
1280    jed_init_mark (m, 0);
1281 
1282    m->next = CBuf->user_marks;
1283 
1284    CBuf->user_marks = m;
1285 
1286    um->b = CBuf;
1287 
1288    return mmt;
1289 }
1290 
1291 /*}}}*/
1292 
1293 
create_user_mark(void)1294 void create_user_mark (void) /*{{{*/
1295 {
1296    SLang_MMT_Type *mmt;
1297 
1298    if (NULL != (mmt = jed_make_user_object_mark ()))
1299      {
1300 	if (-1 == SLang_push_mmt (mmt))
1301 	  SLang_free_mmt (mmt);
1302      }
1303 }
1304 
1305 /*}}}*/
1306 
user_mark_buffer(void)1307 char *user_mark_buffer (void) /*{{{*/
1308 {
1309    SLang_MMT_Type *mmt;
1310    User_Mark_Type *um;
1311    char *s;
1312 
1313    if (NULL == (mmt = pop_valid_user_mark (&um)))
1314      return "";
1315 
1316    s = um->b->name;
1317 
1318    SLang_free_mmt (mmt);
1319    return s;
1320 }
1321 
1322 /*}}}*/
1323 
1324 static int
user_mark_bin_op_result(int op,SLtype a,SLtype b,SLtype * c)1325 user_mark_bin_op_result (int op, SLtype a, SLtype b,
1326 			 SLtype *c)
1327 {
1328    (void) a; (void) b;
1329    switch (op)
1330      {
1331       default:
1332 	return 0;
1333 
1334       case SLANG_GT:
1335       case SLANG_GE:
1336       case SLANG_LT:
1337       case SLANG_LE:
1338       case SLANG_EQ:
1339       case SLANG_NE:
1340 	*c = SLANG_INT_TYPE;
1341 	break;
1342      }
1343    return 1;
1344 }
1345 
1346 
1347 static int
user_mark_bin_op(int op,SLtype a_type,VOID_STAR ap,unsigned int na,SLtype b_type,VOID_STAR bp,unsigned int nb,VOID_STAR cp)1348 user_mark_bin_op (int op,
1349 		  SLtype a_type, VOID_STAR ap, unsigned int na,
1350 		  SLtype b_type, VOID_STAR bp, unsigned int nb,
1351 		  VOID_STAR cp)
1352 {
1353    int *ic;
1354    unsigned int n, n_max;
1355    unsigned int da, db;
1356    SLang_MMT_Type **a, **b;
1357 
1358    (void) a_type;
1359    (void) b_type;
1360 
1361    if (na == 1) da = 0; else da = 1;
1362    if (nb == 1) db = 0; else db = 1;
1363 
1364    if (na > nb) n_max = na; else n_max = nb;
1365 
1366    a = (SLang_MMT_Type **) ap;
1367    b = (SLang_MMT_Type **) bp;
1368 
1369    ic = (int *) cp;
1370 
1371    for (n = 0; n < n_max; n++)
1372      {
1373 	User_Mark_Type *ua, *ub;
1374 	Buffer *ba, *bb;
1375 	int pa, pb;
1376 	unsigned int la, lb;
1377 
1378 	ub = NULL;
1379 	ba = bb = NULL;
1380 	pa = pb = 0;
1381 	la = lb = 0;
1382 
1383 	if ((*a != NULL)
1384 	    && (NULL != (ua = (User_Mark_Type *) SLang_object_from_mmt (*a))))
1385 	  {
1386 	     la = ua->m.n;
1387 	     pa = ua->m.point;
1388 	     ba = ua->b;
1389 	  }
1390 
1391 	if ((*b != NULL)
1392 	    && (NULL != (ub = (User_Mark_Type *) SLang_object_from_mmt (*b))))
1393 	  {
1394 	     lb = ub->m.n;
1395 	     pb = ub->m.point;
1396 	     bb = ub->b;
1397 	  }
1398 
1399 	if ((ba == NULL) || (bb == NULL))
1400 	  {
1401 	     ic[n] = 0;
1402 	     a += da;
1403 	     b += db;
1404 	     continue;
1405 	  }
1406 
1407 	switch (op)
1408 	  {
1409 	   case SLANG_GT:
1410 	     ic[n] = ((la > lb)
1411 		      || ((la == lb) && (pa > pb)));
1412 	     break;
1413 
1414 	   case SLANG_GE:
1415 	     ic[n] = ((la > lb)
1416 		      || ((la == lb) && (pa >= pb)));
1417 	     break;
1418 
1419 	   case SLANG_LT:
1420 	     ic[n] = ((la < lb)
1421 		      || ((la == lb) && (pa < pb)));
1422 	     break;
1423 
1424 	   case SLANG_LE:
1425 	     ic[n] = ((la < lb)
1426 		      || ((la == lb) && (pa <= pb)));
1427 	     break;
1428 
1429 	   case SLANG_EQ:
1430 	     ic[n] = ((ba == bb) && (la == lb) && (pa == pb));
1431 	     break;
1432 
1433 	   case SLANG_NE:
1434 	     ic[n] = ((ba != bb) || (la != lb) || (pa != pb));
1435 	     break;
1436 
1437 	   default:
1438 	     return 0;
1439 	  }
1440 
1441 	a += da;
1442 	b += db;
1443      }
1444 
1445    return 1;
1446 }
1447 
1448 
1449 
1450 
1451 /*}}}*/
1452 
1453 #if JED_HAS_LINE_MARKS
jed_create_line_mark(int * color)1454 void jed_create_line_mark (int *color) /*{{{*/
1455 {
1456    SLang_MMT_Type *mmt;
1457    User_Mark_Type *um;
1458 
1459    if (NULL == (mmt = jed_make_user_object_mark ()))
1460      return;
1461 
1462    um = (User_Mark_Type *) SLang_object_from_mmt (mmt);
1463    um->m.flags |= JED_LINE_MARK | (*color & MARK_COLOR_MASK);
1464    if (-1 == SLang_push_mmt (mmt))
1465      SLang_free_mmt (mmt);
1466 }
1467 
1468 /*}}}*/
1469 #endif
1470 
1471 #ifndef SLFUTURE_CONST
1472 # define SLFUTURE_CONST
1473 #endif
1474 
user_mark_sget(SLtype type,SLFUTURE_CONST char * name)1475 static int user_mark_sget (SLtype type, SLFUTURE_CONST char *name)
1476 {
1477    SLang_MMT_Type *mmt;
1478    User_Mark_Type *um;
1479    int status;
1480    Buffer *buf;
1481 
1482    (void) type;
1483 
1484    if (NULL == (mmt = pop_valid_user_mark (&um)))
1485      return -1;
1486 
1487    buf = um->b;
1488 
1489    status = -1;
1490    if (0 == strcmp (name, "buffer_name"))
1491      status = SLang_push_string (buf->name);
1492    else
1493      SLang_verror (SL_NOT_IMPLEMENTED,
1494 		   "Mark_Type.%s is invalid", name);
1495 
1496    SLang_free_mmt (mmt);
1497    return status;
1498 }
1499 
1500 
register_jed_classes(void)1501 int register_jed_classes (void) /*{{{*/
1502 {
1503    SLang_Class_Type *cl;
1504 
1505    cl = SLclass_allocate_class ("Mark_Type");
1506    if (cl == NULL) return -1;
1507    (void) SLclass_set_destroy_function (cl, free_user_mark);
1508 
1509    (void) SLclass_set_sget_function (cl, user_mark_sget);
1510 
1511    if (-1 == SLclass_register_class (cl, JED_MARK_TYPE, sizeof (User_Mark_Type), SLANG_CLASS_TYPE_MMT))
1512      return -1;
1513 
1514    if (-1 == SLclass_add_binary_op (JED_MARK_TYPE, JED_MARK_TYPE, user_mark_bin_op, user_mark_bin_op_result))
1515      return -1;
1516 
1517    return 0;
1518 }
1519 
1520 /*}}}*/
1521 
jed_widen_whole_buffer(Buffer * b)1522 void jed_widen_whole_buffer (Buffer *b) /*{{{*/
1523 {
1524    while (b->narrow != NULL) widen_buffer (b);
1525 }
1526 
1527 /*}}}*/
1528 
1529 #if JED_HAS_SAVE_NARROW
restore_saved_narrow(void)1530 static void restore_saved_narrow (void) /*{{{*/
1531 {
1532    Mark *beg, *end;
1533 
1534    Jed_Save_Narrow_Type *save_narrow;
1535 
1536    if (NULL == (save_narrow = CBuf->save_narrow))
1537      return;
1538 
1539    push_spot ();
1540    /* remove current restriction */
1541    jed_widen_whole_buffer (CBuf);
1542 
1543    beg = save_narrow->beg;
1544    end = save_narrow->end;
1545 
1546    while (beg != NULL)
1547      {
1548 	jed_goto_mark (beg);
1549 	jed_push_mark ();
1550 	jed_goto_mark (end);
1551 	if (end->flags & NARROW_REGION_MARK)
1552 	  narrow_to_region ();
1553 	else narrow_to_lines ();
1554 
1555 	beg = beg->next;
1556 	end = end->next;
1557      }
1558    pop_spot ();
1559 }
1560 
1561 /*}}}*/
free_mark_chain(Mark * m)1562 static void free_mark_chain (Mark *m) /*{{{*/
1563 {
1564    Mark *next;
1565 
1566    while (m != NULL)
1567      {
1568 	next = m->next;
1569 	SLfree ((char *)m);
1570 	m = next;
1571      }
1572 }
1573 
1574 /*}}}*/
jed_free_saved_narrow(Buffer * b)1575 void jed_free_saved_narrow (Buffer *b) /*{{{*/
1576 {
1577    Jed_Save_Narrow_Type *save_narrow;
1578 
1579    save_narrow = b->save_narrow;
1580    if (save_narrow == NULL) return;
1581 
1582    b->save_narrow = save_narrow->next;
1583 
1584    free_mark_chain (save_narrow->beg);
1585    free_mark_chain (save_narrow->end);
1586    SLfree ((char *)save_narrow);
1587 }
1588 
1589 /*}}}*/
jed_push_narrow(void)1590 void jed_push_narrow (void) /*{{{*/
1591 {
1592    Jed_Save_Narrow_Type *save_narrow;
1593 
1594    if (NULL == (save_narrow = (Jed_Save_Narrow_Type *) jed_malloc0 (sizeof (Jed_Save_Narrow_Type))))
1595      {
1596 	exit_error ("push_narrow: malloc error.", 0);
1597      }
1598    save_narrow->beg = save_narrow->end = NULL;
1599    save_narrow->next = CBuf->save_narrow;
1600    CBuf->save_narrow = save_narrow;
1601 
1602    push_spot ();
1603    while (CBuf->narrow != NULL)
1604      {
1605 	Mark *m;
1606 
1607 	bob ();
1608 	m = create_mark (0);
1609 	m->next = save_narrow->beg;
1610 	save_narrow->beg = m;
1611 
1612 	eob ();
1613 	m = create_mark (CBuf->narrow->is_region ? NARROW_REGION_MARK : 0);
1614 	m->next = save_narrow->end;
1615 	save_narrow->end = m;
1616 
1617 	widen_buffer (CBuf);
1618      }
1619 
1620    restore_saved_narrow ();
1621 
1622    pop_spot ();
1623 }
1624 
1625 /*}}}*/
jed_pop_narrow(void)1626 void jed_pop_narrow (void) /*{{{*/
1627 {
1628    restore_saved_narrow ();
1629    jed_free_saved_narrow (CBuf);
1630 }
1631 
1632 /*}}}*/
1633 #endif
1634 
jed_count_narrows(void)1635 int jed_count_narrows (void) /*{{{*/
1636 {
1637    int n = 0;
1638    Narrow_Type *nt = CBuf->narrow;
1639 
1640    while (nt != NULL)
1641      {
1642 	n++;
1643 	nt = nt->next;
1644      }
1645    return n;
1646 }
1647 
1648 /*}}}*/
1649 
jed_count_lines_in_region(void)1650 unsigned int jed_count_lines_in_region (void)
1651 {
1652    Mark *m;
1653    unsigned int n0, n1;
1654 
1655    m = CBuf->marks;
1656    if (m == NULL)
1657      return 0;
1658 
1659    n0 = m->n - CBuf->nup;
1660    n1 = LineNum;
1661 
1662    if (n0 > n1)
1663      return 1 + (n0 - n1);
1664 
1665    return 1 + (n1 - n0);
1666 }
1667 
1668 
1669 
1670