diff options
author | obrien <obrien@FreeBSD.org> | 2000-04-15 04:41:27 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2000-04-15 04:41:27 +0000 |
commit | 4ad28cefef28ce6bdb44a0532cfe20a2076bc694 (patch) | |
tree | 7679c440a91912ee9586cee3ebab24596c0fe1c4 /contrib/tcsh/ed.refresh.c | |
download | FreeBSD-src-4ad28cefef28ce6bdb44a0532cfe20a2076bc694.zip FreeBSD-src-4ad28cefef28ce6bdb44a0532cfe20a2076bc694.tar.gz |
Import the latest version of the 44BSD C-shell -- tcsh-6.09.
Diffstat (limited to 'contrib/tcsh/ed.refresh.c')
-rw-r--r-- | contrib/tcsh/ed.refresh.c | 1317 |
1 files changed, 1317 insertions, 0 deletions
diff --git a/contrib/tcsh/ed.refresh.c b/contrib/tcsh/ed.refresh.c new file mode 100644 index 0000000..46333c9 --- /dev/null +++ b/contrib/tcsh/ed.refresh.c @@ -0,0 +1,1317 @@ +/* $Header: /src/pub/tcsh/ed.refresh.c,v 3.25 1998/11/24 18:17:22 christos Exp $ */ +/* + * ed.refresh.c: Lower level screen refreshing functions + */ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sh.h" + +RCSID("$Id: ed.refresh.c,v 3.25 1998/11/24 18:17:22 christos Exp $") + +#include "ed.h" +/* #define DEBUG_UPDATE */ +/* #define DEBUG_REFRESH */ +/* #define DEBUG_LITERAL */ + +/* refresh.c -- refresh the current set of lines on the screen */ + +Char *litptr[256]; +static int vcursor_h, vcursor_v; +static int rprompt_h, rprompt_v; + +static void Draw __P((int)); +static void Vdraw __P((int)); +static void RefreshPromptpart __P((Char *)); +static void update_line __P((Char *, Char *, int)); +static void str_insert __P((Char *, int, int, Char *, int)); +static void str_delete __P((Char *, int, int, int)); +static void str_cp __P((Char *, Char *, int)); +static void PutPlusOne __P((int)); +static void cpy_pad_spaces __P((Char *, Char *, int)); +#if defined(DSPMBYTE) +static Char *update_line_fix_mbyte_point __P((Char *, Char *, int)); +#endif +#if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL) +static void dprintf __P((char *, ...)); +#ifdef DEBUG_UPDATE +static void dprintstr __P((char *, Char *, Char *)); + +static void +dprintstr(str, f, t) +char *str; +Char *f, *t; +{ + dprintf("%s:\"", str); + while (f < t) + dprintf("%c", *f++ & ASCII); + dprintf("\"\r\n"); +} +#endif /* DEBUG_UPDATE */ + +/* dprintf(): + * Print to $DEBUGTTY, so that we can test editing on one pty, and + * print debugging stuff on another. Don't interrupt the shell while + * debugging cause you'll mangle up the file descriptors! + */ +static void +#ifdef FUNCPROTO +dprintf(char *fmt, ...) +#else +dprintf(va_list) + va_dcl +#endif /* __STDC__ */ +{ + static int fd = -1; + char *dtty; + + if ((dtty = getenv("DEBUGTTY"))) { + int o; + va_list va; +#ifdef FUNCPROTO + va_start(va, fmt); +#else + char *fmt; + va_start(va); + fmt = va_arg(va, char *); +#endif /* __STDC__ */ + + if (fd == -1) + fd = open(dtty, O_RDWR); + o = SHOUT; + flush(); + SHOUT = fd; + xvprintf(fmt, va); + va_end(va); + flush(); + SHOUT = o; + } +} +#endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */ + +static void +Draw(c) /* draw c, expand tabs, ctl chars */ + register int c; +{ + register Char ch = c & CHAR; + + if (Isprint(ch)) { + Vdraw(c); + return; + } + /* from wolman%crltrx.DEC@decwrl.dec.com (Alec Wolman) */ + if (ch == '\n') { /* expand the newline */ + /* + * Don't force a newline if Vdraw does it (i.e. we're at end of line) + * - or we will get two newlines and possibly garbage in between + */ + int oldv = vcursor_v; + + Vdraw('\0'); /* assure end of line */ + if (oldv == vcursor_v) { + vcursor_h = 0; /* reset cursor pos */ + vcursor_v++; + } + return; + } + if (ch == '\t') { /* expand the tab */ + for (;;) { + Vdraw(' '); + if ((vcursor_h & 07) == 0) + break; /* go until tab stop */ + } + } + else if (Iscntrl(ch)) { +#ifndef _OSD_POSIX + Vdraw('^'); + if (ch == CTL_ESC('\177')) { + Vdraw('?'); + } + else { + /* uncontrolify it; works only for iso8859-1 like sets */ + Vdraw((c | 0100)); +#else /*_OSD_POSIX*/ + if (ch == CTL_ESC('\177')) { + Vdraw('^'); + Vdraw('?'); + } + else { + if (Isupper(_toebcdic[_toascii[c]|0100]) + || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) + { + Vdraw('^'); + Vdraw(_toebcdic[_toascii[c]|0100]); + } + else + { + Vdraw('\\'); + Vdraw(((c >> 6) & 7) + '0'); + Vdraw(((c >> 3) & 7) + '0'); + Vdraw((c & 7) + '0'); + } +#endif /*_OSD_POSIX*/ + } + } +#ifdef KANJI + else if (!adrof(STRnokanji)) { + Vdraw(c); + return; + } +#endif + else { + Vdraw('\\'); + Vdraw(((c >> 6) & 7) + '0'); + Vdraw(((c >> 3) & 7) + '0'); + Vdraw((c & 7) + '0'); + } +} + +static void +Vdraw(c) /* draw char c onto V lines */ + register int c; +{ +#ifdef DEBUG_REFRESH +# ifdef SHORT_STRINGS + dprintf("Vdrawing %6.6o '%c'\r\n", c, c & ASCII); +# else + dprintf("Vdrawing %3.3o '%c'\r\n", c, c); +# endif /* SHORT_STRNGS */ +#endif /* DEBUG_REFRESH */ + + Vdisplay[vcursor_v][vcursor_h] = (Char) c; + vcursor_h++; /* advance to next place */ + if (vcursor_h >= TermH) { + Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */ + vcursor_h = 0; /* reset it. */ + vcursor_v++; +#ifdef DEBUG_REFRESH + if (vcursor_v >= TermV) { /* should NEVER happen. */ + dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n", + vcursor_v, TermV); + abort(); + } +#endif /* DEBUG_REFRESH */ + } +} + +/* + * RefreshPromptpart() + * draws a prompt element, expanding literals (we know it's ASCIZ) + */ +static void +RefreshPromptpart(buf) + Char *buf; +{ + register Char *cp; + static unsigned int litnum = 0; + if (buf == NULL) + { + litnum = 0; + return; + } + + for (cp = buf; *cp; cp++) { + if (*cp & LITERAL) { + if (litnum < (sizeof(litptr) / sizeof(litptr[0]))) { + litptr[litnum] = cp; +#ifdef DEBUG_LITERAL + dprintf("litnum = %d, litptr = %x:\r\n", + litnum, litptr[litnum]); +#endif /* DEBUG_LITERAL */ + } + while (*cp & LITERAL) + cp++; + if (*cp) + Vdraw((int) (litnum++ | LITERAL)); + else { + /* + * XXX: This is a bug, we lose the last literal, if it is not + * followed by a normal character, but it is too hard to fix + */ + break; + } + } + else + Draw(*cp); + } +} + +/* + * Refresh() + * draws the new virtual screen image from the current input + * line, then goes line-by-line changing the real image to the new + * virtual image. The routine to re-draw a line can be replaced + * easily in hopes of a smarter one being placed there. + */ +static int OldvcV = 0; +void +Refresh() +{ + register int cur_line; + register Char *cp; + int cur_h, cur_v = 0, new_vcv; + int rhdiff; + Char oldgetting; + +#ifdef DEBUG_REFRESH + dprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf)); + dprintf("InputBuf = :%s:\r\n", short2str(InputBuf)); +#endif /* DEBUG_REFRESH */ + oldgetting = GettingInput; + GettingInput = 0; /* avoid re-entrance via SIGWINCH */ + + /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */ + vcursor_h = 0; + vcursor_v = 0; + RefreshPromptpart(NULL); + RefreshPromptpart(RPromptBuf); + rprompt_h = vcursor_h; + rprompt_v = vcursor_v; + + /* reset the Vdraw cursor, draw prompt */ + vcursor_h = 0; + vcursor_v = 0; + RefreshPromptpart(NULL); + RefreshPromptpart(PromptBuf); + cur_h = -1; /* set flag in case I'm not set */ + + /* draw the current input buffer */ + for (cp = InputBuf; (cp < LastChar); cp++) { + if (cp == Cursor) { + cur_h = vcursor_h; /* save for later */ + cur_v = vcursor_v; + } + Draw(*cp); + } + + if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */ + cur_h = vcursor_h; + cur_v = vcursor_v; + } + + rhdiff = TermH - vcursor_h - rprompt_h; + if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) { + /* + * have a right-hand side prompt that will fit on + * the end of the first line with at least one + * character gap to the input buffer. + */ + while (--rhdiff > 0) /* pad out with spaces */ + Draw(' '); + RefreshPromptpart(RPromptBuf); + } + else { + rprompt_h = 0; /* flag "not using rprompt" */ + rprompt_v = 0; + } + + new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */ + Vdraw('\0'); /* put NUL on end */ + +#ifdef DEBUG_REFRESH + dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n", + TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0])); +#endif /* DEBUG_REFRESH */ + +#ifdef DEBUG_UPDATE + dprintf("updating %d lines.\r\n", new_vcv); +#endif /* DEBUG_UPDATE */ + for (cur_line = 0; cur_line <= new_vcv; cur_line++) { + /* NOTE THAT update_line MAY CHANGE Display[cur_line] */ + update_line(Display[cur_line], Vdisplay[cur_line], cur_line); +#ifdef WINNT + flush(); +#endif /* WINNT */ + + /* + * Copy the new line to be the current one, and pad out with spaces + * to the full width of the terminal so that if we try moving the + * cursor by writing the character that is at the end of the + * screen line, it won't be a NUL or some old leftover stuff. + */ + cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH); +#ifdef notdef + (void) Strncpy(Display[cur_line], Vdisplay[cur_line], (size_t) TermH); + Display[cur_line][TermH] = '\0'; /* just in case */ +#endif + } +#ifdef DEBUG_REFRESH + dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n", + vcursor_v, OldvcV, cur_line); +#endif /* DEBUG_REFRESH */ + if (OldvcV > new_vcv) { + for (; cur_line <= OldvcV; cur_line++) { + update_line(Display[cur_line], STRNULL, cur_line); + *Display[cur_line] = '\0'; + } + } + OldvcV = new_vcv; /* set for next time */ +#ifdef DEBUG_REFRESH + dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n", + CursorH, CursorV, cur_h, cur_v); +#endif /* DEBUG_REFRESH */ +#ifdef WINNT + flush(); +#endif /* WINNT */ + MoveToLine(cur_v); /* go to where the cursor is */ + MoveToChar(cur_h); + SetAttributes(0); /* Clear all attributes */ + flush(); /* send the output... */ + GettingInput = oldgetting; /* reset to old value */ +} + +#ifdef notdef +GotoBottom() +{ /* used to go to last used screen line */ + MoveToLine(OldvcV); +} + +#endif + +void +PastBottom() +{ /* used to go to last used screen line */ + MoveToLine(OldvcV); + (void) putraw('\r'); + (void) putraw('\n'); + ClearDisp(); + flush(); +} + + +/* insert num characters of s into d (in front of the character) at dat, + maximum length of d is dlen */ +static void +str_insert(d, dat, dlen, s, num) + register Char *d; + register int dat, dlen; + register Char *s; + register int num; +{ + register Char *a, *b; + + if (num <= 0) + return; + if (num > dlen - dat) + num = dlen - dat; + +#ifdef DEBUG_REFRESH + dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, short2str(d)); + dprintf("s == \"%s\"n", short2str(s)); +#endif /* DEBUG_REFRESH */ + + /* open up the space for num chars */ + if (num > 0) { + b = d + dlen - 1; + a = b - num; + while (a >= &d[dat]) + *b-- = *a--; + d[dlen] = '\0'; /* just in case */ + } +#ifdef DEBUG_REFRESH + dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, short2str(d)); + dprintf("s == \"%s\"n", short2str(s)); +#endif /* DEBUG_REFRESH */ + + /* copy the characters */ + for (a = d + dat; (a < d + dlen) && (num > 0); num--) + *a++ = *s++; + +#ifdef DEBUG_REFRESH + dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, d, short2str(s)); + dprintf("s == \"%s\"n", short2str(s)); +#endif /* DEBUG_REFRESH */ +} + +/* delete num characters d at dat, maximum length of d is dlen */ +static void +str_delete(d, dat, dlen, num) + register Char *d; + register int dat, dlen, num; +{ + register Char *a, *b; + + if (num <= 0) + return; + if (dat + num >= dlen) { + d[dat] = '\0'; + return; + } + +#ifdef DEBUG_REFRESH + dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, short2str(d)); +#endif /* DEBUG_REFRESH */ + + /* open up the space for num chars */ + if (num > 0) { + b = d + dat; + a = b + num; + while (a < &d[dlen]) + *b++ = *a++; + d[dlen] = '\0'; /* just in case */ + } +#ifdef DEBUG_REFRESH + dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, short2str(d)); +#endif /* DEBUG_REFRESH */ +} + +static void +str_cp(a, b, n) + register Char *a, *b; + register int n; +{ + while (n-- && *b) + *a++ = *b++; +} + + +#if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */ +static Char * +update_line_fix_mbyte_point(start, target, d) + Char *start, *target; + int d; +{ + if (_enable_mbdisp) { + while (*start) { + if (target == start) + break; + if (target < start) + return target + d; + if (Ismbyte1(*start) && Ismbyte2(*(start + 1))) + start++; + start++; + } + } + return target; +} +#endif + +/* **************************************************************** + update_line() is based on finding the middle difference of each line + on the screen; vis: + + /old first difference + /beginning of line | /old last same /old EOL + v v v v +old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as +new: eddie> Oh, my little buggy says to me, as lurgid as + ^ ^ ^ ^ + \beginning of line | \new last same \new end of line + \new first difference + + all are character pointers for the sake of speed. Special cases for + no differences, as well as for end of line additions must be handled. +**************************************************************** */ + +/* Minimum at which doing an insert it "worth it". This should be about + * half the "cost" of going into insert mode, inserting a character, and + * going back out. This should really be calculated from the termcap + * data... For the moment, a good number for ANSI terminals. + */ +#define MIN_END_KEEP 4 + +static void /* could be changed to make it smarter */ +update_line(old, new, cur_line) + register Char *old, *new; + int cur_line; +{ + register Char *o, *n, *p, c; + Char *ofd, *ols, *oe, *nfd, *nls, *ne; + Char *osb, *ose, *nsb, *nse; + int fx, sx; + + /* + * find first diff + */ + for (o = old, n = new; *o && (*o == *n); o++, n++) + continue; + ofd = o; + nfd = n; + + /* + * Find the end of both old and new + */ + while (*o) + o++; + /* + * Remove any trailing blanks off of the end, being careful not to + * back up past the beginning. + */ + while (ofd < o) { + if (o[-1] != ' ') + break; + o--; + } + oe = o; + *oe = (Char) 0; + + while (*n) + n++; + + /* remove blanks from end of new */ + while (nfd < n) { + if (n[-1] != ' ') + break; + n--; + } + ne = n; + *ne = (Char) 0; + + /* + * if no diff, continue to next line of redraw + */ + if (*ofd == '\0' && *nfd == '\0') { +#ifdef DEBUG_UPDATE + dprintf("no difference.\r\n"); +#endif /* DEBUG_UPDATE */ + return; + } + + /* + * find last same pointer + */ + while ((o > ofd) && (n > nfd) && (*--o == *--n)) + continue; + ols = ++o; + nls = ++n; + + /* + * find same begining and same end + */ + osb = ols; + nsb = nls; + ose = ols; + nse = nls; + + /* + * case 1: insert: scan from nfd to nls looking for *ofd + */ + if (*ofd) { + for (c = *ofd, n = nfd; n < nls; n++) { + if (c == *n) { + for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++) + continue; + /* + * if the new match is longer and it's worth keeping, then we + * take it + */ + if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { + nsb = n; + nse = p; + osb = ofd; + ose = o; + } + } + } + } + + /* + * case 2: delete: scan from ofd to ols looking for *nfd + */ + if (*nfd) { + for (c = *nfd, o = ofd; o < ols; o++) { + if (c == *o) { + for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++) + continue; + /* + * if the new match is longer and it's worth keeping, then we + * take it + */ + if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { + nsb = nfd; + nse = n; + osb = o; + ose = p; + } + } + } + } +#ifdef notdef + /* + * If `last same' is before `same end' re-adjust + */ + if (ols < ose) + ols = ose; + if (nls < nse) + nls = nse; +#endif + + /* + * Pragmatics I: If old trailing whitespace or not enough characters to + * save to be worth it, then don't save the last same info. + */ + if ((oe - ols) < MIN_END_KEEP) { + ols = oe; + nls = ne; + } + + /* + * Pragmatics II: if the terminal isn't smart enough, make the data dumber + * so the smart update doesn't try anything fancy + */ + + /* + * fx is the number of characters we need to insert/delete: in the + * beginning to bring the two same begins together + */ + fx = (int) ((nsb - nfd) - (osb - ofd)); + /* + * sx is the number of characters we need to insert/delete: in the end to + * bring the two same last parts together + */ + sx = (int) ((nls - nse) - (ols - ose)); + + if (!T_CanIns) { + if (fx > 0) { + osb = ols; + ose = ols; + nsb = nls; + nse = nls; + } + if (sx > 0) { + ols = oe; + nls = ne; + } + if ((ols - ofd) < (nls - nfd)) { + ols = oe; + nls = ne; + } + } + if (!T_CanDel) { + if (fx < 0) { + osb = ols; + ose = ols; + nsb = nls; + nse = nls; + } + if (sx < 0) { + ols = oe; + nls = ne; + } + if ((ols - ofd) > (nls - nfd)) { + ols = oe; + nls = ne; + } + } + + /* + * Pragmatics III: make sure the middle shifted pointers are correct if + * they don't point to anything (we may have moved ols or nls). + */ + /* if the change isn't worth it, don't bother */ + /* was: if (osb == ose) */ + if ((ose - osb) < MIN_END_KEEP) { + osb = ols; + ose = ols; + nsb = nls; + nse = nls; + } + + /* + * Now that we are done with pragmatics we recompute fx, sx + */ + fx = (int) ((nsb - nfd) - (osb - ofd)); + sx = (int) ((nls - nse) - (ols - ose)); + +#ifdef DEBUG_UPDATE + dprintf("\n"); + dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n", + ofd - old, osb - old, ose - old, ols - old, oe - old); + dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n", + nfd - new, nsb - new, nse - new, nls - new, ne - new); + dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"); + dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"); + dprintstr("old- oe", old, oe); + dprintstr("new- ne", new, ne); + dprintstr("old-ofd", old, ofd); + dprintstr("new-nfd", new, nfd); + dprintstr("ofd-osb", ofd, osb); + dprintstr("nfd-nsb", nfd, nsb); + dprintstr("osb-ose", osb, ose); + dprintstr("nsb-nse", nsb, nse); + dprintstr("ose-ols", ose, ols); + dprintstr("nse-nls", nse, nls); + dprintstr("ols- oe", ols, oe); + dprintstr("nls- ne", nls, ne); +#endif /* DEBUG_UPDATE */ + + /* + * CursorV to this line cur_line MUST be in this routine so that if we + * don't have to change the line, we don't move to it. CursorH to first + * diff char + */ + MoveToLine(cur_line); + +#if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */ + ofd = update_line_fix_mbyte_point(old, ofd, -1); + osb = update_line_fix_mbyte_point(old, osb, 1); + ose = update_line_fix_mbyte_point(old, ose, -1); + ols = update_line_fix_mbyte_point(old, ols, 1); + nfd = update_line_fix_mbyte_point(new, nfd, -1); + nsb = update_line_fix_mbyte_point(new, nsb, 1); + nse = update_line_fix_mbyte_point(new, nse, -1); + nls = update_line_fix_mbyte_point(new, nls, 1); +#endif + + /* + * at this point we have something like this: + * + * /old /ofd /osb /ose /ols /oe + * v.....................v v..................v v........v + * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as + * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as + * ^.....................^ ^..................^ ^........^ + * \new \nfd \nsb \nse \nls \ne + * + * fx is the difference in length between the the chars between nfd and + * nsb, and the chars between ofd and osb, and is thus the number of + * characters to delete if < 0 (new is shorter than old, as above), + * or insert (new is longer than short). + * + * sx is the same for the second differences. + */ + + /* + * if we have a net insert on the first difference, AND inserting the net + * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character + * (which is ne if nls != ne, otherwise is nse) off the edge of the screen + * (TermH - 1) else we do the deletes first so that we keep everything we + * need to. + */ + + /* + * if the last same is the same like the end, there is no last same part, + * otherwise we want to keep the last same part set p to the last useful + * old character + */ + p = (ols != oe) ? oe : ose; + + /* + * if (There is a diffence in the beginning) && (we need to insert + * characters) && (the number of characters to insert is less than the term + * width) We need to do an insert! else if (we need to delete characters) + * We need to delete characters! else No insert or delete + */ + if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) { +#ifdef DEBUG_UPDATE + dprintf("first diff insert at %d...\r\n", nfd - new); +#endif /* DEBUG_UPDATE */ + /* + * Move to the first char to insert, where the first diff is. + */ + MoveToChar(nfd - new); + /* + * Check if we have stuff to keep at end + */ + if (nsb != ne) { +#ifdef DEBUG_UPDATE + dprintf("with stuff to keep at end\r\n"); +#endif /* DEBUG_UPDATE */ + /* + * insert fx chars of new starting at nfd + */ + if (fx > 0) { +#ifdef DEBUG_UPDATE + if (!T_CanIns) + dprintf(" ERROR: cannot insert in early first diff\n"); +#endif /* DEBUG_UPDATE */ + Insert_write(nfd, fx); + str_insert(old, (int) (ofd - old), TermH, nfd, fx); + } + /* + * write (nsb-nfd) - fx chars of new starting at (nfd + fx) + */ + so_write(nfd + fx, (nsb - nfd) - fx); + str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); + } + else { +#ifdef DEBUG_UPDATE + dprintf("without anything to save\r\n"); +#endif /* DEBUG_UPDATE */ + so_write(nfd, (nsb - nfd)); + str_cp(ofd, nfd, (int) (nsb - nfd)); + /* + * Done + */ + return; + } + } + else if (fx < 0) { +#ifdef DEBUG_UPDATE + dprintf("first diff delete at %d...\r\n", ofd - old); +#endif /* DEBUG_UPDATE */ + /* + * move to the first char to delete where the first diff is + */ + MoveToChar(ofd - old); + /* + * Check if we have stuff to save + */ + if (osb != oe) { +#ifdef DEBUG_UPDATE + dprintf("with stuff to save at end\r\n"); +#endif /* DEBUG_UPDATE */ + /* + * fx is less than zero *always* here but we check for code + * symmetry + */ + if (fx < 0) { +#ifdef DEBUG_UPDATE + if (!T_CanDel) + dprintf(" ERROR: cannot delete in first diff\n"); +#endif /* DEBUG_UPDATE */ + DeleteChars(-fx); + str_delete(old, (int) (ofd - old), TermH, -fx); + } + /* + * write (nsb-nfd) chars of new starting at nfd + */ + so_write(nfd, (nsb - nfd)); + str_cp(ofd, nfd, (int) (nsb - nfd)); + + } + else { +#ifdef DEBUG_UPDATE + dprintf("but with nothing left to save\r\n"); +#endif /* DEBUG_UPDATE */ + /* + * write (nsb-nfd) chars of new starting at nfd + */ + so_write(nfd, (nsb - nfd)); +#ifdef DEBUG_REFRESH + dprintf("cleareol %d\n", (oe - old) - (ne - new)); +#endif /* DEBUG_UPDATE */ +#ifndef WINNT + ClearEOL((oe - old) - (ne - new)); +#else + /* + * The calculation above does not work too well on NT + */ + ClearEOL(TermH - CursorH); +#endif /*WINNT*/ + /* + * Done + */ + return; + } + } + else + fx = 0; + + if (sx < 0) { +#ifdef DEBUG_UPDATE + dprintf("second diff delete at %d...\r\n", (ose - old) + fx); +#endif /* DEBUG_UPDATE */ + /* + * Check if we have stuff to delete + */ + /* + * fx is the number of characters inserted (+) or deleted (-) + */ + + MoveToChar((ose - old) + fx); + /* + * Check if we have stuff to save + */ + if (ols != oe) { +#ifdef DEBUG_UPDATE + dprintf("with stuff to save at end\r\n"); +#endif /* DEBUG_UPDATE */ + /* + * Again a duplicate test. + */ + if (sx < 0) { +#ifdef DEBUG_UPDATE + if (!T_CanDel) + dprintf(" ERROR: cannot delete in second diff\n"); +#endif /* DEBUG_UPDATE */ + DeleteChars(-sx); + } + + /* + * write (nls-nse) chars of new starting at nse + */ + so_write(nse, (nls - nse)); + } + else { + int olen = (int) (oe - old + fx); + if (olen > TermH) + olen = TermH; +#ifdef DEBUG_UPDATE + dprintf("but with nothing left to save\r\n"); +#endif /* DEBUG_UPDATE */ + so_write(nse, (nls - nse)); +#ifdef DEBUG_REFRESH + dprintf("cleareol %d\n", olen - (ne - new)); +#endif /* DEBUG_UPDATE */ +#ifndef WINNT + ClearEOL(olen - (ne - new)); +#else + /* + * The calculation above does not work too well on NT + */ + ClearEOL(TermH - CursorH); +#endif /*WINNT*/ + } + } + + /* + * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... + */ + if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { +#ifdef DEBUG_UPDATE + dprintf("late first diff insert at %d...\r\n", nfd - new); +#endif /* DEBUG_UPDATE */ + + MoveToChar(nfd - new); + /* + * Check if we have stuff to keep at the end + */ + if (nsb != ne) { +#ifdef DEBUG_UPDATE + dprintf("with stuff to keep at end\r\n"); +#endif /* DEBUG_UPDATE */ + /* + * We have to recalculate fx here because we set it + * to zero above as a flag saying that we hadn't done + * an early first insert. + */ + fx = (int) ((nsb - nfd) - (osb - ofd)); + if (fx > 0) { + /* + * insert fx chars of new starting at nfd + */ +#ifdef DEBUG_UPDATE + if (!T_CanIns) + dprintf(" ERROR: cannot insert in late first diff\n"); +#endif /* DEBUG_UPDATE */ + Insert_write(nfd, fx); + str_insert(old, (int) (ofd - old), TermH, nfd, fx); + } + + /* + * write (nsb-nfd) - fx chars of new starting at (nfd + fx) + */ + so_write(nfd + fx, (nsb - nfd) - fx); + str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); + } + else { +#ifdef DEBUG_UPDATE + dprintf("without anything to save\r\n"); +#endif /* DEBUG_UPDATE */ + so_write(nfd, (nsb - nfd)); + str_cp(ofd, nfd, (int) (nsb - nfd)); + } + } + + /* + * line is now NEW up to nse + */ + if (sx >= 0) { +#ifdef DEBUG_UPDATE + dprintf("second diff insert at %d...\r\n", nse - new); +#endif /* DEBUG_UPDATE */ + MoveToChar(nse - new); + if (ols != oe) { +#ifdef DEBUG_UPDATE + dprintf("with stuff to keep at end\r\n"); +#endif /* DEBUG_UPDATE */ + if (sx > 0) { + /* insert sx chars of new starting at nse */ +#ifdef DEBUG_UPDATE + if (!T_CanIns) + dprintf(" ERROR: cannot insert in second diff\n"); +#endif /* DEBUG_UPDATE */ + Insert_write(nse, sx); + } + + /* + * write (nls-nse) - sx chars of new starting at (nse + sx) + */ + so_write(nse + sx, (nls - nse) - sx); + } + else { +#ifdef DEBUG_UPDATE + dprintf("without anything to save\r\n"); +#endif /* DEBUG_UPDATE */ + so_write(nse, (nls - nse)); + + /* + * No need to do a clear-to-end here because we were doing + * a second insert, so we will have over written all of the + * old string. + */ + } + } +#ifdef DEBUG_UPDATE + dprintf("done.\r\n"); +#endif /* DEBUG_UPDATE */ +} + + +static void +cpy_pad_spaces(dst, src, width) + register Char *dst, *src; + register int width; +{ + register int i; + + for (i = 0; i < width; i++) { + if (*src == (Char) 0) + break; + *dst++ = *src++; + } + + while (i < width) { + *dst++ = ' '; + i++; + } + *dst = (Char) 0; +} + +void +RefCursor() +{ /* only move to new cursor pos */ + register Char *cp, c; + register int h, th, v; + + /* first we must find where the cursor is... */ + h = 0; + v = 0; + th = TermH; /* optimize for speed */ + + for (cp = PromptBuf; *cp; cp++) { /* do prompt */ + if (*cp & LITERAL) + continue; + c = *cp & CHAR; /* extra speed plus strip the inverse */ + h++; /* all chars at least this long */ + + /* from wolman%crltrx.DEC@decwrl.dec.com (Alec Wolman) */ + /* lets handle newline as part of the prompt */ + + if (c == '\n') { + h = 0; + v++; + } + else { + if (c == '\t') { /* if a tab, to next tab stop */ + while (h & 07) { + h++; + } + } + else if (Iscntrl(c)) { /* if control char */ + h++; + if (h > th) { /* if overflow, compensate */ + h = 1; + v++; + } + } + else if (!Isprint(c)) { + h += 3; + if (h > th) { /* if overflow, compensate */ + h = h - th; + v++; + } + } + } + + if (h >= th) { /* check, extra long tabs picked up here also */ + h = 0; + v++; + } + } + + for (cp = InputBuf; cp < Cursor; cp++) { /* do input buffer to Cursor */ + c = *cp & CHAR; /* extra speed plus strip the inverse */ + h++; /* all chars at least this long */ + + if (c == '\n') { /* handle newline in data part too */ + h = 0; + v++; + } + else { + if (c == '\t') { /* if a tab, to next tab stop */ + while (h & 07) { + h++; + } + } + else if (Iscntrl(c)) { /* if control char */ + h++; + if (h > th) { /* if overflow, compensate */ + h = 1; + v++; + } + } + else if (!Isprint(c)) { + h += 3; + if (h > th) { /* if overflow, compensate */ + h = h - th; + v++; + } + } + } + + if (h >= th) { /* check, extra long tabs picked up here also */ + h = 0; + v++; + } + } + + /* now go there */ + MoveToLine(v); + MoveToChar(h); + flush(); +} + +static void +PutPlusOne(c) + int c; +{ + (void) putraw(c); + Display[CursorV][CursorH++] = (Char) c; + if (CursorH >= TermH) { /* if we must overflow */ + CursorH = 0; + CursorV++; + OldvcV++; + if (T_Margin & MARGIN_AUTO) { + if (T_Margin & MARGIN_MAGIC) { + (void) putraw(' '); + (void) putraw('\b'); + } + } + else { + (void) putraw('\r'); + (void) putraw('\n'); + } + } +} + +void +RefPlusOne() +{ /* we added just one char, handle it fast. + * assumes that screen cursor == real cursor */ + register Char c, mc; + + c = Cursor[-1] & CHAR; /* the char we just added */ + + if (c == '\t' || Cursor != LastChar) { + Refresh(); /* too hard to handle */ + return; + } + + if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) { + Refresh(); /* clear out rprompt if less than one char gap*/ + return; + } /* else (only do at end of line, no TAB) */ + + if (Iscntrl(c)) { /* if control char, do caret */ +#ifndef _OSD_POSIX + mc = (c == '\177') ? '?' : (c | 0100); + PutPlusOne('^'); + PutPlusOne(mc); +#else /*_OSD_POSIX*/ + if (_toascii[c] == '\177' || Isupper(_toebcdic[_toascii[c]|0100]) + || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) + { + mc = (_toascii[c] == '\177') ? '?' : _toebcdic[_toascii[c]|0100]; + PutPlusOne('^'); + PutPlusOne(mc); + } + else + { + PutPlusOne('\\'); + PutPlusOne(((c >> 6) & 7) + '0'); + PutPlusOne(((c >> 3) & 7) + '0'); + PutPlusOne((c & 7) + '0'); + } +#endif /*_OSD_POSIX*/ + } + else if (Isprint(c)) { /* normal char */ + PutPlusOne(c); + } +#ifdef KANJI + else if (!adrof(STRnokanji)) { + PutPlusOne(c); + } +#endif + else { + PutPlusOne('\\'); + PutPlusOne(((c >> 6) & 7) + '0'); + PutPlusOne(((c >> 3) & 7) + '0'); + PutPlusOne((c & 7) + '0'); + } + flush(); +} + +/* clear the screen buffers so that new new prompt starts fresh. */ + +void +ClearDisp() +{ + register int i; + + CursorV = 0; /* clear the display buffer */ + CursorH = 0; + for (i = 0; i < TermV; i++) + (void) memset(Display[i], 0, TermH * sizeof(Display[0][0])); + OldvcV = 0; +} + +void +ClearLines() +{ /* Make sure all lines are *really* blank */ + register int i; + + if (T_CanCEOL) { + /* + * Clear the lines from the bottom up so that if we try moving + * the cursor down by writing the character that is at the end + * of the screen line, we won't rewrite a character that shouldn't + * be there. + */ + for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */ + MoveToLine(i); + MoveToChar(0); + ClearEOL(TermH); + } + } + else { + MoveToLine(OldvcV); /* go to last line */ + (void) putraw('\r'); /* go to BOL */ + (void) putraw('\n'); /* go to new line */ + } +} |