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