1 /*======================================================================*\
2 |* Editor mined *|
3 |* Paste buffer handling *|
4 \*======================================================================*/
5
6 #include "mined.h"
7 #include "io.h" /* for flush, set_cursor, highlight_selection */
8 #include "textfile.h"
9 #include "charprop.h"
10
11 #include <errno.h>
12
13
14 /*======================================================================*\
15 |* System file link behaviour *|
16 \*======================================================================*/
17
18 #ifdef unix
19 #define linkyank
20 #endif
21
22 #ifdef __pcgcc__
23 #undef linkyank
24 #endif
25 #ifdef __MINGW32__
26 #undef linkyank
27 #endif
28 #ifdef __CYGWIN__
29 #define linkyank
30 #endif
31
32
33 /*======================================================================*\
34 |* Global variables *|
35 \*======================================================================*/
36
37 FLAG yank_status = NOT_VALID; /* Status of yank_file */
38 static FLAG html_status = NOT_VALID; /* Status of html_file */
39 static int yank_buf_no = 0; /* Buffer # for trials and multiple buffers */
40 static int max_yank_buf_no = 0; /* Max Buffer # used */
41
42 /* pasted area markers for "Paste previous" function */
43 static LINE * pasted_start_line = NIL_LINE;
44 static char * pasted_start_textp = NIL_PTR;
45 static LINE * pasted_end_line = NIL_LINE;
46 static char * pasted_end_textp = NIL_PTR;
47
48 int buffer_open_flag = 0; /* Counter flag for the collective buffer */
49
50 static FLAG highlight_selection = False;
51 static FLAG alt_rectangular_mode = False;
52 #define rectangular_paste_mode (rectangular_paste_flag != alt_rectangular_mode)
53
54 static int last_sel_x = 0; /* Last selection mouse column */
55
56
57 /*======================================================================*\
58 |* Marker stack *|
59 \*======================================================================*/
60
61 /* default marker */
62 static LINE * mark_line = NIL_LINE; /* For marking position. */
63 static char * mark_text = NIL_PTR;
64
65 /* explicit markers */
66 static struct {
67 LINE * line;
68 char * text;
69 } marker_n [] = {
70 {NIL_LINE, NIL_PTR},
71 {NIL_LINE, NIL_PTR},
72 {NIL_LINE, NIL_PTR},
73 {NIL_LINE, NIL_PTR},
74 {NIL_LINE, NIL_PTR},
75 {NIL_LINE, NIL_PTR},
76 {NIL_LINE, NIL_PTR},
77 {NIL_LINE, NIL_PTR},
78 {NIL_LINE, NIL_PTR},
79 {NIL_LINE, NIL_PTR},
80 {NIL_LINE, NIL_PTR},
81 {NIL_LINE, NIL_PTR},
82 {NIL_LINE, NIL_PTR},
83 {NIL_LINE, NIL_PTR},
84 {NIL_LINE, NIL_PTR},
85 {NIL_LINE, NIL_PTR},
86 };
87 #define maxmarkers arrlen (marker_n)
88
89 /* implicit marker stack */
90 static struct {
91 LINE * line;
92 char * text;
93 char * file;
94 int lineno;
95 int pos;
96 FLAG detectCR;
97 } mark_stack [] = {
98 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
99 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
100 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
101 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
102 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
103 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
104 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
105 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
106 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
107 {NIL_LINE, NIL_PTR, NIL_PTR, -1, -1, False},
108 };
109 #define markstacklen arrlen (mark_stack)
110 static int mark_stack_poi = 0;
111 static int mark_stack_top = 0;
112 static int mark_stack_bottom = 0;
113 static int mark_stack_count_top = 0;
114 static int mark_stack_count_poi = 0;
115
116 #define dont_debug_mark_stack
117
118 #ifdef debug_mark_stack
119 #define printf_mark_stack(s) printf ("%s - mark_stack [%d..%d(%d)] @ %d(%d)\n", s, mark_stack_bottom, mark_stack_top, mark_stack_count_top, mark_stack_poi, mark_stack_count_poi)
120 #define printf_debug_mark_stack(s) printf (s)
121 #else
122 #define printf_mark_stack(s)
123 #define printf_debug_mark_stack(s)
124 #endif
125
126
127 static
128 char *
copied_file_name()129 copied_file_name ()
130 {
131 int i;
132 char * dup;
133 char * filei;
134
135 /* check if file name already in stack */
136 for (i = 0; i < markstacklen; i ++) {
137 filei = mark_stack [i].file;
138 if (filei != NIL_PTR && streq (filei, file_name)) {
139 /* reuse the copy; note: it's not being freed ! */
140 return filei;
141 }
142 }
143
144 /* make a new copy of file name string */
145 dup = alloc (strlen (file_name) + 1);
146 if (dup != NIL_PTR) {
147 strcpy (dup, file_name);
148 }
149 return dup;
150 }
151
152 /*
153 Setmark sets the current position into the current slot of the mark stack.
154 */
155 static
156 FLAG
Setmark()157 Setmark ()
158 {
159 char * fn = copied_file_name ();
160 if (fn) {
161 mark_stack [mark_stack_poi].line = cur_line;
162 mark_stack [mark_stack_poi].text = cur_text;
163 mark_stack [mark_stack_poi].file = fn;
164 mark_stack [mark_stack_poi].lineno = line_number;
165 mark_stack [mark_stack_poi].pos = get_cur_pos ();
166 mark_stack [mark_stack_poi].detectCR = lineends_detectCR;
167
168 printf_mark_stack ("Filled");
169 return True;
170 } else {
171 return False;
172 }
173 }
174
175 /*
176 Pushmark pushes the current position to the mark stack.
177 */
178 void
Pushmark()179 Pushmark ()
180 {
181 /* truncate stack to current position */
182 mark_stack_top = mark_stack_poi;
183 mark_stack_count_top = mark_stack_count_poi;
184
185 /* fill data */
186 if (Setmark ()) {
187
188 /* increase top of stack */
189 mark_stack_top = (mark_stack_top + 1) % markstacklen;
190 /* leave 1 slot empty for Setmark called in Popmark */
191 if (mark_stack_count_top < markstacklen - 1) {
192 mark_stack_count_top ++;
193 } else {
194 mark_stack_bottom = (mark_stack_bottom + 1) % markstacklen;
195 }
196
197 /* set current position to new top of stack */
198 mark_stack_poi = mark_stack_top;
199 mark_stack_count_poi = mark_stack_count_top;
200
201 printf_mark_stack ("Pushed");
202 } else {
203 ring_bell ();
204
205 printf_mark_stack ("Not Pushed - no mem");
206 }
207 }
208
209 /*
210 Upmark moves one position up the stack (toward top).
211 */
212 void
Upmark()213 Upmark ()
214 {
215 hop_flag = 1;
216 Popmark ();
217 }
218
219 /*
220 Popmark moves one position down the stack (towards bottom).
221 */
222 void
Popmark()223 Popmark ()
224 {
225 FLAG switch_files;
226
227 if (hop_flag > 0) {
228 /* climb up stack towards top */
229 printf_mark_stack ("HOP Pop");
230 if (mark_stack_count_poi == mark_stack_count_top) {
231 printf_debug_mark_stack ("HOP Pop no more\n");
232 error ("No more stacked positions");
233 return;
234 }
235 /* adjust current position */
236 if (Setmark ()) {
237 mark_stack_poi = (mark_stack_poi + 1) % markstacklen;
238 mark_stack_count_poi ++;
239
240 printf_mark_stack ("Up:");
241 } else {
242 ring_bell ();
243
244 printf_mark_stack ("Not Up: - no mem");
245 }
246 } else {
247 /* climb down stack towards bottom */
248 if (mark_stack_count_poi == 0) {
249 printf_debug_mark_stack ("Pop no more\n");
250 error ("No more stacked positions");
251 return;
252 }
253 /* adjust current position */
254 if (Setmark ()) {
255 if (mark_stack_poi == 0) {
256 mark_stack_poi = markstacklen;
257 }
258 mark_stack_poi --;
259 mark_stack_count_poi --;
260
261 printf_mark_stack ("Dn:");
262 } else {
263 ring_bell ();
264
265 printf_mark_stack ("Not Dn: - no mem");
266 }
267 }
268
269 if (mark_stack [mark_stack_poi].file == NIL_PTR) {
270 printf_debug_mark_stack ("not valid\n");
271 error ("Stacked position not valid");
272 return;
273 }
274 switch_files = ! streq (mark_stack [mark_stack_poi].file, file_name);
275 if (switch_files ||
276 checkmark (mark_stack [mark_stack_poi].line,
277 mark_stack [mark_stack_poi].text) == NOT_VALID)
278 {
279 int mark_lineno;
280 LINE * open_line;
281
282 if (switch_files) {
283 lineends_detectCR = mark_stack [mark_stack_poi].detectCR;
284 if (save_text_load_file (mark_stack [mark_stack_poi].file) == ERRORS) {
285 return;
286 }
287 }
288
289 mark_lineno = mark_stack [mark_stack_poi].lineno - 1;
290 open_line = proceed (header->next, mark_lineno);
291 if (open_line == tail) {
292 EFILE ();
293 error ("Stacked position not present anymore");
294 } else {
295 int mark_col = mark_stack [mark_stack_poi].pos;
296 int cur_pos = 0;
297 char * cpoi;
298
299 move_to (0, find_y (open_line));
300 cpoi = cur_line->text;
301 while (* cpoi != '\n' && cur_pos < mark_col) {
302 advance_char (& cpoi);
303 cur_pos ++;
304 }
305 move_address (cpoi, y);
306 }
307 } else {
308 clear_highlight_selection ();
309
310 move_address (mark_stack [mark_stack_poi].text,
311 find_y (mark_stack [mark_stack_poi].line));
312 }
313 }
314
315
316 /*======================================================================*\
317 |* Basic Paste operations *|
318 \*======================================================================*/
319
320 /*
321 * Legal () checks if mark_text is still a valid pointer.
322 */
323 static
324 int
legal(mark_line,mark_text)325 legal (mark_line, mark_text)
326 register LINE * mark_line;
327 register char * mark_text;
328 {
329 register char * textp = mark_line->text;
330
331 /* Locate mark_text on mark_line */
332 while (textp != mark_text && * textp != '\0') {
333 textp ++;
334 }
335 return (* textp == '\0') ? ERRORS : FINE;
336 }
337
338 /*
339 * Check_mark () checks if mark_line and mark_text are still valid pointers.
340 * If they are it returns
341 * SMALLER if the marked position is before the current,
342 * BIGGER if it isn't or SAME if somebody didn't get the point.
343 * NOT_VALID is returned when mark_line and/or mark_text are no longer valid.
344 * Legal () checks if mark_text is valid on the mark_line.
345 */
346 FLAG
checkmark(mark_line,mark_text)347 checkmark (mark_line, mark_text)
348 LINE * mark_line;
349 char * mark_text;
350 {
351 LINE * lineup;
352 LINE * linedown;
353 FLAG do_continue;
354
355 if (mark_line == NIL_LINE || legal (mark_line, mark_text) == ERRORS) {
356 /* mark_text dangling (not pointing into mark_line) */
357 return NOT_VALID;
358 }
359
360 if (mark_line == cur_line) {
361 if (mark_text == cur_text) {
362 return SAME;
363 } else if (mark_text < cur_text) {
364 return SMALLER;
365 } else {
366 return BIGGER;
367 }
368 }
369
370 /* search for mark_line;
371 proceed from cur_line in both directions;
372 in case a large file is partially swapped out, this is more efficient
373 */
374 lineup = cur_line;
375 linedown = cur_line;
376 do {
377 do_continue = False;
378 if (lineup != header) {
379 lineup = lineup->prev;
380 if (lineup == mark_line) {
381 return SMALLER;
382 } else {
383 do_continue = True;
384 }
385 }
386 if (linedown != tail) {
387 linedown = linedown->next;
388 if (linedown == mark_line) {
389 return BIGGER;
390 } else {
391 do_continue = True;
392 }
393 }
394 } while (do_continue);
395 /* mark_line not found */
396 return NOT_VALID;
397
398 #ifdef old_impl
399 LINE * line;
400 FLAG cur_seen = False;
401
402 /* Special case: check is mark_line and cur_line are the same. */
403 if (mark_line == cur_line) {
404 if (mark_text == cur_text) {
405 /* Even same place */
406 return SAME;
407 }
408 if (legal (mark_line, mark_text) == ERRORS) {
409 /* mark_text dangling (not pointing into mark_line) */
410 return NOT_VALID;
411 }
412 if (mark_text < cur_text) {
413 return SMALLER;
414 } else {
415 return BIGGER;
416 }
417 }
418
419 /* Start looking for mark_line in the line structure */
420 for (line = header->next; line != tail; line = line->next) {
421 if (line == cur_line) {
422 cur_seen = True;
423 } else if (line == mark_line) {
424 break;
425 }
426 }
427
428 /* If we found mark_line (line != tail) check for legality of mark_text */
429 if (line == tail || legal (mark_line, mark_text) == ERRORS) {
430 return NOT_VALID;
431 }
432
433 /* cur_seen is True if cur_line is before mark_line */
434 if (cur_seen) {
435 return BIGGER;
436 } else {
437 return SMALLER;
438 }
439 #endif
440 }
441
442
443 /*======================================================================*\
444 |* Cumulative buffer handling *|
445 \*======================================================================*/
446
447 static
448 void
set_buffer_open(appending)449 set_buffer_open (appending)
450 FLAG appending;
451 {
452 #ifdef debug_ring_buffer
453 printf ("set_buffer_open %d\n", buffer_open_flag);
454 #endif
455 if (buffer_open_flag == 0 && (appending == False || yank_buf_no == 0)) {
456 yank_buf_no ++;
457 if (yank_buf_no > max_yank_buf_no) {
458 max_yank_buf_no = yank_buf_no;
459 }
460 yank_status = NOT_VALID;
461 #ifdef debug_ring_buffer
462 flags_changed = True;
463 #endif
464 }
465 buffer_open_flag = 2;
466 }
467
468 static
469 void
close_buffer()470 close_buffer ()
471 {
472 #ifdef debug_ring_buffer
473 if (buffer_open_flag > 0) {
474 flags_changed = True;
475 }
476 #endif
477 buffer_open_flag = 0;
478 }
479
480 static
481 void
revert_yank_buf()482 revert_yank_buf ()
483 {
484 yank_buf_no --;
485 if (yank_buf_no <= 0) {
486 yank_buf_no = max_yank_buf_no;
487 }
488 }
489
490
491 /*======================================================================*\
492 |* Yank text handling *|
493 \*======================================================================*/
494
495 #define dont_debug_rectangular_paste_area
496 #define dont_debug_sel
497 #define dont_debug_sel_text
498 #define dont_debug_rectangular_paste_insert
499
500 /*
501 Return text column position within line.
502 */
503 static
504 int
get_text_col(line,textp,with_shift)505 get_text_col (line, textp, with_shift)
506 LINE * line;
507 char * textp;
508 FLAG with_shift;
509 {
510 char * tp = line->text;
511 int col = 0;
512 if (with_shift) {
513 col = line->shift_count * SHIFT_SIZE;
514 }
515
516 while (tp != textp && * tp != '\n' && * tp != '\0') {
517 advance_char_scr (& tp, & col, line->text);
518 }
519 return col;
520 }
521
522 static
523 char *
text_at(line,colpoi,targcol)524 text_at (line, colpoi, targcol)
525 LINE * line;
526 int * colpoi;
527 int targcol;
528 {
529 char * cpoi = line->text;
530 char * prev_cpoi = cpoi;
531 int col = 0;
532 int prev_col = 0;
533 while (col <= targcol) {
534 prev_cpoi = cpoi;
535 prev_col = col;
536 if (* cpoi == '\n') {
537 break;
538 }
539 advance_char_scr (& cpoi, & col, line->text);
540 }
541 * colpoi = prev_col;
542 return prev_cpoi;
543 }
544
545 #ifdef debug_rectangular_paste_area
546 #define trace_cols(tag) printf ("(%s) %s->%d, %d\n", tag, line->text, start_col, end_col);
547 #else
548 #define trace_cols(tag)
549 #endif
550
551 /*
552 yank_text () puts copies text between start position and end position
553 into the buffer.
554 Parameters start_line/start_textp and end_line/end_textp
555 must be in the correct order!
556 Options:
557 - do_remove: cut
558 - do_rectangular_paste: rectangular area
559 The caller must check that the arguments to yank_text () are valid
560 and in the right order.
561 */
562 static
563 FLAG
yank_text(fd,buf_status,start_line,start_textp,end_line,end_textp,do_remove,appending,do_rectangular_paste,start_end_reversed)564 yank_text (fd, buf_status,
565 start_line, start_textp, end_line, end_textp,
566 do_remove, appending, do_rectangular_paste, start_end_reversed)
567 int fd;
568 FLAG * buf_status;
569 LINE * start_line;
570 char * start_textp;
571 LINE * end_line;
572 char * end_textp;
573 FLAG do_remove; /* == DELETE if text should be deleted */
574 FLAG appending; /* == True if text should is appended to yank buffer */
575 FLAG do_rectangular_paste;
576 FLAG start_end_reversed;
577 {
578 LINE * line = start_line;
579 char * textp = start_textp;
580 FLAG do_continue;
581 FLAG at_eol = False; /* end of rectangular area in line */
582 long chars_written = 0L; /* chars written to buffer this time */
583 long bytes_written = 0L; /* bytes written to buffer this time */
584 int lines_written = 0; /* lines written to buffer this time */
585 int return_len;
586
587 /* only used if do_rectangular_paste: (avoid -Wmaybe-uninitialized) */
588 char * line_startp = NIL_PTR; /* start of line text for area to delete */
589 int start_col = 0; /* left border of rectangular area */
590 int end_col = 0; /* right border of rectangular area */
591 int col = 0; /* measure rectangular area */
592
593 /* Check file to hold buffer */
594 if (fd == ERRORS) {
595 return ERRORS;
596 }
597
598 /* Inform about running operation (to be seen in case it takes long) */
599 if (appending) {
600 status_msg ("Appending text ...");
601 } else {
602 status_msg ("Saving text ...");
603 chars_saved = 0L;
604 bytes_saved = 0L;
605 lines_saved = 0;
606 }
607
608 /* Prepare */
609 if (do_rectangular_paste) {
610 /* check left and right block boundaries */
611 start_col = get_text_col (start_line, start_textp, False);
612 end_col = get_text_col (end_line, end_textp, False);
613 trace_cols ("...");
614
615 /* adapt column to actual mouse position */
616 if (start_end_reversed == REVERSE) {
617 if (last_sel_x > start_col) {
618 start_col = last_sel_x;
619 }
620 } else {
621 if (last_sel_x > end_col) {
622 end_col = last_sel_x;
623 }
624 }
625 /* fix right-to-left selection */
626 if (start_col > end_col) {
627 int dum = end_col;
628 end_col = start_col;
629 start_col = dum;
630 }
631 trace_cols ("r-to-l fix");
632 /* reject empty copy */
633 if (start_col == end_col) {
634 error ("Rectangular area empty");
635 return ERRORS;
636 }
637
638 line_startp = textp = text_at (line, & col, start_col);
639 do_continue = True;
640 } else {
641 chars_written = char_count (textp) - 1;
642 do_continue = textp != end_textp;
643 }
644
645 /* Keep writing chars until the end_location is reached. */
646 while (do_continue) {
647 if (* textp == '\n' || at_eol) {
648 if (! do_rectangular_paste && line == end_line) {
649 error ("Internal error: passed end of text to be copied");
650 (void) close (fd);
651 return ERRORS;
652 }
653
654 /* fill rectangular area */
655 if (do_rectangular_paste) {
656 if (col < start_col) {
657 col = start_col;
658 }
659 while (col < end_col) {
660 col ++;
661 if (writechar (fd, ' ') == ERRORS) {
662 error2 ("Write to buffer failed: ", serror ());
663 (void) close (fd);
664 return ERRORS;
665 }
666 }
667 }
668
669 /* handle different line ends */
670 pasting = True;
671 return_len = write_lineend (fd, line->return_type, False);
672 pasting = False;
673 if (return_len == ERRORS) {
674 error2 ("Write to buffer failed: ", serror ());
675 (void) close (fd);
676 return ERRORS;
677 }
678 lines_written ++;
679 if (line->return_type != lineend_NONE) {
680 chars_written ++;
681 }
682 bytes_written += return_len;
683
684 if (do_rectangular_paste) {
685 /* delete rectangular area part of line */
686 if (do_remove == DELETE && line_startp != textp) {
687 if (ERRORS == delete_text_only (line, line_startp, line, textp)) {
688 /* give time to read allocation error msg */
689 sleep (2);
690 }
691 /* refresh cursor position to keep it valid */
692 move_to (x, y);
693 }
694
695 /* move to the next line */
696 if (line == end_line) {
697 do_continue = False;
698 } else {
699 line = line->next;
700 line_startp = textp = text_at (line, & col, start_col);
701 at_eol = False;
702 }
703 } else {
704 line = line->next;
705 textp = line->text;
706
707 chars_written += char_count (textp) - 1;
708 }
709 } else {
710 if (pastebuf_utf8 && ! utf8_text) { /* write UTF-8 */
711 character unibuf [13];
712 char * up = (char *) unibuf;
713
714 /* get Unicode character */
715 unsigned long unichar = charvalue (textp);
716 if (cjk_text || mapped_text) {
717 unichar = lookup_encodedchar (unichar);
718 if (no_unichar (unichar)) {
719 unichar = '';
720 }
721 }
722
723 /* handle 2 char special case */
724 if (unichar >= 0x80000000) {
725 /* special encoding of 2 Unicode chars,
726 mapped from 1 CJK character */
727 up += utfencode (unichar & 0xFFFF, up);
728 unichar = (unichar >> 16) & 0x7FFF;
729 if (do_rectangular_paste) {
730 chars_written ++;
731 }
732 }
733 (void) utfencode (unichar, up);
734
735 /* write UTF-8 */
736 /* don't use write_line which might write UTF-16 ! */
737 up = (char *) unibuf;
738 while (* up != '\0') {
739 if (writechar (fd, * up) == ERRORS) {
740 error2 ("Write to buffer failed: ", serror ());
741 (void) close (fd);
742 return ERRORS;
743 }
744 up ++;
745 bytes_written ++;
746 }
747
748 /* move to the next character */
749 if (do_rectangular_paste) {
750 chars_written ++;
751 advance_char_scr (& textp, & col, line->text);
752 } else {
753 advance_char (& textp);
754 }
755 } else if (do_rectangular_paste) { /* write native char */
756 unsigned long thischar = charvalue (textp);
757 char * buf = encode_char (thischar);
758
759 /* write char code */
760 while (* buf) {
761 if (writechar (fd, * buf) == ERRORS) {
762 error2 ("Write to buffer failed: ", serror ());
763 (void) close (fd);
764 return ERRORS;
765 }
766 buf ++;
767 bytes_written ++;
768 }
769 /* move to the next character */
770 chars_written ++;
771 advance_char_scr (& textp, & col, line->text);
772 } else { /* write bytes transparently */
773 if (writechar (fd, * textp) == ERRORS) {
774 error2 ("Write to buffer failed: ", serror ());
775 (void) close (fd);
776 return ERRORS;
777 }
778 bytes_written ++;
779
780 /* move to the next byte */
781 textp ++;
782 }
783
784 if (do_rectangular_paste && col >= end_col) {
785 at_eol = True;
786 }
787 }
788 if (! do_rectangular_paste && textp == end_textp) {
789 do_continue = False;
790 }
791 }
792
793 /* Final fix */
794 if (! do_rectangular_paste) {
795 chars_written -= char_count (end_textp) - 1;
796 }
797
798 /* After rectangular cut: update screen */
799 if (do_remove == DELETE && do_rectangular_paste) {
800 int top_y, bottom_y;
801 if (end_line == cur_line) {
802 LINE * line;
803 bottom_y = y;
804 top_y = y - lines_written + 1;
805 if (top_y < 0) {
806 top_y = 0;
807 }
808 line = proceed (top_line, top_y);
809 display (top_y, line, bottom_y - top_y, y);
810 } else {
811 top_y = y;
812 bottom_y = y + lines_written - 1;
813 if (bottom_y > last_y) {
814 bottom_y = last_y;
815 }
816 display (y, cur_line, bottom_y - top_y, y);
817 }
818 /* Fix position:
819 avoid leaving the cursor aside the delection area;
820 go to upper left corner of deleted block */
821 move_to (LINE_START, find_y (start_line)); /* unshift line */
822 move_to (start_col, y);
823 }
824
825 /* Flush the I/O buffer and close file */
826 if (flush_filebuf (fd) == ERRORS) {
827 error2 ("Write to buffer failed: ", serror ());
828 (void) close (fd);
829 return ERRORS;
830 }
831 if (close (fd) < 0) {
832 error2 ("Write to buffer failed: ", serror ());
833 return ERRORS;
834 }
835 * buf_status = VALID;
836
837
838 /*
839 * Check if the text should be deleted as well. In case it should,
840 * the following hack is used to save a lot of code.
841 * First move back to the start_position (this might be the current
842 * location) and then delete the text.
843 * delete_text () will fix the screen.
844 */
845 if (do_remove == DELETE && ! do_rectangular_paste) {
846 move_to (find_x (start_line, start_textp), find_y (start_line));
847 if (delete_text (start_line, start_textp, end_line, end_textp)
848 == ERRORS) {
849 sleep (2) /* give time to read allocation error msg */;
850 }
851 mark_line = cur_line;
852 mark_text = cur_text;
853 }
854
855 bytes_saved += bytes_written;
856 chars_saved += chars_written;
857 lines_saved += lines_written;
858
859 build_string (text_buffer, "%s %s: lines %d chars %ld (bytes %ld) - Paste with %s/Insert",
860 (do_remove == DELETE) ?
861 appending ? "Cut/appended" : "Cut/moved"
862 : appending ? "Appended" : "Copied",
863 do_rectangular_paste ? "rectangular area" : "paste buffer",
864 lines_written,
865 chars_written,
866 bytes_written,
867 emulation == 'e' ? "^Y" /* emacs yank */
868 : emulation == 's' ? "^K^C" /* WordStar block copy */
869 : emulation == 'p' ? "^U" /* pico uncut */
870 : emulation == 'w' ? "^V" /* Windows paste */
871 : "^P" /* mined paste */
872 );
873 status_uni (text_buffer);
874 return FINE;
875 }
876
877
878 /**
879 Variation of delete_text ().
880 Optionally handles the emacs ring buffer.
881 Parameters start_line/start_textp and end_line/end_textp
882 must be in the correct order!
883 */
884 void
delete_text_buf(start_line,start_textp,end_line,end_textp)885 delete_text_buf (start_line, start_textp, end_line, end_textp)
886 LINE * start_line;
887 char * start_textp;
888 LINE * end_line;
889 char * end_textp;
890 {
891 if (emacs_buffer) {
892 set_buffer_open (False);
893 (void)
894 yank_text (yankfile (WRITE, True), & yank_status,
895 start_line, start_textp, end_line, end_textp,
896 DELETE, True, False, FORWARD);
897 } else {
898 (void) delete_text (start_line, start_textp, end_line, end_textp);
899 }
900 }
901
902
903 /*======================================================================*\
904 |* Yank file reading *|
905 \*======================================================================*/
906
907 /**
908 get_pasteline calls get_line and converts from Unicode if desired
909 */
910 static
911 int
get_pasteline(fd,buffer,len)912 get_pasteline (fd, buffer, len)
913 int fd;
914 char buffer [maxLINElen];
915 int * len;
916 {
917 int ret;
918 pasting = True;
919 ret = get_line (fd, buffer, len, False);
920 pasting = False;
921
922 if (ret == NO_INPUT || ret == ERRORS) {
923 return ret;
924 }
925
926 if (utf8_text || ! pastebuf_utf8) {
927 return ret;
928 } else {
929 char nativebuf [2 * maxLINElen];
930 char * poi = buffer;
931 char * npoi = nativebuf;
932 unsigned long prev_uc = 0;
933 char * prev_npoi = npoi;
934
935 while (* poi) {
936 int ulen = UTF8_len (* poi);
937 unsigned long uc = utf8value (poi);
938 char * ppoi = poi;
939
940 advance_utf8 (& poi);
941 if (ppoi + ulen != poi || (* ppoi & 0xC0) == 0x80) {
942 /* illegal UTF-8 value */
943 * npoi ++ = '';
944 prev_uc = 0;
945 } else if (cjk_text || mapped_text) {
946 unsigned long nc = encodedchar2 (prev_uc, uc);
947 if (no_char (nc)) {
948 nc = encodedchar (uc);
949 } else {
950 npoi = prev_npoi;
951 }
952
953 prev_uc = uc;
954 prev_npoi = npoi;
955
956 if (no_char (nc)) {
957 /* character not known in current encoding */
958 * npoi ++ = '';
959 } else if (cjk_text) {
960 int cjklen = cjkencode (nc, npoi);
961 npoi += cjklen;
962 } else {
963 * npoi ++ = (character) nc;
964 }
965 } else {
966 if (uc >= 0x100) {
967 /* character not known in current encoding */
968 * npoi ++ = '';
969 } else {
970 * npoi ++ = (character) uc;
971 }
972 }
973 }
974 * npoi = '\0';
975
976 * len = strlen (nativebuf);
977 if (* len >= maxLINElen) {
978 error ("Line too long in current encoding");
979 return ERRORS;
980 } else {
981 strcpy (buffer, nativebuf);
982 return ret;
983 }
984 }
985 }
986
987
988 #ifdef debug_rectangular_paste_insert
989 static
990 void
print_str(s)991 print_str (s)
992 char * s;
993 {
994 if (! s) {
995 printf ("(null)");
996 return;
997 }
998 printf ("\"");
999 while (* s) {
1000 if (* s == '\n') {
1001 printf ("\\n");
1002 } else if (* s == '"') {
1003 printf ("\\\"");
1004 } else {
1005 printf ("%c", * s);
1006 }
1007 s ++;
1008 }
1009 printf ("\"");
1010 }
1011
1012 static
1013 char *
line_spec(line)1014 line_spec (line)
1015 LINE * line;
1016 {
1017 if (line == tail) {
1018 return "tail";
1019 } else if (line == header) {
1020 return "head";
1021 } else {
1022 return " ";
1023 }
1024 }
1025
1026 static
1027 void
trace_line(tag,line)1028 trace_line (tag, line)
1029 char * tag;
1030 LINE * line;
1031 {
1032 printf ("[%s-1] %s ", tag, line_spec (line->prev)); print_str (line->prev->text); printf ("\n");
1033 printf ("[%s ] %s [1m", tag, line_spec (line)); print_str (line->text); printf ("[0m\n");
1034 printf ("[%s+1] %s ", tag, line_spec (line->next)); print_str (line->next->text); printf ("\n");
1035 }
1036 #define trace_rectangular_paste(args) printf args
1037 #else
1038 #define trace_line(tag, line)
1039 #define trace_rectangular_paste(args)
1040 #endif
1041
1042 /*
1043 * paste_file () inserts the contents of an opened file (as given by
1044 filedescriptor fd) at the current location.
1045 Call insert_file () only via paste_file ().
1046 If the rectangular_paste_mode is True, a rectangular area will
1047 be inserted, proceeding line by line.
1048 After the insertion, if stay_old_pos is True, the cursor remains at the
1049 start of the inserted text, if stay_old_pos is False, it is placed to
1050 its end.
1051 */
1052 static
1053 void
insert_file(fd,stay_old_pos,from_text_file)1054 insert_file (fd, stay_old_pos, from_text_file)
1055 int fd;
1056 FLAG stay_old_pos;
1057 FLAG from_text_file; /* consider UTF-16 ? */
1058 {
1059 char line_buffer [maxLINElen]; /* buffer for next line to insert */
1060 LINE * line = cur_line;
1061 int line_count = total_lines; /* determine # lines inserted */
1062 LINE * page = cur_line;
1063 int ret;
1064 int len;
1065 lineend_type return_type;
1066 /* copy rectangular option; this working flag will be reset at end-of-file */
1067 FLAG do_rectangular_paste = rectangular_paste_mode;
1068 int paste_col = get_cur_col (); /* for rectangular paste */
1069
1070 reset_get_line (from_text_file);
1071 trace_rectangular_paste (("-------------------------------------------\n"));
1072
1073 pasted_end_line = NIL_LINE;
1074
1075 /* Get the first line of text (might be ended with a '\n') */
1076 ret = get_pasteline (fd, line_buffer, & len);
1077 if (ret == NO_INPUT) {
1078 /* empty file */
1079 return;
1080 } else if (ret == ERRORS) {
1081 /* sleep; "0 lines" error message? - no, nothing inserted */
1082 return;
1083 }
1084
1085 /* Adjust line end type if present */
1086 if (ret == SPLIT_LINE) {
1087 return_type = lineend_NONE;
1088 } else if (ret == NUL_LINE) {
1089 return_type = lineend_NUL;
1090 } else if (ret != NO_LINE) {
1091 return_type = got_lineend;
1092 } else {
1093 return_type = cur_line->return_type;
1094 }
1095
1096 /* Insert this text at the current location */
1097 len = cur_text - cur_line->text;
1098 if (do_rectangular_paste) {
1099 /* strip final newline */
1100 char * nl = strchr (line_buffer, '\n');
1101 if (nl) {
1102 * nl = '\0';
1103 }
1104 }
1105 trace_line ("first<", line);
1106 trace_rectangular_paste (("insert <%s>\n", line_buffer));
1107 if (insert_text (line, cur_text, line_buffer) == ERRORS) {
1108 /* "Out of memory" error already shown, nothing inserted
1109 sleep (2);
1110 ring_bell ();
1111 error ("Partial line inserted");
1112 */
1113 return;
1114 }
1115 trace_line ("first>", line);
1116 if (! do_rectangular_paste) {
1117 cur_line->return_type = return_type;
1118 }
1119
1120 pasted_end_line = line;
1121 pasted_end_textp = line->text + len + length_of (line_buffer);
1122
1123
1124 /* Repeat getting lines (and inserting lines) until EOF is reached */
1125 while (ret != ERRORS /*line != NIL_LINE*/
1126 && (ret = get_pasteline (fd, line_buffer, & len)) != ERRORS
1127 /* NO_LINE (line without newline) is handled separately
1128 unless in rectangular paste mode */
1129 && ret != NO_INPUT
1130 && (ret != NO_LINE || do_rectangular_paste)
1131 )
1132 {
1133 /* at end of text, switch to normal paste mode */
1134 if (line != NIL_LINE && line->next == tail) {
1135 #ifdef switch_to_normal_at_eof
1136 trace_rectangular_paste (("switching to normal\n"));
1137 do_rectangular_paste = False;
1138 #endif
1139 #ifdef handle_last_line_separately
1140 /* NO_LINE (line without newline) is handled separately */
1141 if (ret == NO_LINE) {
1142 trace_rectangular_paste (("NO_LINE -> break\n"));
1143 break;
1144 }
1145 #endif
1146 }
1147
1148 if (do_rectangular_paste) {
1149 char * inspoi;
1150 int inscol = 0;
1151 char * nl;
1152
1153 if (line->next == tail) {
1154 LINE * new_line = line_insert_after (line, "\n", 1, line->return_type);
1155 if (new_line == NIL_LINE) {
1156 ring_bell ();
1157 status_fmt2 ("Out of memory - ", "Insertion failed");
1158 ret = ERRORS;
1159 break;
1160 } else {
1161 line = new_line;
1162 }
1163 line = line->prev;
1164 trace_rectangular_paste (("EOF: append line\n"));
1165 trace_line ("eof++", line);
1166 }
1167
1168 line = line->next;
1169 trace_rectangular_paste (("line = line->next\n"));
1170 trace_line ("next", line);
1171 if (line == tail) {
1172 break; /* cannot occur; prevented above */
1173 }
1174 /* strip final newline */
1175 nl = strchr (line_buffer, '\n');
1176 if (nl) {
1177 * nl = '\0';
1178 }
1179 inspoi = line->text;
1180 while (inscol < paste_col && * inspoi != '\n' && * inspoi != '\0') {
1181 advance_char_scr (& inspoi, & inscol, line->text);
1182 }
1183
1184 if (inscol < paste_col) {
1185 /* fill short line up to paste column */
1186 char fill_buffer [2 * maxLINElen];
1187 char * fill_poi = fill_buffer;
1188
1189 char * reftext = line->prev->text;
1190 int refcol = 0;
1191 char * refprev = "";
1192
1193 /* append space, take from ref line if possible */
1194 while (inscol < paste_col) {
1195 unsigned long ch;
1196 unsigned long unich;
1197
1198 /* look up end of insert position in ref line */
1199 while (refcol <= inscol) {
1200 refprev = reftext;
1201 advance_char_scr (& reftext, & refcol, line->prev->text);
1202 }
1203 /* check ref char advancing position */
1204 ch = charvalue (refprev);
1205 unich = unicode (ch);
1206 /* use ideographic space for double width */
1207 if (unich != 0x3000 && iswide (unich)
1208 && (utf8_text || cjk_text)
1209 ) {
1210 unich = 0x3000;
1211 ch = encodedchar (unich);
1212 }
1213
1214 if (unich == '\t') {
1215 if (tab (inscol) <= paste_col) {
1216 * fill_poi ++ = '\t';
1217 inscol = tab (inscol);
1218 } else {
1219 * fill_poi ++ = ' ';
1220 inscol ++;
1221 }
1222 } else if (iswhitespace (unich)) {
1223 int w = 1;
1224 if (iswide (unich)) {
1225 w = 2;
1226 } else if (iscombining (unich)) {
1227 w = 0;
1228 }
1229 if (w > 0 && inscol + 2 <= paste_col) {
1230 /* clone space character */
1231 char * ec = encode_char (ch);
1232 while (* ec) {
1233 * fill_poi ++ = * ec ++;
1234 }
1235 inscol += w;
1236 } else {
1237 * fill_poi ++ = ' ';
1238 inscol ++;
1239 }
1240 } else {
1241 * fill_poi ++ = ' ';
1242 inscol ++;
1243 }
1244 * fill_poi = '\0';
1245 }
1246
1247 /* append fill buffer */
1248 trace_rectangular_paste (("fill <%s>\n", fill_buffer));
1249 if (insert_text (line, inspoi, fill_buffer) == ERRORS) {
1250 ret = ERRORS;
1251 break;
1252 }
1253 trace_line ("fill>", line);
1254 /* adjust insert pointer */
1255 inscol = 0;
1256 inspoi = line->text;
1257 while (inscol < paste_col && * inspoi != '\n' && * inspoi != '\0') {
1258 advance_char_scr (& inspoi, & inscol, line->text);
1259 }
1260 }
1261
1262 len = inspoi - line->text;
1263 trace_rectangular_paste (("insert_text <%s>\n", line_buffer));
1264 if (insert_text (line, inspoi, line_buffer) == ERRORS) {
1265 ret = ERRORS;
1266 break;
1267 }
1268 trace_line ("insert", line);
1269 pasted_end_line = line;
1270 pasted_end_textp = line->text + len + length_of (line_buffer);
1271 } else {
1272 LINE * new_line;
1273 if (ret == SPLIT_LINE) {
1274 return_type = lineend_NONE;
1275 } else if (ret == NUL_LINE) {
1276 return_type = lineend_NUL;
1277 } else {
1278 return_type = got_lineend;
1279 }
1280 trace_rectangular_paste (("line_insert <%s>\n", line_buffer));
1281 new_line = line_insert_after (line, line_buffer, len, return_type);
1282 if (new_line == NIL_LINE) {
1283 ring_bell ();
1284 status_fmt2 ("Out of memory - ", "Insertion failed");
1285 ret = ERRORS;
1286 break;
1287 } else {
1288 line = new_line;
1289 }
1290 trace_line ("insert", line);
1291 }
1292 }
1293
1294 (void) close (fd);
1295
1296 /* Calculate nr of lines added */
1297 line_count = total_lines - line_count;
1298
1299 /* finish pasting, check last line */
1300 if (ret == ERRORS /* || line == NIL_LINE*/) {
1301 pasted_end_line = NIL_LINE;
1302 /* show memory allocation error msg */
1303 sleep (2);
1304 } else if (ret == NO_LINE && ! do_rectangular_paste) {
1305 /* Last line read not ended by a '\n' */
1306 if (line->next == tail) { /* after do_rectangular_paste */
1307 LINE * new_line = line_insert_after (line, "\n", 1, line->return_type);
1308 if (new_line == NIL_LINE) {
1309 /* cannot append empty line; ignore */
1310 }
1311 trace_rectangular_paste (("NO_LINE: append line\n"));
1312 trace_line ("eof++", line);
1313 }
1314 line = line->next;
1315 trace_rectangular_paste (("NO_LINE: line = line->next\n"));
1316 trace_line ("next(eof)", line);
1317 trace_rectangular_paste (("insert_text <%s>\n", line_buffer));
1318 if (insert_text (line, line->text, line_buffer) == ERRORS) {
1319 pasted_end_line = NIL_LINE;
1320 /* give time to read error msg */
1321 sleep (2);
1322 } else {
1323 pasted_end_line = line;
1324 pasted_end_textp = line->text + length_of (line_buffer);
1325 }
1326 } else if (line_count > 0 && ! rectangular_paste_mode) {
1327 pasted_end_line = line->next;
1328 pasted_end_textp = line->next->text;
1329 trace_line ("pasted_end", pasted_end_line);
1330 }
1331
1332 /* report get_line errors */
1333 show_get_l_errors ();
1334
1335 /* rescue post-error situation */
1336 if (ret == ERRORS) {
1337 pasted_end_textp = line->text;
1338 }
1339
1340 /* Update the screen */
1341 if (line_count == 0 && ! rectangular_paste_mode) {
1342 /* Only one line changed */
1343 print_line (y, line);
1344
1345 move_to (x, y);
1346 pasted_start_line = cur_line;
1347 pasted_start_textp = cur_text;
1348 if (stay_old_pos == False) {
1349 move_address (pasted_end_textp, y);
1350 }
1351 } else {
1352 /* Several lines changed, or rectangular paste */
1353 reset (top_line, y); /* Reset pointers */
1354 while (page != line && page != bot_line->next) {
1355 page = page->next;
1356 }
1357 if (page != bot_line->next || stay_old_pos) {
1358 display (y, cur_line, SCREENMAX - y, y);
1359 /* screen display style parameter (last) may be inaccurate */
1360 }
1361
1362 move_to (x, y);
1363 pasted_start_line = cur_line;
1364 pasted_start_textp = cur_text;
1365 if (stay_old_pos == False) {
1366 if (ret == NO_LINE) {
1367 move_address (pasted_end_textp, find_y (line));
1368 } else {
1369 if (do_rectangular_paste) {
1370 trace_line ("end", line);
1371 trace_line ("cur", cur_line);
1372 move_address (pasted_end_textp, find_y (line));
1373 trace_line ("fin", cur_line);
1374 } else {
1375 move_to (0, find_y (line->next));
1376 }
1377 }
1378 }
1379 }
1380
1381 /* If number of added lines >= REPORT_CHANGED_LINES, print the count */
1382 if (ret == ERRORS || line_count >= REPORT_CHANGED_LINES) {
1383 if (ret == ERRORS) {
1384 ring_bell ();
1385 }
1386 status_line (dec_out ((long) line_count), " lines added");
1387 }
1388 }
1389
1390 static
1391 void
paste_file(fd,stay_old_pos,from_text_file)1392 paste_file (fd, stay_old_pos, from_text_file)
1393 int fd;
1394 FLAG stay_old_pos;
1395 FLAG from_text_file; /* consider UTF-16 ? */
1396 {
1397 clear_highlight_selection ();
1398
1399 /* workaround to avoid side effects of reset_get_line:
1400 avoid spoiling UTF-16 information while pasting
1401 */
1402 save_text_info ();
1403
1404 insert_file (fd, stay_old_pos, from_text_file);
1405
1406 /* restore side effects of reset_get_line */
1407 restore_text_info ();
1408 }
1409
1410
1411 /**
1412 Insert the buffer at the current location.
1413 @param old_pos
1414 True: cursor stays @ insert position before inserted text
1415 False: cursor moves behind inserted text
1416 */
1417 static
1418 void
paste_buffer(old_pos,use_clipboard)1419 paste_buffer (old_pos, use_clipboard)
1420 FLAG old_pos;
1421 FLAG use_clipboard;
1422 {
1423 register int fd; /* File descriptor for buffer */
1424 FLAG save_lineends_CRLFtoLF = lineends_CRLFtoLF;
1425
1426 if (dont_modify ()) {
1427 return;
1428 }
1429
1430 #ifdef __CYGWIN__
1431 if (use_clipboard) {
1432 if ((fd = open ("/dev/clipboard", O_RDONLY | O_BINARY, 0)) < 0) {
1433 error ("Cannot access clipboard");
1434 return;
1435 }
1436 status_uni ("Pasting from Windows clipboard");
1437 if (cur_line->return_type == lineend_LF) {
1438 lineends_CRLFtoLF = True; /* temporary, reset below */
1439 }
1440 } else
1441 #endif
1442 if (use_clipboard || hop_flag > 0) {
1443 if ((fd = open (yankie_file, O_RDONLY | O_BINARY, 0)) < 0) {
1444 error ("No inter window buffer present");
1445 return;
1446 }
1447 status_uni ("Pasting from cross-session buffer");
1448 } else {
1449 if ((fd = yankfile (READ, False)) == ERRORS) {
1450 int e = geterrno ();
1451 if (e == 0 || e == ENOENT /* cygwin */) {
1452 status_uni ("Buffer is empty - type F1 k for help on copy/paste");
1453 } else {
1454 error2 ("Cannot read paste buffer: ", serror ());
1455 }
1456 return;
1457 }
1458 status_uni ("Pasting");
1459 if (append_flag) {
1460 close_buffer ();
1461 }
1462 }
1463 /* Insert the buffer */
1464 paste_file (fd, old_pos, False);
1465
1466 lineends_CRLFtoLF = save_lineends_CRLFtoLF;
1467 }
1468
1469
1470 /*======================================================================*\
1471 |* Paste buffer file setup *|
1472 \*======================================================================*/
1473
1474 /*
1475 * scratchfile/yankfile () tries to create a unique file in a temporary directory.
1476 * It tries several different filenames until one can be created
1477 * or MAXTRIALS attempts have been made.
1478 * After MAXTRIALS times, an error message is given and ERRORS is returned.
1479 */
1480
1481 #define MAXTRIALS 99
1482
1483 static
1484 void
set_yank_file_name(buf_name,which,no)1485 set_yank_file_name (buf_name, which, no)
1486 char * buf_name;
1487 char * which;
1488 int no;
1489 {
1490 #ifdef msdos
1491 build_string (buf_name, "%s-%s.%d", yankie_file, which, no);
1492 #else
1493 build_string (buf_name, "%s_%s.%d_%d", yankie_file, which, (int) getpid (), no);
1494 #endif
1495 }
1496
1497 /*
1498 * Delete yank file if there is one.
1499 */
1500 void
delete_yank_files()1501 delete_yank_files ()
1502 {
1503 /* if (yank_status == VALID) {
1504 (void) delete_file (yank_file);
1505 }
1506 */
1507 while (max_yank_buf_no > 0) {
1508 set_yank_file_name (yank_file, "buf", max_yank_buf_no);
1509 (void) delete_file (yank_file);
1510 max_yank_buf_no --;
1511 }
1512
1513 if (html_status == VALID) {
1514 (void) delete_file (html_file);
1515 }
1516 }
1517
1518 static
1519 int
scratchfile(mode,append,buf_name,which,buf_status)1520 scratchfile (mode, append, buf_name, which, buf_status)
1521 FLAG mode; /* Can be READ or WRITE permission */
1522 FLAG append; /* == True if text should only be appended to yank buffer */
1523 char * buf_name;
1524 char * which;
1525 FLAG * buf_status;
1526 {
1527 int fd = 0; /* Filedescriptor to buffer */
1528
1529 set_yank_file_name (buf_name, which, yank_buf_no);
1530
1531 /* If * buf_status == NOT_VALID, scratchfile is called for the first time */
1532 if (* buf_status == NOT_VALID && mode == WRITE) { /* Create new file */
1533 /* Generate file name. */
1534 /*set_yank_file_name (buf_name, which, yank_buf_no);*/
1535 /* Check file existence */
1536 if (access (buf_name, F_OK) == 0
1537 || (
1538 fd = open (buf_name, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, bufprot)
1539 ) < 0)
1540 {
1541 if (++ yank_buf_no >= MAXTRIALS) {
1542 if (fd == 0) {
1543 error2 ("Cannot create buffer file: " /* , buf_name */, "File exists");
1544 } else {
1545 error2 ("Cannot create buffer file: " /* , buf_name */, serror ());
1546 }
1547 return ERRORS;
1548 } else { /* try again */
1549 return scratchfile (mode, append, buf_name, which, buf_status);
1550 }
1551 }
1552 }
1553 else if (* buf_status == NOT_VALID && mode == READ) {
1554 errno = 0;
1555 return ERRORS;
1556 }
1557 else /* * buf_status == VALID */
1558 if ( (mode == READ && (fd = open (buf_name, O_RDONLY | O_BINARY, 0)) < 0)
1559 || (mode == WRITE &&
1560 (fd = open (buf_name, O_WRONLY | O_CREAT
1561 | (append ? O_APPEND : O_TRUNC)
1562 | O_BINARY
1563 , bufprot)) < 0))
1564 {
1565 * buf_status = NOT_VALID;
1566 return ERRORS;
1567 }
1568
1569 clear_filebuf ();
1570 return fd;
1571 }
1572
1573 int
yankfile(mode,append)1574 yankfile (mode, append)
1575 FLAG mode; /* Can be READ or WRITE permission */
1576 FLAG append; /* == True if text should only be appended to yank buffer */
1577 {
1578 return scratchfile (mode, append, yank_file, "buf", & yank_status);
1579 }
1580
1581 static
1582 int
htmlfile(mode,append)1583 htmlfile (mode, append)
1584 FLAG mode; /* Can be READ or WRITE permission */
1585 FLAG append; /* == True if text should only be appended to yank buffer */
1586 {
1587 return scratchfile (mode, append, html_file, "tag", & html_status);
1588 }
1589
1590
1591 /*======================================================================*\
1592 |* Copy/Paste and Marker handling *|
1593 \*======================================================================*/
1594
1595 void
PASTEEXT()1596 PASTEEXT ()
1597 {
1598 if (hop_flag) { /* paste from clipboard */
1599 hop_flag = 0;
1600 paste_buffer (paste_stay_left, True);
1601 } else { /* paste from other mined session */
1602 hop_flag = 1;
1603 paste_buffer (paste_stay_left, False);
1604 }
1605 }
1606
1607 void
PASTE()1608 PASTE ()
1609 {
1610 FLAG use_clipboard = (keyshift & shift_mask) || (hop_flag && (keyshift & alt_mask));
1611 paste_buffer (paste_stay_left, use_clipboard);
1612 }
1613
1614 void
PASTEstay()1615 PASTEstay ()
1616 {
1617 FLAG use_clipboard = (keyshift & shift_mask) || (hop_flag && (keyshift & alt_mask));
1618 paste_buffer (True, use_clipboard);
1619 }
1620
1621 void
YANKRING()1622 YANKRING ()
1623 {
1624 FLAG check = checkmark (pasted_start_line, pasted_start_textp);
1625
1626 if (cur_line == pasted_end_line && cur_text == pasted_end_textp
1627 && check == SMALLER)
1628 {
1629 move_address (pasted_start_textp, find_y (pasted_start_line));
1630 if (delete_text (pasted_start_line, pasted_start_textp, pasted_end_line, pasted_end_textp)
1631 == ERRORS) {
1632 sleep (2) /* give time to read allocation error msg */;
1633 } else {
1634 /* for some mysterious reason,
1635 this is needed to fix the display: */
1636 clear_status ();
1637
1638 revert_yank_buf ();
1639 paste_buffer (False, False);
1640 }
1641 } else if (cur_line == pasted_start_line && cur_text == pasted_start_textp
1642 && check == SAME)
1643 {
1644 if (delete_text (pasted_start_line, pasted_start_textp, pasted_end_line, pasted_end_textp)
1645 == ERRORS) {
1646 sleep (2) /* give time to read allocation error msg */;
1647 } else {
1648 /* for some mysterious reason,
1649 this is needed to fix the display: */
1650 clear_status ();
1651
1652 revert_yank_buf ();
1653 paste_buffer (True, False);
1654 }
1655 } else {
1656 error ("No previous paste to exchange");
1657 }
1658 }
1659
1660 /*
1661 * paste_HTML () inserts the HTML embedding buffer at the current location.
1662 */
1663 void
paste_HTML()1664 paste_HTML ()
1665 {
1666 int fd; /* File descriptor for buffer */
1667
1668 if (dont_modify ()) {
1669 return;
1670 }
1671
1672 if ((fd = open (html_file, O_RDONLY | O_BINARY, 0)) < 0) {
1673 error ("HTML paste buffer vanished");
1674 return;
1675 }
1676 paste_file (fd, False, False);
1677 }
1678
1679 /*
1680 * INSFILE () prompts for a filename and inserts the file at the current
1681 * location in the file.
1682 */
1683 void
INSFILE()1684 INSFILE ()
1685 {
1686 register int fd; /* File descriptor of file */
1687 char name [maxFILENAMElen]; /* Buffer for file name */
1688
1689 if (restricted) {
1690 restrictederr ();
1691 return;
1692 }
1693
1694 if (dont_modify ()) {
1695 return;
1696 }
1697
1698 /* Get the file name */
1699 if (get_filename ("Insert file:", name, False) != FINE) {
1700 return;
1701 }
1702 clear_status ();
1703
1704 status_line ("Inserting ", name);
1705 if ((fd = open (name, O_RDONLY | O_BINARY, 0)) < 0) {
1706 error2 ("Cannot open file: " /*, name */, serror ());
1707 } else { /* Insert the file */
1708 paste_file (fd, True, True); /* leave cursor at begin of insertion */
1709 }
1710 }
1711
1712 /*
1713 * WB () writes the buffer (yank_file) into another file, which
1714 * is prompted for.
1715 */
1716 void
WB()1717 WB ()
1718 {
1719 register int new_fd; /* Filedescriptor to copy file */
1720 int yank_fd; /* Filedescriptor to buffer */
1721 register int cnt; /* Count check for read/write */
1722 int ret = FINE; /* Error check for write */
1723 char wfile_name [maxFILENAMElen]; /* Output file name */
1724 char * msg_doing; char * msg_done;
1725
1726 if (restricted) {
1727 restrictederr ();
1728 return;
1729 }
1730
1731 /* Checkout the buffer */
1732 if ((yank_fd = yankfile (READ, False)) == ERRORS) {
1733 int e = geterrno ();
1734 if (e == 0 || e == ENOENT /* cygwin */) {
1735 error ("Paste buffer is empty");
1736 } else {
1737 error2 ("Cannot read paste buffer: ", serror ());
1738 }
1739 return;
1740 }
1741
1742 /* Get file name */
1743 if (get_filename ((hop_flag > 0)
1744 ? "Append buffer to file:"
1745 : "Write buffer to file (use with HOP to append):",
1746 wfile_name, False) != FINE) {
1747 return;
1748 }
1749
1750 /* Create the new file or open previous file for appending */
1751 if (hop_flag > 0) {
1752 status_line ("Opening ", wfile_name);
1753 if ((new_fd = open (wfile_name, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, fprot0)) < 0) {
1754 error2 ("Cannot append to file: " /* , wfile_name */, serror ());
1755 return;
1756 }
1757 msg_doing = "Appending buffer to ";
1758 msg_done = "Appended buffer to";
1759 } else {
1760 FLAG ovw = checkoverwrite (wfile_name);
1761 if (ovw == False) {
1762 return;
1763 } else {
1764 if (ovw == True && backup_mode) {
1765 #ifndef backup_only_edited_file
1766 (void) do_backup (wfile_name);
1767 #endif
1768 }
1769
1770 status_line ("Opening ", wfile_name);
1771 if ((new_fd = open (wfile_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, fprot0)) < 0) {
1772 error2 ("Cannot create file: " /* , wfile_name */, serror ());
1773 return;
1774 }
1775 }
1776 msg_doing = "Writing buffer to ";
1777 msg_done = "Wrote buffer to";
1778 }
1779
1780 status_line (msg_doing, wfile_name);
1781 flush ();
1782
1783 /* Copy buffer into file */
1784 while ((cnt = read (yank_fd, text_buffer, sizeof (text_buffer))) > 0) {
1785 if (write (new_fd, text_buffer, (unsigned int) cnt) != cnt) {
1786 error2 ("Writing buffer to file failed: ", serror ());
1787 ret = ERRORS;
1788 break;
1789 }
1790 }
1791 if (cnt < 0) {
1792 error2 ("Reading paste buffer failed: ", serror ());
1793 ret = ERRORS;
1794 }
1795
1796 /* Clean up open files and status line */
1797 (void) close (yank_fd);
1798 if (close (new_fd) < 0) {
1799 if (ret != ERRORS) {
1800 error2 ("Writing buffer to file failed: ", serror ());
1801 ret = ERRORS;
1802 }
1803 }
1804
1805 if (ret != ERRORS) {
1806 file_status (msg_done, bytes_saved, chars_saved,
1807 wfile_name, lines_saved,
1808 False, True, False, False);
1809 }
1810 }
1811
1812 /*
1813 setMARK sets position marker to current line / text pointer.
1814 MARK sets position marker or goes to it or (if on it) clears visible selection.
1815 */
1816 void
setMARK(set_only)1817 setMARK (set_only)
1818 FLAG set_only;
1819 {
1820 clear_highlight_selection ();
1821
1822 mark_line = cur_line;
1823 mark_text = cur_text;
1824 start_highlight_selection ();
1825 if (! set_only) {
1826 status_uni ("Mark set - type F1 k for help on copy/paste - HOP Mark toggles rectangular");
1827 }
1828 }
1829
1830 void
MARK()1831 MARK ()
1832 {
1833 if (hop_flag > 0) {
1834 hop_flag = 0;
1835 GOMA ();
1836 } else if (highlight_selection && mark_line == cur_line && mark_text == cur_text) {
1837 clear_highlight_selection ();
1838 status_uni ("Mark set -selection hidden- HOP Mark toggles rectangular");
1839 } else {
1840 setMARK (False);
1841 }
1842 }
1843
1844 /*
1845 * toggleMARK sets / unsets mark (for pico mode).
1846 */
1847 void
toggleMARK()1848 toggleMARK ()
1849 {
1850 if (checkmark (mark_line, mark_text) == NOT_VALID) {
1851 setMARK (True);
1852 } else {
1853 mark_line = NIL_LINE;
1854 mark_text = NIL_PTR;
1855 status_msg ("Mark unset");
1856 }
1857 }
1858
1859 /*
1860 * GOMA moves to the marked position
1861 */
1862 void
GOMA()1863 GOMA ()
1864 {
1865 if (checkmark (mark_line, mark_text) == NOT_VALID) {
1866 error ("Mark not set");
1867 } else if (mark_line == cur_line && mark_text == cur_text) {
1868 /* toggle rectangular selection */
1869 toggle_rectangular_paste_mode ();
1870 if (rectangular_paste_flag) {
1871 status_msg ("Rectangular selection enabled");
1872 } else {
1873 status_msg ("Rectangular selection disabled");
1874 }
1875 start_highlight_selection ();
1876 } else {
1877 Pushmark ();
1878
1879 move_address (mark_text, find_y (mark_line));
1880
1881 /*continue_highlight_selection ();*/
1882 clear_highlight_selection ();
1883 }
1884 }
1885
1886 /*
1887 * MARKn sets mark n to the current line / current text pointer.
1888 * mark_n sets it silently.
1889 */
1890 void
MARKn(n)1891 MARKn (n)
1892 int n;
1893 {
1894 if (hop_flag > 0) {
1895 GOMAn (n);
1896 } else {
1897 if (n < 0 || n >= maxmarkers) {
1898 error ("Marker # out of range");
1899 return;
1900 }
1901 marker_n [n].line = cur_line;
1902 marker_n [n].text = cur_text;
1903 status_msg ("Marker set");
1904 }
1905 }
1906
1907 void
mark_n(n)1908 mark_n (n)
1909 int n;
1910 {
1911 if (n == -1) { /* initial mark */
1912 mark_line = cur_line;
1913 mark_text = cur_text;
1914 } else if (n < 0 || n >= maxmarkers) {
1915 error ("Marker # out of range");
1916 return;
1917 } else {
1918 marker_n [n].line = cur_line;
1919 marker_n [n].text = cur_text;
1920 }
1921 }
1922
1923 /*
1924 * GOMAn moves to the marked position n
1925 */
1926 void
GOMAn(n)1927 GOMAn (n)
1928 int n;
1929 {
1930 Pushmark ();
1931
1932 if (n < 0 || n >= maxmarkers) {
1933 error ("Marker # out of range");
1934 return;
1935 }
1936
1937 if (checkmark (marker_n [n].line, marker_n [n].text) == NOT_VALID) {
1938 error ("Marker not set");
1939 } else {
1940 move_address (marker_n [n].text, find_y (marker_n [n].line));
1941 }
1942 }
1943
1944
1945 /*
1946 * Yankie () provides a reference to the last saved buffer to be read
1947 * by other mined invocations.
1948 */
1949 static
1950 void
yankie()1951 yankie ()
1952 {
1953 #ifdef __CYGWIN__
1954 /* also copy to Windows clipboard */
1955 status_uni ("Copying to Windows clipboard");
1956 if (copyfile (yank_file, "/dev/clipboard") != True) {
1957 /* ignore error */
1958 }
1959 status_uni (text_buffer);
1960 #endif
1961
1962 #ifdef linkyank
1963 (void) delete_file (yankie_file);
1964 if (link (yank_file, yankie_file) == 0) {
1965 return;
1966 }
1967 if (geterrno () != EPERM
1968 #ifdef EOPNOTSUPP
1969 && geterrno () != EOPNOTSUPP /* Haiku */
1970 #endif
1971 #ifdef ENOTSUP
1972 && geterrno () != ENOTSUP /* just in case */
1973 #endif
1974 #ifdef ENOSYS
1975 && geterrno () != ENOSYS /* just in case */
1976 #endif
1977 ) {
1978 /* no error handling here as a message would inappropriately
1979 obscure the original paste buffer copy information message
1980 or an error message to the paste buffer copy function;
1981 */
1982 return;
1983 }
1984 /* resort to copying if the file system does not support hard links
1985 */
1986 #endif
1987 status_uni ("Copying to cross-session buffer");
1988 if (copyfile (yank_file, yankie_file) != True) {
1989 /* no error handling here as a message would inappropriately
1990 obscure the original paste buffer copy information message
1991 or an error message to the paste buffer copy function */
1992 }
1993 status_uni (text_buffer);
1994 }
1995
1996 /*
1997 * yank_block is an interface to the actual yank.
1998 * It calls checkmark () to check if the marked position is still valid.
1999 * If it is, yank_text is called.
2000 */
2001 static
2002 void
yank_block(remove,append)2003 yank_block (remove, append)
2004 FLAG remove; /* == DELETE if text should be deleted */
2005 FLAG append; /* == True if text should only be appended to yank buffer */
2006 {
2007 switch (checkmark (mark_line, mark_text)) {
2008 case NOT_VALID :
2009 if (remove == DELETE) {
2010 #ifdef oldstyle_DELkey
2011 # ifdef msdos
2012 status_uni ("Mark not set for Cut to paste buffer - type Ctrl-Del to delete char, F1 k for help");
2013 # else
2014 if (mined_keypad) {
2015 status_uni ("Mark not set for Cut to paste buffer - type Alt-Del to delete char, F1 k for help");
2016 } else {
2017 status_uni ("Mark not set for Cut to paste buffer - type F1 k for help");
2018 }
2019 # endif
2020 #else
2021 status_uni ("Mark not set for Cut to paste buffer - type F1 k for help");
2022 #endif
2023 } else {
2024 status_uni ("Mark not set for Copy to paste buffer - type F1 k for help");
2025 }
2026 return;
2027 case SMALLER :
2028 set_buffer_open (append);
2029 if (yank_text (yankfile (WRITE, append), & yank_status,
2030 mark_line, mark_text, cur_line, cur_text,
2031 remove, append, rectangular_paste_mode, FORWARD)
2032 == FINE) {
2033 yankie ();
2034 }
2035 break;
2036 case BIGGER :
2037 set_buffer_open (append);
2038 if (yank_text (yankfile (WRITE, append), & yank_status,
2039 cur_line, cur_text, mark_line, mark_text,
2040 remove, append, rectangular_paste_mode, REVERSE)
2041 == FINE) {
2042 yankie ();
2043 }
2044 break;
2045 case SAME :
2046 status_uni ("No text selected for Copy or Cut");
2047 break;
2048 default :
2049 error ("Internal mark error");
2050 return;
2051 }
2052 alt_rectangular_mode = False;
2053 }
2054
2055 void
yank_HTML(remove)2056 yank_HTML (remove)
2057 FLAG remove; /* == DELETE if text should be deleted */
2058 {
2059 switch (checkmark (mark_line, mark_text)) {
2060 case NOT_VALID :
2061 error ("HTML tag selection failed");
2062 return;
2063 case SMALLER :
2064 (void)
2065 yank_text (htmlfile (WRITE, False), & html_status,
2066 mark_line, mark_text, cur_line, cur_text,
2067 remove, False, False, FORWARD);
2068 break;
2069 case BIGGER :
2070 (void)
2071 yank_text (htmlfile (WRITE, False), & html_status,
2072 cur_line, cur_text, mark_line, mark_text,
2073 remove, False, False, REVERSE);
2074 break;
2075 case SAME :
2076 error ("HTML tag selection failed");
2077 break;
2078 default :
2079 error ("Internal mark error");
2080 return;
2081 }
2082 }
2083
2084 /*
2085 * COPY () puts the text between the marked position and the current
2086 * in the buffer.
2087 */
2088 void
COPY()2089 COPY ()
2090 {
2091 if (visselect_copydeselect) {
2092 clear_highlight_selection ();
2093 }
2094
2095 if (append_flag) {
2096 yank_block (NO_DELETE, True);
2097 } else if (hop_flag > 0) {
2098 yank_block (NO_DELETE, True);
2099 } else {
2100 yank_block (NO_DELETE, False);
2101 }
2102 }
2103
2104 /*
2105 * CUT () is essentially the same as COPY (), but the text is deleted.
2106 */
2107 void
CUT()2108 CUT ()
2109 {
2110 clear_highlight_selection ();
2111
2112 if (dont_modify ()) {
2113 return;
2114 }
2115
2116 if (append_flag) {
2117 yank_block (DELETE, True);
2118 } else if (hop_flag > 0) {
2119 yank_block (DELETE, True);
2120 } else {
2121 yank_block (DELETE, False);
2122 }
2123 }
2124
2125
2126 /*======================================================================*\
2127 |* Selection highlighting *|
2128 \*======================================================================*/
2129
2130 #ifdef debug_sel_text
2131 static
2132 void
trace_line_text(line,text)2133 trace_line_text (line, text)
2134 LINE * line;
2135 char * text;
2136 {
2137 char * s = line->text;
2138 if (! s) {
2139 printf ("(null)");
2140 return;
2141 }
2142 printf ("\"");
2143 while (* s) {
2144 if (s == text) {
2145 printf ("[7m");
2146 } else if (s == mark_text) {
2147 printf ("[41m");
2148 } else if (s == cur_text) {
2149 printf ("[46m");
2150 }
2151 if (* s == '\n') {
2152 printf ("\\n");
2153 } else if (* s == '"') {
2154 printf ("\\\"");
2155 } else {
2156 printf ("%c", * s);
2157 }
2158 s ++;
2159 }
2160 printf ("[0m");
2161 printf ("\"");
2162 printf ("\n");
2163 }
2164 #else
2165 #define trace_line_text(line, text)
2166 #endif
2167
2168 static
2169 void
select_line(line,sel_begin,sel_end)2170 select_line (line, sel_begin, sel_end)
2171 LINE * line;
2172 char * sel_begin;
2173 char * sel_end;
2174 {
2175 if (sel_begin != line->sel_begin) {
2176 line->sel_begin = sel_begin;
2177 line->dirty = True;
2178 }
2179 if (sel_end != line->sel_end) {
2180 line->sel_end = sel_end;
2181 line->dirty = True;
2182 }
2183 #ifdef debug_sel
2184 printf ("%p %p %c ", sel_begin, sel_end, line->dirty ? '!' : '-');
2185 trace_line_text (line, 0);
2186 #endif
2187 }
2188
2189 static
2190 void
do_update_selection_marks(select,pos_x)2191 do_update_selection_marks (select, pos_x)
2192 FLAG select;
2193 int pos_x;
2194 {
2195 #ifdef debug_sel
2196 printf ("do_update_selection_marks sel %d pos %d\n", select, pos_x);
2197 #endif
2198 /*
2199 check which lines have changed being in the selection area or not;
2200 proceed lines
2201 - from current position until mark
2202 - beyond mark until previous position / end of previous selection
2203 - from current position in other direction until previous ...
2204 and mark them dirty if changed
2205 print_line should clear and optionally evaluate the dirty flag
2206 */
2207 if (highlight_selection) {
2208 /* only used if rectangular_paste_mode: (avoid -Wmaybe-uninitialized) */
2209 int start_col = 0;
2210 int end_col = 0;
2211
2212 LINE * clearup;
2213 LINE * cleardown;
2214 FLAG check = NOT_VALID;
2215 if (select) {
2216 check = checkmark (mark_line, mark_text);
2217 }
2218
2219 if (check == NOT_VALID) {
2220 highlight_selection = False;
2221 }
2222
2223 if (check != NOT_VALID && rectangular_paste_mode) {
2224 /* check block boundaries */
2225 start_col = get_text_col (mark_line, mark_text, False);
2226 /*end_col = pos_x;*/
2227 end_col = get_text_col (cur_line, cur_text, False);
2228 #ifdef debug_sel
2229 printf ("start: %d/%d .. end @%d(%d): %d/%d -> %d..%d",
2230 get_text_col (mark_line, mark_text, False),
2231 get_text_col (mark_line, mark_text, True),
2232 pos_x, last_sel_x,
2233 get_text_col (cur_line, cur_text, False),
2234 get_text_col (cur_line, cur_text, True),
2235 start_col, end_col);
2236 #endif
2237 /* adapt column to actual mouse position */
2238 if (last_sel_x > end_col) {
2239 end_col = last_sel_x;
2240 #ifdef debug_sel
2241 printf (" ->> %d..%d", start_col, end_col);
2242 #endif
2243 }
2244 /* fix right-to-left selection */
2245 if (start_col > end_col) {
2246 int dum = end_col;
2247 end_col = start_col;
2248 start_col = dum;
2249 #ifdef debug_sel
2250 printf (" -/> %d..%d", start_col, end_col);
2251 #endif
2252 }
2253 #ifdef debug_sel
2254 printf ("\n");
2255 #endif
2256 }
2257
2258 if (check == SMALLER) {
2259 /* blablabla MMMMM X blablabla */
2260 /* bla O MMMM blablabla */
2261 /* blablabla MM O blablabla */
2262 /* blablabla MMMMMMMM O blablabla */
2263 LINE * line = cur_line;
2264 char * sel_end = cur_text;
2265
2266 /* select lines above until marker */
2267 while (line != header) {
2268 char * sel_begin;
2269 int dumcol;
2270 if (rectangular_paste_mode) {
2271 sel_begin = text_at (line, & dumcol, start_col);
2272 sel_end = text_at (line, & dumcol, end_col);
2273 } else if (line == mark_line) {
2274 sel_begin = mark_text;
2275 } else {
2276 sel_begin = line->text;
2277 }
2278 select_line (line, sel_begin, sel_end);
2279 if (line == mark_line) {
2280 /* end of selecting */
2281 break;
2282 }
2283
2284 line = line->prev;
2285 /* select lines above to their end */
2286 sel_end = NIL_PTR;
2287 }
2288
2289 /* deselect lines above marker */
2290 clearup = line->prev;
2291
2292 /* deselect lines below cur_line */
2293 cleardown = cur_line->next;
2294
2295 } else if (check == BIGGER) {
2296 /* blablabla X MMMMM blablabla */
2297 /* blablablablabla MMMM O blabla */
2298 /* blablablabla O MM blablabla */
2299 /* blabla O MMMMMMMM blablabla */
2300 LINE * line = cur_line;
2301 char * sel_begin = cur_text;
2302
2303 /* select lines below until marker */
2304 while (line != tail) {
2305 char * sel_end;
2306 int dumcol;
2307 if (rectangular_paste_mode) {
2308 sel_begin = text_at (line, & dumcol, start_col);
2309 sel_end = text_at (line, & dumcol, end_col);
2310 } else if (line == mark_line) {
2311 sel_end = mark_text;
2312 } else {
2313 sel_end = NIL_PTR; /* end of line and beyond */
2314 }
2315 select_line (line, sel_begin, sel_end);
2316 if (line == mark_line) {
2317 /* end of selecting */
2318 break;
2319 }
2320
2321 line = line->next;
2322 /* select lines below from their start */
2323 sel_begin = line->text;
2324 }
2325
2326 /* deselect lines below marker */
2327 cleardown = line->next;
2328
2329 /* deselect lines above cur_line */
2330 clearup = cur_line->prev;
2331
2332 } else /* (check == SAME || check == NOT_VALID) */ {
2333 /* deselect cur_line and lines above */
2334 clearup = cur_line;
2335 /* deselect lines below cur_line */
2336 cleardown = cur_line->next;
2337 }
2338
2339 /* deselect lines above selection as long as still selected */
2340 while (clearup != header && clearup->sel_begin) {
2341 select_line (clearup, NIL_PTR, NIL_PTR);
2342 clearup = clearup->prev;
2343 }
2344
2345 /* deselect lines below selection as long as still selected */
2346 while (cleardown != tail && cleardown->sel_begin) {
2347 select_line (cleardown, NIL_PTR, NIL_PTR);
2348 cleardown = cleardown->next;
2349 }
2350 }
2351 }
2352
2353
2354 void
start_highlight_selection()2355 start_highlight_selection ()
2356 {
2357 highlight_selection = True;
2358 }
2359
2360 void
clear_highlight_selection()2361 clear_highlight_selection ()
2362 {
2363 do_update_selection_marks (False, 0);
2364 }
2365
2366
2367 void
update_selection_marks(until_x)2368 update_selection_marks (until_x)
2369 int until_x;
2370 {
2371 #define fix_shift_update
2372 #ifdef fix_shift_update
2373 until_x -= cur_line->shift_count * SHIFT_SIZE;
2374 #endif
2375 if (until_x != LINE_END) {
2376 last_sel_x = until_x;
2377 }
2378 do_update_selection_marks (True, until_x);
2379 }
2380
2381 void
continue_highlight_selection(until_x)2382 continue_highlight_selection (until_x)
2383 int until_x;
2384 {
2385 highlight_selection = True;
2386 update_selection_marks (until_x);
2387 }
2388
2389
2390 FLAG
has_active_selection()2391 has_active_selection ()
2392 {
2393 if (highlight_selection) {
2394 FLAG check = checkmark (mark_line, mark_text);
2395 if (check == BIGGER || check == SMALLER) {
2396 return True;
2397 }
2398 }
2399 return False;
2400 }
2401
2402 void
trigger_highlight_selection()2403 trigger_highlight_selection ()
2404 {
2405 if (keyshift & shift_mask) {
2406 if (has_active_selection ()) {
2407 continue_highlight_selection (last_sel_x);
2408 } else {
2409 setMARK (True);
2410 }
2411 keyshift &= ~ shift_mask;
2412 } else {
2413 clear_highlight_selection ();
2414 }
2415 }
2416
2417 void
toggle_rectangular_paste_mode()2418 toggle_rectangular_paste_mode ()
2419 {
2420 if (rectangular_paste_flag) {
2421 rectangular_paste_flag = False;
2422 } else {
2423 rectangular_paste_flag = True;
2424 }
2425 displayflags ();
2426 update_selection_marks (x);
2427 /* display_flush (); */
2428 }
2429
2430 void
adjust_rectangular_mode(alt_mouse)2431 adjust_rectangular_mode (alt_mouse)
2432 FLAG alt_mouse;
2433 {
2434 if (alt_mouse != alt_rectangular_mode) {
2435 alt_rectangular_mode = alt_mouse;
2436 /* update_selection_marks (x); call followed by move_to anyway */
2437 /* display_flush (); */
2438 }
2439 }
2440
2441
2442 void
SELECTION()2443 SELECTION ()
2444 {
2445 if (hop_flag > 0) {
2446 clear_highlight_selection ();
2447 } else {
2448 continue_highlight_selection (last_sel_x);
2449 if (! highlight_selection) {
2450 error ("Mark not set");
2451 }
2452 }
2453 }
2454
2455
2456 /*======================================================================*\
2457 |* End *|
2458 \*======================================================================*/
2459