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