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

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