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