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: }

Defined functions

Draw defined in line 64; used 4 times
GotoBottom defined in line 265; never used
PastBottom defined in line 272; used 2 times
PutPlusOne defined in line 963; used 7 times
RefCursor defined in line 864; never used
RefPlusOne defined in line 978; never used
Vdraw defined in line 106; used 12 times
Vnewline defined in line 134; used 1 times
has_other_than_spaces defined in line 282; used 1 times
rcsid defined in line 39; never used
str_cp defined in line 379; used 5 times
str_delete defined in line 346; used 1 times
str_insert defined in line 300; used 2 times
update_line defined in line 415; used 1 times

Defined variables

OldvcV defined in line 147; used 10 times
litptr defined in line 51; used 4 times
vcur_h defined in line 52; used 11 times
vcur_v defined in line 52; used 13 times

Defined macros

MIN_END_KEEP defined in line 413; used 1 times
Last modified: 1991-08-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4402
Valid CSS Valid XHTML 1.0 Strict