159243Sobrien/* 259243Sobrien * ed.refresh.c: Lower level screen refreshing functions 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "ed.h" 3459243Sobrien/* #define DEBUG_UPDATE */ 3559243Sobrien/* #define DEBUG_REFRESH */ 3659243Sobrien/* #define DEBUG_LITERAL */ 3759243Sobrien 3859243Sobrien/* refresh.c -- refresh the current set of lines on the screen */ 3959243Sobrien 40145479SmpChar *litptr; 4159243Sobrienstatic int vcursor_h, vcursor_v; 4259243Sobrienstatic int rprompt_h, rprompt_v; 4359243Sobrien 44167465Smpstatic int MakeLiteral (Char *, int, Char); 45316957Sdchaginstatic int Draw (Char *, int, int); 46167465Smpstatic void Vdraw (Char, int); 47167465Smpstatic void RefreshPromptpart (Char *); 48167465Smpstatic void update_line (Char *, Char *, int); 49167465Smpstatic void str_insert (Char *, int, int, Char *, int); 50167465Smpstatic void str_delete (Char *, int, int, int); 51167465Smpstatic void str_cp (Char *, Char *, int); 52131962Smp#ifndef WINNT_NATIVE 53131962Smpstatic 54131962Smp#else 55131962Smpextern 56131962Smp#endif 57167465Smp void PutPlusOne (Char, int); 58167465Smpstatic void cpy_pad_spaces (Char *, Char *, int); 5959243Sobrien#if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL) 60231990Smpstatic void reprintf (char *, ...); 6159243Sobrien#ifdef DEBUG_UPDATE 62167465Smpstatic void dprintstr (char *, const Char *, const Char *); 6359243Sobrien 6459243Sobrienstatic void 65167465Smpdprintstr(char *str, const Char *f, const Char *t) 6659243Sobrien{ 67231990Smp reprintf("%s:\"", str); 68145479Smp while (f < t) { 69167465Smp if (ASC(*f) & ~ASCII) 70231990Smp reprintf("[%x]", *f++); 71145479Smp else 72231990Smp reprintf("%c", CTL_ESC(ASCII & ASC(*f++))); 73145479Smp } 74231990Smp reprintf("\"\r\n"); 75145479Smp} 7659243Sobrien#endif /* DEBUG_UPDATE */ 7759243Sobrien 78231990Smp/* reprintf(): 7959243Sobrien * Print to $DEBUGTTY, so that we can test editing on one pty, and 8059243Sobrien * print debugging stuff on another. Don't interrupt the shell while 8159243Sobrien * debugging cause you'll mangle up the file descriptors! 8259243Sobrien */ 8359243Sobrienstatic void 84231990Smpreprintf(char *fmt, ...) 8559243Sobrien{ 8659243Sobrien static int fd = -1; 8759243Sobrien char *dtty; 8859243Sobrien 8959243Sobrien if ((dtty = getenv("DEBUGTTY"))) { 9059243Sobrien int o; 9159243Sobrien va_list va; 9259243Sobrien va_start(va, fmt); 9359243Sobrien 9459243Sobrien if (fd == -1) 95167465Smp fd = xopen(dtty, O_RDWR); 9659243Sobrien o = SHOUT; 9759243Sobrien flush(); 9859243Sobrien SHOUT = fd; 9959243Sobrien xvprintf(fmt, va); 10059243Sobrien va_end(va); 10159243Sobrien flush(); 10259243Sobrien SHOUT = o; 10359243Sobrien } 10459243Sobrien} 10559243Sobrien#endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */ 10659243Sobrien 107145479Smpstatic int litlen = 0, litalloc = 0; 108145479Smp 109167465Smpstatic int MakeLiteral(Char *str, int len, Char addlit) 11059243Sobrien{ 111145479Smp int i, addlitlen = 0; 112145479Smp Char *addlitptr = 0; 113145479Smp if (addlit) { 114145479Smp if ((addlit & LITERAL) != 0) { 115145479Smp addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; 116145479Smp addlitlen = Strlen(addlitptr); 117145479Smp } else { 118145479Smp addlitptr = &addlit; 119145479Smp addlitlen = 1; 120145479Smp } 121145479Smp for (i = 0; i < litlen; i += LIT_FACTOR) 122145479Smp if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0) 123145479Smp return (i / LIT_FACTOR) | LITERAL; 124145479Smp } else { 125145479Smp addlitlen = 0; 126145479Smp for (i = 0; i < litlen; i += LIT_FACTOR) 127145479Smp if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0) 128145479Smp return (i / LIT_FACTOR) | LITERAL; 12959243Sobrien } 130145479Smp if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) { 131145479Smp Char *newlitptr; 132145479Smp int add = 256; 133145479Smp while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add) 134145479Smp add *= 2; 135167465Smp newlitptr = xrealloc(litptr, (litalloc + add) * sizeof(Char)); 136145479Smp if (!newlitptr) 137145479Smp return '?'; 138145479Smp litptr = newlitptr; 139145479Smp litalloc += add; 140145479Smp if (addlitptr && addlitptr != &addlit) 141145479Smp addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; 142145479Smp } 143145479Smp i = litlen / LIT_FACTOR; 144145479Smp if (i >= LITERAL || i == CHAR_DBWIDTH) 145145479Smp return '?'; 146145479Smp if (addlitptr) { 147145479Smp Strncpy(litptr + litlen, addlitptr, addlitlen); 148145479Smp litlen += addlitlen; 149145479Smp } 150145479Smp Strncpy(litptr + litlen, str, len); 151145479Smp litlen += len; 152145479Smp do 153145479Smp litptr[litlen++] = 0; 154145479Smp while (litlen % LIT_FACTOR); 155145479Smp return i | LITERAL; 156145479Smp} 15759243Sobrien 158316957Sdchagin/* draw char at cp, expand tabs, ctl chars */ 159145479Smpstatic int 160316957SdchaginDraw(Char *cp, int nocomb, int drawPrompt) 161145479Smp{ 162167465Smp int w, i, lv, lh; 163167465Smp Char c, attr; 164145479Smp 165316957Sdchagin#ifdef WIDE_STRINGS 166316957Sdchagin if (!drawPrompt) { /* draw command-line */ 167316957Sdchagin attr = 0; 168316957Sdchagin c = *cp; 169316957Sdchagin } else { /* draw prompt */ 170316957Sdchagin /* prompt with attributes(UNDER,BOLD,STANDOUT) */ 171316957Sdchagin if (*cp & (UNDER | BOLD | STANDOUT)) { /* *cp >= STANDOUT */ 172316957Sdchagin 173316957Sdchagin /* example) 174316957Sdchagin * We can't distinguish whether (*cp=)0x02ffffff is 175316957Sdchagin * U+02FFFFFF or U+00FFFFFF|STANDOUT. 176316957Sdchagin * We handle as U+00FFFFFF|STANDOUT, only when drawing prompt. */ 177316957Sdchagin attr = (*cp & ATTRIBUTES); 178316957Sdchagin /* ~(UNDER | BOLD | STANDOUT) = 0xf1ffffff */ 179316957Sdchagin c = *cp & ~(UNDER | BOLD | STANDOUT); 180316957Sdchagin 181316957Sdchagin /* if c is ctrl code, we handle *cp as havnig no attributes */ 182316957Sdchagin if ((c < 0x20 && c >= 0) || c == 0x7f) { 183316957Sdchagin attr = 0; 184316957Sdchagin c = *cp; 185316957Sdchagin } 186316957Sdchagin } else { /* prompt without attributes */ 187316957Sdchagin attr = 0; 188316957Sdchagin c = *cp; 189316957Sdchagin } 190316957Sdchagin } 191316957Sdchagin#else 192145479Smp attr = *cp & ~CHAR; 193167465Smp c = *cp & CHAR; 194316957Sdchagin#endif 195316957Sdchagin w = NLSClassify(c, nocomb, drawPrompt); 196145479Smp switch (w) { 197145479Smp case NLSCLASS_NL: 198145479Smp Vdraw('\0', 0); /* assure end of line */ 199145479Smp vcursor_h = 0; /* reset cursor pos */ 20059243Sobrien vcursor_v++; 201145479Smp break; 202145479Smp case NLSCLASS_TAB: 203145479Smp do { 204145479Smp Vdraw(' ', 1); 205145479Smp } while ((vcursor_h & 07) != 0); 206145479Smp break; 207145479Smp case NLSCLASS_CTRL: 208145479Smp Vdraw('^' | attr, 1); 209145479Smp if (c == CTL_ESC('\177')) { 210145479Smp Vdraw('?' | attr, 1); 211145479Smp } else { 21269408Sache#ifdef IS_ASCII 213145479Smp /* uncontrolify it; works only for iso8859-1 like sets */ 214145479Smp Vdraw(c | 0100 | attr, 1); 21569408Sache#else 216145479Smp Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1); 217145479Smp#endif 21859243Sobrien } 219145479Smp break; 220145479Smp case NLSCLASS_ILLEGAL: 221145479Smp Vdraw('\\' | attr, 1); 222167465Smp Vdraw((((c >> 6) & 7) + '0') | attr, 1); 223167465Smp Vdraw((((c >> 3) & 7) + '0') | attr, 1); 224167465Smp Vdraw(((c & 7) + '0') | attr, 1); 225145479Smp break; 226145479Smp case NLSCLASS_ILLEGAL2: 227145479Smp case NLSCLASS_ILLEGAL3: 228145479Smp case NLSCLASS_ILLEGAL4: 229316957Sdchagin case NLSCLASS_ILLEGAL5: 230316957Sdchagin Vdraw('\\', 1); 231316957Sdchagin Vdraw('U', 1); 232316957Sdchagin Vdraw('+', 1); 233316957Sdchagin for (i = 16 + 4 * (-w-5); i >= 0; i -= 4) 234145479Smp Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1); 235145479Smp break; 236145479Smp case 0: 237145479Smp lv = vcursor_v; 238145479Smp lh = vcursor_h; 239145479Smp for (;;) { 240145479Smp lh--; 241145479Smp if (lh < 0) { 242145479Smp lv--; 243145479Smp if (lv < 0) 244145479Smp break; 245145479Smp lh = Strlen(Vdisplay[lv]) - 1; 246145479Smp } 247145479Smp if (Vdisplay[lv][lh] != CHAR_DBWIDTH) 248145479Smp break; 249145479Smp } 250145479Smp if (lv < 0) { 251167465Smp Vdraw('\\' | attr, 1); 252167465Smp Vdraw((((c >> 6) & 7) + '0') | attr, 1); 253167465Smp Vdraw((((c >> 3) & 7) + '0') | attr, 1); 254167465Smp Vdraw(((c & 7) + '0') | attr, 1); 255167465Smp break; 256145479Smp } 257167465Smp Vdisplay[lv][lh] = MakeLiteral(cp, 1, Vdisplay[lv][lh]); 258145479Smp break; 259145479Smp default: 260167465Smp Vdraw(*cp, w); 261145479Smp break; 26259243Sobrien } 263167465Smp return 1; 26459243Sobrien} 26559243Sobrien 26659243Sobrienstatic void 267167465SmpVdraw(Char c, int width) /* draw char c onto V lines */ 26859243Sobrien{ 26959243Sobrien#ifdef DEBUG_REFRESH 27059243Sobrien# ifdef SHORT_STRINGS 271231990Smp reprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width); 27259243Sobrien# else 273231990Smp reprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width); 27459243Sobrien# endif /* SHORT_STRNGS */ 27559243Sobrien#endif /* DEBUG_REFRESH */ 27659243Sobrien 277145479Smp /* Hopefully this is what all the terminals do with multi-column characters 278145479Smp that "span line breaks". */ 279145479Smp while (vcursor_h + width > TermH) 280145479Smp Vdraw(' ', 1); 281167465Smp Vdisplay[vcursor_v][vcursor_h] = c; 282145479Smp if (width) 283145479Smp vcursor_h++; /* advance to next place */ 284145479Smp while (--width > 0) 285145479Smp Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH; 28659243Sobrien if (vcursor_h >= TermH) { 28759243Sobrien Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */ 28859243Sobrien vcursor_h = 0; /* reset it. */ 28959243Sobrien vcursor_v++; 29059243Sobrien#ifdef DEBUG_REFRESH 29159243Sobrien if (vcursor_v >= TermV) { /* should NEVER happen. */ 292231990Smp reprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n", 29359243Sobrien vcursor_v, TermV); 29459243Sobrien abort(); 29559243Sobrien } 29659243Sobrien#endif /* DEBUG_REFRESH */ 29759243Sobrien } 29859243Sobrien} 29959243Sobrien 30059243Sobrien/* 30159243Sobrien * RefreshPromptpart() 30259243Sobrien * draws a prompt element, expanding literals (we know it's ASCIZ) 30359243Sobrien */ 30459243Sobrienstatic void 305167465SmpRefreshPromptpart(Char *buf) 30659243Sobrien{ 307145479Smp Char *cp; 308167465Smp int w; 30959243Sobrien 310167465Smp if (buf == NULL) 311167465Smp return; 312145479Smp for (cp = buf; *cp; ) { 31359243Sobrien if (*cp & LITERAL) { 314145479Smp Char *litstart = cp; 31559243Sobrien while (*cp & LITERAL) 31659243Sobrien cp++; 317145479Smp if (*cp) { 318167465Smp w = NLSWidth(*cp & CHAR); 319167465Smp Vdraw(MakeLiteral(litstart, cp + 1 - litstart, 0), w); 320167465Smp cp++; 321145479Smp } 32259243Sobrien else { 32359243Sobrien /* 32459243Sobrien * XXX: This is a bug, we lose the last literal, if it is not 32559243Sobrien * followed by a normal character, but it is too hard to fix 32659243Sobrien */ 32759243Sobrien break; 32859243Sobrien } 32959243Sobrien } 33059243Sobrien else 331316957Sdchagin cp += Draw(cp, cp == buf, 1); 33259243Sobrien } 33359243Sobrien} 33459243Sobrien 33559243Sobrien/* 33659243Sobrien * Refresh() 33759243Sobrien * draws the new virtual screen image from the current input 33859243Sobrien * line, then goes line-by-line changing the real image to the new 33959243Sobrien * virtual image. The routine to re-draw a line can be replaced 34059243Sobrien * easily in hopes of a smarter one being placed there. 34159243Sobrien */ 342131962Smp#ifndef WINNT_NATIVE 343131962Smpstatic 344131962Smp#endif 345131962Smpint OldvcV = 0; 346131962Smp 34759243Sobrienvoid 348167465SmpRefresh(void) 34959243Sobrien{ 350145479Smp int cur_line; 351145479Smp Char *cp; 35259243Sobrien int cur_h, cur_v = 0, new_vcv; 35359243Sobrien int rhdiff; 35459243Sobrien Char oldgetting; 35559243Sobrien 35659243Sobrien#ifdef DEBUG_REFRESH 357231990Smp reprintf("Prompt = :%s:\r\n", short2str(Prompt)); 358231990Smp reprintf("InputBuf = :%s:\r\n", short2str(InputBuf)); 35959243Sobrien#endif /* DEBUG_REFRESH */ 36059243Sobrien oldgetting = GettingInput; 36159243Sobrien GettingInput = 0; /* avoid re-entrance via SIGWINCH */ 36259243Sobrien 36359243Sobrien /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */ 36459243Sobrien vcursor_h = 0; 36559243Sobrien vcursor_v = 0; 366167465Smp RefreshPromptpart(RPrompt); 36759243Sobrien rprompt_h = vcursor_h; 36859243Sobrien rprompt_v = vcursor_v; 36959243Sobrien 37059243Sobrien /* reset the Vdraw cursor, draw prompt */ 37159243Sobrien vcursor_h = 0; 37259243Sobrien vcursor_v = 0; 373167465Smp RefreshPromptpart(Prompt); 37459243Sobrien cur_h = -1; /* set flag in case I'm not set */ 37559243Sobrien 37659243Sobrien /* draw the current input buffer */ 377145479Smp for (cp = InputBuf; (cp < LastChar); ) { 378145479Smp if (cp >= Cursor && cur_h == -1) { 37959243Sobrien cur_h = vcursor_h; /* save for later */ 38059243Sobrien cur_v = vcursor_v; 381145479Smp Cursor = cp; 38259243Sobrien } 383316957Sdchagin cp += Draw(cp, cp == InputBuf, 0); 38459243Sobrien } 38559243Sobrien 38659243Sobrien if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */ 38759243Sobrien cur_h = vcursor_h; 38859243Sobrien cur_v = vcursor_v; 38959243Sobrien } 39059243Sobrien 39159243Sobrien rhdiff = TermH - vcursor_h - rprompt_h; 39259243Sobrien if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) { 39359243Sobrien /* 39459243Sobrien * have a right-hand side prompt that will fit on 39559243Sobrien * the end of the first line with at least one 39659243Sobrien * character gap to the input buffer. 39759243Sobrien */ 39859243Sobrien while (--rhdiff > 0) /* pad out with spaces */ 399145479Smp Vdraw(' ', 1); 400167465Smp RefreshPromptpart(RPrompt); 40159243Sobrien } 40259243Sobrien else { 40359243Sobrien rprompt_h = 0; /* flag "not using rprompt" */ 40459243Sobrien rprompt_v = 0; 40559243Sobrien } 40659243Sobrien 40759243Sobrien new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */ 408145479Smp Vdraw('\0', 1); /* put NUL on end */ 40959243Sobrien 410145479Smp#if defined (DEBUG_REFRESH) 411231990Smp reprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n", 41259243Sobrien TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0])); 41359243Sobrien#endif /* DEBUG_REFRESH */ 41459243Sobrien 41559243Sobrien#ifdef DEBUG_UPDATE 416231990Smp reprintf("updating %d lines.\r\n", new_vcv); 41759243Sobrien#endif /* DEBUG_UPDATE */ 41859243Sobrien for (cur_line = 0; cur_line <= new_vcv; cur_line++) { 41959243Sobrien /* NOTE THAT update_line MAY CHANGE Display[cur_line] */ 42059243Sobrien update_line(Display[cur_line], Vdisplay[cur_line], cur_line); 42169408Sache#ifdef WINNT_NATIVE 42259243Sobrien flush(); 42369408Sache#endif /* WINNT_NATIVE */ 42459243Sobrien 42559243Sobrien /* 42659243Sobrien * Copy the new line to be the current one, and pad out with spaces 42759243Sobrien * to the full width of the terminal so that if we try moving the 42859243Sobrien * cursor by writing the character that is at the end of the 42959243Sobrien * screen line, it won't be a NUL or some old leftover stuff. 43059243Sobrien */ 43159243Sobrien cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH); 43259243Sobrien } 43359243Sobrien#ifdef DEBUG_REFRESH 434231990Smp reprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n", 43559243Sobrien vcursor_v, OldvcV, cur_line); 43659243Sobrien#endif /* DEBUG_REFRESH */ 43759243Sobrien if (OldvcV > new_vcv) { 43859243Sobrien for (; cur_line <= OldvcV; cur_line++) { 43959243Sobrien update_line(Display[cur_line], STRNULL, cur_line); 44059243Sobrien *Display[cur_line] = '\0'; 44159243Sobrien } 44259243Sobrien } 44359243Sobrien OldvcV = new_vcv; /* set for next time */ 44459243Sobrien#ifdef DEBUG_REFRESH 445231990Smp reprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n", 44659243Sobrien CursorH, CursorV, cur_h, cur_v); 44759243Sobrien#endif /* DEBUG_REFRESH */ 44869408Sache#ifdef WINNT_NATIVE 44959243Sobrien flush(); 45069408Sache#endif /* WINNT_NATIVE */ 45159243Sobrien MoveToLine(cur_v); /* go to where the cursor is */ 45259243Sobrien MoveToChar(cur_h); 45359243Sobrien SetAttributes(0); /* Clear all attributes */ 45459243Sobrien flush(); /* send the output... */ 45559243Sobrien GettingInput = oldgetting; /* reset to old value */ 45659243Sobrien} 45759243Sobrien 45859243Sobrien#ifdef notdef 459167465SmpGotoBottom(void) 46059243Sobrien{ /* used to go to last used screen line */ 46159243Sobrien MoveToLine(OldvcV); 46259243Sobrien} 46359243Sobrien 46459243Sobrien#endif 46559243Sobrien 46659243Sobrienvoid 467167465SmpPastBottom(void) 46859243Sobrien{ /* used to go to last used screen line */ 46959243Sobrien MoveToLine(OldvcV); 47059243Sobrien (void) putraw('\r'); 47159243Sobrien (void) putraw('\n'); 47259243Sobrien ClearDisp(); 47359243Sobrien flush(); 47459243Sobrien} 47559243Sobrien 47659243Sobrien 47759243Sobrien/* insert num characters of s into d (in front of the character) at dat, 47859243Sobrien maximum length of d is dlen */ 47959243Sobrienstatic void 480167465Smpstr_insert(Char *d, int dat, int dlen, Char *s, int num) 48159243Sobrien{ 482145479Smp Char *a, *b; 48359243Sobrien 48459243Sobrien if (num <= 0) 48559243Sobrien return; 48659243Sobrien if (num > dlen - dat) 48759243Sobrien num = dlen - dat; 48859243Sobrien 48959243Sobrien#ifdef DEBUG_REFRESH 490231990Smp reprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n", 49159243Sobrien num, dat, dlen, short2str(d)); 492231990Smp reprintf("s == \"%s\"n", short2str(s)); 49359243Sobrien#endif /* DEBUG_REFRESH */ 49459243Sobrien 49559243Sobrien /* open up the space for num chars */ 49659243Sobrien if (num > 0) { 49759243Sobrien b = d + dlen - 1; 49859243Sobrien a = b - num; 49959243Sobrien while (a >= &d[dat]) 50059243Sobrien *b-- = *a--; 50159243Sobrien d[dlen] = '\0'; /* just in case */ 50259243Sobrien } 50359243Sobrien#ifdef DEBUG_REFRESH 504231990Smp reprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n", 50559243Sobrien num, dat, dlen, short2str(d)); 506231990Smp reprintf("s == \"%s\"n", short2str(s)); 50759243Sobrien#endif /* DEBUG_REFRESH */ 50859243Sobrien 50959243Sobrien /* copy the characters */ 51059243Sobrien for (a = d + dat; (a < d + dlen) && (num > 0); num--) 51159243Sobrien *a++ = *s++; 51259243Sobrien 51359243Sobrien#ifdef DEBUG_REFRESH 514231990Smp reprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n", 51559243Sobrien num, dat, dlen, d, short2str(s)); 516231990Smp reprintf("s == \"%s\"n", short2str(s)); 51759243Sobrien#endif /* DEBUG_REFRESH */ 51859243Sobrien} 51959243Sobrien 52059243Sobrien/* delete num characters d at dat, maximum length of d is dlen */ 52159243Sobrienstatic void 522167465Smpstr_delete(Char *d, int dat, int dlen, int num) 52359243Sobrien{ 524145479Smp Char *a, *b; 52559243Sobrien 52659243Sobrien if (num <= 0) 52759243Sobrien return; 52859243Sobrien if (dat + num >= dlen) { 52959243Sobrien d[dat] = '\0'; 53059243Sobrien return; 53159243Sobrien } 53259243Sobrien 53359243Sobrien#ifdef DEBUG_REFRESH 534231990Smp reprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n", 53559243Sobrien num, dat, dlen, short2str(d)); 53659243Sobrien#endif /* DEBUG_REFRESH */ 53759243Sobrien 53859243Sobrien /* open up the space for num chars */ 53959243Sobrien if (num > 0) { 54059243Sobrien b = d + dat; 54159243Sobrien a = b + num; 54259243Sobrien while (a < &d[dlen]) 54359243Sobrien *b++ = *a++; 54459243Sobrien d[dlen] = '\0'; /* just in case */ 54559243Sobrien } 54659243Sobrien#ifdef DEBUG_REFRESH 547231990Smp reprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n", 54859243Sobrien num, dat, dlen, short2str(d)); 54959243Sobrien#endif /* DEBUG_REFRESH */ 55059243Sobrien} 55159243Sobrien 55259243Sobrienstatic void 553167465Smpstr_cp(Char *a, Char *b, int n) 55459243Sobrien{ 55559243Sobrien while (n-- && *b) 55659243Sobrien *a++ = *b++; 55759243Sobrien} 55859243Sobrien 55959243Sobrien 56059243Sobrien/* **************************************************************** 56159243Sobrien update_line() is based on finding the middle difference of each line 56259243Sobrien on the screen; vis: 56359243Sobrien 56459243Sobrien /old first difference 56559243Sobrien /beginning of line | /old last same /old EOL 56659243Sobrien v v v v 56759243Sobrienold: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 56859243Sobriennew: eddie> Oh, my little buggy says to me, as lurgid as 56959243Sobrien ^ ^ ^ ^ 57059243Sobrien \beginning of line | \new last same \new end of line 57159243Sobrien \new first difference 57259243Sobrien 57359243Sobrien all are character pointers for the sake of speed. Special cases for 57459243Sobrien no differences, as well as for end of line additions must be handled. 57559243Sobrien**************************************************************** */ 57659243Sobrien 57759243Sobrien/* Minimum at which doing an insert it "worth it". This should be about 57859243Sobrien * half the "cost" of going into insert mode, inserting a character, and 57959243Sobrien * going back out. This should really be calculated from the termcap 58059243Sobrien * data... For the moment, a good number for ANSI terminals. 58159243Sobrien */ 58259243Sobrien#define MIN_END_KEEP 4 58359243Sobrien 58459243Sobrienstatic void /* could be changed to make it smarter */ 585167465Smpupdate_line(Char *old, Char *new, int cur_line) 58659243Sobrien{ 587145479Smp Char *o, *n, *p, c; 588145479Smp Char *ofd, *ols, *oe, *nfd, *nls, *ne; 589145479Smp Char *osb, *ose, *nsb, *nse; 59059243Sobrien int fx, sx; 59159243Sobrien 59259243Sobrien /* 593145479Smp * find first diff (won't be CHAR_DBWIDTH in either line) 59459243Sobrien */ 59559243Sobrien for (o = old, n = new; *o && (*o == *n); o++, n++) 59659243Sobrien continue; 59759243Sobrien ofd = o; 59859243Sobrien nfd = n; 59959243Sobrien 60059243Sobrien /* 60159243Sobrien * Find the end of both old and new 60259243Sobrien */ 603167465Smp o = Strend(o); 604167465Smp 60559243Sobrien /* 60659243Sobrien * Remove any trailing blanks off of the end, being careful not to 60759243Sobrien * back up past the beginning. 60859243Sobrien */ 609167465Smp if (!(adrof(STRhighlight) && MarkIsSet)) { 61059243Sobrien while (ofd < o) { 61159243Sobrien if (o[-1] != ' ') 61259243Sobrien break; 61359243Sobrien o--; 61459243Sobrien } 615167465Smp } 61659243Sobrien oe = o; 61759243Sobrien *oe = (Char) 0; 61859243Sobrien 619167465Smp n = Strend(n); 620167465Smp 62159243Sobrien /* remove blanks from end of new */ 622167465Smp if (!(adrof(STRhighlight) && MarkIsSet)) { 62359243Sobrien while (nfd < n) { 62459243Sobrien if (n[-1] != ' ') 62559243Sobrien break; 62659243Sobrien n--; 62759243Sobrien } 628167465Smp } 62959243Sobrien ne = n; 63059243Sobrien *ne = (Char) 0; 63159243Sobrien 63259243Sobrien /* 63359243Sobrien * if no diff, continue to next line of redraw 63459243Sobrien */ 63559243Sobrien if (*ofd == '\0' && *nfd == '\0') { 63659243Sobrien#ifdef DEBUG_UPDATE 637231990Smp reprintf("no difference.\r\n"); 63859243Sobrien#endif /* DEBUG_UPDATE */ 63959243Sobrien return; 64059243Sobrien } 64159243Sobrien 64259243Sobrien /* 64359243Sobrien * find last same pointer 64459243Sobrien */ 64559243Sobrien while ((o > ofd) && (n > nfd) && (*--o == *--n)) 64659243Sobrien continue; 647145479Smp if (*o != *n) { 648145479Smp o++; 649145479Smp n++; 650145479Smp } 651145479Smp while (*o == CHAR_DBWIDTH) { 652145479Smp o++; 653145479Smp n++; 654145479Smp } 655145479Smp ols = o; 656145479Smp nls = n; 65759243Sobrien 65859243Sobrien /* 65959243Sobrien * find same begining and same end 66059243Sobrien */ 66159243Sobrien osb = ols; 66259243Sobrien nsb = nls; 66359243Sobrien ose = ols; 66459243Sobrien nse = nls; 66559243Sobrien 66659243Sobrien /* 66759243Sobrien * case 1: insert: scan from nfd to nls looking for *ofd 66859243Sobrien */ 66959243Sobrien if (*ofd) { 67059243Sobrien for (c = *ofd, n = nfd; n < nls; n++) { 67159243Sobrien if (c == *n) { 67259243Sobrien for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++) 67359243Sobrien continue; 67459243Sobrien /* 67559243Sobrien * if the new match is longer and it's worth keeping, then we 67659243Sobrien * take it 67759243Sobrien */ 67859243Sobrien if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { 67959243Sobrien nsb = n; 68059243Sobrien nse = p; 68159243Sobrien osb = ofd; 68259243Sobrien ose = o; 68359243Sobrien } 68459243Sobrien } 68559243Sobrien } 68659243Sobrien } 68759243Sobrien 68859243Sobrien /* 68959243Sobrien * case 2: delete: scan from ofd to ols looking for *nfd 69059243Sobrien */ 69159243Sobrien if (*nfd) { 69259243Sobrien for (c = *nfd, o = ofd; o < ols; o++) { 69359243Sobrien if (c == *o) { 69459243Sobrien for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++) 69559243Sobrien continue; 69659243Sobrien /* 69759243Sobrien * if the new match is longer and it's worth keeping, then we 69859243Sobrien * take it 69959243Sobrien */ 70059243Sobrien if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { 70159243Sobrien nsb = nfd; 70259243Sobrien nse = n; 70359243Sobrien osb = o; 70459243Sobrien ose = p; 70559243Sobrien } 70659243Sobrien } 70759243Sobrien } 70859243Sobrien } 70959243Sobrien#ifdef notdef 71059243Sobrien /* 71159243Sobrien * If `last same' is before `same end' re-adjust 71259243Sobrien */ 71359243Sobrien if (ols < ose) 71459243Sobrien ols = ose; 71559243Sobrien if (nls < nse) 71659243Sobrien nls = nse; 71759243Sobrien#endif 71859243Sobrien 71959243Sobrien /* 72059243Sobrien * Pragmatics I: If old trailing whitespace or not enough characters to 72159243Sobrien * save to be worth it, then don't save the last same info. 72259243Sobrien */ 72359243Sobrien if ((oe - ols) < MIN_END_KEEP) { 72459243Sobrien ols = oe; 72559243Sobrien nls = ne; 72659243Sobrien } 72759243Sobrien 72859243Sobrien /* 72959243Sobrien * Pragmatics II: if the terminal isn't smart enough, make the data dumber 73059243Sobrien * so the smart update doesn't try anything fancy 73159243Sobrien */ 73259243Sobrien 73359243Sobrien /* 73459243Sobrien * fx is the number of characters we need to insert/delete: in the 73559243Sobrien * beginning to bring the two same begins together 73659243Sobrien */ 73759243Sobrien fx = (int) ((nsb - nfd) - (osb - ofd)); 73859243Sobrien /* 73959243Sobrien * sx is the number of characters we need to insert/delete: in the end to 74059243Sobrien * bring the two same last parts together 74159243Sobrien */ 74259243Sobrien sx = (int) ((nls - nse) - (ols - ose)); 74359243Sobrien 74459243Sobrien if (!T_CanIns) { 74559243Sobrien if (fx > 0) { 74659243Sobrien osb = ols; 74759243Sobrien ose = ols; 74859243Sobrien nsb = nls; 74959243Sobrien nse = nls; 75059243Sobrien } 75159243Sobrien if (sx > 0) { 75259243Sobrien ols = oe; 75359243Sobrien nls = ne; 75459243Sobrien } 75559243Sobrien if ((ols - ofd) < (nls - nfd)) { 75659243Sobrien ols = oe; 75759243Sobrien nls = ne; 75859243Sobrien } 75959243Sobrien } 76059243Sobrien if (!T_CanDel) { 76159243Sobrien if (fx < 0) { 76259243Sobrien osb = ols; 76359243Sobrien ose = ols; 76459243Sobrien nsb = nls; 76559243Sobrien nse = nls; 76659243Sobrien } 76759243Sobrien if (sx < 0) { 76859243Sobrien ols = oe; 76959243Sobrien nls = ne; 77059243Sobrien } 77159243Sobrien if ((ols - ofd) > (nls - nfd)) { 77259243Sobrien ols = oe; 77359243Sobrien nls = ne; 77459243Sobrien } 77559243Sobrien } 77659243Sobrien 77759243Sobrien /* 77859243Sobrien * Pragmatics III: make sure the middle shifted pointers are correct if 77959243Sobrien * they don't point to anything (we may have moved ols or nls). 78059243Sobrien */ 78159243Sobrien /* if the change isn't worth it, don't bother */ 78259243Sobrien /* was: if (osb == ose) */ 78359243Sobrien if ((ose - osb) < MIN_END_KEEP) { 78459243Sobrien osb = ols; 78559243Sobrien ose = ols; 78659243Sobrien nsb = nls; 78759243Sobrien nse = nls; 78859243Sobrien } 78959243Sobrien 79059243Sobrien /* 79159243Sobrien * Now that we are done with pragmatics we recompute fx, sx 79259243Sobrien */ 79359243Sobrien fx = (int) ((nsb - nfd) - (osb - ofd)); 79459243Sobrien sx = (int) ((nls - nse) - (ols - ose)); 79559243Sobrien 79659243Sobrien#ifdef DEBUG_UPDATE 797231990Smp reprintf("\n"); 798231990Smp reprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n", 79959243Sobrien ofd - old, osb - old, ose - old, ols - old, oe - old); 800231990Smp reprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n", 80159243Sobrien nfd - new, nsb - new, nse - new, nls - new, ne - new); 802231990Smp reprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"); 803231990Smp reprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"); 80459243Sobrien dprintstr("old- oe", old, oe); 80559243Sobrien dprintstr("new- ne", new, ne); 80659243Sobrien dprintstr("old-ofd", old, ofd); 80759243Sobrien dprintstr("new-nfd", new, nfd); 80859243Sobrien dprintstr("ofd-osb", ofd, osb); 80959243Sobrien dprintstr("nfd-nsb", nfd, nsb); 81059243Sobrien dprintstr("osb-ose", osb, ose); 81159243Sobrien dprintstr("nsb-nse", nsb, nse); 81259243Sobrien dprintstr("ose-ols", ose, ols); 81359243Sobrien dprintstr("nse-nls", nse, nls); 81459243Sobrien dprintstr("ols- oe", ols, oe); 81559243Sobrien dprintstr("nls- ne", nls, ne); 81659243Sobrien#endif /* DEBUG_UPDATE */ 81759243Sobrien 81859243Sobrien /* 81959243Sobrien * CursorV to this line cur_line MUST be in this routine so that if we 82059243Sobrien * don't have to change the line, we don't move to it. CursorH to first 82159243Sobrien * diff char 82259243Sobrien */ 82359243Sobrien MoveToLine(cur_line); 82459243Sobrien 82559243Sobrien /* 82659243Sobrien * at this point we have something like this: 82759243Sobrien * 82859243Sobrien * /old /ofd /osb /ose /ols /oe 82959243Sobrien * v.....................v v..................v v........v 83059243Sobrien * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as 83159243Sobrien * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as 83259243Sobrien * ^.....................^ ^..................^ ^........^ 83359243Sobrien * \new \nfd \nsb \nse \nls \ne 83459243Sobrien * 83559243Sobrien * fx is the difference in length between the the chars between nfd and 83659243Sobrien * nsb, and the chars between ofd and osb, and is thus the number of 83759243Sobrien * characters to delete if < 0 (new is shorter than old, as above), 83859243Sobrien * or insert (new is longer than short). 83959243Sobrien * 84059243Sobrien * sx is the same for the second differences. 84159243Sobrien */ 84259243Sobrien 84359243Sobrien /* 84459243Sobrien * if we have a net insert on the first difference, AND inserting the net 84559243Sobrien * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character 84659243Sobrien * (which is ne if nls != ne, otherwise is nse) off the edge of the screen 84759243Sobrien * (TermH - 1) else we do the deletes first so that we keep everything we 84859243Sobrien * need to. 84959243Sobrien */ 85059243Sobrien 85159243Sobrien /* 85259243Sobrien * if the last same is the same like the end, there is no last same part, 85359243Sobrien * otherwise we want to keep the last same part set p to the last useful 85459243Sobrien * old character 85559243Sobrien */ 85659243Sobrien p = (ols != oe) ? oe : ose; 85759243Sobrien 85859243Sobrien /* 85959243Sobrien * if (There is a diffence in the beginning) && (we need to insert 86059243Sobrien * characters) && (the number of characters to insert is less than the term 86159243Sobrien * width) We need to do an insert! else if (we need to delete characters) 86259243Sobrien * We need to delete characters! else No insert or delete 86359243Sobrien */ 86459243Sobrien if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) { 86559243Sobrien#ifdef DEBUG_UPDATE 866231990Smp reprintf("first diff insert at %d...\r\n", nfd - new); 86759243Sobrien#endif /* DEBUG_UPDATE */ 86859243Sobrien /* 86959243Sobrien * Move to the first char to insert, where the first diff is. 87059243Sobrien */ 87159243Sobrien MoveToChar(nfd - new); 87259243Sobrien /* 87359243Sobrien * Check if we have stuff to keep at end 87459243Sobrien */ 87559243Sobrien if (nsb != ne) { 87659243Sobrien#ifdef DEBUG_UPDATE 877231990Smp reprintf("with stuff to keep at end\r\n"); 87859243Sobrien#endif /* DEBUG_UPDATE */ 87959243Sobrien /* 88059243Sobrien * insert fx chars of new starting at nfd 88159243Sobrien */ 88259243Sobrien if (fx > 0) { 88359243Sobrien#ifdef DEBUG_UPDATE 88459243Sobrien if (!T_CanIns) 885231990Smp reprintf(" ERROR: cannot insert in early first diff\n"); 88659243Sobrien#endif /* DEBUG_UPDATE */ 88759243Sobrien Insert_write(nfd, fx); 88859243Sobrien str_insert(old, (int) (ofd - old), TermH, nfd, fx); 88959243Sobrien } 89059243Sobrien /* 89159243Sobrien * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 89259243Sobrien */ 89359243Sobrien so_write(nfd + fx, (nsb - nfd) - fx); 89459243Sobrien str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); 89559243Sobrien } 89659243Sobrien else { 89759243Sobrien#ifdef DEBUG_UPDATE 898231990Smp reprintf("without anything to save\r\n"); 89959243Sobrien#endif /* DEBUG_UPDATE */ 90059243Sobrien so_write(nfd, (nsb - nfd)); 90159243Sobrien str_cp(ofd, nfd, (int) (nsb - nfd)); 90259243Sobrien /* 90359243Sobrien * Done 90459243Sobrien */ 90559243Sobrien return; 90659243Sobrien } 90759243Sobrien } 90859243Sobrien else if (fx < 0) { 90959243Sobrien#ifdef DEBUG_UPDATE 910231990Smp reprintf("first diff delete at %d...\r\n", ofd - old); 91159243Sobrien#endif /* DEBUG_UPDATE */ 91259243Sobrien /* 91359243Sobrien * move to the first char to delete where the first diff is 91459243Sobrien */ 91559243Sobrien MoveToChar(ofd - old); 91659243Sobrien /* 91759243Sobrien * Check if we have stuff to save 91859243Sobrien */ 91959243Sobrien if (osb != oe) { 92059243Sobrien#ifdef DEBUG_UPDATE 921231990Smp reprintf("with stuff to save at end\r\n"); 92259243Sobrien#endif /* DEBUG_UPDATE */ 92359243Sobrien /* 92459243Sobrien * fx is less than zero *always* here but we check for code 92559243Sobrien * symmetry 92659243Sobrien */ 92759243Sobrien if (fx < 0) { 92859243Sobrien#ifdef DEBUG_UPDATE 92959243Sobrien if (!T_CanDel) 930231990Smp reprintf(" ERROR: cannot delete in first diff\n"); 93159243Sobrien#endif /* DEBUG_UPDATE */ 93259243Sobrien DeleteChars(-fx); 93359243Sobrien str_delete(old, (int) (ofd - old), TermH, -fx); 93459243Sobrien } 93559243Sobrien /* 93659243Sobrien * write (nsb-nfd) chars of new starting at nfd 93759243Sobrien */ 93859243Sobrien so_write(nfd, (nsb - nfd)); 93959243Sobrien str_cp(ofd, nfd, (int) (nsb - nfd)); 94059243Sobrien 94159243Sobrien } 94259243Sobrien else { 94359243Sobrien#ifdef DEBUG_UPDATE 944231990Smp reprintf("but with nothing left to save\r\n"); 94559243Sobrien#endif /* DEBUG_UPDATE */ 94659243Sobrien /* 94759243Sobrien * write (nsb-nfd) chars of new starting at nfd 94859243Sobrien */ 94959243Sobrien so_write(nfd, (nsb - nfd)); 95059243Sobrien#ifdef DEBUG_REFRESH 951231990Smp reprintf("cleareol %d\n", (oe - old) - (ne - new)); 95259243Sobrien#endif /* DEBUG_UPDATE */ 95369408Sache#ifndef WINNT_NATIVE 95459243Sobrien ClearEOL((oe - old) - (ne - new)); 95559243Sobrien#else 95659243Sobrien /* 95759243Sobrien * The calculation above does not work too well on NT 95859243Sobrien */ 95959243Sobrien ClearEOL(TermH - CursorH); 96069408Sache#endif /*WINNT_NATIVE*/ 96159243Sobrien /* 96259243Sobrien * Done 96359243Sobrien */ 96459243Sobrien return; 96559243Sobrien } 96659243Sobrien } 96759243Sobrien else 96859243Sobrien fx = 0; 96959243Sobrien 97059243Sobrien if (sx < 0) { 97159243Sobrien#ifdef DEBUG_UPDATE 972231990Smp reprintf("second diff delete at %d...\r\n", (ose - old) + fx); 97359243Sobrien#endif /* DEBUG_UPDATE */ 97459243Sobrien /* 97559243Sobrien * Check if we have stuff to delete 97659243Sobrien */ 97759243Sobrien /* 97859243Sobrien * fx is the number of characters inserted (+) or deleted (-) 97959243Sobrien */ 98059243Sobrien 98159243Sobrien MoveToChar((ose - old) + fx); 98259243Sobrien /* 98359243Sobrien * Check if we have stuff to save 98459243Sobrien */ 98559243Sobrien if (ols != oe) { 98659243Sobrien#ifdef DEBUG_UPDATE 987231990Smp reprintf("with stuff to save at end\r\n"); 98859243Sobrien#endif /* DEBUG_UPDATE */ 98959243Sobrien /* 99059243Sobrien * Again a duplicate test. 99159243Sobrien */ 99259243Sobrien if (sx < 0) { 99359243Sobrien#ifdef DEBUG_UPDATE 99459243Sobrien if (!T_CanDel) 995231990Smp reprintf(" ERROR: cannot delete in second diff\n"); 99659243Sobrien#endif /* DEBUG_UPDATE */ 99759243Sobrien DeleteChars(-sx); 99859243Sobrien } 99959243Sobrien 100059243Sobrien /* 100159243Sobrien * write (nls-nse) chars of new starting at nse 100259243Sobrien */ 100359243Sobrien so_write(nse, (nls - nse)); 100459243Sobrien } 100559243Sobrien else { 100659243Sobrien int olen = (int) (oe - old + fx); 100759243Sobrien if (olen > TermH) 100859243Sobrien olen = TermH; 100959243Sobrien#ifdef DEBUG_UPDATE 1010231990Smp reprintf("but with nothing left to save\r\n"); 101159243Sobrien#endif /* DEBUG_UPDATE */ 101259243Sobrien so_write(nse, (nls - nse)); 101359243Sobrien#ifdef DEBUG_REFRESH 1014231990Smp reprintf("cleareol %d\n", olen - (ne - new)); 101559243Sobrien#endif /* DEBUG_UPDATE */ 101669408Sache#ifndef WINNT_NATIVE 101759243Sobrien ClearEOL(olen - (ne - new)); 101859243Sobrien#else 101959243Sobrien /* 102059243Sobrien * The calculation above does not work too well on NT 102159243Sobrien */ 102259243Sobrien ClearEOL(TermH - CursorH); 102369408Sache#endif /*WINNT_NATIVE*/ 102459243Sobrien } 102559243Sobrien } 102659243Sobrien 102759243Sobrien /* 102859243Sobrien * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... 102959243Sobrien */ 103059243Sobrien if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { 103159243Sobrien#ifdef DEBUG_UPDATE 1032231990Smp reprintf("late first diff insert at %d...\r\n", nfd - new); 103359243Sobrien#endif /* DEBUG_UPDATE */ 103459243Sobrien 103559243Sobrien MoveToChar(nfd - new); 103659243Sobrien /* 103759243Sobrien * Check if we have stuff to keep at the end 103859243Sobrien */ 103959243Sobrien if (nsb != ne) { 104059243Sobrien#ifdef DEBUG_UPDATE 1041231990Smp reprintf("with stuff to keep at end\r\n"); 104259243Sobrien#endif /* DEBUG_UPDATE */ 104359243Sobrien /* 104459243Sobrien * We have to recalculate fx here because we set it 104559243Sobrien * to zero above as a flag saying that we hadn't done 104659243Sobrien * an early first insert. 104759243Sobrien */ 104859243Sobrien fx = (int) ((nsb - nfd) - (osb - ofd)); 104959243Sobrien if (fx > 0) { 105059243Sobrien /* 105159243Sobrien * insert fx chars of new starting at nfd 105259243Sobrien */ 105359243Sobrien#ifdef DEBUG_UPDATE 105459243Sobrien if (!T_CanIns) 1055231990Smp reprintf(" ERROR: cannot insert in late first diff\n"); 105659243Sobrien#endif /* DEBUG_UPDATE */ 105759243Sobrien Insert_write(nfd, fx); 105859243Sobrien str_insert(old, (int) (ofd - old), TermH, nfd, fx); 105959243Sobrien } 106059243Sobrien 106159243Sobrien /* 106259243Sobrien * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 106359243Sobrien */ 106459243Sobrien so_write(nfd + fx, (nsb - nfd) - fx); 106559243Sobrien str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); 106659243Sobrien } 106759243Sobrien else { 106859243Sobrien#ifdef DEBUG_UPDATE 1069231990Smp reprintf("without anything to save\r\n"); 107059243Sobrien#endif /* DEBUG_UPDATE */ 107159243Sobrien so_write(nfd, (nsb - nfd)); 107259243Sobrien str_cp(ofd, nfd, (int) (nsb - nfd)); 107359243Sobrien } 107459243Sobrien } 107559243Sobrien 107659243Sobrien /* 107759243Sobrien * line is now NEW up to nse 107859243Sobrien */ 107959243Sobrien if (sx >= 0) { 108059243Sobrien#ifdef DEBUG_UPDATE 1081231990Smp reprintf("second diff insert at %d...\r\n", nse - new); 108259243Sobrien#endif /* DEBUG_UPDATE */ 108359243Sobrien MoveToChar(nse - new); 108459243Sobrien if (ols != oe) { 108559243Sobrien#ifdef DEBUG_UPDATE 1086231990Smp reprintf("with stuff to keep at end\r\n"); 108759243Sobrien#endif /* DEBUG_UPDATE */ 108859243Sobrien if (sx > 0) { 108959243Sobrien /* insert sx chars of new starting at nse */ 109059243Sobrien#ifdef DEBUG_UPDATE 109159243Sobrien if (!T_CanIns) 1092231990Smp reprintf(" ERROR: cannot insert in second diff\n"); 109359243Sobrien#endif /* DEBUG_UPDATE */ 109459243Sobrien Insert_write(nse, sx); 109559243Sobrien } 109659243Sobrien 109759243Sobrien /* 109859243Sobrien * write (nls-nse) - sx chars of new starting at (nse + sx) 109959243Sobrien */ 110059243Sobrien so_write(nse + sx, (nls - nse) - sx); 110159243Sobrien } 110259243Sobrien else { 110359243Sobrien#ifdef DEBUG_UPDATE 1104231990Smp reprintf("without anything to save\r\n"); 110559243Sobrien#endif /* DEBUG_UPDATE */ 110659243Sobrien so_write(nse, (nls - nse)); 110759243Sobrien 110859243Sobrien /* 110959243Sobrien * No need to do a clear-to-end here because we were doing 111059243Sobrien * a second insert, so we will have over written all of the 111159243Sobrien * old string. 111259243Sobrien */ 111359243Sobrien } 111459243Sobrien } 111559243Sobrien#ifdef DEBUG_UPDATE 1116231990Smp reprintf("done.\r\n"); 111759243Sobrien#endif /* DEBUG_UPDATE */ 111859243Sobrien} 111959243Sobrien 112059243Sobrien 112159243Sobrienstatic void 1122167465Smpcpy_pad_spaces(Char *dst, Char *src, int width) 112359243Sobrien{ 1124145479Smp int i; 112559243Sobrien 112659243Sobrien for (i = 0; i < width; i++) { 112759243Sobrien if (*src == (Char) 0) 112859243Sobrien break; 112959243Sobrien *dst++ = *src++; 113059243Sobrien } 113159243Sobrien 113259243Sobrien while (i < width) { 113359243Sobrien *dst++ = ' '; 113459243Sobrien i++; 113559243Sobrien } 113659243Sobrien *dst = (Char) 0; 113759243Sobrien} 113859243Sobrien 113959243Sobrienvoid 1140167465SmpRefCursor(void) 114159243Sobrien{ /* only move to new cursor pos */ 1142145479Smp Char *cp; 1143167465Smp int w, h, th, v; 114459243Sobrien 114559243Sobrien /* first we must find where the cursor is... */ 114659243Sobrien h = 0; 114759243Sobrien v = 0; 114859243Sobrien th = TermH; /* optimize for speed */ 114959243Sobrien 1150167465Smp for (cp = Prompt; cp != NULL && *cp; ) { /* do prompt */ 1151145479Smp if (*cp & LITERAL) { 1152145479Smp cp++; 115359243Sobrien continue; 115459243Sobrien } 1155316957Sdchagin w = NLSClassify(*cp & CHAR, cp == Prompt, 0); 1156167465Smp cp++; 1157145479Smp switch(w) { 1158145479Smp case NLSCLASS_NL: 1159145479Smp h = 0; 1160145479Smp v++; 1161145479Smp break; 1162145479Smp case NLSCLASS_TAB: 1163145479Smp while (++h & 07) 1164145479Smp ; 1165145479Smp break; 1166145479Smp case NLSCLASS_CTRL: 1167145479Smp h += 2; 1168145479Smp break; 1169145479Smp case NLSCLASS_ILLEGAL: 1170145479Smp h += 4; 1171145479Smp break; 1172145479Smp case NLSCLASS_ILLEGAL2: 1173145479Smp case NLSCLASS_ILLEGAL3: 1174145479Smp case NLSCLASS_ILLEGAL4: 1175145479Smp h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); 1176145479Smp break; 1177145479Smp default: 1178145479Smp h += w; 117959243Sobrien } 118059243Sobrien if (h >= th) { /* check, extra long tabs picked up here also */ 1181145479Smp h -= th; 118259243Sobrien v++; 118359243Sobrien } 118459243Sobrien } 118559243Sobrien 1186145479Smp for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */ 1187316957Sdchagin w = NLSClassify(*cp & CHAR, cp == InputBuf, 0); 1188167465Smp cp++; 1189145479Smp switch(w) { 1190145479Smp case NLSCLASS_NL: 1191145479Smp h = 0; 1192145479Smp v++; 1193145479Smp break; 1194145479Smp case NLSCLASS_TAB: 1195145479Smp while (++h & 07) 1196145479Smp ; 1197145479Smp break; 1198145479Smp case NLSCLASS_CTRL: 1199145479Smp h += 2; 1200145479Smp break; 1201145479Smp case NLSCLASS_ILLEGAL: 1202145479Smp h += 4; 1203145479Smp break; 1204145479Smp case NLSCLASS_ILLEGAL2: 1205145479Smp case NLSCLASS_ILLEGAL3: 1206145479Smp case NLSCLASS_ILLEGAL4: 1207145479Smp h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); 1208145479Smp break; 1209145479Smp default: 1210145479Smp h += w; 121159243Sobrien } 121259243Sobrien if (h >= th) { /* check, extra long tabs picked up here also */ 1213145479Smp h -= th; 121459243Sobrien v++; 121559243Sobrien } 121659243Sobrien } 121759243Sobrien 121859243Sobrien /* now go there */ 121959243Sobrien MoveToLine(v); 122059243Sobrien MoveToChar(h); 1221167465Smp if (adrof(STRhighlight) && MarkIsSet) { 1222167465Smp ClearLines(); 1223167465Smp ClearDisp(); 1224167465Smp Refresh(); 1225167465Smp } 122659243Sobrien flush(); 122759243Sobrien} 122859243Sobrien 1229131962Smp#ifndef WINTT_NATIVE 123059243Sobrienstatic void 1231167465SmpPutPlusOne(Char c, int width) 123259243Sobrien{ 1233145479Smp while (width > 1 && CursorH + width > TermH) 1234145479Smp PutPlusOne(' ', 1); 1235145479Smp if ((c & LITERAL) != 0) { 1236145479Smp Char *d; 1237145479Smp for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++) 1238145479Smp (void) putwraw(*d); 1239145479Smp } else { 1240145479Smp (void) putwraw(c); 1241145479Smp } 124259243Sobrien Display[CursorV][CursorH++] = (Char) c; 1243145479Smp while (--width > 0) 1244145479Smp Display[CursorV][CursorH++] = CHAR_DBWIDTH; 124559243Sobrien if (CursorH >= TermH) { /* if we must overflow */ 124659243Sobrien CursorH = 0; 124759243Sobrien CursorV++; 124859243Sobrien OldvcV++; 124959243Sobrien if (T_Margin & MARGIN_AUTO) { 125059243Sobrien if (T_Margin & MARGIN_MAGIC) { 125159243Sobrien (void) putraw(' '); 125259243Sobrien (void) putraw('\b'); 125359243Sobrien } 125459243Sobrien } 125559243Sobrien else { 125659243Sobrien (void) putraw('\r'); 125759243Sobrien (void) putraw('\n'); 125859243Sobrien } 125959243Sobrien } 126059243Sobrien} 1261131962Smp#endif 126259243Sobrien 126359243Sobrienvoid 1264145479SmpRefPlusOne(int l) 126559243Sobrien{ /* we added just one char, handle it fast. 126659243Sobrien * assumes that screen cursor == real cursor */ 1267167465Smp Char *cp, c; 1268145479Smp int w; 126959243Sobrien 1270145479Smp if (Cursor != LastChar) { 127159243Sobrien Refresh(); /* too hard to handle */ 127259243Sobrien return; 127359243Sobrien } 127459243Sobrien if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) { 127559243Sobrien Refresh(); /* clear out rprompt if less than one char gap*/ 127659243Sobrien return; 1277145479Smp } 1278145479Smp cp = Cursor - l; 1279167465Smp c = *cp & CHAR; 1280316957Sdchagin w = NLSClassify(c, cp == InputBuf, 0); 1281145479Smp switch(w) { 1282145479Smp case NLSCLASS_CTRL: 1283145479Smp PutPlusOne('^', 1); 1284145479Smp if (c == CTL_ESC('\177')) { 1285145479Smp PutPlusOne('?', 1); 1286145479Smp break; 1287145479Smp } 128869408Sache#ifdef IS_ASCII 1289145479Smp /* uncontrolify it; works only for iso8859-1 like sets */ 1290145479Smp PutPlusOne((c | 0100), 1); 129169408Sache#else 1292145479Smp PutPlusOne(_toebcdic[_toascii[c]|0100], 1); 129369408Sache#endif 1294145479Smp break; 1295145479Smp case NLSCLASS_ILLEGAL: 1296145479Smp PutPlusOne('\\', 1); 1297145479Smp PutPlusOne(((c >> 6) & 7) + '0', 1); 1298145479Smp PutPlusOne(((c >> 3) & 7) + '0', 1); 1299145479Smp PutPlusOne((c & 7) + '0', 1); 1300145479Smp break; 1301145479Smp case 1: 1302167465Smp if (adrof(STRhighlight) && MarkIsSet) 1303167465Smp StartHighlight(); 1304145479Smp if (l > 1) 1305145479Smp PutPlusOne(MakeLiteral(cp, l, 0), 1); 1306145479Smp else 1307145479Smp PutPlusOne(*cp, 1); 1308167465Smp if (adrof(STRhighlight) && MarkIsSet) 1309167465Smp StopHighlight(); 1310145479Smp break; 1311145479Smp default: 1312145479Smp Refresh(); /* too hard to handle */ 1313145479Smp return; 131459243Sobrien } 131559243Sobrien flush(); 131659243Sobrien} 131759243Sobrien 131859243Sobrien/* clear the screen buffers so that new new prompt starts fresh. */ 131959243Sobrien 132059243Sobrienvoid 1321167465SmpClearDisp(void) 132259243Sobrien{ 1323145479Smp int i; 132459243Sobrien 132559243Sobrien CursorV = 0; /* clear the display buffer */ 132659243Sobrien CursorH = 0; 132759243Sobrien for (i = 0; i < TermV; i++) 1328316957Sdchagin (void) memset(Display[i], 0, (TermH + 1) * sizeof(Display[0][0])); 132959243Sobrien OldvcV = 0; 1330145479Smp litlen = 0; 133159243Sobrien} 133259243Sobrien 133359243Sobrienvoid 1334167465SmpClearLines(void) 133559243Sobrien{ /* Make sure all lines are *really* blank */ 1336145479Smp int i; 133759243Sobrien 133859243Sobrien if (T_CanCEOL) { 133959243Sobrien /* 134059243Sobrien * Clear the lines from the bottom up so that if we try moving 134159243Sobrien * the cursor down by writing the character that is at the end 134259243Sobrien * of the screen line, we won't rewrite a character that shouldn't 134359243Sobrien * be there. 134459243Sobrien */ 134559243Sobrien for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */ 134659243Sobrien MoveToLine(i); 134759243Sobrien MoveToChar(0); 134859243Sobrien ClearEOL(TermH); 134959243Sobrien } 135059243Sobrien } 135159243Sobrien else { 135259243Sobrien MoveToLine(OldvcV); /* go to last line */ 135359243Sobrien (void) putraw('\r'); /* go to BOL */ 135459243Sobrien (void) putraw('\n'); /* go to new line */ 135559243Sobrien } 135659243Sobrien} 1357