1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/ed.refresh.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ 2: /* 3: * ed.refresh.c: Lower level screen refreshing functions 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: ed.refresh.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #include "ed.h" 45: /* #define DEBUG_UPDATE */ 46: /* #define DEBUG_REFRESH */ 47: /* #define DEBUG_LITERAL */ 48: 49: /* refresh.c -- refresh the current set of lines on the screen */ 50: 51: Char *litptr[256]; 52: static int vcur_h, vcur_v; 53: 54: static void Draw __P((int)); 55: static void Vdraw __P((int)); 56: static void Vnewline __P((void)); 57: static void update_line __P((Char *, Char *, int)); 58: static int has_other_than_spaces __P((Char *, int)); 59: static void str_insert __P((Char *, int, int, Char *, int)); 60: static void str_delete __P((Char *, int, int, int)); 61: static void str_cp __P((Char *, Char *, int)); 62: static void PutPlusOne __P((int)); 63: 64: static void 65: Draw(c) /* draw c, expand tabs, ctl chars */ 66: register int c; 67: { 68: register Char ch = c & CHAR; 69: 70: if (Isprint(ch)) { 71: Vdraw(c); 72: return; 73: } 74: /* from wolman%crltrx.DEC@decwrl.dec.com (Alec Wolman) */ 75: if (ch == '\n') { /* expand the newline */ 76: Vdraw('\0'); /* assure end of line */ 77: vcur_h = 0; /* reset cursor pos */ 78: vcur_v++; 79: return; 80: } 81: if (ch == '\t') { /* expand the tab */ 82: for (;;) { 83: Vdraw(' '); 84: if ((vcur_h & 07) == 0) 85: break; /* go until tab stop */ 86: } 87: } 88: else if (Iscntrl(ch)) { 89: Vdraw('^'); 90: if (ch == '\177') { 91: Vdraw('?'); 92: } 93: else { 94: /* uncontrolify it; works only for iso8859-1 like sets */ 95: Vdraw((c | 0100)); 96: } 97: } 98: else { 99: Vdraw('\\'); 100: Vdraw(((c >> 6) & 7) + '0'); 101: Vdraw(((c >> 3) & 7) + '0'); 102: Vdraw((c & 7) + '0'); 103: } 104: } 105: 106: static void 107: Vdraw(c) /* draw char c onto V lines */ 108: register int c; 109: { 110: #ifdef DEBUG_REFRESH 111: # ifdef SHORT_STRINGS 112: xprintf("Vdrawing %6.6o '%c'\r\n", c, c & ASCII); 113: # else 114: xprintf("Vdrawing %3.3o '%c'\r\n", c, c); 115: # endif 116: #endif 117: 118: Vdisplay[vcur_v][vcur_h] = c; 119: vcur_h++; /* advance to next place */ 120: if (vcur_h >= TermH) { 121: Vdisplay[vcur_v][TermH] = '\0'; /* assure end of line */ 122: vcur_h = 0; /* reset it. */ 123: vcur_v++; 124: if (vcur_v >= TermV) { /* should NEVER happen. */ 125: #ifdef DEBUG_REFRESH 126: xprintf("\r\nVdraw: vcur_v overflow! Vcursor_v == %d > %d\r\n", 127: vcur_v, TermV); 128: abort(); 129: #endif /* DEBUG_REFRESH */ 130: } 131: } 132: } 133: 134: static void 135: Vnewline() 136: { 137: /* needs work. */ 138: } 139: 140: /* 141: * Refresh() 142: * draws the new virtual screen image from the current input 143: * line, then goes line-by-line changing the real image to the new 144: * virtual image. The routine to re-draw a line can be replaced 145: * easily in hopes of a smarter one being placed there. 146: */ 147: static int OldvcV = 0; 148: void 149: Refresh() 150: { 151: register int cur_line; 152: register Char *cp; 153: int cur_h, cur_v = 0, new_vcv; 154: Char oldgetting; 155: int litnum = 0; 156: 157: #ifdef DEBUG_REFRESH 158: xprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf)); 159: xprintf("InputBuf = :%s:\r\n", short2str(InputBuf)); 160: #endif 161: oldgetting = GettingInput; 162: GettingInput = 0; /* avoid re-entrance via SIGWINCH */ 163: 164: /* reset the Vdraw cursor */ 165: vcur_h = 0; 166: vcur_v = 0; 167: 168: /* draw prompt, we know it's ASCIZ */ 169: for (cp = PromptBuf; *cp; cp++) { 170: if (*cp & LITERAL) { 171: if (litnum < (sizeof(litptr) / sizeof(litptr[0]))) { 172: litptr[litnum] = cp; 173: #ifdef DEBUG_LITERAL 174: xprintf("litnum = %d, litptr = %x:\r\n", 175: litnum, litptr[litnum]); 176: #endif 177: } 178: while (*cp & LITERAL) 179: cp++; 180: if (*cp) 181: Vdraw(litnum++ | LITERAL); 182: else { 183: /* 184: * XXX: This is a bug, we lose the last literal, if it is not 185: * followed by a normal character, but it is too hard to fix 186: */ 187: break; 188: } 189: } 190: else 191: Draw(*cp); 192: } 193: cur_h = -1; /* set flag in case I'm not set */ 194: 195: /* draw the current input buffer */ 196: for (cp = InputBuf; (cp < LastChar); cp++) { 197: if (cp == Cursor) { 198: cur_h = vcur_h; /* save for later */ 199: cur_v = vcur_v; 200: } 201: Draw(*cp); 202: } 203: 204: /* to next line and draw the current search prompt if searching */ 205: if (DoingSearch) { 206: Vnewline(); 207: for (cp = SearchPrompt; *cp; cp++) 208: Draw(*cp); 209: for (cp = InputBuf; (cp < LastChar); cp++) { 210: if (cp == Cursor) { 211: cur_h = vcur_h; /* save for later */ 212: cur_v = vcur_v; 213: } 214: Draw(*cp); 215: } 216: } 217: 218: if (cur_h == -1) { /* if I havn't been set yet, I'm at the end */ 219: cur_h = vcur_h; 220: cur_v = vcur_v; 221: } 222: new_vcv = vcur_v; /* must be done BEFORE the NUL is written */ 223: Vdraw('\0'); /* put NUL on end */ 224: 225: #ifdef DEBUG_REFRESH 226: xprintf( 227: "TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n", 228: TermH, vcur_h, vcur_v, short2str(Vdisplay[0])); 229: #endif 230: 231: for (cur_line = 0; cur_line <= new_vcv; cur_line++) { 232: /* NOTE THAT update_line MAY CHANGE Display[cur_line] */ 233: update_line(Display[cur_line], Vdisplay[cur_line], cur_line); 234: (void) Strncpy(Display[cur_line], Vdisplay[cur_line], TermH); 235: Display[cur_line][TermH] = '\0'; /* just in case */ 236: } 237: #ifdef DEBUG_REFRESH 238: xprintf("\r\nvcur_v = %d, OldvcV = %d, cur_line = %d\r\n", 239: vcur_v, OldvcV, cur_line); 240: #endif 241: if (OldvcV > new_vcv) { 242: for (; cur_line <= OldvcV; cur_line++) { 243: MoveToLine(cur_line); 244: MoveToChar(0); 245: ClearEOL(Strlen(Display[cur_line])); 246: #ifdef DEBUG_REFRESH 247: so_write(str2short("C\b"), 2); 248: #endif 249: *Display[cur_line] = '\0'; 250: } 251: } 252: OldvcV = new_vcv; /* set for next time */ 253: #ifdef DEBUG_REFRESH 254: xprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n", 255: CursorH, CursorV, cur_h, cur_v); 256: #endif 257: MoveToLine(cur_v); /* go to where the cursor is */ 258: MoveToChar(cur_h); 259: SetAttributes(0); /* Clear all attributes */ 260: flush(); /* send the output... */ 261: GettingInput = oldgetting; /* reset to old value */ 262: } 263: 264: #ifdef notdef 265: GotoBottom() 266: { /* used to go to last used screen line */ 267: MoveToLine(OldvcV); 268: } 269: 270: #endif 271: 272: void 273: PastBottom() 274: { /* used to go to last used screen line */ 275: MoveToLine(OldvcV); 276: (void) putraw('\r'); 277: (void) putraw('\n'); 278: ClearDisp(); 279: flush(); 280: } 281: 282: static int 283: has_other_than_spaces(s, n) 284: register Char *s; 285: register int n; 286: { 287: if (n <= 0) 288: return 0; 289: 290: while (n-- > 0) { 291: if (*s != '\0' && *s != ' ') 292: return 1; 293: s++; 294: } 295: return 0; 296: } 297: 298: /* insert num characters of s into d (in front of the character) at dat, 299: maximum length of d is dlen */ 300: static void 301: str_insert(d, dat, dlen, s, num) 302: register Char *d; 303: register int dat, dlen; 304: register Char *s; 305: register int num; 306: { 307: register Char *a, *b; 308: 309: if (num <= 0) 310: return; 311: if (num > dlen - dat) 312: num = dlen - dat; 313: 314: #ifdef DEBUG_REFRESH 315: xprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n", 316: num, dat, dlen, short2str(d)); 317: xprintf("s == \"%s\"n", short2str(s)); 318: #endif 319: 320: /* open up the space for num chars */ 321: if (num > 0) { 322: b = d + dlen - 1; 323: a = b - num; 324: while (a >= &d[dat]) 325: *b-- = *a--; 326: d[dlen] = '\0'; /* just in case */ 327: } 328: #ifdef DEBUG_REFRESH 329: xprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n", 330: num, dat, dlen, short2str(d)); 331: xprintf("s == \"%s\"n", short2str(s)); 332: #endif 333: 334: /* copy the characters */ 335: for (a = d + dat; (a < d + dlen) && (num > 0); num--) 336: *a++ = *s++; 337: 338: #ifdef DEBUG_REFRESH 339: xprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n", 340: num, dat, dlen, d, short2str(s)); 341: xprintf("s == \"%s\"n", short2str(s)); 342: #endif 343: } 344: 345: /* delete num characters d at dat, maximum length of d is dlen */ 346: static void 347: str_delete(d, dat, dlen, num) 348: register Char *d; 349: register int dat, dlen, num; 350: { 351: register Char *a, *b; 352: 353: if (num <= 0) 354: return; 355: if (dat + num >= dlen) { 356: d[dat] = '\0'; 357: return; 358: } 359: 360: #ifdef DEBUG_REFRESH 361: xprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n", 362: num, dat, dlen, short2str(d)); 363: #endif 364: 365: /* open up the space for num chars */ 366: if (num > 0) { 367: b = d + dat; 368: a = b + num; 369: while (a < &d[dlen]) 370: *b++ = *a++; 371: d[dlen] = '\0'; /* just in case */ 372: } 373: #ifdef DEBUG_REFRESH 374: xprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n", 375: num, dat, dlen, short2str(d)); 376: #endif 377: } 378: 379: static void 380: str_cp(a, b, n) 381: register Char *a, *b; 382: register int n; 383: { 384: while (n-- && *b) 385: *a++ = *b++; 386: } 387: 388: 389: 390: /* **************************************************************** 391: update_line() is based on finding the middle difference of each line 392: on the screen; vis: 393: 394: 395: /old first difference 396: /beginning of line | /old last same /old EOL 397: v v v v 398: old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 399: new: eddie> Oh, my little buggy says to me, as lurgid as 400: ^ ^ ^ ^ 401: \beginning of line | \new last same \new end of line 402: \new first difference 403: 404: all are character pointers for the sake of speed. Special cases for 405: no differences, as well as for end of line additions must be handled. 406: **************************************************************** */ 407: 408: /* Minimum at which doing an insert it "worth it". This should be about 409: * half the "cost" of going into insert mode, inserting a character, and 410: * going back out. This should really be calculated from the t_c_ 411: * data... For the moment, a good number for ANSI terminals. 412: */ 413: #define MIN_END_KEEP 4 414: 415: static void /* could be changed to make it smarter */ 416: update_line(old, new, cur_line) 417: register Char *old, *new; 418: int cur_line; 419: { 420: register Char *o, *n, *p, c; 421: Char *ofd, *ols, *oe, *nfd, *nls, *ne; 422: Char *osb, *ose, *nsb, *nse; 423: int fx, sx; 424: 425: /* 426: * find first diff 427: */ 428: for (o = old, n = new; *o && (*o == *n); o++, n++); 429: ofd = o; 430: nfd = n; 431: 432: /* 433: * if no diff, continue to next line 434: */ 435: if (*ofd == '\0' && *nfd == '\0') { 436: #ifdef DEBUG_UPDATE 437: DEBUGPRINT("no difference.\r\n", 0); 438: #endif /* DEBUG_UPDATE */ 439: return; 440: } 441: 442: /* 443: * Find the end of both old and new 444: */ 445: while (*o) 446: o++; 447: oe = o; 448: 449: while (*n) 450: n++; 451: ne = n; 452: 453: /* 454: * find last same * 455: */ 456: for (; (o > ofd) && (n > nfd) && (o[-1] == n[-1]); o--, n--); 457: ols = o; 458: nls = n; 459: 460: /* 461: * find same begining and same end 462: */ 463: osb = ols; 464: nsb = nls; 465: ose = ols; 466: nse = nls; 467: 468: /* 469: * case 1: insert: scan from nfd to nls looking for *ofd 470: */ 471: if (*ofd) { 472: for (c = *ofd, n = nfd; n < nls; n++) { 473: if (c == *n) { 474: for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++); 475: /* 476: * if the new match is longer and it's worth keeping, then we 477: * take it 478: */ 479: if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { 480: nsb = n; 481: nse = p; 482: osb = ofd; 483: ose = o; 484: } 485: } 486: } 487: } 488: 489: /* 490: * case 2: delete: scan from ofd to ols looking for *nfd 491: */ 492: if (*nfd) { 493: for (c = *nfd, o = ofd; o < ols; o++) { 494: if (c == *o) { 495: for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++); 496: /* 497: * if the new match is longer and it's worth keeping, then we 498: * take it 499: */ 500: if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { 501: nsb = nfd; 502: nse = n; 503: osb = o; 504: ose = p; 505: } 506: } 507: } 508: } 509: 510: /* 511: * Pragmatics I: If old trailing whitespace or not enough characters to 512: * save to be worth it, then don't save the last same info. 513: */ 514: if ((oe - ols) < MIN_END_KEEP) { 515: ols = oe; 516: nls = ne; 517: } 518: 519: /* 520: * Pragmatics II: if the terminal isn't smart enough, make the data dumber 521: * so the smart update doesn't try anything fancy 522: */ 523: 524: /* 525: * fx is the number of characters we need to insert/delete: in the 526: * beginning to bring the two same begins together 527: */ 528: fx = (nsb - nfd) - (osb - ofd); 529: /* 530: * sx is the number of characters we need to insert/delete: in the end to 531: * bring the two same last parts together 532: */ 533: sx = (nls - nse) - (ols - ose); 534: 535: if (!T_CanIns) { 536: if (fx > 0) { 537: osb = ols; 538: ose = ols; 539: nsb = nls; 540: nse = nls; 541: } 542: if (sx > 0) { 543: ols = oe; 544: nls = ne; 545: } 546: if ((ols - ofd) < (nls - nfd)) { 547: ols = oe; 548: nls = ne; 549: } 550: } 551: if (!T_CanDel) { 552: if (fx < 0) { 553: osb = ols; 554: ose = ols; 555: nsb = nls; 556: nse = nls; 557: } 558: if (sx < 0) { 559: ols = oe; 560: nls = ne; 561: } 562: if ((ols - ofd) > (nls - nfd)) { 563: ols = oe; 564: nls = ne; 565: } 566: } 567: 568: /* 569: * Pragmatics III: make sure the middle shifted pointers are correct if 570: * they don't point to anything (we may have moved ols or nls). 571: */ 572: if (osb == ose) { 573: osb = ols; 574: ose = ols; 575: nsb = nls; 576: nse = nls; 577: } 578: 579: /* 580: * Now that we are done with pragmatics we recompute fx, sx 581: */ 582: fx = (nsb - nfd) - (osb - ofd); 583: sx = (nls - nse) - (ols - ose); 584: 585: #ifdef DEBUG_UPDATE 586: xprintf("\n"); 587: xprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n", 588: ofd - old, osb - old, ose - old, ols - old, oe - old); 589: xprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n", 590: nfd - new, nsb - new, nse - new, nls - new, ne - new); 591: xprintf("old:\"%s\"\r\n", short2str(old)); 592: xprintf("new:\"%s\"\r\n", short2str(new)); 593: xprintf("ofd:\"%s\"\r\n", short2str(ofd)); 594: xprintf("nfd:\"%s\"\r\n", short2str(nfd)); 595: xprintf("ols:\"%s\"\r\n", short2str(ols)); 596: xprintf("nls:\"%s\"\r\n", short2str(nls)); 597: xprintf("*oe:%o,*ne:%o\r\n", *oe, *ne); 598: xprintf("osb:\"%s\"\r\n", short2str(osb)); 599: xprintf("ose:\"%s\"\r\n", short2str(ose)); 600: xprintf("nsb:\"%s\"\r\n", short2str(nsb)); 601: xprintf("nse:\"%s\"\r\n", short2str(nse)); 602: #endif /* DEBUG_UPDATE */ 603: 604: /* 605: * CursorV to this line cur_line MUST be in this routine so that if we 606: * don't have to change the line, we don't move to it. CursorH to first 607: * diff char 608: */ 609: MoveToLine(cur_line); 610: 611: /* 612: * at this point we have something like this: 613: * 614: * /old /ofd /osb /ose /ols /oe 615: * v.....................v v..................v v........v 616: * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as 617: * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as 618: * ^.....................^ ^..................^ ^........^ 619: * \new \nfd \nsb \nse \nls \ne 620: * 621: */ 622: 623: /* 624: * if we have a net insert on the first difference, AND inserting the net 625: * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character 626: * (which is ne if nls != ne, otherwise is nse) off the edge of the screen 627: * (TermH) else we do the deletes first so that we keep everything we need 628: * to. 629: */ 630: 631: /* 632: * if the last same is the same like the end, there is no last same part, 633: * otherwise we want to keep the last same part set p to the last useful 634: * old character 635: */ 636: p = (ols != oe) ? oe : ose; 637: 638: /* 639: * if (There is a diffence in the beginning) && (we need to insert 640: * characters) && (the number of characters to insert is less than the term 641: * width) We need to do an insert! else if (we need to delete characters) 642: * We need to delete characters! else No insert or delete 643: */ 644: if ((nsb != nfd) && fx > 0 && ((p - old) + fx <= TermH)) { 645: #ifdef DEBUG_UPDATE 646: DEBUGPRINT("\nfirst diff insert at %d...\n", nfd - new); 647: #endif /* DEBUG_UPDATE */ 648: /* 649: * Move to the first char to insert, where the first diff is. 650: */ 651: MoveToChar(nfd - new); 652: /* 653: * Check if we have stuff to keep at end 654: */ 655: if (nsb != ne) { 656: #ifdef DEBUG_UPDATE 657: DEBUGPRINT("\nwith stuff to keep at end\n", 0); 658: #endif /* DEBUG_UPDATE */ 659: /* 660: * insert fx chars of new starting at nfd 661: */ 662: if (fx > 0) { 663: #ifdef DEBUG_UPDATE 664: if (!T_CanIns) 665: xprintf(" ERROR: cannot insert in early first diff\n"); 666: #endif /* DEBUG_UPDATE */ 667: Insert_write(nfd, fx); 668: str_insert(old, ofd - old, TermH, nfd, fx); 669: } 670: /* 671: * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 672: */ 673: so_write(nfd + fx, (nsb - nfd) - fx); 674: str_cp(ofd + fx, nfd + fx, (nsb - nfd) - fx); 675: } 676: else { 677: #ifdef DEBUG_UPDATE 678: DEBUGPRINT("\nwithout anything to save\n", 0); 679: #endif /* DEBUG_UPDATE */ 680: so_write(nfd, (nsb - nfd)); 681: str_cp(ofd, nfd, (nsb - nfd)); 682: /* 683: * Done 684: */ 685: return; 686: } 687: } 688: else if (fx < 0) { 689: #ifdef DEBUG_UPDATE 690: DEBUGPRINT("\nfirst diff delete at %d...\n", ofd - old); 691: #endif /* DEBUG_UPDATE */ 692: /* 693: * move to the first char to delete where the first diff is 694: */ 695: MoveToChar(ofd - old); 696: /* 697: * Check if we have stuff to save 698: */ 699: if (osb != oe) { 700: #ifdef DEBUG_UPDATE 701: DEBUGPRINT("\nwith stuff to save at end\n", 0); 702: #endif /* DEBUG_UPDATE */ 703: /* 704: * fx is less than zero *always* here but we check for code 705: * symmetry 706: */ 707: if (fx < 0) { 708: if (!T_CanDel) 709: xprintf(" ERROR: cannot delete in first diff\n"); 710: DeleteChars(-fx); 711: str_delete(old, ofd - old, TermH, -fx); 712: } 713: /* 714: * write (nsb-nfd) chars of new starting at nfd 715: */ 716: so_write(nfd, (nsb - nfd)); 717: str_cp(ofd, nfd, (nsb - nfd)); 718: 719: } 720: else { 721: #ifdef DEBUG_UPDATE 722: DEBUGPRINT("\nbut with nothing left to save\n", 0); 723: #endif /* DEBUG_UPDATE */ 724: /* 725: * write (nsb-nfd) chars of new starting at nfd 726: */ 727: so_write(nfd, (nsb - nfd)); 728: #ifdef DEBUG_UPDATE 729: DEBUGPRINT("cleareol %d\n", (oe - old) - (ne - new)); 730: #endif /* DEBUG_UPDATE */ 731: ClearEOL((oe - old) - (ne - new)); 732: /* 733: * Done 734: */ 735: return; 736: } 737: } 738: else 739: fx = 0; 740: 741: if (sx < 0) { 742: #ifdef DEBUG_UPDATE 743: DEBUGPRINT("\nsecond diff delete at %d...\n", (ose - old) + fx); 744: #endif /* DEBUG_UPDATE */ 745: /* 746: * Check if we have stuff to delete 747: */ 748: /* 749: * fx is the number of characters inserted (+) or deleted (-) 750: */ 751: MoveToChar((ose - old) + fx); 752: if (ols != oe) { 753: #ifdef DEBUG_UPDATE 754: DEBUGPRINT("\nwith stuff to save at end\n", 0); 755: #endif /* DEBUG_UPDATE */ 756: /* 757: * Again a duplicate test. 758: */ 759: if (sx < 0) { 760: #ifdef DEBUG_UPDATE 761: if (!T_CanDel) 762: xprintf(" ERROR: cannot delete in second diff\n"); 763: #endif /* DEBUG_UPDATE */ 764: DeleteChars(-sx); 765: } 766: 767: /* 768: * write (nls-nse) chars of new starting at nse 769: */ 770: so_write(nse, (nls - nse)); 771: } 772: else { 773: #ifdef DEBUG_UPDATE 774: DEBUGPRINT("\nbut with nothing left to save\n", 0); 775: #endif /* DEBUG_UPDATE */ 776: so_write(nse, (nls - nse)); 777: #ifdef DEBUG_UPDATE 778: DEBUGPRINT("cleareol %d\n", (oe - old) - (ne - new)); 779: #endif /* DEBUG_UPDATE */ 780: ClearEOL((oe - old) - (ne - new)); 781: } 782: } 783: 784: /* 785: * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... 786: */ 787: if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { 788: #ifdef DEBUG_UPDATE 789: DEBUGPRINT("\nlate first diff insert at %d...\n", nfd - new); 790: #endif /* DEBUG_UPDATE */ 791: MoveToChar(nfd - new); 792: /* 793: * Check if we have stuff to keep at the end 794: */ 795: if (nsb != ne) { 796: #ifdef DEBUG_UPDATE 797: DEBUGPRINT("\nwith stuff to keep at end\n", 0); 798: #endif /* DEBUG_UPDATE */ 799: if (fx > 0) { 800: /* 801: * insert fx chars of new starting at nfd 802: */ 803: #ifdef DEBUG_UPDATE 804: if (!T_CanIns) 805: xprintf(" ERROR: cannot insert in late first diff\n"); 806: #endif /* DEBUG_UPDATE */ 807: Insert_write(nfd, fx); 808: str_insert(old, ofd - old, TermH, nfd, fx); 809: } 810: 811: /* 812: * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 813: */ 814: so_write(nfd + fx, (nsb - nfd) - fx); 815: str_cp(ofd + fx, nfd + fx, (nsb - nfd) - fx); 816: } 817: else { 818: #ifdef DEBUG_UPDATE 819: DEBUGPRINT("\nwithout anything to save\n", 0); 820: #endif /* DEBUG_UPDATE */ 821: so_write(nfd, (nsb - nfd)); 822: str_cp(ofd, nfd, (nsb - nfd)); 823: } 824: } 825: 826: /* 827: * line is now NEW up to nse 828: */ 829: if ((nls != nse) && has_other_than_spaces(nse, (nls - nse)) && sx >= 0) { 830: #ifdef DEBUG_UPDATE 831: DEBUGPRINT("\nsecond diff insert at %d...\n", nse - new); 832: #endif /* DEBUG_UPDATE */ 833: MoveToChar(nse - new); 834: if (nls != ne) { 835: #ifdef DEBUG_UPDATE 836: DEBUGPRINT("\nwith stuff to keep at end\n", 0); 837: #endif /* DEBUG_UPDATE */ 838: if (sx > 0) { 839: /* insert sx chars of new starting at nse */ 840: #ifdef DEBUG_UPDATE 841: if (!T_CanIns) 842: xprintf(" ERROR: cannot insert in second diff\n"); 843: #endif /* DEBUG_UPDATE */ 844: Insert_write(nse, sx); 845: } 846: 847: /* 848: * write (nls-nse) - sx chars of new starting at (nse + sx) 849: */ 850: so_write(nse + sx, (nls - nse) - sx); 851: } 852: else { 853: #ifdef DEBUG_UPDATE 854: DEBUGPRINT("\nwithout anything to save\n", 0); 855: #endif /* DEBUG_UPDATE */ 856: so_write(nse, (nls - nse)); 857: } 858: } 859: #ifdef DEBUG_UPDATE 860: DEBUGPRINT("\ndone.\n", 0); 861: #endif /* DEBUG_UPDATE */ 862: } 863: 864: void 865: RefCursor() 866: { /* only move to new cursor pos */ 867: register Char *cp, c; 868: register int h, th, v; 869: 870: if (DoingSearch) { 871: Refresh(); 872: return; 873: } 874: 875: /* first we must find where the cursor is... */ 876: h = 0; 877: v = 0; 878: th = TermH; /* optimize for speed */ 879: 880: for (cp = PromptBuf; *cp; cp++) { /* do prompt */ 881: if (*cp & LITERAL) 882: continue; 883: c = *cp & CHAR; /* extra speed plus strip the inverse */ 884: h++; /* all chars at least this long */ 885: 886: /* from wolman%crltrx.DEC@decwrl.dec.com (Alec Wolman) */ 887: /* lets handle newline as part of the prompt */ 888: 889: if (c == '\n') { 890: h = 0; 891: v++; 892: } 893: else { 894: if (c == '\t') { /* if a tab, to next tab stop */ 895: while (h & 07) { 896: h++; 897: } 898: } 899: else if (Iscntrl(c)) { /* if control char */ 900: h++; 901: if (h > th) { /* if overflow, compensate */ 902: h = 1; 903: v++; 904: } 905: } 906: else if (!Isprint(c)) { 907: h += 3; 908: if (h > th) { /* if overflow, compensate */ 909: h = h - th; 910: v++; 911: } 912: } 913: } 914: 915: if (h >= th) { /* check, extra long tabs picked up here also */ 916: h = 0; 917: v++; 918: } 919: } 920: 921: for (cp = InputBuf; cp < Cursor; cp++) { /* do input buffer to Cursor */ 922: c = *cp & CHAR; /* extra speed plus strip the inverse */ 923: h++; /* all chars at least this long */ 924: 925: if (c == '\n') { /* handle newline in data part too */ 926: h = 0; 927: v++; 928: } 929: else { 930: if (c == '\t') { /* if a tab, to next tab stop */ 931: while (h & 07) { 932: h++; 933: } 934: } 935: else if (Iscntrl(c)) { /* if control char */ 936: h++; 937: if (h > th) { /* if overflow, compensate */ 938: h = 1; 939: v++; 940: } 941: } 942: else if (!Isprint(c)) { 943: h += 3; 944: if (h > th) { /* if overflow, compensate */ 945: h = h - th; 946: v++; 947: } 948: } 949: } 950: 951: if (h >= th) { /* check, extra long tabs picked up here also */ 952: h = 0; 953: v++; 954: } 955: } 956: 957: /* now go there */ 958: MoveToLine(v); 959: MoveToChar(h); 960: flush(); 961: } 962: 963: static void 964: PutPlusOne(c) 965: int c; 966: { 967: (void) putraw(c); 968: Display[CursorV][CursorH++] = c; 969: if (CursorH >= TermH) { /* if we must overflow */ 970: CursorH = 0; 971: CursorV++; 972: OldvcV++; 973: (void) putraw('\r'); 974: (void) putraw('\n'); 975: } 976: } 977: 978: void 979: RefPlusOne() 980: { /* we added just one char, handle it fast *//* a 981: * ssumes that screen cursor == real cursor */ 982: register Char c, mc; 983: 984: c = Cursor[-1] & CHAR; /* the char we just added */ 985: 986: if (c == '\t' || Cursor != LastChar) { 987: Refresh(); /* too hard to handle */ 988: return; 989: } /* else (only do at end of line, no TAB) */ 990: 991: if (DoingSearch) { 992: Refresh(); 993: return; 994: } 995: 996: if (Iscntrl(c)) { /* if control char, do caret */ 997: mc = (c == '\177') ? '?' : (c | 0100); 998: PutPlusOne('^'); 999: PutPlusOne(mc); 1000: } 1001: else if (Isprint(c)) { /* normal char */ 1002: PutPlusOne(c); 1003: } 1004: else { 1005: PutPlusOne('\\'); 1006: PutPlusOne(((c >> 6) & 7) + '0'); 1007: PutPlusOne(((c >> 3) & 7) + '0'); 1008: PutPlusOne((c & 7) + '0'); 1009: } 1010: flush(); 1011: } 1012: 1013: /* clear the screen buffers so that new new prompt starts fresh. */ 1014: 1015: void 1016: ClearDisp() 1017: { 1018: register int i; 1019: 1020: CursorV = 0; /* clear the display buffer */ 1021: CursorH = 0; 1022: for (i = 0; i < TermV; i++) 1023: Display[i][0] = '\0'; 1024: OldvcV = 0; 1025: } 1026: 1027: void 1028: ClearLines() 1029: { /* Make sure all lines are *really* blank */ 1030: register int i; 1031: 1032: if (T_CanCEOL) { 1033: MoveToChar(0); 1034: for (i = 0; i <= OldvcV; i++) { /* for each line on the screen */ 1035: MoveToLine(i); 1036: ClearEOL(TermH); 1037: } 1038: MoveToLine(0); 1039: } 1040: else { 1041: MoveToLine(OldvcV); /* go to last line */ 1042: (void) putraw('\r'); /* go to BOL */ 1043: (void) putraw('\n'); /* go to new line */ 1044: } 1045: }