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

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