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