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