142660Smarkm/* $Header: /p/tcsh/cvsroot/tcsh/ed.refresh.c,v 3.47 2011/02/27 00:14:51 christos Exp $ */ 2146515Sru/* 321495Sjmacd * ed.refresh.c: Lower level screen refreshing functions 442660Smarkm */ 521495Sjmacd/*- 621495Sjmacd * Copyright (c) 1980, 1991 The Regents of the University of California. 7146515Sru * All rights reserved. 821495Sjmacd * 921495Sjmacd * Redistribution and use in source and binary forms, with or without 1021495Sjmacd * modification, are permitted provided that the following conditions 1121495Sjmacd * are met: 1221495Sjmacd * 1. Redistributions of source code must retain the above copyright 1321495Sjmacd * notice, this list of conditions and the following disclaimer. 1421495Sjmacd * 2. Redistributions in binary form must reproduce the above copyright 1521495Sjmacd * notice, this list of conditions and the following disclaimer in the 1621495Sjmacd * documentation and/or other materials provided with the distribution. 1721495Sjmacd * 3. Neither the name of the University nor the names of its contributors 1821495Sjmacd * may be used to endorse or promote products derived from this software 1921495Sjmacd * without specific prior written permission. 2021495Sjmacd * 2121495Sjmacd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2221495Sjmacd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2321495Sjmacd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2421495Sjmacd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2542660Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2642660Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2721495Sjmacd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28146515Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2921495Sjmacd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3021495Sjmacd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3121495Sjmacd * SUCH DAMAGE. 3221495Sjmacd */ 3321495Sjmacd#include "sh.h" 3421495Sjmacd 3521495SjmacdRCSID("$tcsh: ed.refresh.c,v 3.47 2011/02/27 00:14:51 christos Exp $") 3621495Sjmacd 3721495Sjmacd#include "ed.h" 3821495Sjmacd/* #define DEBUG_UPDATE */ 3921495Sjmacd/* #define DEBUG_REFRESH */ 4021495Sjmacd/* #define DEBUG_LITERAL */ 4121495Sjmacd 4221495Sjmacd/* refresh.c -- refresh the current set of lines on the screen */ 4321495Sjmacd 4421495SjmacdChar *litptr; 4521495Sjmacdstatic int vcursor_h, vcursor_v; 4621495Sjmacdstatic int rprompt_h, rprompt_v; 4721495Sjmacd 4842660Smarkmstatic int MakeLiteral (Char *, int, Char); 4942660Smarkmstatic int Draw (Char *, int); 5042660Smarkmstatic void Vdraw (Char, int); 5121495Sjmacdstatic void RefreshPromptpart (Char *); 5221495Sjmacdstatic void update_line (Char *, Char *, int); 5321495Sjmacdstatic void str_insert (Char *, int, int, Char *, int); 5421495Sjmacdstatic void str_delete (Char *, int, int, int); 5521495Sjmacdstatic void str_cp (Char *, Char *, int); 5621495Sjmacd#ifndef WINNT_NATIVE 5721495Sjmacdstatic 5842660Smarkm#else 5942660Smarkmextern 6042660Smarkm#endif 6142660Smarkm void PutPlusOne (Char, int); 6242660Smarkmstatic void cpy_pad_spaces (Char *, Char *, int); 6342660Smarkm#if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL) 6442660Smarkmstatic void reprintf (char *, ...); 6542660Smarkm#ifdef DEBUG_UPDATE 6642660Smarkmstatic void dprintstr (char *, const Char *, const Char *); 6742660Smarkm 6842660Smarkmstatic void 6942660Smarkmdprintstr(char *str, const Char *f, const Char *t) 7042660Smarkm{ 7142660Smarkm reprintf("%s:\"", str); 7221495Sjmacd while (f < t) { 7321495Sjmacd if (ASC(*f) & ~ASCII) 7421495Sjmacd reprintf("[%x]", *f++); 7542660Smarkm else 7621495Sjmacd reprintf("%c", CTL_ESC(ASCII & ASC(*f++))); 7721495Sjmacd } 78146515Sru reprintf("\"\r\n"); 79146515Sru} 80146515Sru#endif /* DEBUG_UPDATE */ 81146515Sru 82146515Sru/* reprintf(): 83146515Sru * Print to $DEBUGTTY, so that we can test editing on one pty, and 84146515Sru * print debugging stuff on another. Don't interrupt the shell while 85146515Sru * debugging cause you'll mangle up the file descriptors! 8642660Smarkm */ 8742660Smarkmstatic void 8842660Smarkmreprintf(char *fmt, ...) 8942660Smarkm{ 9042660Smarkm static int fd = -1; 9142660Smarkm char *dtty; 9242660Smarkm 9321495Sjmacd if ((dtty = getenv("DEBUGTTY"))) { 9442660Smarkm int o; 9542660Smarkm va_list va; 9642660Smarkm va_start(va, fmt); 9742660Smarkm 9821495Sjmacd if (fd == -1) 9921495Sjmacd fd = xopen(dtty, O_RDWR); 10021495Sjmacd o = SHOUT; 10121495Sjmacd flush(); 10221495Sjmacd SHOUT = fd; 10321495Sjmacd xvprintf(fmt, va); 10421495Sjmacd va_end(va); 10521495Sjmacd flush(); 106146515Sru SHOUT = o; 10721495Sjmacd } 10821495Sjmacd} 10921495Sjmacd#endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */ 11021495Sjmacd 111146515Srustatic int litlen = 0, litalloc = 0; 11221495Sjmacd 11321495Sjmacdstatic int MakeLiteral(Char *str, int len, Char addlit) 11421495Sjmacd{ 11521495Sjmacd int i, addlitlen = 0; 11621495Sjmacd Char *addlitptr = 0; 11721495Sjmacd if (addlit) { 118146515Sru if ((addlit & LITERAL) != 0) { 11921495Sjmacd addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; 12021495Sjmacd addlitlen = Strlen(addlitptr); 12121495Sjmacd } else { 12221495Sjmacd addlitptr = &addlit; 123146515Sru addlitlen = 1; 12421495Sjmacd } 12521495Sjmacd for (i = 0; i < litlen; i += LIT_FACTOR) 12621495Sjmacd if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0) 12721495Sjmacd return (i / LIT_FACTOR) | LITERAL; 12821495Sjmacd } else { 12921495Sjmacd addlitlen = 0; 13021495Sjmacd for (i = 0; i < litlen; i += LIT_FACTOR) 13121495Sjmacd if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0) 132146515Sru return (i / LIT_FACTOR) | LITERAL; 13321495Sjmacd } 13421495Sjmacd if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) { 13521495Sjmacd Char *newlitptr; 13621495Sjmacd int add = 256; 13721495Sjmacd while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add) 138146515Sru add *= 2; 13921495Sjmacd newlitptr = xrealloc(litptr, (litalloc + add) * sizeof(Char)); 14021495Sjmacd if (!newlitptr) 14121495Sjmacd return '?'; 14221495Sjmacd litptr = newlitptr; 143146515Sru litalloc += add; 14421495Sjmacd if (addlitptr && addlitptr != &addlit) 14521495Sjmacd addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; 146146515Sru } 14721495Sjmacd i = litlen / LIT_FACTOR; 14821495Sjmacd if (i >= LITERAL || i == CHAR_DBWIDTH) 14921495Sjmacd return '?'; 15021495Sjmacd if (addlitptr) { 15121495Sjmacd Strncpy(litptr + litlen, addlitptr, addlitlen); 15221495Sjmacd litlen += addlitlen; 153146515Sru } 15421495Sjmacd Strncpy(litptr + litlen, str, len); 15521495Sjmacd litlen += len; 15621495Sjmacd do 157146515Sru litptr[litlen++] = 0; 15821495Sjmacd while (litlen % LIT_FACTOR); 15921495Sjmacd return i | LITERAL; 160146515Sru} 16121495Sjmacd 16221495Sjmacdstatic int 163146515SruDraw(Char *cp, int nocomb) /* draw char at cp, expand tabs, ctl chars */ 16421495Sjmacd{ 16521495Sjmacd int w, i, lv, lh; 166146515Sru Char c, attr; 16721495Sjmacd 16821495Sjmacd attr = *cp & ~CHAR; 16921495Sjmacd c = *cp & CHAR; 170146515Sru w = NLSClassify(c, nocomb); 17121495Sjmacd switch (w) { 17221495Sjmacd case NLSCLASS_NL: 173146515Sru Vdraw('\0', 0); /* assure end of line */ 17421495Sjmacd vcursor_h = 0; /* reset cursor pos */ 17521495Sjmacd vcursor_v++; 176146515Sru break; 177146515Sru case NLSCLASS_TAB: 17821495Sjmacd do { 17921495Sjmacd Vdraw(' ', 1); 180146515Sru } while ((vcursor_h & 07) != 0); 18121495Sjmacd break; 18221495Sjmacd case NLSCLASS_CTRL: 183146515Sru Vdraw('^' | attr, 1); 18421495Sjmacd if (c == CTL_ESC('\177')) { 18521495Sjmacd Vdraw('?' | attr, 1); 186146515Sru } else { 18721495Sjmacd#ifdef IS_ASCII 18821495Sjmacd /* uncontrolify it; works only for iso8859-1 like sets */ 18921495Sjmacd Vdraw(c | 0100 | attr, 1); 19021495Sjmacd#else 19121495Sjmacd Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1); 192146515Sru#endif 19321495Sjmacd } 19421495Sjmacd break; 19521495Sjmacd case NLSCLASS_ILLEGAL: 19621495Sjmacd Vdraw('\\' | attr, 1); 19721495Sjmacd Vdraw((((c >> 6) & 7) + '0') | attr, 1); 198146515Sru Vdraw((((c >> 3) & 7) + '0') | attr, 1); 199146515Sru Vdraw(((c & 7) + '0') | attr, 1); 20021495Sjmacd break; 20121495Sjmacd case NLSCLASS_ILLEGAL2: 20221495Sjmacd case NLSCLASS_ILLEGAL3: 203146515Sru case NLSCLASS_ILLEGAL4: 20421495Sjmacd Vdraw('\\' | attr, 1); 20521495Sjmacd Vdraw('U' | attr, 1); 20621495Sjmacd Vdraw('+' | attr, 1); 207146515Sru for (i = 8 * NLSCLASS_ILLEGAL_SIZE(w) - 4; i >= 0; i -= 4) 20821495Sjmacd Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1); 20921495Sjmacd break; 21021495Sjmacd case 0: 211146515Sru lv = vcursor_v; 21221495Sjmacd lh = vcursor_h; 21321495Sjmacd for (;;) { 214146515Sru lh--; 21521495Sjmacd if (lh < 0) { 21621495Sjmacd lv--; 21721495Sjmacd if (lv < 0) 218146515Sru break; 21921495Sjmacd lh = Strlen(Vdisplay[lv]) - 1; 22021495Sjmacd } 22121495Sjmacd if (Vdisplay[lv][lh] != CHAR_DBWIDTH) 222146515Sru break; 22321495Sjmacd } 22421495Sjmacd if (lv < 0) { 225146515Sru Vdraw('\\' | attr, 1); 22621495Sjmacd Vdraw((((c >> 6) & 7) + '0') | attr, 1); 22721495Sjmacd Vdraw((((c >> 3) & 7) + '0') | attr, 1); 228146515Sru Vdraw(((c & 7) + '0') | attr, 1); 22921495Sjmacd break; 23021495Sjmacd } 231146515Sru Vdisplay[lv][lh] = MakeLiteral(cp, 1, Vdisplay[lv][lh]); 23221495Sjmacd break; 23321495Sjmacd default: 234146515Sru Vdraw(*cp, w); 235146515Sru break; 23621495Sjmacd } 23721495Sjmacd return 1; 23821495Sjmacd} 239146515Sru 24021495Sjmacdstatic void 24142660SmarkmVdraw(Char c, int width) /* draw char c onto V lines */ 242{ 243#ifdef DEBUG_REFRESH 244# ifdef SHORT_STRINGS 245 reprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width); 246# else 247 reprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width); 248# endif /* SHORT_STRNGS */ 249#endif /* DEBUG_REFRESH */ 250 251 /* Hopefully this is what all the terminals do with multi-column characters 252 that "span line breaks". */ 253 while (vcursor_h + width > TermH) 254 Vdraw(' ', 1); 255 Vdisplay[vcursor_v][vcursor_h] = c; 256 if (width) 257 vcursor_h++; /* advance to next place */ 258 while (--width > 0) 259 Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH; 260 if (vcursor_h >= TermH) { 261 Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */ 262 vcursor_h = 0; /* reset it. */ 263 vcursor_v++; 264#ifdef DEBUG_REFRESH 265 if (vcursor_v >= TermV) { /* should NEVER happen. */ 266 reprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n", 267 vcursor_v, TermV); 268 abort(); 269 } 270#endif /* DEBUG_REFRESH */ 271 } 272} 273 274/* 275 * RefreshPromptpart() 276 * draws a prompt element, expanding literals (we know it's ASCIZ) 277 */ 278static void 279RefreshPromptpart(Char *buf) 280{ 281 Char *cp; 282 int w; 283 284 if (buf == NULL) 285 return; 286 for (cp = buf; *cp; ) { 287 if (*cp & LITERAL) { 288 Char *litstart = cp; 289 while (*cp & LITERAL) 290 cp++; 291 if (*cp) { 292 w = NLSWidth(*cp & CHAR); 293 Vdraw(MakeLiteral(litstart, cp + 1 - litstart, 0), w); 294 cp++; 295 } 296 else { 297 /* 298 * XXX: This is a bug, we lose the last literal, if it is not 299 * followed by a normal character, but it is too hard to fix 300 */ 301 break; 302 } 303 } 304 else 305 cp += Draw(cp, cp == buf); 306 } 307} 308 309/* 310 * Refresh() 311 * draws the new virtual screen image from the current input 312 * line, then goes line-by-line changing the real image to the new 313 * virtual image. The routine to re-draw a line can be replaced 314 * easily in hopes of a smarter one being placed there. 315 */ 316#ifndef WINNT_NATIVE 317static 318#endif 319int OldvcV = 0; 320 321void 322Refresh(void) 323{ 324 int cur_line; 325 Char *cp; 326 int cur_h, cur_v = 0, new_vcv; 327 int rhdiff; 328 Char oldgetting; 329 330#ifdef DEBUG_REFRESH 331 reprintf("Prompt = :%s:\r\n", short2str(Prompt)); 332 reprintf("InputBuf = :%s:\r\n", short2str(InputBuf)); 333#endif /* DEBUG_REFRESH */ 334 oldgetting = GettingInput; 335 GettingInput = 0; /* avoid re-entrance via SIGWINCH */ 336 337 /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */ 338 vcursor_h = 0; 339 vcursor_v = 0; 340 RefreshPromptpart(RPrompt); 341 rprompt_h = vcursor_h; 342 rprompt_v = vcursor_v; 343 344 /* reset the Vdraw cursor, draw prompt */ 345 vcursor_h = 0; 346 vcursor_v = 0; 347 RefreshPromptpart(Prompt); 348 cur_h = -1; /* set flag in case I'm not set */ 349 350 /* draw the current input buffer */ 351 for (cp = InputBuf; (cp < LastChar); ) { 352 if (cp >= Cursor && cur_h == -1) { 353 cur_h = vcursor_h; /* save for later */ 354 cur_v = vcursor_v; 355 Cursor = cp; 356 } 357 cp += Draw(cp, cp == InputBuf); 358 } 359 360 if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */ 361 cur_h = vcursor_h; 362 cur_v = vcursor_v; 363 } 364 365 rhdiff = TermH - vcursor_h - rprompt_h; 366 if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) { 367 /* 368 * have a right-hand side prompt that will fit on 369 * the end of the first line with at least one 370 * character gap to the input buffer. 371 */ 372 while (--rhdiff > 0) /* pad out with spaces */ 373 Vdraw(' ', 1); 374 RefreshPromptpart(RPrompt); 375 } 376 else { 377 rprompt_h = 0; /* flag "not using rprompt" */ 378 rprompt_v = 0; 379 } 380 381 new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */ 382 Vdraw('\0', 1); /* put NUL on end */ 383 384#if defined (DEBUG_REFRESH) 385 reprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n", 386 TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0])); 387#endif /* DEBUG_REFRESH */ 388 389#ifdef DEBUG_UPDATE 390 reprintf("updating %d lines.\r\n", new_vcv); 391#endif /* DEBUG_UPDATE */ 392 for (cur_line = 0; cur_line <= new_vcv; cur_line++) { 393 /* NOTE THAT update_line MAY CHANGE Display[cur_line] */ 394 update_line(Display[cur_line], Vdisplay[cur_line], cur_line); 395#ifdef WINNT_NATIVE 396 flush(); 397#endif /* WINNT_NATIVE */ 398 399 /* 400 * Copy the new line to be the current one, and pad out with spaces 401 * to the full width of the terminal so that if we try moving the 402 * cursor by writing the character that is at the end of the 403 * screen line, it won't be a NUL or some old leftover stuff. 404 */ 405 cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH); 406 } 407#ifdef DEBUG_REFRESH 408 reprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n", 409 vcursor_v, OldvcV, cur_line); 410#endif /* DEBUG_REFRESH */ 411 if (OldvcV > new_vcv) { 412 for (; cur_line <= OldvcV; cur_line++) { 413 update_line(Display[cur_line], STRNULL, cur_line); 414 *Display[cur_line] = '\0'; 415 } 416 } 417 OldvcV = new_vcv; /* set for next time */ 418#ifdef DEBUG_REFRESH 419 reprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n", 420 CursorH, CursorV, cur_h, cur_v); 421#endif /* DEBUG_REFRESH */ 422#ifdef WINNT_NATIVE 423 flush(); 424#endif /* WINNT_NATIVE */ 425 MoveToLine(cur_v); /* go to where the cursor is */ 426 MoveToChar(cur_h); 427 SetAttributes(0); /* Clear all attributes */ 428 flush(); /* send the output... */ 429 GettingInput = oldgetting; /* reset to old value */ 430} 431 432#ifdef notdef 433GotoBottom(void) 434{ /* used to go to last used screen line */ 435 MoveToLine(OldvcV); 436} 437 438#endif 439 440void 441PastBottom(void) 442{ /* used to go to last used screen line */ 443 MoveToLine(OldvcV); 444 (void) putraw('\r'); 445 (void) putraw('\n'); 446 ClearDisp(); 447 flush(); 448} 449 450 451/* insert num characters of s into d (in front of the character) at dat, 452 maximum length of d is dlen */ 453static void 454str_insert(Char *d, int dat, int dlen, Char *s, int num) 455{ 456 Char *a, *b; 457 458 if (num <= 0) 459 return; 460 if (num > dlen - dat) 461 num = dlen - dat; 462 463#ifdef DEBUG_REFRESH 464 reprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n", 465 num, dat, dlen, short2str(d)); 466 reprintf("s == \"%s\"n", short2str(s)); 467#endif /* DEBUG_REFRESH */ 468 469 /* open up the space for num chars */ 470 if (num > 0) { 471 b = d + dlen - 1; 472 a = b - num; 473 while (a >= &d[dat]) 474 *b-- = *a--; 475 d[dlen] = '\0'; /* just in case */ 476 } 477#ifdef DEBUG_REFRESH 478 reprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n", 479 num, dat, dlen, short2str(d)); 480 reprintf("s == \"%s\"n", short2str(s)); 481#endif /* DEBUG_REFRESH */ 482 483 /* copy the characters */ 484 for (a = d + dat; (a < d + dlen) && (num > 0); num--) 485 *a++ = *s++; 486 487#ifdef DEBUG_REFRESH 488 reprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n", 489 num, dat, dlen, d, short2str(s)); 490 reprintf("s == \"%s\"n", short2str(s)); 491#endif /* DEBUG_REFRESH */ 492} 493 494/* delete num characters d at dat, maximum length of d is dlen */ 495static void 496str_delete(Char *d, int dat, int dlen, int num) 497{ 498 Char *a, *b; 499 500 if (num <= 0) 501 return; 502 if (dat + num >= dlen) { 503 d[dat] = '\0'; 504 return; 505 } 506 507#ifdef DEBUG_REFRESH 508 reprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n", 509 num, dat, dlen, short2str(d)); 510#endif /* DEBUG_REFRESH */ 511 512 /* open up the space for num chars */ 513 if (num > 0) { 514 b = d + dat; 515 a = b + num; 516 while (a < &d[dlen]) 517 *b++ = *a++; 518 d[dlen] = '\0'; /* just in case */ 519 } 520#ifdef DEBUG_REFRESH 521 reprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n", 522 num, dat, dlen, short2str(d)); 523#endif /* DEBUG_REFRESH */ 524} 525 526static void 527str_cp(Char *a, Char *b, int n) 528{ 529 while (n-- && *b) 530 *a++ = *b++; 531} 532 533 534/* **************************************************************** 535 update_line() is based on finding the middle difference of each line 536 on the screen; vis: 537 538 /old first difference 539 /beginning of line | /old last same /old EOL 540 v v v v 541old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 542new: eddie> Oh, my little buggy says to me, as lurgid as 543 ^ ^ ^ ^ 544 \beginning of line | \new last same \new end of line 545 \new first difference 546 547 all are character pointers for the sake of speed. Special cases for 548 no differences, as well as for end of line additions must be handled. 549**************************************************************** */ 550 551/* Minimum at which doing an insert it "worth it". This should be about 552 * half the "cost" of going into insert mode, inserting a character, and 553 * going back out. This should really be calculated from the termcap 554 * data... For the moment, a good number for ANSI terminals. 555 */ 556#define MIN_END_KEEP 4 557 558static void /* could be changed to make it smarter */ 559update_line(Char *old, Char *new, int cur_line) 560{ 561 Char *o, *n, *p, c; 562 Char *ofd, *ols, *oe, *nfd, *nls, *ne; 563 Char *osb, *ose, *nsb, *nse; 564 int fx, sx; 565 566 /* 567 * find first diff (won't be CHAR_DBWIDTH in either line) 568 */ 569 for (o = old, n = new; *o && (*o == *n); o++, n++) 570 continue; 571 ofd = o; 572 nfd = n; 573 574 /* 575 * Find the end of both old and new 576 */ 577 o = Strend(o); 578 579 /* 580 * Remove any trailing blanks off of the end, being careful not to 581 * back up past the beginning. 582 */ 583 if (!(adrof(STRhighlight) && MarkIsSet)) { 584 while (ofd < o) { 585 if (o[-1] != ' ') 586 break; 587 o--; 588 } 589 } 590 oe = o; 591 *oe = (Char) 0; 592 593 n = Strend(n); 594 595 /* remove blanks from end of new */ 596 if (!(adrof(STRhighlight) && MarkIsSet)) { 597 while (nfd < n) { 598 if (n[-1] != ' ') 599 break; 600 n--; 601 } 602 } 603 ne = n; 604 *ne = (Char) 0; 605 606 /* 607 * if no diff, continue to next line of redraw 608 */ 609 if (*ofd == '\0' && *nfd == '\0') { 610#ifdef DEBUG_UPDATE 611 reprintf("no difference.\r\n"); 612#endif /* DEBUG_UPDATE */ 613 return; 614 } 615 616 /* 617 * find last same pointer 618 */ 619 while ((o > ofd) && (n > nfd) && (*--o == *--n)) 620 continue; 621 if (*o != *n) { 622 o++; 623 n++; 624 } 625 while (*o == CHAR_DBWIDTH) { 626 o++; 627 n++; 628 } 629 ols = o; 630 nls = n; 631 632 /* 633 * find same begining and same end 634 */ 635 osb = ols; 636 nsb = nls; 637 ose = ols; 638 nse = nls; 639 640 /* 641 * case 1: insert: scan from nfd to nls looking for *ofd 642 */ 643 if (*ofd) { 644 for (c = *ofd, n = nfd; n < nls; n++) { 645 if (c == *n) { 646 for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++) 647 continue; 648 /* 649 * if the new match is longer and it's worth keeping, then we 650 * take it 651 */ 652 if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { 653 nsb = n; 654 nse = p; 655 osb = ofd; 656 ose = o; 657 } 658 } 659 } 660 } 661 662 /* 663 * case 2: delete: scan from ofd to ols looking for *nfd 664 */ 665 if (*nfd) { 666 for (c = *nfd, o = ofd; o < ols; o++) { 667 if (c == *o) { 668 for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++) 669 continue; 670 /* 671 * if the new match is longer and it's worth keeping, then we 672 * take it 673 */ 674 if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { 675 nsb = nfd; 676 nse = n; 677 osb = o; 678 ose = p; 679 } 680 } 681 } 682 } 683#ifdef notdef 684 /* 685 * If `last same' is before `same end' re-adjust 686 */ 687 if (ols < ose) 688 ols = ose; 689 if (nls < nse) 690 nls = nse; 691#endif 692 693 /* 694 * Pragmatics I: If old trailing whitespace or not enough characters to 695 * save to be worth it, then don't save the last same info. 696 */ 697 if ((oe - ols) < MIN_END_KEEP) { 698 ols = oe; 699 nls = ne; 700 } 701 702 /* 703 * Pragmatics II: if the terminal isn't smart enough, make the data dumber 704 * so the smart update doesn't try anything fancy 705 */ 706 707 /* 708 * fx is the number of characters we need to insert/delete: in the 709 * beginning to bring the two same begins together 710 */ 711 fx = (int) ((nsb - nfd) - (osb - ofd)); 712 /* 713 * sx is the number of characters we need to insert/delete: in the end to 714 * bring the two same last parts together 715 */ 716 sx = (int) ((nls - nse) - (ols - ose)); 717 718 if (!T_CanIns) { 719 if (fx > 0) { 720 osb = ols; 721 ose = ols; 722 nsb = nls; 723 nse = nls; 724 } 725 if (sx > 0) { 726 ols = oe; 727 nls = ne; 728 } 729 if ((ols - ofd) < (nls - nfd)) { 730 ols = oe; 731 nls = ne; 732 } 733 } 734 if (!T_CanDel) { 735 if (fx < 0) { 736 osb = ols; 737 ose = ols; 738 nsb = nls; 739 nse = nls; 740 } 741 if (sx < 0) { 742 ols = oe; 743 nls = ne; 744 } 745 if ((ols - ofd) > (nls - nfd)) { 746 ols = oe; 747 nls = ne; 748 } 749 } 750 751 /* 752 * Pragmatics III: make sure the middle shifted pointers are correct if 753 * they don't point to anything (we may have moved ols or nls). 754 */ 755 /* if the change isn't worth it, don't bother */ 756 /* was: if (osb == ose) */ 757 if ((ose - osb) < MIN_END_KEEP) { 758 osb = ols; 759 ose = ols; 760 nsb = nls; 761 nse = nls; 762 } 763 764 /* 765 * Now that we are done with pragmatics we recompute fx, sx 766 */ 767 fx = (int) ((nsb - nfd) - (osb - ofd)); 768 sx = (int) ((nls - nse) - (ols - ose)); 769 770#ifdef DEBUG_UPDATE 771 reprintf("\n"); 772 reprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n", 773 ofd - old, osb - old, ose - old, ols - old, oe - old); 774 reprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n", 775 nfd - new, nsb - new, nse - new, nls - new, ne - new); 776 reprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"); 777 reprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"); 778 dprintstr("old- oe", old, oe); 779 dprintstr("new- ne", new, ne); 780 dprintstr("old-ofd", old, ofd); 781 dprintstr("new-nfd", new, nfd); 782 dprintstr("ofd-osb", ofd, osb); 783 dprintstr("nfd-nsb", nfd, nsb); 784 dprintstr("osb-ose", osb, ose); 785 dprintstr("nsb-nse", nsb, nse); 786 dprintstr("ose-ols", ose, ols); 787 dprintstr("nse-nls", nse, nls); 788 dprintstr("ols- oe", ols, oe); 789 dprintstr("nls- ne", nls, ne); 790#endif /* DEBUG_UPDATE */ 791 792 /* 793 * CursorV to this line cur_line MUST be in this routine so that if we 794 * don't have to change the line, we don't move to it. CursorH to first 795 * diff char 796 */ 797 MoveToLine(cur_line); 798 799 /* 800 * at this point we have something like this: 801 * 802 * /old /ofd /osb /ose /ols /oe 803 * v.....................v v..................v v........v 804 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as 805 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as 806 * ^.....................^ ^..................^ ^........^ 807 * \new \nfd \nsb \nse \nls \ne 808 * 809 * fx is the difference in length between the the chars between nfd and 810 * nsb, and the chars between ofd and osb, and is thus the number of 811 * characters to delete if < 0 (new is shorter than old, as above), 812 * or insert (new is longer than short). 813 * 814 * sx is the same for the second differences. 815 */ 816 817 /* 818 * if we have a net insert on the first difference, AND inserting the net 819 * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character 820 * (which is ne if nls != ne, otherwise is nse) off the edge of the screen 821 * (TermH - 1) else we do the deletes first so that we keep everything we 822 * need to. 823 */ 824 825 /* 826 * if the last same is the same like the end, there is no last same part, 827 * otherwise we want to keep the last same part set p to the last useful 828 * old character 829 */ 830 p = (ols != oe) ? oe : ose; 831 832 /* 833 * if (There is a diffence in the beginning) && (we need to insert 834 * characters) && (the number of characters to insert is less than the term 835 * width) We need to do an insert! else if (we need to delete characters) 836 * We need to delete characters! else No insert or delete 837 */ 838 if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) { 839#ifdef DEBUG_UPDATE 840 reprintf("first diff insert at %d...\r\n", nfd - new); 841#endif /* DEBUG_UPDATE */ 842 /* 843 * Move to the first char to insert, where the first diff is. 844 */ 845 MoveToChar(nfd - new); 846 /* 847 * Check if we have stuff to keep at end 848 */ 849 if (nsb != ne) { 850#ifdef DEBUG_UPDATE 851 reprintf("with stuff to keep at end\r\n"); 852#endif /* DEBUG_UPDATE */ 853 /* 854 * insert fx chars of new starting at nfd 855 */ 856 if (fx > 0) { 857#ifdef DEBUG_UPDATE 858 if (!T_CanIns) 859 reprintf(" ERROR: cannot insert in early first diff\n"); 860#endif /* DEBUG_UPDATE */ 861 Insert_write(nfd, fx); 862 str_insert(old, (int) (ofd - old), TermH, nfd, fx); 863 } 864 /* 865 * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 866 */ 867 so_write(nfd + fx, (nsb - nfd) - fx); 868 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); 869 } 870 else { 871#ifdef DEBUG_UPDATE 872 reprintf("without anything to save\r\n"); 873#endif /* DEBUG_UPDATE */ 874 so_write(nfd, (nsb - nfd)); 875 str_cp(ofd, nfd, (int) (nsb - nfd)); 876 /* 877 * Done 878 */ 879 return; 880 } 881 } 882 else if (fx < 0) { 883#ifdef DEBUG_UPDATE 884 reprintf("first diff delete at %d...\r\n", ofd - old); 885#endif /* DEBUG_UPDATE */ 886 /* 887 * move to the first char to delete where the first diff is 888 */ 889 MoveToChar(ofd - old); 890 /* 891 * Check if we have stuff to save 892 */ 893 if (osb != oe) { 894#ifdef DEBUG_UPDATE 895 reprintf("with stuff to save at end\r\n"); 896#endif /* DEBUG_UPDATE */ 897 /* 898 * fx is less than zero *always* here but we check for code 899 * symmetry 900 */ 901 if (fx < 0) { 902#ifdef DEBUG_UPDATE 903 if (!T_CanDel) 904 reprintf(" ERROR: cannot delete in first diff\n"); 905#endif /* DEBUG_UPDATE */ 906 DeleteChars(-fx); 907 str_delete(old, (int) (ofd - old), TermH, -fx); 908 } 909 /* 910 * write (nsb-nfd) chars of new starting at nfd 911 */ 912 so_write(nfd, (nsb - nfd)); 913 str_cp(ofd, nfd, (int) (nsb - nfd)); 914 915 } 916 else { 917#ifdef DEBUG_UPDATE 918 reprintf("but with nothing left to save\r\n"); 919#endif /* DEBUG_UPDATE */ 920 /* 921 * write (nsb-nfd) chars of new starting at nfd 922 */ 923 so_write(nfd, (nsb - nfd)); 924#ifdef DEBUG_REFRESH 925 reprintf("cleareol %d\n", (oe - old) - (ne - new)); 926#endif /* DEBUG_UPDATE */ 927#ifndef WINNT_NATIVE 928 ClearEOL((oe - old) - (ne - new)); 929#else 930 /* 931 * The calculation above does not work too well on NT 932 */ 933 ClearEOL(TermH - CursorH); 934#endif /*WINNT_NATIVE*/ 935 /* 936 * Done 937 */ 938 return; 939 } 940 } 941 else 942 fx = 0; 943 944 if (sx < 0) { 945#ifdef DEBUG_UPDATE 946 reprintf("second diff delete at %d...\r\n", (ose - old) + fx); 947#endif /* DEBUG_UPDATE */ 948 /* 949 * Check if we have stuff to delete 950 */ 951 /* 952 * fx is the number of characters inserted (+) or deleted (-) 953 */ 954 955 MoveToChar((ose - old) + fx); 956 /* 957 * Check if we have stuff to save 958 */ 959 if (ols != oe) { 960#ifdef DEBUG_UPDATE 961 reprintf("with stuff to save at end\r\n"); 962#endif /* DEBUG_UPDATE */ 963 /* 964 * Again a duplicate test. 965 */ 966 if (sx < 0) { 967#ifdef DEBUG_UPDATE 968 if (!T_CanDel) 969 reprintf(" ERROR: cannot delete in second diff\n"); 970#endif /* DEBUG_UPDATE */ 971 DeleteChars(-sx); 972 } 973 974 /* 975 * write (nls-nse) chars of new starting at nse 976 */ 977 so_write(nse, (nls - nse)); 978 } 979 else { 980 int olen = (int) (oe - old + fx); 981 if (olen > TermH) 982 olen = TermH; 983#ifdef DEBUG_UPDATE 984 reprintf("but with nothing left to save\r\n"); 985#endif /* DEBUG_UPDATE */ 986 so_write(nse, (nls - nse)); 987#ifdef DEBUG_REFRESH 988 reprintf("cleareol %d\n", olen - (ne - new)); 989#endif /* DEBUG_UPDATE */ 990#ifndef WINNT_NATIVE 991 ClearEOL(olen - (ne - new)); 992#else 993 /* 994 * The calculation above does not work too well on NT 995 */ 996 ClearEOL(TermH - CursorH); 997#endif /*WINNT_NATIVE*/ 998 } 999 } 1000 1001 /* 1002 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... 1003 */ 1004 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { 1005#ifdef DEBUG_UPDATE 1006 reprintf("late first diff insert at %d...\r\n", nfd - new); 1007#endif /* DEBUG_UPDATE */ 1008 1009 MoveToChar(nfd - new); 1010 /* 1011 * Check if we have stuff to keep at the end 1012 */ 1013 if (nsb != ne) { 1014#ifdef DEBUG_UPDATE 1015 reprintf("with stuff to keep at end\r\n"); 1016#endif /* DEBUG_UPDATE */ 1017 /* 1018 * We have to recalculate fx here because we set it 1019 * to zero above as a flag saying that we hadn't done 1020 * an early first insert. 1021 */ 1022 fx = (int) ((nsb - nfd) - (osb - ofd)); 1023 if (fx > 0) { 1024 /* 1025 * insert fx chars of new starting at nfd 1026 */ 1027#ifdef DEBUG_UPDATE 1028 if (!T_CanIns) 1029 reprintf(" ERROR: cannot insert in late first diff\n"); 1030#endif /* DEBUG_UPDATE */ 1031 Insert_write(nfd, fx); 1032 str_insert(old, (int) (ofd - old), TermH, nfd, fx); 1033 } 1034 1035 /* 1036 * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 1037 */ 1038 so_write(nfd + fx, (nsb - nfd) - fx); 1039 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); 1040 } 1041 else { 1042#ifdef DEBUG_UPDATE 1043 reprintf("without anything to save\r\n"); 1044#endif /* DEBUG_UPDATE */ 1045 so_write(nfd, (nsb - nfd)); 1046 str_cp(ofd, nfd, (int) (nsb - nfd)); 1047 } 1048 } 1049 1050 /* 1051 * line is now NEW up to nse 1052 */ 1053 if (sx >= 0) { 1054#ifdef DEBUG_UPDATE 1055 reprintf("second diff insert at %d...\r\n", nse - new); 1056#endif /* DEBUG_UPDATE */ 1057 MoveToChar(nse - new); 1058 if (ols != oe) { 1059#ifdef DEBUG_UPDATE 1060 reprintf("with stuff to keep at end\r\n"); 1061#endif /* DEBUG_UPDATE */ 1062 if (sx > 0) { 1063 /* insert sx chars of new starting at nse */ 1064#ifdef DEBUG_UPDATE 1065 if (!T_CanIns) 1066 reprintf(" ERROR: cannot insert in second diff\n"); 1067#endif /* DEBUG_UPDATE */ 1068 Insert_write(nse, sx); 1069 } 1070 1071 /* 1072 * write (nls-nse) - sx chars of new starting at (nse + sx) 1073 */ 1074 so_write(nse + sx, (nls - nse) - sx); 1075 } 1076 else { 1077#ifdef DEBUG_UPDATE 1078 reprintf("without anything to save\r\n"); 1079#endif /* DEBUG_UPDATE */ 1080 so_write(nse, (nls - nse)); 1081 1082 /* 1083 * No need to do a clear-to-end here because we were doing 1084 * a second insert, so we will have over written all of the 1085 * old string. 1086 */ 1087 } 1088 } 1089#ifdef DEBUG_UPDATE 1090 reprintf("done.\r\n"); 1091#endif /* DEBUG_UPDATE */ 1092} 1093 1094 1095static void 1096cpy_pad_spaces(Char *dst, Char *src, int width) 1097{ 1098 int i; 1099 1100 for (i = 0; i < width; i++) { 1101 if (*src == (Char) 0) 1102 break; 1103 *dst++ = *src++; 1104 } 1105 1106 while (i < width) { 1107 *dst++ = ' '; 1108 i++; 1109 } 1110 *dst = (Char) 0; 1111} 1112 1113void 1114RefCursor(void) 1115{ /* only move to new cursor pos */ 1116 Char *cp; 1117 int w, h, th, v; 1118 1119 /* first we must find where the cursor is... */ 1120 h = 0; 1121 v = 0; 1122 th = TermH; /* optimize for speed */ 1123 1124 for (cp = Prompt; cp != NULL && *cp; ) { /* do prompt */ 1125 if (*cp & LITERAL) { 1126 cp++; 1127 continue; 1128 } 1129 w = NLSClassify(*cp & CHAR, cp == Prompt); 1130 cp++; 1131 switch(w) { 1132 case NLSCLASS_NL: 1133 h = 0; 1134 v++; 1135 break; 1136 case NLSCLASS_TAB: 1137 while (++h & 07) 1138 ; 1139 break; 1140 case NLSCLASS_CTRL: 1141 h += 2; 1142 break; 1143 case NLSCLASS_ILLEGAL: 1144 h += 4; 1145 break; 1146 case NLSCLASS_ILLEGAL2: 1147 case NLSCLASS_ILLEGAL3: 1148 case NLSCLASS_ILLEGAL4: 1149 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); 1150 break; 1151 default: 1152 h += w; 1153 } 1154 if (h >= th) { /* check, extra long tabs picked up here also */ 1155 h -= th; 1156 v++; 1157 } 1158 } 1159 1160 for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */ 1161 w = NLSClassify(*cp & CHAR, cp == InputBuf); 1162 cp++; 1163 switch(w) { 1164 case NLSCLASS_NL: 1165 h = 0; 1166 v++; 1167 break; 1168 case NLSCLASS_TAB: 1169 while (++h & 07) 1170 ; 1171 break; 1172 case NLSCLASS_CTRL: 1173 h += 2; 1174 break; 1175 case NLSCLASS_ILLEGAL: 1176 h += 4; 1177 break; 1178 case NLSCLASS_ILLEGAL2: 1179 case NLSCLASS_ILLEGAL3: 1180 case NLSCLASS_ILLEGAL4: 1181 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); 1182 break; 1183 default: 1184 h += w; 1185 } 1186 if (h >= th) { /* check, extra long tabs picked up here also */ 1187 h -= th; 1188 v++; 1189 } 1190 } 1191 1192 /* now go there */ 1193 MoveToLine(v); 1194 MoveToChar(h); 1195 if (adrof(STRhighlight) && MarkIsSet) { 1196 ClearLines(); 1197 ClearDisp(); 1198 Refresh(); 1199 } 1200 flush(); 1201} 1202 1203#ifndef WINTT_NATIVE 1204static void 1205PutPlusOne(Char c, int width) 1206{ 1207 while (width > 1 && CursorH + width > TermH) 1208 PutPlusOne(' ', 1); 1209 if ((c & LITERAL) != 0) { 1210 Char *d; 1211 for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++) 1212 (void) putwraw(*d); 1213 } else { 1214 (void) putwraw(c); 1215 } 1216 Display[CursorV][CursorH++] = (Char) c; 1217 while (--width > 0) 1218 Display[CursorV][CursorH++] = CHAR_DBWIDTH; 1219 if (CursorH >= TermH) { /* if we must overflow */ 1220 CursorH = 0; 1221 CursorV++; 1222 OldvcV++; 1223 if (T_Margin & MARGIN_AUTO) { 1224 if (T_Margin & MARGIN_MAGIC) { 1225 (void) putraw(' '); 1226 (void) putraw('\b'); 1227 } 1228 } 1229 else { 1230 (void) putraw('\r'); 1231 (void) putraw('\n'); 1232 } 1233 } 1234} 1235#endif 1236 1237void 1238RefPlusOne(int l) 1239{ /* we added just one char, handle it fast. 1240 * assumes that screen cursor == real cursor */ 1241 Char *cp, c; 1242 int w; 1243 1244 if (Cursor != LastChar) { 1245 Refresh(); /* too hard to handle */ 1246 return; 1247 } 1248 if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) { 1249 Refresh(); /* clear out rprompt if less than one char gap*/ 1250 return; 1251 } 1252 cp = Cursor - l; 1253 c = *cp & CHAR; 1254 w = NLSClassify(c, cp == InputBuf); 1255 switch(w) { 1256 case NLSCLASS_CTRL: 1257 PutPlusOne('^', 1); 1258 if (c == CTL_ESC('\177')) { 1259 PutPlusOne('?', 1); 1260 break; 1261 } 1262#ifdef IS_ASCII 1263 /* uncontrolify it; works only for iso8859-1 like sets */ 1264 PutPlusOne((c | 0100), 1); 1265#else 1266 PutPlusOne(_toebcdic[_toascii[c]|0100], 1); 1267#endif 1268 break; 1269 case NLSCLASS_ILLEGAL: 1270 PutPlusOne('\\', 1); 1271 PutPlusOne(((c >> 6) & 7) + '0', 1); 1272 PutPlusOne(((c >> 3) & 7) + '0', 1); 1273 PutPlusOne((c & 7) + '0', 1); 1274 break; 1275 case 1: 1276 if (adrof(STRhighlight) && MarkIsSet) 1277 StartHighlight(); 1278 if (l > 1) 1279 PutPlusOne(MakeLiteral(cp, l, 0), 1); 1280 else 1281 PutPlusOne(*cp, 1); 1282 if (adrof(STRhighlight) && MarkIsSet) 1283 StopHighlight(); 1284 break; 1285 default: 1286 Refresh(); /* too hard to handle */ 1287 return; 1288 } 1289 flush(); 1290} 1291 1292/* clear the screen buffers so that new new prompt starts fresh. */ 1293 1294void 1295ClearDisp(void) 1296{ 1297 int i; 1298 1299 CursorV = 0; /* clear the display buffer */ 1300 CursorH = 0; 1301 for (i = 0; i < TermV; i++) 1302 (void) memset(Display[i], 0, TermH * sizeof(Display[0][0])); 1303 OldvcV = 0; 1304 litlen = 0; 1305} 1306 1307void 1308ClearLines(void) 1309{ /* Make sure all lines are *really* blank */ 1310 int i; 1311 1312 if (T_CanCEOL) { 1313 /* 1314 * Clear the lines from the bottom up so that if we try moving 1315 * the cursor down by writing the character that is at the end 1316 * of the screen line, we won't rewrite a character that shouldn't 1317 * be there. 1318 */ 1319 for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */ 1320 MoveToLine(i); 1321 MoveToChar(0); 1322 ClearEOL(TermH); 1323 } 1324 } 1325 else { 1326 MoveToLine(OldvcV); /* go to last line */ 1327 (void) putraw('\r'); /* go to BOL */ 1328 (void) putraw('\n'); /* go to new line */ 1329 } 1330} 1331