1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/ed.refresh.c,v 3.47 2011/02/27 00:14:51 christos Exp $ */ 259243Sobrien/* 359243Sobrien * ed.refresh.c: Lower level screen refreshing functions 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35232633SmpRCSID("$tcsh: ed.refresh.c,v 3.47 2011/02/27 00:14:51 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 3859243Sobrien/* #define DEBUG_UPDATE */ 3959243Sobrien/* #define DEBUG_REFRESH */ 4059243Sobrien/* #define DEBUG_LITERAL */ 4159243Sobrien 4259243Sobrien/* refresh.c -- refresh the current set of lines on the screen */ 4359243Sobrien 44145479SmpChar *litptr; 4559243Sobrienstatic int vcursor_h, vcursor_v; 4659243Sobrienstatic int rprompt_h, rprompt_v; 4759243Sobrien 48167465Smpstatic int MakeLiteral (Char *, int, Char); 49167465Smpstatic int Draw (Char *, int); 50167465Smpstatic void Vdraw (Char, int); 51167465Smpstatic void RefreshPromptpart (Char *); 52167465Smpstatic void update_line (Char *, Char *, int); 53167465Smpstatic void str_insert (Char *, int, int, Char *, int); 54167465Smpstatic void str_delete (Char *, int, int, int); 55167465Smpstatic void str_cp (Char *, Char *, int); 56131962Smp#ifndef WINNT_NATIVE 57131962Smpstatic 58131962Smp#else 59131962Smpextern 60131962Smp#endif 61167465Smp void PutPlusOne (Char, int); 62167465Smpstatic void cpy_pad_spaces (Char *, Char *, int); 6359243Sobrien#if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL) 64232633Smpstatic void reprintf (char *, ...); 6559243Sobrien#ifdef DEBUG_UPDATE 66167465Smpstatic void dprintstr (char *, const Char *, const Char *); 6759243Sobrien 6859243Sobrienstatic void 69167465Smpdprintstr(char *str, const Char *f, const Char *t) 7059243Sobrien{ 71232633Smp reprintf("%s:\"", str); 72145479Smp while (f < t) { 73167465Smp if (ASC(*f) & ~ASCII) 74232633Smp reprintf("[%x]", *f++); 75145479Smp else 76232633Smp reprintf("%c", CTL_ESC(ASCII & ASC(*f++))); 77145479Smp } 78232633Smp reprintf("\"\r\n"); 79145479Smp} 8059243Sobrien#endif /* DEBUG_UPDATE */ 8159243Sobrien 82232633Smp/* reprintf(): 8359243Sobrien * Print to $DEBUGTTY, so that we can test editing on one pty, and 8459243Sobrien * print debugging stuff on another. Don't interrupt the shell while 8559243Sobrien * debugging cause you'll mangle up the file descriptors! 8659243Sobrien */ 8759243Sobrienstatic void 88232633Smpreprintf(char *fmt, ...) 8959243Sobrien{ 9059243Sobrien static int fd = -1; 9159243Sobrien char *dtty; 9259243Sobrien 9359243Sobrien if ((dtty = getenv("DEBUGTTY"))) { 9459243Sobrien int o; 9559243Sobrien va_list va; 9659243Sobrien va_start(va, fmt); 9759243Sobrien 9859243Sobrien if (fd == -1) 99167465Smp fd = xopen(dtty, O_RDWR); 10059243Sobrien o = SHOUT; 10159243Sobrien flush(); 10259243Sobrien SHOUT = fd; 10359243Sobrien xvprintf(fmt, va); 10459243Sobrien va_end(va); 10559243Sobrien flush(); 10659243Sobrien SHOUT = o; 10759243Sobrien } 10859243Sobrien} 10959243Sobrien#endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */ 11059243Sobrien 111145479Smpstatic int litlen = 0, litalloc = 0; 112145479Smp 113167465Smpstatic int MakeLiteral(Char *str, int len, Char addlit) 11459243Sobrien{ 115145479Smp int i, addlitlen = 0; 116145479Smp Char *addlitptr = 0; 117145479Smp if (addlit) { 118145479Smp if ((addlit & LITERAL) != 0) { 119145479Smp addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; 120145479Smp addlitlen = Strlen(addlitptr); 121145479Smp } else { 122145479Smp addlitptr = &addlit; 123145479Smp addlitlen = 1; 124145479Smp } 125145479Smp for (i = 0; i < litlen; i += LIT_FACTOR) 126145479Smp if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0) 127145479Smp return (i / LIT_FACTOR) | LITERAL; 128145479Smp } else { 129145479Smp addlitlen = 0; 130145479Smp for (i = 0; i < litlen; i += LIT_FACTOR) 131145479Smp if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0) 132145479Smp return (i / LIT_FACTOR) | LITERAL; 13359243Sobrien } 134145479Smp if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) { 135145479Smp Char *newlitptr; 136145479Smp int add = 256; 137145479Smp while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add) 138145479Smp add *= 2; 139167465Smp newlitptr = xrealloc(litptr, (litalloc + add) * sizeof(Char)); 140145479Smp if (!newlitptr) 141145479Smp return '?'; 142145479Smp litptr = newlitptr; 143145479Smp litalloc += add; 144145479Smp if (addlitptr && addlitptr != &addlit) 145145479Smp addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; 146145479Smp } 147145479Smp i = litlen / LIT_FACTOR; 148145479Smp if (i >= LITERAL || i == CHAR_DBWIDTH) 149145479Smp return '?'; 150145479Smp if (addlitptr) { 151145479Smp Strncpy(litptr + litlen, addlitptr, addlitlen); 152145479Smp litlen += addlitlen; 153145479Smp } 154145479Smp Strncpy(litptr + litlen, str, len); 155145479Smp litlen += len; 156145479Smp do 157145479Smp litptr[litlen++] = 0; 158145479Smp while (litlen % LIT_FACTOR); 159145479Smp return i | LITERAL; 160145479Smp} 16159243Sobrien 162145479Smpstatic int 163167465SmpDraw(Char *cp, int nocomb) /* draw char at cp, expand tabs, ctl chars */ 164145479Smp{ 165167465Smp int w, i, lv, lh; 166167465Smp Char c, attr; 167145479Smp 168145479Smp attr = *cp & ~CHAR; 169167465Smp c = *cp & CHAR; 170145479Smp w = NLSClassify(c, nocomb); 171145479Smp switch (w) { 172145479Smp case NLSCLASS_NL: 173145479Smp Vdraw('\0', 0); /* assure end of line */ 174145479Smp vcursor_h = 0; /* reset cursor pos */ 17559243Sobrien vcursor_v++; 176145479Smp break; 177145479Smp case NLSCLASS_TAB: 178145479Smp do { 179145479Smp Vdraw(' ', 1); 180145479Smp } while ((vcursor_h & 07) != 0); 181145479Smp break; 182145479Smp case NLSCLASS_CTRL: 183145479Smp Vdraw('^' | attr, 1); 184145479Smp if (c == CTL_ESC('\177')) { 185145479Smp Vdraw('?' | attr, 1); 186145479Smp } else { 18769408Sache#ifdef IS_ASCII 188145479Smp /* uncontrolify it; works only for iso8859-1 like sets */ 189145479Smp Vdraw(c | 0100 | attr, 1); 19069408Sache#else 191145479Smp Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1); 192145479Smp#endif 19359243Sobrien } 194145479Smp break; 195145479Smp case NLSCLASS_ILLEGAL: 196145479Smp Vdraw('\\' | attr, 1); 197167465Smp Vdraw((((c >> 6) & 7) + '0') | attr, 1); 198167465Smp Vdraw((((c >> 3) & 7) + '0') | attr, 1); 199167465Smp Vdraw(((c & 7) + '0') | attr, 1); 200145479Smp break; 201145479Smp case NLSCLASS_ILLEGAL2: 202145479Smp case NLSCLASS_ILLEGAL3: 203145479Smp case NLSCLASS_ILLEGAL4: 204145479Smp Vdraw('\\' | attr, 1); 205145479Smp Vdraw('U' | attr, 1); 206145479Smp Vdraw('+' | attr, 1); 207145479Smp for (i = 8 * NLSCLASS_ILLEGAL_SIZE(w) - 4; i >= 0; i -= 4) 208145479Smp Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1); 209145479Smp break; 210145479Smp case 0: 211145479Smp lv = vcursor_v; 212145479Smp lh = vcursor_h; 213145479Smp for (;;) { 214145479Smp lh--; 215145479Smp if (lh < 0) { 216145479Smp lv--; 217145479Smp if (lv < 0) 218145479Smp break; 219145479Smp lh = Strlen(Vdisplay[lv]) - 1; 220145479Smp } 221145479Smp if (Vdisplay[lv][lh] != CHAR_DBWIDTH) 222145479Smp break; 223145479Smp } 224145479Smp if (lv < 0) { 225167465Smp Vdraw('\\' | attr, 1); 226167465Smp Vdraw((((c >> 6) & 7) + '0') | attr, 1); 227167465Smp Vdraw((((c >> 3) & 7) + '0') | attr, 1); 228167465Smp Vdraw(((c & 7) + '0') | attr, 1); 229167465Smp break; 230145479Smp } 231167465Smp Vdisplay[lv][lh] = MakeLiteral(cp, 1, Vdisplay[lv][lh]); 232145479Smp break; 233145479Smp default: 234167465Smp Vdraw(*cp, w); 235145479Smp break; 23659243Sobrien } 237167465Smp return 1; 23859243Sobrien} 23959243Sobrien 24059243Sobrienstatic void 241167465SmpVdraw(Char c, int width) /* draw char c onto V lines */ 24259243Sobrien{ 24359243Sobrien#ifdef DEBUG_REFRESH 24459243Sobrien# ifdef SHORT_STRINGS 245232633Smp reprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width); 24659243Sobrien# else 247232633Smp reprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width); 24859243Sobrien# endif /* SHORT_STRNGS */ 24959243Sobrien#endif /* DEBUG_REFRESH */ 25059243Sobrien 251145479Smp /* Hopefully this is what all the terminals do with multi-column characters 252145479Smp that "span line breaks". */ 253145479Smp while (vcursor_h + width > TermH) 254145479Smp Vdraw(' ', 1); 255167465Smp Vdisplay[vcursor_v][vcursor_h] = c; 256145479Smp if (width) 257145479Smp vcursor_h++; /* advance to next place */ 258145479Smp while (--width > 0) 259145479Smp Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH; 26059243Sobrien if (vcursor_h >= TermH) { 26159243Sobrien Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */ 26259243Sobrien vcursor_h = 0; /* reset it. */ 26359243Sobrien vcursor_v++; 26459243Sobrien#ifdef DEBUG_REFRESH 26559243Sobrien if (vcursor_v >= TermV) { /* should NEVER happen. */ 266232633Smp reprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n", 26759243Sobrien vcursor_v, TermV); 26859243Sobrien abort(); 26959243Sobrien } 27059243Sobrien#endif /* DEBUG_REFRESH */ 27159243Sobrien } 27259243Sobrien} 27359243Sobrien 27459243Sobrien/* 27559243Sobrien * RefreshPromptpart() 27659243Sobrien * draws a prompt element, expanding literals (we know it's ASCIZ) 27759243Sobrien */ 27859243Sobrienstatic void 279167465SmpRefreshPromptpart(Char *buf) 28059243Sobrien{ 281145479Smp Char *cp; 282167465Smp int w; 28359243Sobrien 284167465Smp if (buf == NULL) 285167465Smp return; 286145479Smp for (cp = buf; *cp; ) { 28759243Sobrien if (*cp & LITERAL) { 288145479Smp Char *litstart = cp; 28959243Sobrien while (*cp & LITERAL) 29059243Sobrien cp++; 291145479Smp if (*cp) { 292167465Smp w = NLSWidth(*cp & CHAR); 293167465Smp Vdraw(MakeLiteral(litstart, cp + 1 - litstart, 0), w); 294167465Smp cp++; 295145479Smp } 29659243Sobrien else { 29759243Sobrien /* 29859243Sobrien * XXX: This is a bug, we lose the last literal, if it is not 29959243Sobrien * followed by a normal character, but it is too hard to fix 30059243Sobrien */ 30159243Sobrien break; 30259243Sobrien } 30359243Sobrien } 30459243Sobrien else 305145479Smp cp += Draw(cp, cp == buf); 30659243Sobrien } 30759243Sobrien} 30859243Sobrien 30959243Sobrien/* 31059243Sobrien * Refresh() 31159243Sobrien * draws the new virtual screen image from the current input 31259243Sobrien * line, then goes line-by-line changing the real image to the new 31359243Sobrien * virtual image. The routine to re-draw a line can be replaced 31459243Sobrien * easily in hopes of a smarter one being placed there. 31559243Sobrien */ 316131962Smp#ifndef WINNT_NATIVE 317131962Smpstatic 318131962Smp#endif 319131962Smpint OldvcV = 0; 320131962Smp 32159243Sobrienvoid 322167465SmpRefresh(void) 32359243Sobrien{ 324145479Smp int cur_line; 325145479Smp Char *cp; 32659243Sobrien int cur_h, cur_v = 0, new_vcv; 32759243Sobrien int rhdiff; 32859243Sobrien Char oldgetting; 32959243Sobrien 33059243Sobrien#ifdef DEBUG_REFRESH 331232633Smp reprintf("Prompt = :%s:\r\n", short2str(Prompt)); 332232633Smp reprintf("InputBuf = :%s:\r\n", short2str(InputBuf)); 33359243Sobrien#endif /* DEBUG_REFRESH */ 33459243Sobrien oldgetting = GettingInput; 33559243Sobrien GettingInput = 0; /* avoid re-entrance via SIGWINCH */ 33659243Sobrien 33759243Sobrien /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */ 33859243Sobrien vcursor_h = 0; 33959243Sobrien vcursor_v = 0; 340167465Smp RefreshPromptpart(RPrompt); 34159243Sobrien rprompt_h = vcursor_h; 34259243Sobrien rprompt_v = vcursor_v; 34359243Sobrien 34459243Sobrien /* reset the Vdraw cursor, draw prompt */ 34559243Sobrien vcursor_h = 0; 34659243Sobrien vcursor_v = 0; 347167465Smp RefreshPromptpart(Prompt); 34859243Sobrien cur_h = -1; /* set flag in case I'm not set */ 34959243Sobrien 35059243Sobrien /* draw the current input buffer */ 351145479Smp for (cp = InputBuf; (cp < LastChar); ) { 352145479Smp if (cp >= Cursor && cur_h == -1) { 35359243Sobrien cur_h = vcursor_h; /* save for later */ 35459243Sobrien cur_v = vcursor_v; 355145479Smp Cursor = cp; 35659243Sobrien } 357145479Smp cp += Draw(cp, cp == InputBuf); 35859243Sobrien } 35959243Sobrien 36059243Sobrien if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */ 36159243Sobrien cur_h = vcursor_h; 36259243Sobrien cur_v = vcursor_v; 36359243Sobrien } 36459243Sobrien 36559243Sobrien rhdiff = TermH - vcursor_h - rprompt_h; 36659243Sobrien if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) { 36759243Sobrien /* 36859243Sobrien * have a right-hand side prompt that will fit on 36959243Sobrien * the end of the first line with at least one 37059243Sobrien * character gap to the input buffer. 37159243Sobrien */ 37259243Sobrien while (--rhdiff > 0) /* pad out with spaces */ 373145479Smp Vdraw(' ', 1); 374167465Smp RefreshPromptpart(RPrompt); 37559243Sobrien } 37659243Sobrien else { 37759243Sobrien rprompt_h = 0; /* flag "not using rprompt" */ 37859243Sobrien rprompt_v = 0; 37959243Sobrien } 38059243Sobrien 38159243Sobrien new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */ 382145479Smp Vdraw('\0', 1); /* put NUL on end */ 38359243Sobrien 384145479Smp#if defined (DEBUG_REFRESH) 385232633Smp reprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n", 38659243Sobrien TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0])); 38759243Sobrien#endif /* DEBUG_REFRESH */ 38859243Sobrien 38959243Sobrien#ifdef DEBUG_UPDATE 390232633Smp reprintf("updating %d lines.\r\n", new_vcv); 39159243Sobrien#endif /* DEBUG_UPDATE */ 39259243Sobrien for (cur_line = 0; cur_line <= new_vcv; cur_line++) { 39359243Sobrien /* NOTE THAT update_line MAY CHANGE Display[cur_line] */ 39459243Sobrien update_line(Display[cur_line], Vdisplay[cur_line], cur_line); 39569408Sache#ifdef WINNT_NATIVE 39659243Sobrien flush(); 39769408Sache#endif /* WINNT_NATIVE */ 39859243Sobrien 39959243Sobrien /* 40059243Sobrien * Copy the new line to be the current one, and pad out with spaces 40159243Sobrien * to the full width of the terminal so that if we try moving the 40259243Sobrien * cursor by writing the character that is at the end of the 40359243Sobrien * screen line, it won't be a NUL or some old leftover stuff. 40459243Sobrien */ 40559243Sobrien cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH); 40659243Sobrien } 40759243Sobrien#ifdef DEBUG_REFRESH 408232633Smp reprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n", 40959243Sobrien vcursor_v, OldvcV, cur_line); 41059243Sobrien#endif /* DEBUG_REFRESH */ 41159243Sobrien if (OldvcV > new_vcv) { 41259243Sobrien for (; cur_line <= OldvcV; cur_line++) { 41359243Sobrien update_line(Display[cur_line], STRNULL, cur_line); 41459243Sobrien *Display[cur_line] = '\0'; 41559243Sobrien } 41659243Sobrien } 41759243Sobrien OldvcV = new_vcv; /* set for next time */ 41859243Sobrien#ifdef DEBUG_REFRESH 419232633Smp reprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n", 42059243Sobrien CursorH, CursorV, cur_h, cur_v); 42159243Sobrien#endif /* DEBUG_REFRESH */ 42269408Sache#ifdef WINNT_NATIVE 42359243Sobrien flush(); 42469408Sache#endif /* WINNT_NATIVE */ 42559243Sobrien MoveToLine(cur_v); /* go to where the cursor is */ 42659243Sobrien MoveToChar(cur_h); 42759243Sobrien SetAttributes(0); /* Clear all attributes */ 42859243Sobrien flush(); /* send the output... */ 42959243Sobrien GettingInput = oldgetting; /* reset to old value */ 43059243Sobrien} 43159243Sobrien 43259243Sobrien#ifdef notdef 433167465SmpGotoBottom(void) 43459243Sobrien{ /* used to go to last used screen line */ 43559243Sobrien MoveToLine(OldvcV); 43659243Sobrien} 43759243Sobrien 43859243Sobrien#endif 43959243Sobrien 44059243Sobrienvoid 441167465SmpPastBottom(void) 44259243Sobrien{ /* used to go to last used screen line */ 44359243Sobrien MoveToLine(OldvcV); 44459243Sobrien (void) putraw('\r'); 44559243Sobrien (void) putraw('\n'); 44659243Sobrien ClearDisp(); 44759243Sobrien flush(); 44859243Sobrien} 44959243Sobrien 45059243Sobrien 45159243Sobrien/* insert num characters of s into d (in front of the character) at dat, 45259243Sobrien maximum length of d is dlen */ 45359243Sobrienstatic void 454167465Smpstr_insert(Char *d, int dat, int dlen, Char *s, int num) 45559243Sobrien{ 456145479Smp Char *a, *b; 45759243Sobrien 45859243Sobrien if (num <= 0) 45959243Sobrien return; 46059243Sobrien if (num > dlen - dat) 46159243Sobrien num = dlen - dat; 46259243Sobrien 46359243Sobrien#ifdef DEBUG_REFRESH 464232633Smp reprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n", 46559243Sobrien num, dat, dlen, short2str(d)); 466232633Smp reprintf("s == \"%s\"n", short2str(s)); 46759243Sobrien#endif /* DEBUG_REFRESH */ 46859243Sobrien 46959243Sobrien /* open up the space for num chars */ 47059243Sobrien if (num > 0) { 47159243Sobrien b = d + dlen - 1; 47259243Sobrien a = b - num; 47359243Sobrien while (a >= &d[dat]) 47459243Sobrien *b-- = *a--; 47559243Sobrien d[dlen] = '\0'; /* just in case */ 47659243Sobrien } 47759243Sobrien#ifdef DEBUG_REFRESH 478232633Smp reprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n", 47959243Sobrien num, dat, dlen, short2str(d)); 480232633Smp reprintf("s == \"%s\"n", short2str(s)); 48159243Sobrien#endif /* DEBUG_REFRESH */ 48259243Sobrien 48359243Sobrien /* copy the characters */ 48459243Sobrien for (a = d + dat; (a < d + dlen) && (num > 0); num--) 48559243Sobrien *a++ = *s++; 48659243Sobrien 48759243Sobrien#ifdef DEBUG_REFRESH 488232633Smp reprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n", 48959243Sobrien num, dat, dlen, d, short2str(s)); 490232633Smp reprintf("s == \"%s\"n", short2str(s)); 49159243Sobrien#endif /* DEBUG_REFRESH */ 49259243Sobrien} 49359243Sobrien 49459243Sobrien/* delete num characters d at dat, maximum length of d is dlen */ 49559243Sobrienstatic void 496167465Smpstr_delete(Char *d, int dat, int dlen, int num) 49759243Sobrien{ 498145479Smp Char *a, *b; 49959243Sobrien 50059243Sobrien if (num <= 0) 50159243Sobrien return; 50259243Sobrien if (dat + num >= dlen) { 50359243Sobrien d[dat] = '\0'; 50459243Sobrien return; 50559243Sobrien } 50659243Sobrien 50759243Sobrien#ifdef DEBUG_REFRESH 508232633Smp reprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n", 50959243Sobrien num, dat, dlen, short2str(d)); 51059243Sobrien#endif /* DEBUG_REFRESH */ 51159243Sobrien 51259243Sobrien /* open up the space for num chars */ 51359243Sobrien if (num > 0) { 51459243Sobrien b = d + dat; 51559243Sobrien a = b + num; 51659243Sobrien while (a < &d[dlen]) 51759243Sobrien *b++ = *a++; 51859243Sobrien d[dlen] = '\0'; /* just in case */ 51959243Sobrien } 52059243Sobrien#ifdef DEBUG_REFRESH 521232633Smp reprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n", 52259243Sobrien num, dat, dlen, short2str(d)); 52359243Sobrien#endif /* DEBUG_REFRESH */ 52459243Sobrien} 52559243Sobrien 52659243Sobrienstatic void 527167465Smpstr_cp(Char *a, Char *b, int n) 52859243Sobrien{ 52959243Sobrien while (n-- && *b) 53059243Sobrien *a++ = *b++; 53159243Sobrien} 53259243Sobrien 53359243Sobrien 53459243Sobrien/* **************************************************************** 53559243Sobrien update_line() is based on finding the middle difference of each line 53659243Sobrien on the screen; vis: 53759243Sobrien 53859243Sobrien /old first difference 53959243Sobrien /beginning of line | /old last same /old EOL 54059243Sobrien v v v v 54159243Sobrienold: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 54259243Sobriennew: eddie> Oh, my little buggy says to me, as lurgid as 54359243Sobrien ^ ^ ^ ^ 54459243Sobrien \beginning of line | \new last same \new end of line 54559243Sobrien \new first difference 54659243Sobrien 54759243Sobrien all are character pointers for the sake of speed. Special cases for 54859243Sobrien no differences, as well as for end of line additions must be handled. 54959243Sobrien**************************************************************** */ 55059243Sobrien 55159243Sobrien/* Minimum at which doing an insert it "worth it". This should be about 55259243Sobrien * half the "cost" of going into insert mode, inserting a character, and 55359243Sobrien * going back out. This should really be calculated from the termcap 55459243Sobrien * data... For the moment, a good number for ANSI terminals. 55559243Sobrien */ 55659243Sobrien#define MIN_END_KEEP 4 55759243Sobrien 55859243Sobrienstatic void /* could be changed to make it smarter */ 559167465Smpupdate_line(Char *old, Char *new, int cur_line) 56059243Sobrien{ 561145479Smp Char *o, *n, *p, c; 562145479Smp Char *ofd, *ols, *oe, *nfd, *nls, *ne; 563145479Smp Char *osb, *ose, *nsb, *nse; 56459243Sobrien int fx, sx; 56559243Sobrien 56659243Sobrien /* 567145479Smp * find first diff (won't be CHAR_DBWIDTH in either line) 56859243Sobrien */ 56959243Sobrien for (o = old, n = new; *o && (*o == *n); o++, n++) 57059243Sobrien continue; 57159243Sobrien ofd = o; 57259243Sobrien nfd = n; 57359243Sobrien 57459243Sobrien /* 57559243Sobrien * Find the end of both old and new 57659243Sobrien */ 577167465Smp o = Strend(o); 578167465Smp 57959243Sobrien /* 58059243Sobrien * Remove any trailing blanks off of the end, being careful not to 58159243Sobrien * back up past the beginning. 58259243Sobrien */ 583167465Smp if (!(adrof(STRhighlight) && MarkIsSet)) { 58459243Sobrien while (ofd < o) { 58559243Sobrien if (o[-1] != ' ') 58659243Sobrien break; 58759243Sobrien o--; 58859243Sobrien } 589167465Smp } 59059243Sobrien oe = o; 59159243Sobrien *oe = (Char) 0; 59259243Sobrien 593167465Smp n = Strend(n); 594167465Smp 59559243Sobrien /* remove blanks from end of new */ 596167465Smp if (!(adrof(STRhighlight) && MarkIsSet)) { 59759243Sobrien while (nfd < n) { 59859243Sobrien if (n[-1] != ' ') 59959243Sobrien break; 60059243Sobrien n--; 60159243Sobrien } 602167465Smp } 60359243Sobrien ne = n; 60459243Sobrien *ne = (Char) 0; 60559243Sobrien 60659243Sobrien /* 60759243Sobrien * if no diff, continue to next line of redraw 60859243Sobrien */ 60959243Sobrien if (*ofd == '\0' && *nfd == '\0') { 61059243Sobrien#ifdef DEBUG_UPDATE 611232633Smp reprintf("no difference.\r\n"); 61259243Sobrien#endif /* DEBUG_UPDATE */ 61359243Sobrien return; 61459243Sobrien } 61559243Sobrien 61659243Sobrien /* 61759243Sobrien * find last same pointer 61859243Sobrien */ 61959243Sobrien while ((o > ofd) && (n > nfd) && (*--o == *--n)) 62059243Sobrien continue; 621145479Smp if (*o != *n) { 622145479Smp o++; 623145479Smp n++; 624145479Smp } 625145479Smp while (*o == CHAR_DBWIDTH) { 626145479Smp o++; 627145479Smp n++; 628145479Smp } 629145479Smp ols = o; 630145479Smp nls = n; 63159243Sobrien 63259243Sobrien /* 63359243Sobrien * find same begining and same end 63459243Sobrien */ 63559243Sobrien osb = ols; 63659243Sobrien nsb = nls; 63759243Sobrien ose = ols; 63859243Sobrien nse = nls; 63959243Sobrien 64059243Sobrien /* 64159243Sobrien * case 1: insert: scan from nfd to nls looking for *ofd 64259243Sobrien */ 64359243Sobrien if (*ofd) { 64459243Sobrien for (c = *ofd, n = nfd; n < nls; n++) { 64559243Sobrien if (c == *n) { 64659243Sobrien for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++) 64759243Sobrien continue; 64859243Sobrien /* 64959243Sobrien * if the new match is longer and it's worth keeping, then we 65059243Sobrien * take it 65159243Sobrien */ 65259243Sobrien if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { 65359243Sobrien nsb = n; 65459243Sobrien nse = p; 65559243Sobrien osb = ofd; 65659243Sobrien ose = o; 65759243Sobrien } 65859243Sobrien } 65959243Sobrien } 66059243Sobrien } 66159243Sobrien 66259243Sobrien /* 66359243Sobrien * case 2: delete: scan from ofd to ols looking for *nfd 66459243Sobrien */ 66559243Sobrien if (*nfd) { 66659243Sobrien for (c = *nfd, o = ofd; o < ols; o++) { 66759243Sobrien if (c == *o) { 66859243Sobrien for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++) 66959243Sobrien continue; 67059243Sobrien /* 67159243Sobrien * if the new match is longer and it's worth keeping, then we 67259243Sobrien * take it 67359243Sobrien */ 67459243Sobrien if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { 67559243Sobrien nsb = nfd; 67659243Sobrien nse = n; 67759243Sobrien osb = o; 67859243Sobrien ose = p; 67959243Sobrien } 68059243Sobrien } 68159243Sobrien } 68259243Sobrien } 68359243Sobrien#ifdef notdef 68459243Sobrien /* 68559243Sobrien * If `last same' is before `same end' re-adjust 68659243Sobrien */ 68759243Sobrien if (ols < ose) 68859243Sobrien ols = ose; 68959243Sobrien if (nls < nse) 69059243Sobrien nls = nse; 69159243Sobrien#endif 69259243Sobrien 69359243Sobrien /* 69459243Sobrien * Pragmatics I: If old trailing whitespace or not enough characters to 69559243Sobrien * save to be worth it, then don't save the last same info. 69659243Sobrien */ 69759243Sobrien if ((oe - ols) < MIN_END_KEEP) { 69859243Sobrien ols = oe; 69959243Sobrien nls = ne; 70059243Sobrien } 70159243Sobrien 70259243Sobrien /* 70359243Sobrien * Pragmatics II: if the terminal isn't smart enough, make the data dumber 70459243Sobrien * so the smart update doesn't try anything fancy 70559243Sobrien */ 70659243Sobrien 70759243Sobrien /* 70859243Sobrien * fx is the number of characters we need to insert/delete: in the 70959243Sobrien * beginning to bring the two same begins together 71059243Sobrien */ 71159243Sobrien fx = (int) ((nsb - nfd) - (osb - ofd)); 71259243Sobrien /* 71359243Sobrien * sx is the number of characters we need to insert/delete: in the end to 71459243Sobrien * bring the two same last parts together 71559243Sobrien */ 71659243Sobrien sx = (int) ((nls - nse) - (ols - ose)); 71759243Sobrien 71859243Sobrien if (!T_CanIns) { 71959243Sobrien if (fx > 0) { 72059243Sobrien osb = ols; 72159243Sobrien ose = ols; 72259243Sobrien nsb = nls; 72359243Sobrien nse = nls; 72459243Sobrien } 72559243Sobrien if (sx > 0) { 72659243Sobrien ols = oe; 72759243Sobrien nls = ne; 72859243Sobrien } 72959243Sobrien if ((ols - ofd) < (nls - nfd)) { 73059243Sobrien ols = oe; 73159243Sobrien nls = ne; 73259243Sobrien } 73359243Sobrien } 73459243Sobrien if (!T_CanDel) { 73559243Sobrien if (fx < 0) { 73659243Sobrien osb = ols; 73759243Sobrien ose = ols; 73859243Sobrien nsb = nls; 73959243Sobrien nse = nls; 74059243Sobrien } 74159243Sobrien if (sx < 0) { 74259243Sobrien ols = oe; 74359243Sobrien nls = ne; 74459243Sobrien } 74559243Sobrien if ((ols - ofd) > (nls - nfd)) { 74659243Sobrien ols = oe; 74759243Sobrien nls = ne; 74859243Sobrien } 74959243Sobrien } 75059243Sobrien 75159243Sobrien /* 75259243Sobrien * Pragmatics III: make sure the middle shifted pointers are correct if 75359243Sobrien * they don't point to anything (we may have moved ols or nls). 75459243Sobrien */ 75559243Sobrien /* if the change isn't worth it, don't bother */ 75659243Sobrien /* was: if (osb == ose) */ 75759243Sobrien if ((ose - osb) < MIN_END_KEEP) { 75859243Sobrien osb = ols; 75959243Sobrien ose = ols; 76059243Sobrien nsb = nls; 76159243Sobrien nse = nls; 76259243Sobrien } 76359243Sobrien 76459243Sobrien /* 76559243Sobrien * Now that we are done with pragmatics we recompute fx, sx 76659243Sobrien */ 76759243Sobrien fx = (int) ((nsb - nfd) - (osb - ofd)); 76859243Sobrien sx = (int) ((nls - nse) - (ols - ose)); 76959243Sobrien 77059243Sobrien#ifdef DEBUG_UPDATE 771232633Smp reprintf("\n"); 772232633Smp reprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n", 77359243Sobrien ofd - old, osb - old, ose - old, ols - old, oe - old); 774232633Smp reprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n", 77559243Sobrien nfd - new, nsb - new, nse - new, nls - new, ne - new); 776232633Smp reprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"); 777232633Smp reprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"); 77859243Sobrien dprintstr("old- oe", old, oe); 77959243Sobrien dprintstr("new- ne", new, ne); 78059243Sobrien dprintstr("old-ofd", old, ofd); 78159243Sobrien dprintstr("new-nfd", new, nfd); 78259243Sobrien dprintstr("ofd-osb", ofd, osb); 78359243Sobrien dprintstr("nfd-nsb", nfd, nsb); 78459243Sobrien dprintstr("osb-ose", osb, ose); 78559243Sobrien dprintstr("nsb-nse", nsb, nse); 78659243Sobrien dprintstr("ose-ols", ose, ols); 78759243Sobrien dprintstr("nse-nls", nse, nls); 78859243Sobrien dprintstr("ols- oe", ols, oe); 78959243Sobrien dprintstr("nls- ne", nls, ne); 79059243Sobrien#endif /* DEBUG_UPDATE */ 79159243Sobrien 79259243Sobrien /* 79359243Sobrien * CursorV to this line cur_line MUST be in this routine so that if we 79459243Sobrien * don't have to change the line, we don't move to it. CursorH to first 79559243Sobrien * diff char 79659243Sobrien */ 79759243Sobrien MoveToLine(cur_line); 79859243Sobrien 79959243Sobrien /* 80059243Sobrien * at this point we have something like this: 80159243Sobrien * 80259243Sobrien * /old /ofd /osb /ose /ols /oe 80359243Sobrien * v.....................v v..................v v........v 80459243Sobrien * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as 80559243Sobrien * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as 80659243Sobrien * ^.....................^ ^..................^ ^........^ 80759243Sobrien * \new \nfd \nsb \nse \nls \ne 80859243Sobrien * 80959243Sobrien * fx is the difference in length between the the chars between nfd and 81059243Sobrien * nsb, and the chars between ofd and osb, and is thus the number of 81159243Sobrien * characters to delete if < 0 (new is shorter than old, as above), 81259243Sobrien * or insert (new is longer than short). 81359243Sobrien * 81459243Sobrien * sx is the same for the second differences. 81559243Sobrien */ 81659243Sobrien 81759243Sobrien /* 81859243Sobrien * if we have a net insert on the first difference, AND inserting the net 81959243Sobrien * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character 82059243Sobrien * (which is ne if nls != ne, otherwise is nse) off the edge of the screen 82159243Sobrien * (TermH - 1) else we do the deletes first so that we keep everything we 82259243Sobrien * need to. 82359243Sobrien */ 82459243Sobrien 82559243Sobrien /* 82659243Sobrien * if the last same is the same like the end, there is no last same part, 82759243Sobrien * otherwise we want to keep the last same part set p to the last useful 82859243Sobrien * old character 82959243Sobrien */ 83059243Sobrien p = (ols != oe) ? oe : ose; 83159243Sobrien 83259243Sobrien /* 83359243Sobrien * if (There is a diffence in the beginning) && (we need to insert 83459243Sobrien * characters) && (the number of characters to insert is less than the term 83559243Sobrien * width) We need to do an insert! else if (we need to delete characters) 83659243Sobrien * We need to delete characters! else No insert or delete 83759243Sobrien */ 83859243Sobrien if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) { 83959243Sobrien#ifdef DEBUG_UPDATE 840232633Smp reprintf("first diff insert at %d...\r\n", nfd - new); 84159243Sobrien#endif /* DEBUG_UPDATE */ 84259243Sobrien /* 84359243Sobrien * Move to the first char to insert, where the first diff is. 84459243Sobrien */ 84559243Sobrien MoveToChar(nfd - new); 84659243Sobrien /* 84759243Sobrien * Check if we have stuff to keep at end 84859243Sobrien */ 84959243Sobrien if (nsb != ne) { 85059243Sobrien#ifdef DEBUG_UPDATE 851232633Smp reprintf("with stuff to keep at end\r\n"); 85259243Sobrien#endif /* DEBUG_UPDATE */ 85359243Sobrien /* 85459243Sobrien * insert fx chars of new starting at nfd 85559243Sobrien */ 85659243Sobrien if (fx > 0) { 85759243Sobrien#ifdef DEBUG_UPDATE 85859243Sobrien if (!T_CanIns) 859232633Smp reprintf(" ERROR: cannot insert in early first diff\n"); 86059243Sobrien#endif /* DEBUG_UPDATE */ 86159243Sobrien Insert_write(nfd, fx); 86259243Sobrien str_insert(old, (int) (ofd - old), TermH, nfd, fx); 86359243Sobrien } 86459243Sobrien /* 86559243Sobrien * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 86659243Sobrien */ 86759243Sobrien so_write(nfd + fx, (nsb - nfd) - fx); 86859243Sobrien str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); 86959243Sobrien } 87059243Sobrien else { 87159243Sobrien#ifdef DEBUG_UPDATE 872232633Smp reprintf("without anything to save\r\n"); 87359243Sobrien#endif /* DEBUG_UPDATE */ 87459243Sobrien so_write(nfd, (nsb - nfd)); 87559243Sobrien str_cp(ofd, nfd, (int) (nsb - nfd)); 87659243Sobrien /* 87759243Sobrien * Done 87859243Sobrien */ 87959243Sobrien return; 88059243Sobrien } 88159243Sobrien } 88259243Sobrien else if (fx < 0) { 88359243Sobrien#ifdef DEBUG_UPDATE 884232633Smp reprintf("first diff delete at %d...\r\n", ofd - old); 88559243Sobrien#endif /* DEBUG_UPDATE */ 88659243Sobrien /* 88759243Sobrien * move to the first char to delete where the first diff is 88859243Sobrien */ 88959243Sobrien MoveToChar(ofd - old); 89059243Sobrien /* 89159243Sobrien * Check if we have stuff to save 89259243Sobrien */ 89359243Sobrien if (osb != oe) { 89459243Sobrien#ifdef DEBUG_UPDATE 895232633Smp reprintf("with stuff to save at end\r\n"); 89659243Sobrien#endif /* DEBUG_UPDATE */ 89759243Sobrien /* 89859243Sobrien * fx is less than zero *always* here but we check for code 89959243Sobrien * symmetry 90059243Sobrien */ 90159243Sobrien if (fx < 0) { 90259243Sobrien#ifdef DEBUG_UPDATE 90359243Sobrien if (!T_CanDel) 904232633Smp reprintf(" ERROR: cannot delete in first diff\n"); 90559243Sobrien#endif /* DEBUG_UPDATE */ 90659243Sobrien DeleteChars(-fx); 90759243Sobrien str_delete(old, (int) (ofd - old), TermH, -fx); 90859243Sobrien } 90959243Sobrien /* 91059243Sobrien * write (nsb-nfd) chars of new starting at nfd 91159243Sobrien */ 91259243Sobrien so_write(nfd, (nsb - nfd)); 91359243Sobrien str_cp(ofd, nfd, (int) (nsb - nfd)); 91459243Sobrien 91559243Sobrien } 91659243Sobrien else { 91759243Sobrien#ifdef DEBUG_UPDATE 918232633Smp reprintf("but with nothing left to save\r\n"); 91959243Sobrien#endif /* DEBUG_UPDATE */ 92059243Sobrien /* 92159243Sobrien * write (nsb-nfd) chars of new starting at nfd 92259243Sobrien */ 92359243Sobrien so_write(nfd, (nsb - nfd)); 92459243Sobrien#ifdef DEBUG_REFRESH 925232633Smp reprintf("cleareol %d\n", (oe - old) - (ne - new)); 92659243Sobrien#endif /* DEBUG_UPDATE */ 92769408Sache#ifndef WINNT_NATIVE 92859243Sobrien ClearEOL((oe - old) - (ne - new)); 92959243Sobrien#else 93059243Sobrien /* 93159243Sobrien * The calculation above does not work too well on NT 93259243Sobrien */ 93359243Sobrien ClearEOL(TermH - CursorH); 93469408Sache#endif /*WINNT_NATIVE*/ 93559243Sobrien /* 93659243Sobrien * Done 93759243Sobrien */ 93859243Sobrien return; 93959243Sobrien } 94059243Sobrien } 94159243Sobrien else 94259243Sobrien fx = 0; 94359243Sobrien 94459243Sobrien if (sx < 0) { 94559243Sobrien#ifdef DEBUG_UPDATE 946232633Smp reprintf("second diff delete at %d...\r\n", (ose - old) + fx); 94759243Sobrien#endif /* DEBUG_UPDATE */ 94859243Sobrien /* 94959243Sobrien * Check if we have stuff to delete 95059243Sobrien */ 95159243Sobrien /* 95259243Sobrien * fx is the number of characters inserted (+) or deleted (-) 95359243Sobrien */ 95459243Sobrien 95559243Sobrien MoveToChar((ose - old) + fx); 95659243Sobrien /* 95759243Sobrien * Check if we have stuff to save 95859243Sobrien */ 95959243Sobrien if (ols != oe) { 96059243Sobrien#ifdef DEBUG_UPDATE 961232633Smp reprintf("with stuff to save at end\r\n"); 96259243Sobrien#endif /* DEBUG_UPDATE */ 96359243Sobrien /* 96459243Sobrien * Again a duplicate test. 96559243Sobrien */ 96659243Sobrien if (sx < 0) { 96759243Sobrien#ifdef DEBUG_UPDATE 96859243Sobrien if (!T_CanDel) 969232633Smp reprintf(" ERROR: cannot delete in second diff\n"); 97059243Sobrien#endif /* DEBUG_UPDATE */ 97159243Sobrien DeleteChars(-sx); 97259243Sobrien } 97359243Sobrien 97459243Sobrien /* 97559243Sobrien * write (nls-nse) chars of new starting at nse 97659243Sobrien */ 97759243Sobrien so_write(nse, (nls - nse)); 97859243Sobrien } 97959243Sobrien else { 98059243Sobrien int olen = (int) (oe - old + fx); 98159243Sobrien if (olen > TermH) 98259243Sobrien olen = TermH; 98359243Sobrien#ifdef DEBUG_UPDATE 984232633Smp reprintf("but with nothing left to save\r\n"); 98559243Sobrien#endif /* DEBUG_UPDATE */ 98659243Sobrien so_write(nse, (nls - nse)); 98759243Sobrien#ifdef DEBUG_REFRESH 988232633Smp reprintf("cleareol %d\n", olen - (ne - new)); 98959243Sobrien#endif /* DEBUG_UPDATE */ 99069408Sache#ifndef WINNT_NATIVE 99159243Sobrien ClearEOL(olen - (ne - new)); 99259243Sobrien#else 99359243Sobrien /* 99459243Sobrien * The calculation above does not work too well on NT 99559243Sobrien */ 99659243Sobrien ClearEOL(TermH - CursorH); 99769408Sache#endif /*WINNT_NATIVE*/ 99859243Sobrien } 99959243Sobrien } 100059243Sobrien 100159243Sobrien /* 100259243Sobrien * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... 100359243Sobrien */ 100459243Sobrien if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { 100559243Sobrien#ifdef DEBUG_UPDATE 1006232633Smp reprintf("late first diff insert at %d...\r\n", nfd - new); 100759243Sobrien#endif /* DEBUG_UPDATE */ 100859243Sobrien 100959243Sobrien MoveToChar(nfd - new); 101059243Sobrien /* 101159243Sobrien * Check if we have stuff to keep at the end 101259243Sobrien */ 101359243Sobrien if (nsb != ne) { 101459243Sobrien#ifdef DEBUG_UPDATE 1015232633Smp reprintf("with stuff to keep at end\r\n"); 101659243Sobrien#endif /* DEBUG_UPDATE */ 101759243Sobrien /* 101859243Sobrien * We have to recalculate fx here because we set it 101959243Sobrien * to zero above as a flag saying that we hadn't done 102059243Sobrien * an early first insert. 102159243Sobrien */ 102259243Sobrien fx = (int) ((nsb - nfd) - (osb - ofd)); 102359243Sobrien if (fx > 0) { 102459243Sobrien /* 102559243Sobrien * insert fx chars of new starting at nfd 102659243Sobrien */ 102759243Sobrien#ifdef DEBUG_UPDATE 102859243Sobrien if (!T_CanIns) 1029232633Smp reprintf(" ERROR: cannot insert in late first diff\n"); 103059243Sobrien#endif /* DEBUG_UPDATE */ 103159243Sobrien Insert_write(nfd, fx); 103259243Sobrien str_insert(old, (int) (ofd - old), TermH, nfd, fx); 103359243Sobrien } 103459243Sobrien 103559243Sobrien /* 103659243Sobrien * write (nsb-nfd) - fx chars of new starting at (nfd + fx) 103759243Sobrien */ 103859243Sobrien so_write(nfd + fx, (nsb - nfd) - fx); 103959243Sobrien str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); 104059243Sobrien } 104159243Sobrien else { 104259243Sobrien#ifdef DEBUG_UPDATE 1043232633Smp reprintf("without anything to save\r\n"); 104459243Sobrien#endif /* DEBUG_UPDATE */ 104559243Sobrien so_write(nfd, (nsb - nfd)); 104659243Sobrien str_cp(ofd, nfd, (int) (nsb - nfd)); 104759243Sobrien } 104859243Sobrien } 104959243Sobrien 105059243Sobrien /* 105159243Sobrien * line is now NEW up to nse 105259243Sobrien */ 105359243Sobrien if (sx >= 0) { 105459243Sobrien#ifdef DEBUG_UPDATE 1055232633Smp reprintf("second diff insert at %d...\r\n", nse - new); 105659243Sobrien#endif /* DEBUG_UPDATE */ 105759243Sobrien MoveToChar(nse - new); 105859243Sobrien if (ols != oe) { 105959243Sobrien#ifdef DEBUG_UPDATE 1060232633Smp reprintf("with stuff to keep at end\r\n"); 106159243Sobrien#endif /* DEBUG_UPDATE */ 106259243Sobrien if (sx > 0) { 106359243Sobrien /* insert sx chars of new starting at nse */ 106459243Sobrien#ifdef DEBUG_UPDATE 106559243Sobrien if (!T_CanIns) 1066232633Smp reprintf(" ERROR: cannot insert in second diff\n"); 106759243Sobrien#endif /* DEBUG_UPDATE */ 106859243Sobrien Insert_write(nse, sx); 106959243Sobrien } 107059243Sobrien 107159243Sobrien /* 107259243Sobrien * write (nls-nse) - sx chars of new starting at (nse + sx) 107359243Sobrien */ 107459243Sobrien so_write(nse + sx, (nls - nse) - sx); 107559243Sobrien } 107659243Sobrien else { 107759243Sobrien#ifdef DEBUG_UPDATE 1078232633Smp reprintf("without anything to save\r\n"); 107959243Sobrien#endif /* DEBUG_UPDATE */ 108059243Sobrien so_write(nse, (nls - nse)); 108159243Sobrien 108259243Sobrien /* 108359243Sobrien * No need to do a clear-to-end here because we were doing 108459243Sobrien * a second insert, so we will have over written all of the 108559243Sobrien * old string. 108659243Sobrien */ 108759243Sobrien } 108859243Sobrien } 108959243Sobrien#ifdef DEBUG_UPDATE 1090232633Smp reprintf("done.\r\n"); 109159243Sobrien#endif /* DEBUG_UPDATE */ 109259243Sobrien} 109359243Sobrien 109459243Sobrien 109559243Sobrienstatic void 1096167465Smpcpy_pad_spaces(Char *dst, Char *src, int width) 109759243Sobrien{ 1098145479Smp int i; 109959243Sobrien 110059243Sobrien for (i = 0; i < width; i++) { 110159243Sobrien if (*src == (Char) 0) 110259243Sobrien break; 110359243Sobrien *dst++ = *src++; 110459243Sobrien } 110559243Sobrien 110659243Sobrien while (i < width) { 110759243Sobrien *dst++ = ' '; 110859243Sobrien i++; 110959243Sobrien } 111059243Sobrien *dst = (Char) 0; 111159243Sobrien} 111259243Sobrien 111359243Sobrienvoid 1114167465SmpRefCursor(void) 111559243Sobrien{ /* only move to new cursor pos */ 1116145479Smp Char *cp; 1117167465Smp int w, h, th, v; 111859243Sobrien 111959243Sobrien /* first we must find where the cursor is... */ 112059243Sobrien h = 0; 112159243Sobrien v = 0; 112259243Sobrien th = TermH; /* optimize for speed */ 112359243Sobrien 1124167465Smp for (cp = Prompt; cp != NULL && *cp; ) { /* do prompt */ 1125145479Smp if (*cp & LITERAL) { 1126145479Smp cp++; 112759243Sobrien continue; 112859243Sobrien } 1129167465Smp w = NLSClassify(*cp & CHAR, cp == Prompt); 1130167465Smp cp++; 1131145479Smp switch(w) { 1132145479Smp case NLSCLASS_NL: 1133145479Smp h = 0; 1134145479Smp v++; 1135145479Smp break; 1136145479Smp case NLSCLASS_TAB: 1137145479Smp while (++h & 07) 1138145479Smp ; 1139145479Smp break; 1140145479Smp case NLSCLASS_CTRL: 1141145479Smp h += 2; 1142145479Smp break; 1143145479Smp case NLSCLASS_ILLEGAL: 1144145479Smp h += 4; 1145145479Smp break; 1146145479Smp case NLSCLASS_ILLEGAL2: 1147145479Smp case NLSCLASS_ILLEGAL3: 1148145479Smp case NLSCLASS_ILLEGAL4: 1149145479Smp h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); 1150145479Smp break; 1151145479Smp default: 1152145479Smp h += w; 115359243Sobrien } 115459243Sobrien if (h >= th) { /* check, extra long tabs picked up here also */ 1155145479Smp h -= th; 115659243Sobrien v++; 115759243Sobrien } 115859243Sobrien } 115959243Sobrien 1160145479Smp for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */ 1161167465Smp w = NLSClassify(*cp & CHAR, cp == InputBuf); 1162167465Smp cp++; 1163145479Smp switch(w) { 1164145479Smp case NLSCLASS_NL: 1165145479Smp h = 0; 1166145479Smp v++; 1167145479Smp break; 1168145479Smp case NLSCLASS_TAB: 1169145479Smp while (++h & 07) 1170145479Smp ; 1171145479Smp break; 1172145479Smp case NLSCLASS_CTRL: 1173145479Smp h += 2; 1174145479Smp break; 1175145479Smp case NLSCLASS_ILLEGAL: 1176145479Smp h += 4; 1177145479Smp break; 1178145479Smp case NLSCLASS_ILLEGAL2: 1179145479Smp case NLSCLASS_ILLEGAL3: 1180145479Smp case NLSCLASS_ILLEGAL4: 1181145479Smp h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); 1182145479Smp break; 1183145479Smp default: 1184145479Smp h += w; 118559243Sobrien } 118659243Sobrien if (h >= th) { /* check, extra long tabs picked up here also */ 1187145479Smp h -= th; 118859243Sobrien v++; 118959243Sobrien } 119059243Sobrien } 119159243Sobrien 119259243Sobrien /* now go there */ 119359243Sobrien MoveToLine(v); 119459243Sobrien MoveToChar(h); 1195167465Smp if (adrof(STRhighlight) && MarkIsSet) { 1196167465Smp ClearLines(); 1197167465Smp ClearDisp(); 1198167465Smp Refresh(); 1199167465Smp } 120059243Sobrien flush(); 120159243Sobrien} 120259243Sobrien 1203131962Smp#ifndef WINTT_NATIVE 120459243Sobrienstatic void 1205167465SmpPutPlusOne(Char c, int width) 120659243Sobrien{ 1207145479Smp while (width > 1 && CursorH + width > TermH) 1208145479Smp PutPlusOne(' ', 1); 1209145479Smp if ((c & LITERAL) != 0) { 1210145479Smp Char *d; 1211145479Smp for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++) 1212145479Smp (void) putwraw(*d); 1213145479Smp } else { 1214145479Smp (void) putwraw(c); 1215145479Smp } 121659243Sobrien Display[CursorV][CursorH++] = (Char) c; 1217145479Smp while (--width > 0) 1218145479Smp Display[CursorV][CursorH++] = CHAR_DBWIDTH; 121959243Sobrien if (CursorH >= TermH) { /* if we must overflow */ 122059243Sobrien CursorH = 0; 122159243Sobrien CursorV++; 122259243Sobrien OldvcV++; 122359243Sobrien if (T_Margin & MARGIN_AUTO) { 122459243Sobrien if (T_Margin & MARGIN_MAGIC) { 122559243Sobrien (void) putraw(' '); 122659243Sobrien (void) putraw('\b'); 122759243Sobrien } 122859243Sobrien } 122959243Sobrien else { 123059243Sobrien (void) putraw('\r'); 123159243Sobrien (void) putraw('\n'); 123259243Sobrien } 123359243Sobrien } 123459243Sobrien} 1235131962Smp#endif 123659243Sobrien 123759243Sobrienvoid 1238145479SmpRefPlusOne(int l) 123959243Sobrien{ /* we added just one char, handle it fast. 124059243Sobrien * assumes that screen cursor == real cursor */ 1241167465Smp Char *cp, c; 1242145479Smp int w; 124359243Sobrien 1244145479Smp if (Cursor != LastChar) { 124559243Sobrien Refresh(); /* too hard to handle */ 124659243Sobrien return; 124759243Sobrien } 124859243Sobrien if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) { 124959243Sobrien Refresh(); /* clear out rprompt if less than one char gap*/ 125059243Sobrien return; 1251145479Smp } 1252145479Smp cp = Cursor - l; 1253167465Smp c = *cp & CHAR; 1254145479Smp w = NLSClassify(c, cp == InputBuf); 1255145479Smp switch(w) { 1256145479Smp case NLSCLASS_CTRL: 1257145479Smp PutPlusOne('^', 1); 1258145479Smp if (c == CTL_ESC('\177')) { 1259145479Smp PutPlusOne('?', 1); 1260145479Smp break; 1261145479Smp } 126269408Sache#ifdef IS_ASCII 1263145479Smp /* uncontrolify it; works only for iso8859-1 like sets */ 1264145479Smp PutPlusOne((c | 0100), 1); 126569408Sache#else 1266145479Smp PutPlusOne(_toebcdic[_toascii[c]|0100], 1); 126769408Sache#endif 1268145479Smp break; 1269145479Smp case NLSCLASS_ILLEGAL: 1270145479Smp PutPlusOne('\\', 1); 1271145479Smp PutPlusOne(((c >> 6) & 7) + '0', 1); 1272145479Smp PutPlusOne(((c >> 3) & 7) + '0', 1); 1273145479Smp PutPlusOne((c & 7) + '0', 1); 1274145479Smp break; 1275145479Smp case 1: 1276167465Smp if (adrof(STRhighlight) && MarkIsSet) 1277167465Smp StartHighlight(); 1278145479Smp if (l > 1) 1279145479Smp PutPlusOne(MakeLiteral(cp, l, 0), 1); 1280145479Smp else 1281145479Smp PutPlusOne(*cp, 1); 1282167465Smp if (adrof(STRhighlight) && MarkIsSet) 1283167465Smp StopHighlight(); 1284145479Smp break; 1285145479Smp default: 1286145479Smp Refresh(); /* too hard to handle */ 1287145479Smp return; 128859243Sobrien } 128959243Sobrien flush(); 129059243Sobrien} 129159243Sobrien 129259243Sobrien/* clear the screen buffers so that new new prompt starts fresh. */ 129359243Sobrien 129459243Sobrienvoid 1295167465SmpClearDisp(void) 129659243Sobrien{ 1297145479Smp int i; 129859243Sobrien 129959243Sobrien CursorV = 0; /* clear the display buffer */ 130059243Sobrien CursorH = 0; 130159243Sobrien for (i = 0; i < TermV; i++) 130259243Sobrien (void) memset(Display[i], 0, TermH * sizeof(Display[0][0])); 130359243Sobrien OldvcV = 0; 1304145479Smp litlen = 0; 130559243Sobrien} 130659243Sobrien 130759243Sobrienvoid 1308167465SmpClearLines(void) 130959243Sobrien{ /* Make sure all lines are *really* blank */ 1310145479Smp int i; 131159243Sobrien 131259243Sobrien if (T_CanCEOL) { 131359243Sobrien /* 131459243Sobrien * Clear the lines from the bottom up so that if we try moving 131559243Sobrien * the cursor down by writing the character that is at the end 131659243Sobrien * of the screen line, we won't rewrite a character that shouldn't 131759243Sobrien * be there. 131859243Sobrien */ 131959243Sobrien for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */ 132059243Sobrien MoveToLine(i); 132159243Sobrien MoveToChar(0); 132259243Sobrien ClearEOL(TermH); 132359243Sobrien } 132459243Sobrien } 132559243Sobrien else { 132659243Sobrien MoveToLine(OldvcV); /* go to last line */ 132759243Sobrien (void) putraw('\r'); /* go to BOL */ 132859243Sobrien (void) putraw('\n'); /* go to new line */ 132959243Sobrien } 133059243Sobrien} 1331