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 ", tag, line_spec (line)); print_str (line->text); printf ("\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 ("");
2146 	} else if (s == mark_text) {
2147 		printf ("");
2148 	} else if (s == cur_text) {
2149 		printf ("");
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 ("");
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