source: trunk/third/tcsh/ed.refresh.c @ 22036

Revision 22036, 33.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22035, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/ed.refresh.c,v 1.1.1.3 2005-06-03 14:35:26 ghudson Exp $ */
2/*
3 * ed.refresh.c: Lower level screen refreshing functions
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33#include "sh.h"
34
35RCSID("$Id: ed.refresh.c,v 1.1.1.3 2005-06-03 14:35:26 ghudson Exp $")
36
37#include "ed.h"
38/* #define DEBUG_UPDATE */
39/* #define DEBUG_REFRESH */
40/* #define DEBUG_LITERAL */
41
42/* refresh.c -- refresh the current set of lines on the screen */
43
44Char   *litptr;
45static int vcursor_h, vcursor_v;
46static int rprompt_h, rprompt_v;
47
48static  int     MakeLiteral             __P((Char *, int, Char));
49static  int     Draw                    __P((Char *, int));
50static  void    Vdraw                   __P((Char, int));
51static  void    RefreshPromptpart       __P((Char *));
52static  void    update_line             __P((Char *, Char *, int));
53static  void    str_insert              __P((Char *, int, int, Char *, int));
54static  void    str_delete              __P((Char *, int, int, int));
55static  void    str_cp                  __P((Char *, Char *, int));
56#ifndef WINNT_NATIVE
57static
58#else
59extern
60#endif
61        void    PutPlusOne      __P((Char, int));
62static  void    cpy_pad_spaces          __P((Char *, Char *, int));
63#if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL)
64static  void    dprintf                 __P((char *, ...));
65#ifdef DEBUG_UPDATE
66static  void    dprintstr               __P((char *, const Char *, const Char *));
67
68static void
69dprintstr(str, f, t)
70char *str;
71const Char *f, *t;
72{
73    dprintf("%s:\"", str);
74    while (f < t) {
75        if (*f & ~ASCII)
76          dprintf("[%x]", *f++);
77        else
78          dprintf("%c", *f++ & ASCII);
79    }
80    dprintf("\"\r\n");
81}
82#endif /* DEBUG_UPDATE */
83
84/* dprintf():
85 *      Print to $DEBUGTTY, so that we can test editing on one pty, and
86 *      print debugging stuff on another. Don't interrupt the shell while
87 *      debugging cause you'll mangle up the file descriptors!
88 */
89static void
90#ifdef PROTOTYPES
91dprintf(char *fmt, ...)
92#else
93dprintf(va_list)
94    va_dcl
95#endif /* __STDC__ */
96{
97    static int fd = -1;
98    char *dtty;
99
100    if ((dtty = getenv("DEBUGTTY"))) {
101        int o;
102        va_list va;
103#ifdef PROTOTYPES
104        va_start(va, fmt);
105#else
106        char *fmt;
107        va_start(va);
108        fmt = va_arg(va, char *);
109#endif /* __STDC__ */
110
111        if (fd == -1)
112            fd = open(dtty, O_RDWR);
113        o = SHOUT;
114        flush();
115        SHOUT = fd;
116        xvprintf(fmt, va);
117        va_end(va);
118        flush();
119        SHOUT = o;
120    }
121}
122#endif  /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */
123
124static int litlen = 0, litalloc = 0;
125
126static int MakeLiteral(str, len, addlit)
127    Char *str;
128    int len;
129    Char addlit;
130{
131    int i, addlitlen = 0;
132    Char *addlitptr = 0;
133    if (addlit) {
134        if ((addlit & LITERAL) != 0) {
135            addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
136            addlitlen = Strlen(addlitptr);
137        } else {
138            addlitptr = &addlit;
139            addlitlen = 1;
140        }
141        for (i = 0; i < litlen; i += LIT_FACTOR)
142            if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0)
143                return (i / LIT_FACTOR) | LITERAL;
144    } else {
145        addlitlen = 0;
146        for (i = 0; i < litlen; i += LIT_FACTOR)
147            if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0)
148                return (i / LIT_FACTOR) | LITERAL;
149    }
150    if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) {
151        Char *newlitptr;
152        int add = 256;
153        while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add)
154            add *= 2;
155        if (litptr)
156            newlitptr = (Char *)xrealloc(litptr, (litalloc + add) * sizeof(Char));
157        else
158            newlitptr = (Char *)xmalloc((litalloc + add) * sizeof(Char));
159        if (!newlitptr)
160            return '?';
161        litptr = newlitptr;
162        litalloc += add;
163        if (addlitptr && addlitptr != &addlit)
164            addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
165    }
166    i = litlen / LIT_FACTOR;
167    if (i >= LITERAL || i == CHAR_DBWIDTH)
168        return '?';
169    if (addlitptr) {
170        Strncpy(litptr + litlen, addlitptr, addlitlen);
171        litlen += addlitlen;
172    }
173    Strncpy(litptr + litlen, str, len);
174    litlen += len;
175    do
176        litptr[litlen++] = 0;
177    while (litlen % LIT_FACTOR);
178    return i | LITERAL;
179}
180
181static int
182Draw(cp, nocomb)        /* draw char at cp, expand tabs, ctl chars */
183    Char *cp;
184    int nocomb;
185{
186    int l, w, i, lv, lh;
187    Char ch, attr;
188    NLSChar c;
189
190    attr = *cp & ~CHAR;
191    l = NLSFrom(cp, NLSZEROT, &c);
192    w = NLSClassify(c, nocomb);
193    switch (w) {
194        case NLSCLASS_NL:
195            Vdraw('\0', 0);             /* assure end of line    */
196            vcursor_h = 0;              /* reset cursor pos      */
197            vcursor_v++;
198            break;
199        case NLSCLASS_TAB:
200            do {
201                Vdraw(' ', 1);
202            } while ((vcursor_h & 07) != 0);
203            break;
204        case NLSCLASS_CTRL:
205            Vdraw('^' | attr, 1);
206            if (c == CTL_ESC('\177')) {
207                Vdraw('?' | attr, 1);
208            } else {
209#ifdef IS_ASCII
210                /* uncontrolify it; works only for iso8859-1 like sets */
211                Vdraw(c | 0100 | attr, 1);
212#else
213                Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1);
214#endif
215            }
216            break;
217        case NLSCLASS_ILLEGAL:
218            ch = *cp & CHAR;
219            Vdraw('\\' | attr, 1);
220            Vdraw((((ch >> 6) & 7) + '0') | attr, 1);
221            Vdraw((((ch >> 3) & 7) + '0') | attr, 1);
222            Vdraw(((ch & 7) + '0') | attr, 1);
223            break;
224        case NLSCLASS_ILLEGAL2:
225        case NLSCLASS_ILLEGAL3:
226        case NLSCLASS_ILLEGAL4:
227            Vdraw('\\' | attr, 1);
228            Vdraw('U' | attr, 1);
229            Vdraw('+' | attr, 1);
230            for (i = 8 * NLSCLASS_ILLEGAL_SIZE(w) - 4; i >= 0; i -= 4)
231                Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1);
232            break;
233        case 0:
234            lv = vcursor_v;
235            lh = vcursor_h;
236            for (;;) {
237                lh--;
238                if (lh < 0) {
239                    lv--;
240                    if (lv < 0)
241                        break;
242                    lh = Strlen(Vdisplay[lv]) - 1;
243                }
244                if (Vdisplay[lv][lh] != CHAR_DBWIDTH)
245                    break;
246            }
247            if (lv < 0) {
248                int l2 = l;
249                for (; l2-- > 0; cp++) {
250                    ch = *cp & CHAR;
251                    Vdraw('\\' | attr, 1);
252                    Vdraw((((ch >> 6) & 7) + '0') | attr, 1);
253                    Vdraw((((ch >> 3) & 7) + '0') | attr, 1);
254                    Vdraw(((ch & 7) + '0') | attr, 1);
255                }
256                return l;
257            }
258            Vdisplay[lv][lh] = MakeLiteral(cp, l, Vdisplay[lv][lh]);
259            break;
260        default:
261            if (l > 1)
262                Vdraw(MakeLiteral(cp, l, 0), w);
263            else
264                Vdraw(*cp, w);
265            break;
266    }
267    return l;
268}
269
270static void
271Vdraw(c, width)                 /* draw char c onto V lines */
272    Char c;
273    int width;
274{
275#ifdef DEBUG_REFRESH
276# ifdef SHORT_STRINGS
277    dprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width);
278# else
279    dprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width);
280# endif /* SHORT_STRNGS */
281#endif  /* DEBUG_REFRESH */
282
283    /* Hopefully this is what all the terminals do with multi-column characters
284       that "span line breaks". */
285    while (vcursor_h + width > TermH)
286        Vdraw(' ', 1);
287    Vdisplay[vcursor_v][vcursor_h] = (Char) c;
288    if (width)
289        vcursor_h++;            /* advance to next place */
290    while (--width > 0)
291        Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH;
292    if (vcursor_h >= TermH) {
293        Vdisplay[vcursor_v][TermH] = '\0';      /* assure end of line */
294        vcursor_h = 0;          /* reset it. */
295        vcursor_v++;
296#ifdef DEBUG_REFRESH
297        if (vcursor_v >= TermV) {       /* should NEVER happen. */
298            dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
299                    vcursor_v, TermV);
300            abort();
301        }
302#endif /* DEBUG_REFRESH */
303    }
304}
305
306/*
307 *  RefreshPromptpart()
308 *      draws a prompt element, expanding literals (we know it's ASCIZ)
309 */
310static void
311RefreshPromptpart(buf)
312    Char *buf;
313{
314    Char *cp;
315    NLSChar c;
316    int l, w;
317
318    for (cp = buf; *cp; ) {
319        if (*cp & LITERAL) {
320            Char *litstart = cp;
321            while (*cp & LITERAL)
322                cp++;
323            if (*cp) {
324                l = NLSFrom(cp, NLSZEROT, &c);
325                w = NLSWidth(c);
326                Vdraw(MakeLiteral(litstart, cp + l - litstart, 0), w);
327                cp += l;
328            }
329            else {
330                /*
331                 * XXX: This is a bug, we lose the last literal, if it is not
332                 * followed by a normal character, but it is too hard to fix
333                 */
334                break;
335            }
336        }
337        else
338            cp += Draw(cp, cp == buf);
339    }
340}
341
342/*
343 *  Refresh()
344 *      draws the new virtual screen image from the current input
345 *      line, then goes line-by-line changing the real image to the new
346 *      virtual image. The routine to re-draw a line can be replaced
347 *      easily in hopes of a smarter one being placed there.
348 */
349#ifndef WINNT_NATIVE
350static
351#endif
352int OldvcV = 0;
353
354void
355Refresh()
356{
357    int cur_line;
358    Char *cp;
359    int     cur_h, cur_v = 0, new_vcv;
360    int     rhdiff;
361    Char    oldgetting;
362
363#ifdef DEBUG_REFRESH
364    dprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf));
365    dprintf("InputBuf = :%s:\r\n", short2str(InputBuf));
366#endif /* DEBUG_REFRESH */
367    oldgetting = GettingInput;
368    GettingInput = 0;           /* avoid re-entrance via SIGWINCH */
369
370    /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
371    vcursor_h = 0;
372    vcursor_v = 0;
373    RefreshPromptpart(RPromptBuf);
374    rprompt_h = vcursor_h;
375    rprompt_v = vcursor_v;
376
377    /* reset the Vdraw cursor, draw prompt */
378    vcursor_h = 0;
379    vcursor_v = 0;
380    RefreshPromptpart(PromptBuf);
381    cur_h = -1;                 /* set flag in case I'm not set */
382
383    /* draw the current input buffer */
384    for (cp = InputBuf; (cp < LastChar); ) {
385        if (cp >= Cursor && cur_h == -1) {
386            cur_h = vcursor_h;  /* save for later */
387            cur_v = vcursor_v;
388            Cursor = cp;
389        }
390        cp += Draw(cp, cp == InputBuf);
391    }
392
393    if (cur_h == -1) {          /* if I haven't been set yet, I'm at the end */
394        cur_h = vcursor_h;
395        cur_v = vcursor_v;
396    }
397
398    rhdiff = TermH - vcursor_h - rprompt_h;
399    if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) {
400                        /*
401                         * have a right-hand side prompt that will fit on
402                         * the end of the first line with at least one
403                         * character gap to the input buffer.
404                         */
405        while (--rhdiff > 0)            /* pad out with spaces */
406            Vdraw(' ', 1);
407        RefreshPromptpart(RPromptBuf);
408    }
409    else {
410        rprompt_h = 0;                  /* flag "not using rprompt" */
411        rprompt_v = 0;
412    }
413
414    new_vcv = vcursor_v;        /* must be done BEFORE the NUL is written */
415    Vdraw('\0', 1);             /* put NUL on end */
416
417#if defined (DEBUG_REFRESH)
418    dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
419            TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0]));
420#endif /* DEBUG_REFRESH */
421
422#ifdef DEBUG_UPDATE
423    dprintf("updating %d lines.\r\n", new_vcv);
424#endif  /* DEBUG_UPDATE */
425    for (cur_line = 0; cur_line <= new_vcv; cur_line++) {
426        /* NOTE THAT update_line MAY CHANGE Display[cur_line] */
427        update_line(Display[cur_line], Vdisplay[cur_line], cur_line);
428#ifdef WINNT_NATIVE
429        flush();
430#endif /* WINNT_NATIVE */
431
432        /*
433         * Copy the new line to be the current one, and pad out with spaces
434         * to the full width of the terminal so that if we try moving the
435         * cursor by writing the character that is at the end of the
436         * screen line, it won't be a NUL or some old leftover stuff.
437         */
438        cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH);
439    }
440#ifdef DEBUG_REFRESH
441    dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
442            vcursor_v, OldvcV, cur_line);
443#endif /* DEBUG_REFRESH */
444    if (OldvcV > new_vcv) {
445        for (; cur_line <= OldvcV; cur_line++) {
446            update_line(Display[cur_line], STRNULL, cur_line);
447            *Display[cur_line] = '\0';
448        }
449    }
450    OldvcV = new_vcv;           /* set for next time */
451#ifdef DEBUG_REFRESH
452    dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
453            CursorH, CursorV, cur_h, cur_v);
454#endif /* DEBUG_REFRESH */
455#ifdef WINNT_NATIVE
456    flush();
457#endif /* WINNT_NATIVE */
458    MoveToLine(cur_v);          /* go to where the cursor is */
459    MoveToChar(cur_h);
460    SetAttributes(0);           /* Clear all attributes */
461    flush();                    /* send the output... */
462    GettingInput = oldgetting;  /* reset to old value */
463}
464
465#ifdef notdef
466GotoBottom()
467{                               /* used to go to last used screen line */
468    MoveToLine(OldvcV);
469}
470
471#endif
472
473void
474PastBottom()
475{                               /* used to go to last used screen line */
476    MoveToLine(OldvcV);
477    (void) putraw('\r');
478    (void) putraw('\n');
479    ClearDisp();
480    flush();
481}
482
483
484/* insert num characters of s into d (in front of the character) at dat,
485   maximum length of d is dlen */
486static void
487str_insert(d, dat, dlen, s, num)
488    Char *d;
489    int dat, dlen;
490    Char *s;
491    int num;
492{
493    Char *a, *b;
494
495    if (num <= 0)
496        return;
497    if (num > dlen - dat)
498        num = dlen - dat;
499
500#ifdef DEBUG_REFRESH
501    dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
502            num, dat, dlen, short2str(d));
503    dprintf("s == \"%s\"n", short2str(s));
504#endif /* DEBUG_REFRESH */
505
506    /* open up the space for num chars */
507    if (num > 0) {
508        b = d + dlen - 1;
509        a = b - num;
510        while (a >= &d[dat])
511            *b-- = *a--;
512        d[dlen] = '\0';         /* just in case */
513    }
514#ifdef DEBUG_REFRESH
515    dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
516            num, dat, dlen, short2str(d));
517    dprintf("s == \"%s\"n", short2str(s));
518#endif /* DEBUG_REFRESH */
519
520    /* copy the characters */
521    for (a = d + dat; (a < d + dlen) && (num > 0); num--)
522        *a++ = *s++;
523
524#ifdef DEBUG_REFRESH
525    dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
526            num, dat, dlen, d, short2str(s));
527    dprintf("s == \"%s\"n", short2str(s));
528#endif /* DEBUG_REFRESH */
529}
530
531/* delete num characters d at dat, maximum length of d is dlen */
532static void
533str_delete(d, dat, dlen, num)
534    Char *d;
535    int dat, dlen, num;
536{
537    Char *a, *b;
538
539    if (num <= 0)
540        return;
541    if (dat + num >= dlen) {
542        d[dat] = '\0';
543        return;
544    }
545
546#ifdef DEBUG_REFRESH
547    dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
548            num, dat, dlen, short2str(d));
549#endif /* DEBUG_REFRESH */
550
551    /* open up the space for num chars */
552    if (num > 0) {
553        b = d + dat;
554        a = b + num;
555        while (a < &d[dlen])
556            *b++ = *a++;
557        d[dlen] = '\0';         /* just in case */
558    }
559#ifdef DEBUG_REFRESH
560    dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
561            num, dat, dlen, short2str(d));
562#endif /* DEBUG_REFRESH */
563}
564
565static void
566str_cp(a, b, n)
567    Char *a, *b;
568    int n;
569{
570    while (n-- && *b)
571        *a++ = *b++;
572}
573
574
575/* ****************************************************************
576    update_line() is based on finding the middle difference of each line
577    on the screen; vis:
578
579                             /old first difference
580        /beginning of line   |              /old last same       /old EOL
581        v                    v              v                    v
582old:    eddie> Oh, my little gruntle-buggy is to me, as lurgid as
583new:    eddie> Oh, my little buggy says to me, as lurgid as
584        ^                    ^        ^                    ^
585        \beginning of line   |        \new last same       \new end of line
586                             \new first difference
587
588    all are character pointers for the sake of speed.  Special cases for
589    no differences, as well as for end of line additions must be handled.
590**************************************************************** */
591
592/* Minimum at which doing an insert it "worth it".  This should be about
593 * half the "cost" of going into insert mode, inserting a character, and
594 * going back out.  This should really be calculated from the termcap
595 * data...  For the moment, a good number for ANSI terminals.
596 */
597#define MIN_END_KEEP    4
598
599static void                     /* could be changed to make it smarter */
600update_line(old, new, cur_line)
601    Char *old, *new;
602    int     cur_line;
603{
604    Char *o, *n, *p, c;
605    Char  *ofd, *ols, *oe, *nfd, *nls, *ne;
606    Char  *osb, *ose, *nsb, *nse;
607    int     fx, sx;
608
609    /*
610     * find first diff (won't be CHAR_DBWIDTH in either line)
611     */
612    for (o = old, n = new; *o && (*o == *n); o++, n++)
613        continue;
614    ofd = o;
615    nfd = n;
616
617    /*
618     * Find the end of both old and new
619     */
620    while (*o)
621        o++;
622    /*
623     * Remove any trailing blanks off of the end, being careful not to
624     * back up past the beginning.
625     */
626    while (ofd < o) {
627        if (o[-1] != ' ')
628            break;
629        o--;
630    }
631    oe = o;
632    *oe = (Char) 0;
633 
634    while (*n)
635        n++;
636
637    /* remove blanks from end of new */
638    while (nfd < n) {
639        if (n[-1] != ' ')
640            break;
641        n--;
642    }
643    ne = n;
644    *ne = (Char) 0;
645 
646    /*
647     * if no diff, continue to next line of redraw
648     */
649    if (*ofd == '\0' && *nfd == '\0') {
650#ifdef DEBUG_UPDATE
651        dprintf("no difference.\r\n");
652#endif /* DEBUG_UPDATE */
653        return;
654    }
655
656    /*
657     * find last same pointer
658     */
659    while ((o > ofd) && (n > nfd) && (*--o == *--n))
660        continue;
661    if (*o != *n) {
662        o++;
663        n++;
664    }
665    while (*o == CHAR_DBWIDTH) {
666        o++;
667        n++;
668    }
669    ols = o;
670    nls = n;
671
672    /*
673     * find same begining and same end
674     */
675    osb = ols;
676    nsb = nls;
677    ose = ols;
678    nse = nls;
679
680    /*
681     * case 1: insert: scan from nfd to nls looking for *ofd
682     */
683    if (*ofd) {
684        for (c = *ofd, n = nfd; n < nls; n++) {
685            if (c == *n) {
686                for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
687                    continue;
688                /*
689                 * if the new match is longer and it's worth keeping, then we
690                 * take it
691                 */
692                if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
693                    nsb = n;
694                    nse = p;
695                    osb = ofd;
696                    ose = o;
697                }
698            }
699        }
700    }
701
702    /*
703     * case 2: delete: scan from ofd to ols looking for *nfd
704     */
705    if (*nfd) {
706        for (c = *nfd, o = ofd; o < ols; o++) {
707            if (c == *o) {
708                for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
709                    continue;
710                /*
711                 * if the new match is longer and it's worth keeping, then we
712                 * take it
713                 */
714                if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
715                    nsb = nfd;
716                    nse = n;
717                    osb = o;
718                    ose = p;
719                }
720            }
721        }
722    }
723#ifdef notdef
724    /*
725     * If `last same' is before `same end' re-adjust
726     */
727    if (ols < ose)
728        ols = ose;
729    if (nls < nse)
730        nls = nse;
731#endif
732
733    /*
734     * Pragmatics I: If old trailing whitespace or not enough characters to
735     * save to be worth it, then don't save the last same info.
736     */
737    if ((oe - ols) < MIN_END_KEEP) {
738        ols = oe;
739        nls = ne;
740    }
741
742    /*
743     * Pragmatics II: if the terminal isn't smart enough, make the data dumber
744     * so the smart update doesn't try anything fancy
745     */
746
747    /*
748     * fx is the number of characters we need to insert/delete: in the
749     * beginning to bring the two same begins together
750     */
751    fx = (int) ((nsb - nfd) - (osb - ofd));
752    /*
753     * sx is the number of characters we need to insert/delete: in the end to
754     * bring the two same last parts together
755     */
756    sx = (int) ((nls - nse) - (ols - ose));
757
758    if (!T_CanIns) {
759        if (fx > 0) {
760            osb = ols;
761            ose = ols;
762            nsb = nls;
763            nse = nls;
764        }
765        if (sx > 0) {
766            ols = oe;
767            nls = ne;
768        }
769        if ((ols - ofd) < (nls - nfd)) {
770            ols = oe;
771            nls = ne;
772        }
773    }
774    if (!T_CanDel) {
775        if (fx < 0) {
776            osb = ols;
777            ose = ols;
778            nsb = nls;
779            nse = nls;
780        }
781        if (sx < 0) {
782            ols = oe;
783            nls = ne;
784        }
785        if ((ols - ofd) > (nls - nfd)) {
786            ols = oe;
787            nls = ne;
788        }
789    }
790
791    /*
792     * Pragmatics III: make sure the middle shifted pointers are correct if
793     * they don't point to anything (we may have moved ols or nls).
794     */
795    /* if the change isn't worth it, don't bother */
796    /* was: if (osb == ose) */
797    if ((ose - osb) < MIN_END_KEEP) {
798        osb = ols;
799        ose = ols;
800        nsb = nls;
801        nse = nls;
802    }
803
804    /*
805     * Now that we are done with pragmatics we recompute fx, sx
806     */
807    fx = (int) ((nsb - nfd) - (osb - ofd));
808    sx = (int) ((nls - nse) - (ols - ose));
809
810#ifdef DEBUG_UPDATE
811    dprintf("\n");
812    dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
813            ofd - old, osb - old, ose - old, ols - old, oe - old);
814    dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
815            nfd - new, nsb - new, nse - new, nls - new, ne - new);
816    dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
817    dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
818    dprintstr("old- oe", old, oe);
819    dprintstr("new- ne", new, ne);
820    dprintstr("old-ofd", old, ofd);
821    dprintstr("new-nfd", new, nfd);
822    dprintstr("ofd-osb", ofd, osb);
823    dprintstr("nfd-nsb", nfd, nsb);
824    dprintstr("osb-ose", osb, ose);
825    dprintstr("nsb-nse", nsb, nse);
826    dprintstr("ose-ols", ose, ols);
827    dprintstr("nse-nls", nse, nls);
828    dprintstr("ols- oe", ols, oe);
829    dprintstr("nls- ne", nls, ne);
830#endif /* DEBUG_UPDATE */
831
832    /*
833     * CursorV to this line cur_line MUST be in this routine so that if we
834     * don't have to change the line, we don't move to it. CursorH to first
835     * diff char
836     */
837    MoveToLine(cur_line);
838
839    /*
840     * at this point we have something like this:
841     *
842     * /old                  /ofd    /osb               /ose    /ols     /oe
843     * v.....................v       v..................v       v........v
844     * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
845     * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
846     * ^.....................^     ^..................^       ^........^
847     * \new                  \nfd  \nsb               \nse     \nls    \ne
848     *
849     * fx is the difference in length between the the chars between nfd and
850     * nsb, and the chars between ofd and osb, and is thus the number of
851     * characters to delete if < 0 (new is shorter than old, as above),
852     * or insert (new is longer than short).
853     *
854     * sx is the same for the second differences.
855     */
856
857    /*
858     * if we have a net insert on the first difference, AND inserting the net
859     * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
860     * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
861     * (TermH - 1) else we do the deletes first so that we keep everything we
862     * need to.
863     */
864
865    /*
866     * if the last same is the same like the end, there is no last same part,
867     * otherwise we want to keep the last same part set p to the last useful
868     * old character
869     */
870    p = (ols != oe) ? oe : ose;
871
872    /*
873     * if (There is a diffence in the beginning) && (we need to insert
874     * characters) && (the number of characters to insert is less than the term
875     * width) We need to do an insert! else if (we need to delete characters)
876     * We need to delete characters! else No insert or delete
877     */
878    if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) {
879#ifdef DEBUG_UPDATE
880        dprintf("first diff insert at %d...\r\n", nfd - new);
881#endif  /* DEBUG_UPDATE */
882        /*
883         * Move to the first char to insert, where the first diff is.
884         */
885        MoveToChar(nfd - new);
886        /*
887         * Check if we have stuff to keep at end
888         */
889        if (nsb != ne) {
890#ifdef DEBUG_UPDATE
891            dprintf("with stuff to keep at end\r\n");
892#endif  /* DEBUG_UPDATE */
893            /*
894             * insert fx chars of new starting at nfd
895             */
896            if (fx > 0) {
897#ifdef DEBUG_UPDATE
898                if (!T_CanIns)
899                    dprintf("   ERROR: cannot insert in early first diff\n");
900#endif  /* DEBUG_UPDATE */
901                Insert_write(nfd, fx);
902                str_insert(old, (int) (ofd - old), TermH, nfd, fx);
903            }
904            /*
905             * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
906             */
907            so_write(nfd + fx, (nsb - nfd) - fx);
908            str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
909        }
910        else {
911#ifdef DEBUG_UPDATE
912            dprintf("without anything to save\r\n");
913#endif  /* DEBUG_UPDATE */
914            so_write(nfd, (nsb - nfd));
915            str_cp(ofd, nfd, (int) (nsb - nfd));
916            /*
917             * Done
918             */
919            return;
920        }
921    }
922    else if (fx < 0) {
923#ifdef DEBUG_UPDATE
924        dprintf("first diff delete at %d...\r\n", ofd - old);
925#endif  /* DEBUG_UPDATE */
926        /*
927         * move to the first char to delete where the first diff is
928         */
929        MoveToChar(ofd - old);
930        /*
931         * Check if we have stuff to save
932         */
933        if (osb != oe) {
934#ifdef DEBUG_UPDATE
935            dprintf("with stuff to save at end\r\n");
936#endif  /* DEBUG_UPDATE */
937            /*
938             * fx is less than zero *always* here but we check for code
939             * symmetry
940             */
941            if (fx < 0) {
942#ifdef DEBUG_UPDATE
943                if (!T_CanDel)
944                    dprintf("   ERROR: cannot delete in first diff\n");
945#endif /* DEBUG_UPDATE */
946                DeleteChars(-fx);
947                str_delete(old, (int) (ofd - old), TermH, -fx);
948            }
949            /*
950             * write (nsb-nfd) chars of new starting at nfd
951             */
952            so_write(nfd, (nsb - nfd));
953            str_cp(ofd, nfd, (int) (nsb - nfd));
954
955        }
956        else {
957#ifdef DEBUG_UPDATE
958            dprintf("but with nothing left to save\r\n");
959#endif  /* DEBUG_UPDATE */
960            /*
961             * write (nsb-nfd) chars of new starting at nfd
962             */
963            so_write(nfd, (nsb - nfd));
964#ifdef DEBUG_REFRESH
965            dprintf("cleareol %d\n", (oe - old) - (ne - new));
966#endif  /* DEBUG_UPDATE */
967#ifndef WINNT_NATIVE
968            ClearEOL((oe - old) - (ne - new));
969#else
970            /*
971             * The calculation above does not work too well on NT
972             */
973            ClearEOL(TermH - CursorH);
974#endif /*WINNT_NATIVE*/
975            /*
976             * Done
977             */
978            return;
979        }
980    }
981    else
982        fx = 0;
983
984    if (sx < 0) {
985#ifdef DEBUG_UPDATE
986        dprintf("second diff delete at %d...\r\n", (ose - old) + fx);
987#endif  /* DEBUG_UPDATE */
988        /*
989         * Check if we have stuff to delete
990         */
991        /*
992         * fx is the number of characters inserted (+) or deleted (-)
993         */
994
995        MoveToChar((ose - old) + fx);
996        /*
997         * Check if we have stuff to save
998         */
999        if (ols != oe) {
1000#ifdef DEBUG_UPDATE
1001            dprintf("with stuff to save at end\r\n");
1002#endif  /* DEBUG_UPDATE */
1003            /*
1004             * Again a duplicate test.
1005             */
1006            if (sx < 0) {
1007#ifdef DEBUG_UPDATE
1008                if (!T_CanDel)
1009                    dprintf("   ERROR: cannot delete in second diff\n");
1010#endif  /* DEBUG_UPDATE */
1011                DeleteChars(-sx);
1012            }
1013
1014            /*
1015             * write (nls-nse) chars of new starting at nse
1016             */
1017            so_write(nse, (nls - nse));
1018        }
1019        else {
1020            int olen = (int) (oe - old + fx);
1021            if (olen > TermH)
1022                olen = TermH;
1023#ifdef DEBUG_UPDATE
1024            dprintf("but with nothing left to save\r\n");
1025#endif /* DEBUG_UPDATE */
1026            so_write(nse, (nls - nse));
1027#ifdef DEBUG_REFRESH
1028            dprintf("cleareol %d\n", olen - (ne - new));
1029#endif /* DEBUG_UPDATE */
1030#ifndef WINNT_NATIVE
1031            ClearEOL(olen - (ne - new));
1032#else
1033            /*
1034             * The calculation above does not work too well on NT
1035             */
1036            ClearEOL(TermH - CursorH);
1037#endif /*WINNT_NATIVE*/
1038        }
1039    }
1040
1041    /*
1042     * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
1043     */
1044    if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
1045#ifdef DEBUG_UPDATE
1046        dprintf("late first diff insert at %d...\r\n", nfd - new);
1047#endif /* DEBUG_UPDATE */
1048
1049        MoveToChar(nfd - new);
1050        /*
1051         * Check if we have stuff to keep at the end
1052         */
1053        if (nsb != ne) {
1054#ifdef DEBUG_UPDATE
1055            dprintf("with stuff to keep at end\r\n");
1056#endif /* DEBUG_UPDATE */
1057            /*
1058             * We have to recalculate fx here because we set it
1059             * to zero above as a flag saying that we hadn't done
1060             * an early first insert.
1061             */
1062            fx = (int) ((nsb - nfd) - (osb - ofd));
1063            if (fx > 0) {
1064                /*
1065                 * insert fx chars of new starting at nfd
1066                 */
1067#ifdef DEBUG_UPDATE
1068                if (!T_CanIns)
1069                    dprintf("   ERROR: cannot insert in late first diff\n");
1070#endif /* DEBUG_UPDATE */
1071                Insert_write(nfd, fx);
1072                str_insert(old, (int) (ofd - old), TermH, nfd, fx);
1073            }
1074
1075            /*
1076             * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1077             */
1078            so_write(nfd + fx, (nsb - nfd) - fx);
1079            str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
1080        }
1081        else {
1082#ifdef DEBUG_UPDATE
1083            dprintf("without anything to save\r\n");
1084#endif /* DEBUG_UPDATE */
1085            so_write(nfd, (nsb - nfd));
1086            str_cp(ofd, nfd, (int) (nsb - nfd));
1087        }
1088    }
1089
1090    /*
1091     * line is now NEW up to nse
1092     */
1093    if (sx >= 0) {
1094#ifdef DEBUG_UPDATE
1095        dprintf("second diff insert at %d...\r\n", nse - new);
1096#endif /* DEBUG_UPDATE */
1097        MoveToChar(nse - new);
1098        if (ols != oe) {
1099#ifdef DEBUG_UPDATE
1100            dprintf("with stuff to keep at end\r\n");
1101#endif /* DEBUG_UPDATE */
1102            if (sx > 0) {
1103                /* insert sx chars of new starting at nse */
1104#ifdef DEBUG_UPDATE
1105                if (!T_CanIns)
1106                    dprintf("   ERROR: cannot insert in second diff\n");
1107#endif /* DEBUG_UPDATE */
1108                Insert_write(nse, sx);
1109            }
1110
1111            /*
1112             * write (nls-nse) - sx chars of new starting at (nse + sx)
1113             */
1114            so_write(nse + sx, (nls - nse) - sx);
1115        }
1116        else {
1117#ifdef DEBUG_UPDATE
1118            dprintf("without anything to save\r\n");
1119#endif /* DEBUG_UPDATE */
1120            so_write(nse, (nls - nse));
1121
1122            /*
1123             * No need to do a clear-to-end here because we were doing
1124             * a second insert, so we will have over written all of the
1125             * old string.
1126             */
1127        }
1128    }
1129#ifdef DEBUG_UPDATE
1130    dprintf("done.\r\n");
1131#endif /* DEBUG_UPDATE */
1132}
1133
1134
1135static void
1136cpy_pad_spaces(dst, src, width)
1137    Char *dst, *src;
1138    int width;
1139{
1140    int i;
1141
1142    for (i = 0; i < width; i++) {
1143        if (*src == (Char) 0)
1144            break;
1145        *dst++ = *src++;
1146    }
1147
1148    while (i < width) {
1149        *dst++ = ' ';
1150        i++;
1151    }
1152    *dst = (Char) 0;
1153}
1154
1155void
1156RefCursor()
1157{                               /* only move to new cursor pos */
1158    Char *cp;
1159    NLSChar c;
1160    int l, w, h, th, v;
1161
1162    /* first we must find where the cursor is... */
1163    h = 0;
1164    v = 0;
1165    th = TermH;                 /* optimize for speed */
1166
1167    for (cp = PromptBuf; *cp; ) {       /* do prompt */
1168        if (*cp & LITERAL) {
1169            cp++;
1170            continue;
1171        }
1172        l = NLSFrom(cp, NLSZEROT, &c);
1173        w = NLSClassify(c, cp == PromptBuf);
1174        cp += l;
1175        switch(w) {
1176            case NLSCLASS_NL:
1177                h = 0;
1178                v++;
1179                break;
1180            case NLSCLASS_TAB:
1181                while (++h & 07)
1182                    ;
1183                break;
1184            case NLSCLASS_CTRL:
1185                h += 2;
1186                break;
1187            case NLSCLASS_ILLEGAL:
1188                h += 4;
1189                break;
1190            case NLSCLASS_ILLEGAL2:
1191            case NLSCLASS_ILLEGAL3:
1192            case NLSCLASS_ILLEGAL4:
1193                h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1194                break;
1195            default:
1196                h += w;
1197        }
1198        if (h >= th) {          /* check, extra long tabs picked up here also */
1199            h -= th;
1200            v++;
1201        }
1202    }
1203
1204    for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */
1205        l = NLSFrom(cp, Cursor - cp, &c);
1206        w = NLSClassify(c, cp == InputBuf);
1207        cp += l;
1208        switch(w) {
1209            case NLSCLASS_NL:
1210                h = 0;
1211                v++;
1212                break;
1213            case NLSCLASS_TAB:
1214                while (++h & 07)
1215                    ;
1216                break;
1217            case NLSCLASS_CTRL:
1218                h += 2;
1219                break;
1220            case NLSCLASS_ILLEGAL:
1221                h += 4;
1222                break;
1223            case NLSCLASS_ILLEGAL2:
1224            case NLSCLASS_ILLEGAL3:
1225            case NLSCLASS_ILLEGAL4:
1226                h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1227                break;
1228            default:
1229                h += w;
1230        }
1231        if (h >= th) {          /* check, extra long tabs picked up here also */
1232            h -= th;
1233            v++;
1234        }
1235    }
1236
1237    /* now go there */
1238    MoveToLine(v);
1239    MoveToChar(h);
1240    flush();
1241}
1242
1243#ifndef WINTT_NATIVE
1244static void
1245PutPlusOne(c, width)
1246    Char   c;
1247    int    width;
1248{
1249    while (width > 1 && CursorH + width > TermH)
1250        PutPlusOne(' ', 1);
1251    if ((c & LITERAL) != 0) {
1252        Char *d;
1253        for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++)
1254            (void) putwraw(*d);
1255    } else {
1256        (void) putwraw(c);
1257    }
1258    Display[CursorV][CursorH++] = (Char) c;
1259    while (--width > 0)
1260        Display[CursorV][CursorH++] = CHAR_DBWIDTH;
1261    if (CursorH >= TermH) {     /* if we must overflow */
1262        CursorH = 0;
1263        CursorV++;
1264        OldvcV++;
1265        if (T_Margin & MARGIN_AUTO) {
1266            if (T_Margin & MARGIN_MAGIC) {
1267                (void) putraw(' ');
1268                (void) putraw('\b');
1269            }
1270        }
1271        else {
1272            (void) putraw('\r');
1273            (void) putraw('\n');
1274        }
1275    }
1276}
1277#endif
1278
1279void
1280RefPlusOne(int l)
1281{                               /* we added just one char, handle it fast.
1282                                 * assumes that screen cursor == real cursor */
1283    Char *cp;
1284    int w;
1285    NLSChar c;
1286
1287    if (Cursor != LastChar) {
1288        Refresh();              /* too hard to handle */
1289        return;
1290    }
1291    if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) {
1292        Refresh();              /* clear out rprompt if less than one char gap*/
1293        return;
1294    }
1295    cp = Cursor - l;
1296    NLSFrom(cp, (size_t)l, &c);
1297    w = NLSClassify(c, cp == InputBuf);
1298    switch(w) {
1299        case NLSCLASS_CTRL:
1300            PutPlusOne('^', 1);
1301            if (c == CTL_ESC('\177')) {
1302                PutPlusOne('?', 1);
1303                break;
1304            }
1305#ifdef IS_ASCII
1306            /* uncontrolify it; works only for iso8859-1 like sets */
1307            PutPlusOne((c | 0100), 1);
1308#else
1309            PutPlusOne(_toebcdic[_toascii[c]|0100], 1);
1310#endif
1311            break;
1312        case NLSCLASS_ILLEGAL:
1313            PutPlusOne('\\', 1);
1314            PutPlusOne(((c >> 6) & 7) + '0', 1);
1315            PutPlusOne(((c >> 3) & 7) + '0', 1);
1316            PutPlusOne((c & 7) + '0', 1);
1317            break;
1318        case 1:
1319            if (l > 1)
1320                PutPlusOne(MakeLiteral(cp, l, 0), 1);
1321            else
1322                PutPlusOne(*cp, 1);
1323            break;
1324        default:
1325            Refresh();          /* too hard to handle */
1326            return;
1327    }
1328    flush();
1329}
1330
1331/* clear the screen buffers so that new new prompt starts fresh. */
1332
1333void
1334ClearDisp()
1335{
1336    int i;
1337
1338    CursorV = 0;                /* clear the display buffer */
1339    CursorH = 0;
1340    for (i = 0; i < TermV; i++)
1341        (void) memset(Display[i], 0, TermH * sizeof(Display[0][0]));
1342    OldvcV = 0;
1343    litlen = 0;
1344}
1345
1346void
1347ClearLines()
1348{                               /* Make sure all lines are *really* blank */
1349    int i;
1350
1351    if (T_CanCEOL) {
1352        /*
1353         * Clear the lines from the bottom up so that if we try moving
1354         * the cursor down by writing the character that is at the end
1355         * of the screen line, we won't rewrite a character that shouldn't
1356         * be there.
1357         */
1358        for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */
1359            MoveToLine(i);
1360            MoveToChar(0);
1361            ClearEOL(TermH);
1362        }
1363    }
1364    else {
1365        MoveToLine(OldvcV);     /* go to last line */
1366        (void) putraw('\r');    /* go to BOL */
1367        (void) putraw('\n');    /* go to new line */
1368    }
1369}
Note: See TracBrowser for help on using the repository browser.