1/* Copyright (c) 1993-2002
2 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24#include <sys/types.h>
25
26#include "config.h"
27#include "screen.h"
28#include "mark.h"
29#include "extern.h"
30
31#ifdef COPY_PASTE
32
33/*
34 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35 *
36 * WARNING: these routines use the global variables "fore" and
37 * "flayer" to make things easier.
38 *
39 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
40 */
41
42static int  is_letter __P((int));
43static void nextword __P((int *, int *, int, int));
44static int  linestart __P((int));
45static int  lineend __P((int));
46static int  rem __P((int, int , int , int , int , char *, int));
47static int  eq __P((int, int ));
48static int  MarkScrollDownDisplay __P((int));
49static int  MarkScrollUpDisplay __P((int));
50
51static void MarkProcess __P((char **, int *));
52static void MarkAbort __P((void));
53static void MarkRedisplayLine __P((int, int, int, int));
54static int  MarkRewrite __P((int, int, int, struct mchar *, int));
55
56extern struct layer *flayer;
57extern struct display *display, *displays;
58extern struct win *fore;
59extern struct mline mline_blank, mline_null;
60extern struct mchar mchar_so;
61
62#ifdef FONT
63int pastefont = 1;
64#endif
65
66static struct LayFuncs MarkLf =
67{
68  MarkProcess,
69  MarkAbort,
70  MarkRedisplayLine,
71  DefClearLine,
72  MarkRewrite,
73  DefResize,
74  DefRestore
75};
76
77int join_with_cr =  0;
78int compacthist = 0;
79
80unsigned char mark_key_tab[256]; /* this array must be initialised first! */
81
82static struct markdata *markdata;
83
84
85/*
86 * VI like is_letter: 0 - whitespace
87 *                    1 - letter
88 *		      2 - other
89 */
90static int is_letter(c)
91char c;
92{
93  if ((c >= 'a' && c <= 'z') ||
94      (c >= 'A' && c <= 'Z') ||
95      (c >= '0' && c <= '9') ||
96      c == '_' || c == '.' ||
97      c == '@' || c == ':' ||
98      c == '%' || c == '!' ||
99      c == '-' || c == '+')
100    /* thus we can catch email-addresses as a word :-) */
101    return 1;
102  else if (c != ' ')
103    return 2;
104  return 0;
105}
106
107static int
108linestart(y)
109int y;
110{
111  register int x;
112  register unsigned char *i;
113
114  for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
115    if (*i++ != ' ')
116      break;
117  if (x == fore->w_width - 1)
118    x = markdata->left_mar;
119  return x;
120}
121
122static int
123lineend(y)
124int y;
125{
126  register int x;
127  register unsigned char *i;
128
129  for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
130    if (*i-- != ' ')
131      break;
132  if (x < 0)
133    x = markdata->left_mar;
134  return x;
135}
136
137
138/*
139 *  nextword calculates the cursor position of the num'th word.
140 *  If the cursor is on a word, it counts as the first.
141 *  NW_BACK:		search backward
142 *  NW_ENDOFWORD:	find the end of the word
143 *  NW_MUSTMOVE:	move at least one char
144 *  NW_BIG:             match WORDs not words
145 */
146
147#define NW_BACK		(1<<0)
148#define NW_ENDOFWORD	(1<<1)
149#define NW_MUSTMOVE	(1<<2)
150#define NW_BIG		(1<<3)
151
152static void
153nextword(xp, yp, flags, num)
154int *xp, *yp, flags, num;
155{
156  int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
157  register int sx, oq, q, x, y;
158  struct mline *ml;
159
160  x = *xp;
161  y = *yp;
162  sx = (flags & NW_BACK) ? -1 : 1;
163  if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
164    x += sx;
165  ml = WIN(y);
166  for (oq = -1; ; x += sx, oq = q)
167    {
168      if (x >= xx || x < 0)
169	q = 0;
170      else if (flags & NW_BIG)
171        q = ml->image[x] == ' ';
172      else
173        q = is_letter(ml->image[x]);
174      if (oq >= 0 && oq != q)
175	{
176	  if (oq == 0 || !(flags & NW_ENDOFWORD))
177	    *xp = x;
178	  else
179	    *xp = x-sx;
180	  *yp = y;
181	  if ((!(flags & NW_ENDOFWORD) && q) ||
182	      ((flags & NW_ENDOFWORD) && oq))
183	    {
184	      if (--num <= 0)
185	        return;
186	    }
187	}
188      if (x == xx)
189	{
190	  x = -1;
191	  if (++y >= yy)
192	    return;
193	  ml = WIN(y);
194	}
195      else if (x < 0)
196	{
197	  x = xx;
198	  if (--y < 0)
199	    return;
200	  ml = WIN(y);
201	}
202    }
203}
204
205
206/*
207 * y1, y2 are WIN coordinates
208 *
209 * redisplay:	0  -  just copy
210 * 		1  -  redisplay + copy
211 *		2  -  count + copy, don't redisplay
212 */
213
214static int
215rem(x1, y1, x2, y2, redisplay, pt, yend)
216int x1, y1, x2, y2, redisplay, yend;
217char *pt;
218{
219  int i, j, from, to, ry, c;
220  int l = 0;
221  unsigned char *im;
222  struct mline *ml;
223#ifdef FONT
224  int cf, font;
225  unsigned char *fo;
226#endif
227
228  markdata->second = 0;
229  if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
230    {
231      i = y2;
232      y2 = y1;
233      y1 = i;
234      i = x2;
235      x2 = x1;
236      x1 = i;
237    }
238  ry = y1 - markdata->hist_offset;
239
240  i = y1;
241  if (redisplay != 2 && pt == 0 && ry <0)
242    {
243      i -= ry;
244      ry = 0;
245    }
246  for (; i <= y2; i++, ry++)
247    {
248      if (redisplay != 2 && pt == 0 && ry > yend)
249	break;
250      ml = WIN(i);
251      from = (i == y1) ? x1 : 0;
252      if (from < markdata->left_mar)
253	from = markdata->left_mar;
254      for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
255        if (*im-- != ' ')
256	  break;
257      if (i == y2 && x2 < to)
258	to = x2;
259      if (to > markdata->right_mar)
260	to = markdata->right_mar;
261      if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
262	MarkRedisplayLine(ry, from, to, 0);
263      if (redisplay != 2 && pt == 0)	/* don't count/copy */
264	continue;
265      j = from;
266#ifdef DW_CHARS
267      if (dw_right(ml, j, fore->w_encoding))
268	j--;
269#endif
270      im = ml->image + j;
271#ifdef FONT
272      fo = ml->font + j;
273      font = ASCII;
274#endif
275      for (; j <= to; j++)
276	{
277	  c = (unsigned char)*im++;
278#ifdef FONT
279	  cf = (unsigned char)*fo++;
280# ifdef UTF8
281	  if (fore->w_encoding == UTF8)
282	    {
283	      c |= cf << 8;
284	      if (c == UCS_HIDDEN)
285		continue;
286	      c = ToUtf8_comb(pt, c);
287	      l += c;
288	      if (pt)
289	        pt += c;
290	      continue;
291	    }
292# endif
293# ifdef DW_CHARS
294	  if (is_dw_font(cf))
295	    {
296	      c = c << 8 | (unsigned char)*im++;
297	      fo++;
298	      j++;
299	    }
300# endif
301	  if (pastefont)
302	    {
303	      c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
304	      l += c;
305	      if (pt)
306		pt += c;
307	      continue;
308	    }
309#endif /* FONT */
310	  if (pt)
311	    *pt++ = c;
312	  l++;
313	}
314#ifdef FONT
315      if (pastefont && font != ASCII)
316	{
317	  if (pt)
318	    {
319	      strcpy(pt, "\033(B");
320	      pt += 3;
321	    }
322	  l += 3;
323	}
324#endif
325      if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' '))
326	{
327	  /*
328	   * this code defines, what glues lines together
329	   */
330	  switch (markdata->nonl)
331	    {
332	    case 0:		/* lines separated by newlines */
333	      if (pt)
334		*pt++ = '\r';
335	      l++;
336	      if (join_with_cr)
337		{
338		  if (pt)
339		    *pt++ = '\n';
340		  l++;
341		}
342	      break;
343	    case 1:		/* nothing to separate lines */
344	      break;
345	    case 2:		/* lines separated by blanks */
346	      if (pt)
347		*pt++ = ' ';
348	      l++;
349	      break;
350	    case 3:		/* seperate by comma, for csh junkies */
351	      if (pt)
352	        *pt++ = ',';
353	      l++;
354	      break;
355	    }
356	}
357    }
358  return l;
359}
360
361/* Check if two chars are identical. All digits are treated
362 * as same. Used for GetHistory()
363 */
364
365static int
366eq(a, b)
367int a, b;
368{
369  if (a == b)
370    return 1;
371  if (a == 0 || b == 0)
372    return 1;
373  if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
374    return 1;
375  return 0;
376}
377
378
379/**********************************************************************/
380
381int
382GetHistory()	/* return value 1 if copybuffer changed */
383{
384  int i = 0, q = 0, xx, yy, x, y;
385  unsigned char *linep;
386  struct mline *ml;
387
388  ASSERT(display && fore);
389  x = fore->w_x;
390  if (x >= fore->w_width)
391    x = fore->w_width - 1;
392  y = fore->w_y + fore->w_histheight;
393  debug2("cursor is at x=%d, y=%d\n", x, y);
394  ml = WIN(y);
395  for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
396    if ((q = *linep--) != ' ' )
397      break;
398  debug3("%c at (%d,%d)\n", q, xx, y);
399  for (yy = y - 1; yy >= 0; yy--)
400    {
401      ml = WIN(yy);
402      linep = ml->image;
403      if (xx < 0 || eq(linep[xx], q))
404	{		/* line is matching... */
405	  for (i = fore->w_width - 1, linep += i; i >= x; i--)
406	    if (*linep-- != ' ')
407	      break;
408	  if (i >= x)
409	    break;
410	}
411    }
412  if (yy < 0)
413    return 0;
414  if (D_user->u_plop.buf)
415    UserFreeCopyBuffer(D_user);
416  if ((D_user->u_plop.buf = (char *)malloc((unsigned) (i - x + 2))) == NULL)
417    {
418      LMsg(0, "Not enough memory... Sorry.");
419      return 0;
420    }
421  bcopy((char *)linep - i + x + 1, D_user->u_plop.buf, i - x + 1);
422  D_user->u_plop.len = i - x + 1;
423#ifdef ENCODINGS
424  D_user->u_plop.enc = fore->w_encoding;
425#endif
426  return 1;
427}
428
429/**********************************************************************/
430
431
432void
433MarkRoutine()
434{
435  int x, y;
436
437  ASSERT(fore && display && D_user);
438
439  debug2("MarkRoutine called: fore nr %d, display %s\n",
440         fore->w_number, D_usertty);
441
442  if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
443    return;
444  flayer->l_encoding = fore->w_encoding;
445  markdata = (struct markdata *)flayer->l_data;
446  markdata->md_user = D_user;	/* XXX: Correct? */
447  markdata->md_window = fore;
448  markdata->second = 0;
449  markdata->rep_cnt = 0;
450  markdata->append_mode = 0;
451  markdata->write_buffer = 0;
452  markdata->nonl = 0;
453  markdata->left_mar  = 0;
454  markdata->right_mar = fore->w_width - 1;
455  markdata->hist_offset = fore->w_histheight;
456  x = fore->w_x;
457  y = D2W(fore->w_y);
458  if (x >= fore->w_width)
459    x = fore->w_width - 1;
460
461  LGotoPos(flayer, x, W2D(y));
462  LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
463      x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
464  markdata->cx = markdata->x1 = x;
465  markdata->cy = markdata->y1 = y;
466  flayer->l_x = x;
467  flayer->l_y = W2D(y);
468}
469
470static void
471MarkProcess(inbufp,inlenp)
472char **inbufp;
473int *inlenp;
474{
475  char *inbuf, *pt;
476  int inlen;
477  int cx, cy, x2, y2, j, yend;
478  int newcopylen = 0, od;
479  int in_mark;
480  int rep_cnt;
481  struct acluser *md_user;
482
483/*
484  char *extrap = 0, extrabuf[100];
485*/
486
487  markdata = (struct markdata *)flayer->l_data;
488  fore = markdata->md_window;
489  md_user = markdata->md_user;
490  if (inbufp == 0)
491    {
492      MarkAbort();
493      return;
494    }
495
496  LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
497  inbuf= *inbufp;
498  inlen= *inlenp;
499  pt = inbuf;
500  in_mark = 1;
501  while (in_mark && (inlen /* || extrap */))
502    {
503/*
504      if (extrap)
505	{
506	  od = *extrap++;
507	  if (*extrap == 0)
508	    extrap = 0;
509	}
510      else
511*/
512	{
513          od = mark_key_tab[(int)(unsigned char)*pt++];
514          inlen--;
515	}
516      rep_cnt = markdata->rep_cnt;
517      if (od >= '0' && od <= '9')
518        {
519	  if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
520	    {
521	      markdata->rep_cnt = 10 * rep_cnt + od - '0';
522	      continue;
523 	      /*
524	       * Now what is that 1001 here? Well, we have a screen with
525	       * 25 * 80 = 2000 characters. Movement is at most across the full
526	       * screen. This we do with word by word movement, as character by
527	       * character movement never steps over line boundaries. The most words
528	       * we can place on the screen are 1000 single letter words. Thus 1001
529	       * is sufficient. Users with bigger screens never write in single letter
530	       * words, as they should be more advanced. jw.
531	       * Oh, wrong. We still give even the experienced user a factor of ten.
532	       */
533	    }
534	}
535      cx = markdata->cx;
536      cy = markdata->cy;
537      switch (od)
538	{
539	case 'o':
540	case 'x':
541	  if (!markdata->second)
542	    break;
543	  markdata->cx = markdata->x1;
544	  markdata->cy = markdata->y1;
545	  markdata->x1 = cx;
546	  markdata->y1 = cy;
547	  revto(markdata->cx, markdata->cy);
548	  break;
549	case '\014':	/* CTRL-L Redisplay */
550	  Redisplay(0);
551	  LGotoPos(flayer, cx, W2D(cy));
552	  break;
553	case 0202:	/* M-C-b */
554	case '\010':	/* CTRL-H Backspace */
555	case 'h':
556	  if (rep_cnt == 0)
557	    rep_cnt = 1;
558	  revto(cx - rep_cnt, cy);
559	  break;
560	case 0216:	/* M-C-p */
561	case '\016':	/* CTRL-N */
562	case 'j':
563	  if (rep_cnt == 0)
564	    rep_cnt = 1;
565	  revto(cx, cy + rep_cnt);
566	  break;
567	case '+':
568	  if (rep_cnt == 0)
569	    rep_cnt = 1;
570	  j = cy + rep_cnt;
571	  if (j > fore->w_histheight + fore->w_height - 1)
572	    j = fore->w_histheight + fore->w_height - 1;
573	  revto(linestart(j), j);
574	  break;
575	case '-':
576	  if (rep_cnt == 0)
577	    rep_cnt = 1;
578	  cy -= rep_cnt;
579	  if (cy < 0)
580	    cy = 0;
581	  revto(linestart(cy), cy);
582	  break;
583	case '^':
584	  revto(linestart(cy), cy);
585	  break;
586	case '\n':
587	  revto(markdata->left_mar, cy + 1);
588	  break;
589	case 0220:	/* M-C-p */
590	case '\020':	/* CTRL-P */
591	case 'k':
592	  if (rep_cnt == 0)
593	    rep_cnt = 1;
594	  revto(cx, cy - rep_cnt);
595	  break;
596	case 0206:	/* M-C-f */
597	case 'l':
598	  if (rep_cnt == 0)
599	    rep_cnt = 1;
600	  revto(cx + rep_cnt, cy);
601	  break;
602	case '\001':	/* CTRL-A from tcsh/emacs */
603	case '0':
604	  revto(markdata->left_mar, cy);
605	  break;
606	case '\004':    /* CTRL-D down half screen */
607	  if (rep_cnt == 0)
608	    rep_cnt = (fore->w_height + 1) >> 1;
609	  revto_line(cx, cy + rep_cnt, W2D(cy));
610	  break;
611	case '$':
612	  revto(lineend(cy), cy);
613	  break;
614        case '\022':	/* CTRL-R emacs style backwards search */
615	  ISearch(-1);
616	  in_mark = 0;
617	  break;
618        case '\023':	/* CTRL-S emacs style search */
619	  ISearch(1);
620	  in_mark = 0;
621	  break;
622	case '\025':	/* CTRL-U up half screen */
623	  if (rep_cnt == 0)
624	    rep_cnt = (fore->w_height + 1) >> 1;
625	  revto_line(cx, cy - rep_cnt, W2D(cy));
626	  break;
627	case '\007':	/* CTRL-G show cursorpos */
628	  if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
629	    LMsg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
630		markdata->hist_offset);
631	  else
632	    LMsg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
633		markdata->left_mar+1, markdata->right_mar+1, W2D(cy)+1, markdata->hist_offset);
634	  break;
635	case '\002':	/* CTRL-B  back one page */
636	  if (rep_cnt == 0)
637	    rep_cnt = 1;
638	  rep_cnt *= fore->w_height;
639	  revto(cx, cy - rep_cnt);
640	  break;
641	case '\006':	/* CTRL-F  forward one page */
642	  if (rep_cnt == 0)
643	    rep_cnt = 1;
644	  rep_cnt *= fore->w_height;
645	  revto(cx, cy + rep_cnt);
646	  break;
647	case '\005':	/* CTRL-E  scroll up */
648	  if (rep_cnt == 0)
649	    rep_cnt = 1;
650	  rep_cnt = MarkScrollUpDisplay(rep_cnt);
651	  if (cy < D2W(0))
652            revto(cx, D2W(0));
653	  else
654            LGotoPos(flayer, cx, W2D(cy));
655	  break;
656	case '\031': /* CTRL-Y  scroll down */
657	  if (rep_cnt == 0)
658	    rep_cnt = 1;
659	  rep_cnt = MarkScrollDownDisplay(rep_cnt);
660	  if (cy > D2W(fore->w_height-1))
661            revto(cx, D2W(fore->w_height-1));
662	  else
663            LGotoPos(flayer, cx, W2D(cy));
664	  break;
665	case '@':
666	  /* it may be usefull to have a key that does nothing */
667	  break;
668	case '%':
669	  rep_cnt--;
670	  /* rep_cnt is a percentage for the history buffer */
671	  if (rep_cnt < 0)
672	    rep_cnt = 0;
673	  if (rep_cnt > 100)
674	    rep_cnt = 100;
675	  revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + fore->w_height)) / 100, (fore->w_height - 1) / 2);
676	  break;
677	case 0201:
678	case 'g':
679	  rep_cnt = 1;
680	  /* FALLTHROUGH */
681	case 0205:
682	case 'G':
683	  /* rep_cnt is here the WIN line number */
684	  if (rep_cnt == 0)
685	    rep_cnt = fore->w_histheight + fore->w_height;
686	  revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
687	  break;
688	case 'H':
689	  revto(markdata->left_mar, D2W(0));
690	  break;
691	case 'M':
692	  revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
693	  break;
694	case 'L':
695	  revto(markdata->left_mar, D2W(fore->w_height - 1));
696	  break;
697	case '|':
698	  revto(--rep_cnt, cy);
699	  break;
700	case 'w':
701	  if (rep_cnt == 0)
702	    rep_cnt = 1;
703	  nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
704	  revto(cx, cy);
705	  break;
706	case 'e':
707	case 'E':
708	  if (rep_cnt == 0)
709	    rep_cnt = 1;
710	  nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
711	  revto(cx, cy);
712	  break;
713	case 'b':
714	case 'B':
715	  if (rep_cnt == 0)
716	    rep_cnt = 1;
717	  nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
718	  revto(cx, cy);
719	  break;
720	case 'a':
721	  markdata->append_mode = 1 - markdata->append_mode;
722	  debug1("append mode %d--\n", markdata->append_mode);
723	  LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
724	  break;
725	case 'v':
726	case 'V':
727	  /* this sets start column to column 9 for VI :set nu users */
728	  if (markdata->left_mar == 8)
729	    rep_cnt = 1;
730	  else
731	    rep_cnt = 9;
732	  /* FALLTHROUGH */
733	case 'c':
734	case 'C':
735	  /* set start column (c) and end column (C) */
736	  if (markdata->second)
737	    {
738	      rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, fore->w_height-1); /* Hack */
739	      markdata->second = 1;	/* rem turns off second */
740	    }
741	  rep_cnt--;
742	  if (rep_cnt < 0)
743	    rep_cnt = cx;
744	  if (od != 'C')
745	    {
746	      markdata->left_mar = rep_cnt;
747	      if (markdata->left_mar > markdata->right_mar)
748		markdata->left_mar = markdata->right_mar;
749	    }
750	  else
751	    {
752	      markdata->right_mar = rep_cnt;
753	      if (markdata->left_mar > markdata->right_mar)
754		markdata->right_mar = markdata->left_mar;
755	    }
756	  if (markdata->second)
757	    {
758	      markdata->cx = markdata->x1; markdata->cy = markdata->y1;
759	      revto(cx, cy);
760	    }
761	  if (od == 'v' || od == 'V')
762	    LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
763	  break;
764	case 'J':
765	  /* how do you join lines in VI ? */
766	  markdata->nonl = (markdata->nonl + 1) % 4;
767	  switch (markdata->nonl)
768	    {
769	    case 0:
770	      if (join_with_cr)
771		LMsg(0, "Multiple lines (CR/LF)");
772	      else
773		LMsg(0, "Multiple lines (LF)");
774	      break;
775	    case 1:
776	      LMsg(0, "Lines joined");
777	      break;
778	    case 2:
779	      LMsg(0, "Lines joined with blanks");
780	      break;
781	    case 3:
782	      LMsg(0, "Lines joined with comma");
783	      break;
784	    }
785	  break;
786	case '/':
787	  Search(1);
788	  in_mark = 0;
789	  break;
790	case '?':
791	  Search(-1);
792	  in_mark = 0;
793	  break;
794	case 'n':
795	  Search(0);
796	  break;
797	case 'y':
798	case 'Y':
799	  if (markdata->second == 0)
800	    {
801	      revto(linestart(cy), cy);
802	      markdata->second++;
803	      cx = markdata->x1 = markdata->cx;
804	      cy = markdata->y1 = markdata->cy;
805	    }
806	  if (--rep_cnt > 0)
807	    revto(cx, cy + rep_cnt);
808	  revto(lineend(markdata->cy), markdata->cy);
809	  if (od == 'y')
810	    break;
811	  /* FALLTHROUGH */
812	case 'W':
813	  if (od == 'W')
814	    {
815	      if (rep_cnt == 0)
816		rep_cnt = 1;
817	      if (!markdata->second)
818		{
819		  nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
820		  revto(cx, cy);
821		  markdata->second++;
822		  cx = markdata->x1 = markdata->cx;
823		  cy = markdata->y1 = markdata->cy;
824		}
825	      nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
826	      revto(cx, cy);
827	    }
828	  cx = markdata->cx;
829	  cy = markdata->cy;
830	  /* FALLTHROUGH */
831	case 'A':
832	  if (od == 'A')
833	    markdata->append_mode = 1;
834	  /* FALLTHROUGH */
835	case '>':
836	  if (od == '>')
837	    markdata->write_buffer = 1;
838	  /* FALLTHROUGH */
839	case ' ':
840	case '\r':
841	  if (!markdata->second)
842	    {
843	      markdata->second++;
844	      markdata->x1 = cx;
845	      markdata->y1 = cy;
846	      revto(cx, cy);
847	      LMsg(0, "First mark set - Column %d Line %d", cx+1, W2D(cy)+1);
848	      break;
849	    }
850	  else
851	    {
852	      int append_mode = markdata->append_mode;
853	      int write_buffer = markdata->write_buffer;
854
855	      x2 = cx;
856	      y2 = cy;
857	      newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
858	      if (md_user->u_plop.buf && !append_mode)
859		UserFreeCopyBuffer(md_user);
860	      yend = fore->w_height - 1;
861	      if (fore->w_histheight - markdata->hist_offset < fore->w_height)
862		{
863		  markdata->second = 0;
864		  yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
865		}
866	      if (newcopylen > 0)
867		{
868		  /* the +3 below is for : cr + lf + \0 */
869		  if (md_user->u_plop.buf)
870		    md_user->u_plop.buf = realloc(md_user->u_plop.buf,
871			(unsigned) (md_user->u_plop.len + newcopylen + 3));
872		  else
873		    {
874		      md_user->u_plop.len = 0;
875		      md_user->u_plop.buf = malloc((unsigned) (newcopylen + 3));
876		    }
877		  if (!md_user->u_plop.buf)
878		    {
879		      MarkAbort();
880		      in_mark = 0;
881		      LMsg(0, "Not enough memory... Sorry.");
882		      md_user->u_plop.len = 0;
883		      md_user->u_plop.buf = 0;
884		      break;
885		    }
886		  if (append_mode)
887		    {
888		      switch (markdata->nonl)
889			{
890			/*
891			 * this code defines, what glues lines together
892			 */
893			case 0:
894			  if (join_with_cr)
895			    {
896			      md_user->u_plop.buf[md_user->u_plop.len] = '\r';
897			      md_user->u_plop.len++;
898			    }
899			  md_user->u_plop.buf[md_user->u_plop.len] = '\n';
900			  md_user->u_plop.len++;
901			  break;
902			case 1:
903			  break;
904			case 2:
905			  md_user->u_plop.buf[md_user->u_plop.len] = ' ';
906			  md_user->u_plop.len++;
907			  break;
908			case 3:
909			  md_user->u_plop.buf[md_user->u_plop.len] = ',';
910			  md_user->u_plop.len++;
911			  break;
912			}
913		    }
914		  md_user->u_plop.len += rem(markdata->x1, markdata->y1, x2, y2,
915		    markdata->hist_offset == fore->w_histheight,
916		    md_user->u_plop.buf + md_user->u_plop.len, yend);
917#ifdef ENCODINGS
918		  md_user->u_plop.enc = fore->w_encoding;
919#endif
920		}
921	      if (markdata->hist_offset != fore->w_histheight)
922		{
923		  LAY_CALL_UP(LRefreshAll(flayer, 0));
924		}
925	      ExitOverlayPage();
926	      if (append_mode)
927		LMsg(0, "Appended %d characters to buffer",
928		    newcopylen);
929	      else
930		LMsg(0, "Copied %d characters into buffer", md_user->u_plop.len);
931	      if (write_buffer)
932		WriteFile(md_user, (char *)0, DUMP_EXCHANGE);
933	      in_mark = 0;
934	      break;
935	    }
936	default:
937	  MarkAbort();
938	  LMsg(0, "Copy mode aborted");
939	  in_mark = 0;
940	  break;
941	}
942      if (in_mark)	/* markdata may be freed */
943        markdata->rep_cnt = 0;
944    }
945  if (in_mark)
946    {
947      flayer->l_x = markdata->cx;
948      flayer->l_y = W2D(markdata->cy);
949    }
950  *inbufp = pt;
951  *inlenp = inlen;
952}
953
954void revto(tx, ty)
955int tx, ty;
956{
957  revto_line(tx, ty, -1);
958}
959
960/* tx, ty: WINDOW,  line: DISPLAY */
961void revto_line(tx, ty, line)
962int tx, ty, line;
963{
964  int fx, fy;
965  int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
966  int ystart = 0, yend = fore->w_height-1;
967  int i, ry;
968  unsigned char *wi;
969  struct mline *ml;
970  struct mchar mc;
971
972  if (tx < 0)
973    tx = 0;
974  else if (tx > fore->w_width - 1)
975    tx = fore->w_width -1;
976  if (ty < 0)
977    ty = 0;
978  else if (ty > fore->w_histheight + fore->w_height - 1)
979    ty = fore->w_histheight + fore->w_height - 1;
980
981  fx = markdata->cx; fy = markdata->cy;
982
983#ifdef DW_CHARS
984  /* don't just move inside of a kanji, the user wants to see something */
985  ml = WIN(ty);
986  if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
987    tx++;
988  if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
989    tx--;
990#endif
991
992  markdata->cx = tx; markdata->cy = ty;
993
994  /*
995   * if we go to a position that is currently offscreen
996   * then scroll the screen
997   */
998  i = 0;
999  if (line >= 0 && line < fore->w_height)
1000    i = W2D(ty) - line;
1001  else if (ty < markdata->hist_offset)
1002    i = ty - markdata->hist_offset;
1003  else if (ty > markdata->hist_offset + (fore->w_height - 1))
1004    i = ty - markdata->hist_offset - (fore->w_height - 1);
1005  if (i > 0)
1006    yend -= MarkScrollUpDisplay(i);
1007  else if (i < 0)
1008    ystart += MarkScrollDownDisplay(-i);
1009
1010  if (markdata->second == 0)
1011    {
1012      LGotoPos(flayer, tx, W2D(ty));
1013      return;
1014    }
1015
1016  qq = markdata->x1 + markdata->y1 * fore->w_width;
1017  ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
1018  tt = tx + ty * fore->w_width; /* "to" offset  in WIN coords*/
1019
1020  if (ff > tt)
1021    {
1022      st = tt; en = ff;
1023      x = tx; y = ty;
1024    }
1025  else
1026    {
1027      st = ff; en = tt;
1028      x = fx; y = fy;
1029    }
1030  if (st > qq)
1031    {
1032      st++;
1033      x++;
1034    }
1035  if (en < qq)
1036    en--;
1037  if (tt > qq)
1038    {
1039      revst = qq; reven = tt;
1040    }
1041  else
1042    {
1043      revst = tt; reven = qq;
1044    }
1045  ry = y - markdata->hist_offset;
1046  if (ry < ystart)
1047    {
1048      y += (ystart - ry);
1049      x = 0;
1050      st = y * fore->w_width;
1051      ry = ystart;
1052    }
1053  ml = WIN(y);
1054  for (t = st; t <= en; t++, x++)
1055    {
1056      if (x >= fore->w_width)
1057	{
1058	  x = 0;
1059	  y++, ry++;
1060	  ml = WIN(y);
1061	}
1062      if (ry > yend)
1063	break;
1064      if (t == st || x == 0)
1065	{
1066	  wi = ml->image + fore->w_width;
1067	  for (ce = fore->w_width; ce >= 0; ce--, wi--)
1068	    if (*wi != ' ')
1069	      break;
1070	}
1071      if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar)
1072	{
1073#ifdef DW_CHARS
1074	  if (dw_right(ml, x, fore->w_encoding))
1075	      {
1076		if (t == revst)
1077		  revst--;
1078	        t--;
1079		x--;
1080	      }
1081#endif
1082	  if (t >= revst && t <= reven)
1083	    {
1084	      mc = mchar_so;
1085#ifdef FONT
1086	      if (pastefont)
1087		mc.font = ml->font[x];
1088#endif
1089	      mc.image = ml->image[x];
1090	    }
1091	  else
1092	    copy_mline2mchar(&mc, ml, x);
1093#ifdef DW_CHARS
1094	  if (dw_left(ml, x, fore->w_encoding))
1095	    {
1096	      mc.mbcs = ml->image[x + 1];
1097	      LPutChar(flayer, &mc, x, W2D(y));
1098	      t++;
1099	    }
1100#endif
1101	  LPutChar(flayer, &mc, x, W2D(y));
1102#ifdef DW_CHARS
1103	  if (dw_left(ml, x, fore->w_encoding))
1104	    x++;
1105#endif
1106	}
1107    }
1108  LGotoPos(flayer, tx, W2D(ty));
1109}
1110
1111static void
1112MarkAbort()
1113{
1114  int yend, redisp;
1115
1116  debug("MarkAbort\n");
1117  markdata = (struct markdata *)flayer->l_data;
1118  fore = markdata->md_window;
1119  yend = fore->w_height - 1;
1120  redisp = markdata->second;
1121  if (fore->w_histheight - markdata->hist_offset < fore->w_height)
1122    {
1123      markdata->second = 0;
1124      yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
1125    }
1126  if (markdata->hist_offset != fore->w_histheight)
1127    {
1128      LAY_CALL_UP(LRefreshAll(flayer, 0));
1129    }
1130  else
1131    {
1132      rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
1133    }
1134  ExitOverlayPage();
1135}
1136
1137
1138static void
1139MarkRedisplayLine(y, xs, xe, isblank)
1140int y;	/* NOTE: y is in DISPLAY coords system! */
1141int xs, xe;
1142int isblank;
1143{
1144  int wy, x, i, rm;
1145  int sta, sto, cp;	/* NOTE: these 3 are in WINDOW coords system */
1146  unsigned char *wi;
1147  struct mline *ml;
1148  struct mchar mchar_marked;
1149
1150  if (y < 0)	/* No special full page handling */
1151    return;
1152
1153  markdata = (struct markdata *)flayer->l_data;
1154  fore = markdata->md_window;
1155
1156  mchar_marked = mchar_so;
1157
1158  wy = D2W(y);
1159  ml = WIN(wy);
1160
1161  if (markdata->second == 0)
1162    {
1163      if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
1164	xs--;
1165      if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
1166	xe++;
1167      if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
1168        LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
1169      else
1170        LCDisplayLine(flayer, ml, y, xs, xe, isblank);
1171      return;
1172    }
1173
1174  sta = markdata->y1 * fore->w_width + markdata->x1;
1175  sto = markdata->cy * fore->w_width + markdata->cx;
1176  if (sta > sto)
1177    {
1178      i=sta; sta=sto; sto=i;
1179    }
1180  cp = wy * fore->w_width + xs;
1181
1182  rm = markdata->right_mar;
1183  for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
1184    if (*wi != ' ')
1185      break;
1186  if (x < rm)
1187    rm = x;
1188
1189  for (x = xs; x <= xe; x++, cp++)
1190    if (cp >= sta && x >= markdata->left_mar)
1191      break;
1192#ifdef DW_CHARS
1193  if (dw_right(ml, x, fore->w_encoding))
1194    x--;
1195#endif
1196  if (x > xs)
1197    LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
1198  for (; x <= xe; x++, cp++)
1199    {
1200      if (cp > sto || x > rm)
1201	break;
1202#ifdef FONT
1203      if (pastefont)
1204	mchar_marked.font = ml->font[x];
1205#endif
1206      mchar_marked.image = ml->image[x];
1207#ifdef DW_CHARS
1208      mchar_marked.mbcs = 0;
1209      if (dw_left(ml, x, fore->w_encoding))
1210	{
1211	  mchar_marked.mbcs = ml->image[x + 1];
1212	  cp++;
1213	}
1214#endif
1215      LPutChar(flayer, &mchar_marked, x, y);
1216#ifdef DW_CHARS
1217      if (dw_left(ml, x, fore->w_encoding))
1218	x++;
1219#endif
1220    }
1221  if (x <= xe)
1222    LCDisplayLine(flayer, ml, y, x, xe, isblank);
1223}
1224
1225
1226/*
1227 * This ugly routine is to speed up GotoPos()
1228 */
1229static int
1230MarkRewrite(ry, xs, xe, rend, doit)
1231int ry, xs, xe, doit;
1232struct mchar *rend;
1233{
1234  int dx, x, y, st, en, t, rm;
1235  unsigned char *i;
1236  struct mline *ml;
1237  struct mchar mchar_marked;
1238
1239  mchar_marked = mchar_so;
1240
1241  debug3("MarkRewrite %d, %d-%d\n", ry, xs, xe);
1242  markdata = (struct markdata *)flayer->l_data;
1243  fore = markdata->md_window;
1244  y = D2W(ry);
1245  ml = WIN(y);
1246#ifdef UTF8
1247  if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(ml, xs, xe, fore->w_encoding))
1248    return EXPENSIVE;
1249#endif
1250  dx = xe - xs + 1;
1251  if (doit)
1252    {
1253      i = ml->image + xs;
1254      while (dx--)
1255        PUTCHAR(*i++);
1256      return 0;
1257    }
1258
1259  if (markdata->second == 0)
1260    st = en = -1;
1261  else
1262    {
1263      st = markdata->y1 * fore->w_width + markdata->x1;
1264      en = markdata->cy * fore->w_width + markdata->cx;
1265      if (st > en)
1266        {
1267          t = st; st = en; en = t;
1268        }
1269    }
1270  t = y * fore->w_width + xs;
1271  for (rm = fore->w_width, i = ml->image + fore->w_width; rm >= 0; rm--)
1272    if (*i-- != ' ')
1273      break;
1274  if (rm > markdata->right_mar)
1275    rm = markdata->right_mar;
1276  x = xs;
1277  while (dx--)
1278    {
1279      if (t >= st && t <= en && x >= markdata->left_mar && x <= rm)
1280        {
1281#ifdef FONT
1282	  if (pastefont)
1283	    mchar_marked.font = ml->font[x];
1284#endif
1285	  rend->image = mchar_marked.image;
1286	  if (!cmp_mchar(rend, &mchar_marked))
1287	    return EXPENSIVE;
1288        }
1289      else
1290        {
1291	  rend->image = ml->image[x];
1292	  if (!cmp_mchar_mline(rend, ml, x))
1293	    return EXPENSIVE;
1294        }
1295      x++;
1296    }
1297  return xe - xs + 1;
1298}
1299
1300
1301/*
1302 * scroll the screen contents up/down.
1303 */
1304static int MarkScrollUpDisplay(n)
1305int n;
1306{
1307  int i;
1308
1309  debug1("MarkScrollUpDisplay(%d)\n", n);
1310  if (n <= 0)
1311    return 0;
1312  if (n > fore->w_histheight - markdata->hist_offset)
1313    n = fore->w_histheight - markdata->hist_offset;
1314  markdata->hist_offset += n;
1315  i = (n < flayer->l_height) ? n : (flayer->l_height);
1316  LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
1317  while (i-- > 0)
1318    MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
1319  return n;
1320}
1321
1322static int
1323MarkScrollDownDisplay(n)
1324int n;
1325{
1326  int i;
1327
1328  debug1("MarkScrollDownDisplay(%d)\n", n);
1329  if (n <= 0)
1330    return 0;
1331  if (n > markdata->hist_offset)
1332    n = markdata->hist_offset;
1333  markdata->hist_offset -= n;
1334  i = (n < flayer->l_height) ? n : (flayer->l_height);
1335  LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
1336  while (i-- > 0)
1337    MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
1338  return n;
1339}
1340
1341int
1342InMark()
1343{
1344  if (flayer && flayer->l_layfn == &MarkLf)
1345    return 1;
1346  return 0;
1347}
1348
1349void
1350MakePaster(pa, buf, len, bufiscopy)
1351struct paster *pa;
1352char *buf;
1353int len;
1354int bufiscopy;
1355{
1356  FreePaster(pa);
1357  pa->pa_pasteptr = buf;
1358  pa->pa_pastelen = len;
1359  if (bufiscopy)
1360    pa->pa_pastebuf = buf;
1361  pa->pa_pastelayer = flayer;
1362  DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1363}
1364
1365void
1366FreePaster(pa)
1367struct paster *pa;
1368{
1369  if (pa->pa_pastebuf)
1370    free(pa->pa_pastebuf);
1371  pa->pa_pastebuf = 0;
1372  pa->pa_pasteptr = 0;
1373  pa->pa_pastelen = 0;
1374  pa->pa_pastelayer = 0;
1375  evdeq(&pa->pa_slowev);
1376}
1377
1378#endif /* COPY_PASTE */
1379
1380