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