1 /* $Header: /src/pub/tcsh/ed.refresh.c,v 3.39 2005/02/15 21:09:02 christos Exp $ */
3 * ed.refresh.c: Lower level screen refreshing functions
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
35 RCSID("$Id: ed.refresh.c,v 3.39 2005/02/15 21:09:02 christos Exp $")
38 /* #define DEBUG_UPDATE */
39 /* #define DEBUG_REFRESH */
40 /* #define DEBUG_LITERAL */
42 /* refresh.c -- refresh the current set of lines on the screen */
45 static int vcursor_h, vcursor_v;
46 static int rprompt_h, rprompt_v;
48 static int MakeLiteral __P((Char *, int, Char));
49 static int Draw __P((Char *, int));
50 static void Vdraw __P((Char, int));
51 static void RefreshPromptpart __P((Char *));
52 static void update_line __P((Char *, Char *, int));
53 static void str_insert __P((Char *, int, int, Char *, int));
54 static void str_delete __P((Char *, int, int, int));
55 static void str_cp __P((Char *, Char *, int));
61 void PutPlusOne __P((Char, int));
62 static void cpy_pad_spaces __P((Char *, Char *, int));
63 #if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL)
64 static void dprintf __P((char *, ...));
66 static void dprintstr __P((char *, const Char *, const Char *));
73 dprintf("%s:\"", str);
76 dprintf("[%x]", *f++);
78 dprintf("%c", *f++ & ASCII);
82 #endif /* DEBUG_UPDATE */
85 * Print to $DEBUGTTY, so that we can test editing on one pty, and
86 * print debugging stuff on another. Don't interrupt the shell while
87 * debugging cause you'll mangle up the file descriptors!
91 dprintf(char *fmt, ...)
100 if ((dtty = getenv("DEBUGTTY"))) {
108 fmt = va_arg(va, char *);
109 #endif /* __STDC__ */
112 fd = open(dtty, O_RDWR);
122 #endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */
124 static int litlen = 0, litalloc = 0;
126 static int MakeLiteral(str, len, addlit)
131 int i, addlitlen = 0;
134 if ((addlit & LITERAL) != 0) {
135 addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
136 addlitlen = Strlen(addlitptr);
141 for (i = 0; i < litlen; i += LIT_FACTOR)
142 if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0)
143 return (i / LIT_FACTOR) | LITERAL;
146 for (i = 0; i < litlen; i += LIT_FACTOR)
147 if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0)
148 return (i / LIT_FACTOR) | LITERAL;
150 if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) {
153 while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add)
156 newlitptr = (Char *)xrealloc(litptr, (litalloc + add) * sizeof(Char));
158 newlitptr = (Char *)xmalloc((litalloc + add) * sizeof(Char));
163 if (addlitptr && addlitptr != &addlit)
164 addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
166 i = litlen / LIT_FACTOR;
167 if (i >= LITERAL || i == CHAR_DBWIDTH)
170 Strncpy(litptr + litlen, addlitptr, addlitlen);
173 Strncpy(litptr + litlen, str, len);
176 litptr[litlen++] = 0;
177 while (litlen % LIT_FACTOR);
182 Draw(cp, nocomb) /* draw char at cp, expand tabs, ctl chars */
191 l = NLSFrom(cp, NLSZEROT, &c);
192 w = NLSClassify(c, nocomb);
195 Vdraw('\0', 0); /* assure end of line */
196 vcursor_h = 0; /* reset cursor pos */
202 } while ((vcursor_h & 07) != 0);
205 Vdraw('^' | attr, 1);
206 if (c == CTL_ESC('\177')) {
207 Vdraw('?' | attr, 1);
210 /* uncontrolify it; works only for iso8859-1 like sets */
211 Vdraw(c | 0100 | attr, 1);
213 Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1);
217 case NLSCLASS_ILLEGAL:
219 Vdraw('\\' | attr, 1);
220 Vdraw((((ch >> 6) & 7) + '0') | attr, 1);
221 Vdraw((((ch >> 3) & 7) + '0') | attr, 1);
222 Vdraw(((ch & 7) + '0') | attr, 1);
224 case NLSCLASS_ILLEGAL2:
225 case NLSCLASS_ILLEGAL3:
226 case NLSCLASS_ILLEGAL4:
227 Vdraw('\\' | attr, 1);
228 Vdraw('U' | attr, 1);
229 Vdraw('+' | attr, 1);
230 for (i = 8 * NLSCLASS_ILLEGAL_SIZE(w) - 4; i >= 0; i -= 4)
231 Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1);
242 lh = Strlen(Vdisplay[lv]) - 1;
244 if (Vdisplay[lv][lh] != CHAR_DBWIDTH)
249 for (; l2-- > 0; cp++) {
251 Vdraw('\\' | attr, 1);
252 Vdraw((((ch >> 6) & 7) + '0') | attr, 1);
253 Vdraw((((ch >> 3) & 7) + '0') | attr, 1);
254 Vdraw(((ch & 7) + '0') | attr, 1);
258 Vdisplay[lv][lh] = MakeLiteral(cp, l, Vdisplay[lv][lh]);
262 Vdraw(MakeLiteral(cp, l, 0), w);
271 Vdraw(c, width) /* draw char c onto V lines */
276 # ifdef SHORT_STRINGS
277 dprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width);
279 dprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width);
280 # endif /* SHORT_STRNGS */
281 #endif /* DEBUG_REFRESH */
283 /* Hopefully this is what all the terminals do with multi-column characters
284 that "span line breaks". */
285 while (vcursor_h + width > TermH)
287 Vdisplay[vcursor_v][vcursor_h] = (Char) c;
289 vcursor_h++; /* advance to next place */
291 Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH;
292 if (vcursor_h >= TermH) {
293 Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */
294 vcursor_h = 0; /* reset it. */
297 if (vcursor_v >= TermV) { /* should NEVER happen. */
298 dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
302 #endif /* DEBUG_REFRESH */
307 * RefreshPromptpart()
308 * draws a prompt element, expanding literals (we know it's ASCIZ)
311 RefreshPromptpart(buf)
318 for (cp = buf; *cp; ) {
321 while (*cp & LITERAL)
324 l = NLSFrom(cp, NLSZEROT, &c);
326 Vdraw(MakeLiteral(litstart, cp + l - litstart, 0), w);
331 * XXX: This is a bug, we lose the last literal, if it is not
332 * followed by a normal character, but it is too hard to fix
338 cp += Draw(cp, cp == buf);
344 * draws the new virtual screen image from the current input
345 * line, then goes line-by-line changing the real image to the new
346 * virtual image. The routine to re-draw a line can be replaced
347 * easily in hopes of a smarter one being placed there.
359 int cur_h, cur_v = 0, new_vcv;
364 dprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf));
365 dprintf("InputBuf = :%s:\r\n", short2str(InputBuf));
366 #endif /* DEBUG_REFRESH */
367 oldgetting = GettingInput;
368 GettingInput = 0; /* avoid re-entrance via SIGWINCH */
370 /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
373 RefreshPromptpart(RPromptBuf);
374 rprompt_h = vcursor_h;
375 rprompt_v = vcursor_v;
377 /* reset the Vdraw cursor, draw prompt */
380 RefreshPromptpart(PromptBuf);
381 cur_h = -1; /* set flag in case I'm not set */
383 /* draw the current input buffer */
384 for (cp = InputBuf; (cp < LastChar); ) {
385 if (cp >= Cursor && cur_h == -1) {
386 cur_h = vcursor_h; /* save for later */
390 cp += Draw(cp, cp == InputBuf);
393 if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */
398 rhdiff = TermH - vcursor_h - rprompt_h;
399 if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) {
401 * have a right-hand side prompt that will fit on
402 * the end of the first line with at least one
403 * character gap to the input buffer.
405 while (--rhdiff > 0) /* pad out with spaces */
407 RefreshPromptpart(RPromptBuf);
410 rprompt_h = 0; /* flag "not using rprompt" */
414 new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */
415 Vdraw('\0', 1); /* put NUL on end */
417 #if defined (DEBUG_REFRESH)
418 dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
419 TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0]));
420 #endif /* DEBUG_REFRESH */
423 dprintf("updating %d lines.\r\n", new_vcv);
424 #endif /* DEBUG_UPDATE */
425 for (cur_line = 0; cur_line <= new_vcv; cur_line++) {
426 /* NOTE THAT update_line MAY CHANGE Display[cur_line] */
427 update_line(Display[cur_line], Vdisplay[cur_line], cur_line);
430 #endif /* WINNT_NATIVE */
433 * Copy the new line to be the current one, and pad out with spaces
434 * to the full width of the terminal so that if we try moving the
435 * cursor by writing the character that is at the end of the
436 * screen line, it won't be a NUL or some old leftover stuff.
438 cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH);
441 dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
442 vcursor_v, OldvcV, cur_line);
443 #endif /* DEBUG_REFRESH */
444 if (OldvcV > new_vcv) {
445 for (; cur_line <= OldvcV; cur_line++) {
446 update_line(Display[cur_line], STRNULL, cur_line);
447 *Display[cur_line] = '\0';
450 OldvcV = new_vcv; /* set for next time */
452 dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
453 CursorH, CursorV, cur_h, cur_v);
454 #endif /* DEBUG_REFRESH */
457 #endif /* WINNT_NATIVE */
458 MoveToLine(cur_v); /* go to where the cursor is */
460 SetAttributes(0); /* Clear all attributes */
461 flush(); /* send the output... */
462 GettingInput = oldgetting; /* reset to old value */
467 { /* used to go to last used screen line */
475 { /* used to go to last used screen line */
484 /* insert num characters of s into d (in front of the character) at dat,
485 maximum length of d is dlen */
487 str_insert(d, dat, dlen, s, num)
497 if (num > dlen - dat)
501 dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
502 num, dat, dlen, short2str(d));
503 dprintf("s == \"%s\"n", short2str(s));
504 #endif /* DEBUG_REFRESH */
506 /* open up the space for num chars */
512 d[dlen] = '\0'; /* just in case */
515 dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
516 num, dat, dlen, short2str(d));
517 dprintf("s == \"%s\"n", short2str(s));
518 #endif /* DEBUG_REFRESH */
520 /* copy the characters */
521 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
525 dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
526 num, dat, dlen, d, short2str(s));
527 dprintf("s == \"%s\"n", short2str(s));
528 #endif /* DEBUG_REFRESH */
531 /* delete num characters d at dat, maximum length of d is dlen */
533 str_delete(d, dat, dlen, num)
541 if (dat + num >= dlen) {
547 dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
548 num, dat, dlen, short2str(d));
549 #endif /* DEBUG_REFRESH */
551 /* open up the space for num chars */
557 d[dlen] = '\0'; /* just in case */
560 dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
561 num, dat, dlen, short2str(d));
562 #endif /* DEBUG_REFRESH */
575 /* ****************************************************************
576 update_line() is based on finding the middle difference of each line
579 /old first difference
580 /beginning of line | /old last same /old EOL
582 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
583 new: eddie> Oh, my little buggy says to me, as lurgid as
585 \beginning of line | \new last same \new end of line
586 \new first difference
588 all are character pointers for the sake of speed. Special cases for
589 no differences, as well as for end of line additions must be handled.
590 **************************************************************** */
592 /* Minimum at which doing an insert it "worth it". This should be about
593 * half the "cost" of going into insert mode, inserting a character, and
594 * going back out. This should really be calculated from the termcap
595 * data... For the moment, a good number for ANSI terminals.
597 #define MIN_END_KEEP 4
599 static void /* could be changed to make it smarter */
600 update_line(old, new, cur_line)
605 Char *ofd, *ols, *oe, *nfd, *nls, *ne;
606 Char *osb, *ose, *nsb, *nse;
610 * find first diff (won't be CHAR_DBWIDTH in either line)
612 for (o = old, n = new; *o && (*o == *n); o++, n++)
618 * Find the end of both old and new
623 * Remove any trailing blanks off of the end, being careful not to
624 * back up past the beginning.
637 /* remove blanks from end of new */
647 * if no diff, continue to next line of redraw
649 if (*ofd == '\0' && *nfd == '\0') {
651 dprintf("no difference.\r\n");
652 #endif /* DEBUG_UPDATE */
657 * find last same pointer
659 while ((o > ofd) && (n > nfd) && (*--o == *--n))
665 while (*o == CHAR_DBWIDTH) {
673 * find same begining and same end
681 * case 1: insert: scan from nfd to nls looking for *ofd
684 for (c = *ofd, n = nfd; n < nls; n++) {
686 for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
689 * if the new match is longer and it's worth keeping, then we
692 if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
703 * case 2: delete: scan from ofd to ols looking for *nfd
706 for (c = *nfd, o = ofd; o < ols; o++) {
708 for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
711 * if the new match is longer and it's worth keeping, then we
714 if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
725 * If `last same' is before `same end' re-adjust
734 * Pragmatics I: If old trailing whitespace or not enough characters to
735 * save to be worth it, then don't save the last same info.
737 if ((oe - ols) < MIN_END_KEEP) {
743 * Pragmatics II: if the terminal isn't smart enough, make the data dumber
744 * so the smart update doesn't try anything fancy
748 * fx is the number of characters we need to insert/delete: in the
749 * beginning to bring the two same begins together
751 fx = (int) ((nsb - nfd) - (osb - ofd));
753 * sx is the number of characters we need to insert/delete: in the end to
754 * bring the two same last parts together
756 sx = (int) ((nls - nse) - (ols - ose));
769 if ((ols - ofd) < (nls - nfd)) {
785 if ((ols - ofd) > (nls - nfd)) {
792 * Pragmatics III: make sure the middle shifted pointers are correct if
793 * they don't point to anything (we may have moved ols or nls).
795 /* if the change isn't worth it, don't bother */
796 /* was: if (osb == ose) */
797 if ((ose - osb) < MIN_END_KEEP) {
805 * Now that we are done with pragmatics we recompute fx, sx
807 fx = (int) ((nsb - nfd) - (osb - ofd));
808 sx = (int) ((nls - nse) - (ols - ose));
812 dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
813 ofd - old, osb - old, ose - old, ols - old, oe - old);
814 dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
815 nfd - new, nsb - new, nse - new, nls - new, ne - new);
816 dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
817 dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
818 dprintstr("old- oe", old, oe);
819 dprintstr("new- ne", new, ne);
820 dprintstr("old-ofd", old, ofd);
821 dprintstr("new-nfd", new, nfd);
822 dprintstr("ofd-osb", ofd, osb);
823 dprintstr("nfd-nsb", nfd, nsb);
824 dprintstr("osb-ose", osb, ose);
825 dprintstr("nsb-nse", nsb, nse);
826 dprintstr("ose-ols", ose, ols);
827 dprintstr("nse-nls", nse, nls);
828 dprintstr("ols- oe", ols, oe);
829 dprintstr("nls- ne", nls, ne);
830 #endif /* DEBUG_UPDATE */
833 * CursorV to this line cur_line MUST be in this routine so that if we
834 * don't have to change the line, we don't move to it. CursorH to first
837 MoveToLine(cur_line);
840 * at this point we have something like this:
842 * /old /ofd /osb /ose /ols /oe
843 * v.....................v v..................v v........v
844 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
845 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
846 * ^.....................^ ^..................^ ^........^
847 * \new \nfd \nsb \nse \nls \ne
849 * fx is the difference in length between the the chars between nfd and
850 * nsb, and the chars between ofd and osb, and is thus the number of
851 * characters to delete if < 0 (new is shorter than old, as above),
852 * or insert (new is longer than short).
854 * sx is the same for the second differences.
858 * if we have a net insert on the first difference, AND inserting the net
859 * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
860 * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
861 * (TermH - 1) else we do the deletes first so that we keep everything we
866 * if the last same is the same like the end, there is no last same part,
867 * otherwise we want to keep the last same part set p to the last useful
870 p = (ols != oe) ? oe : ose;
873 * if (There is a diffence in the beginning) && (we need to insert
874 * characters) && (the number of characters to insert is less than the term
875 * width) We need to do an insert! else if (we need to delete characters)
876 * We need to delete characters! else No insert or delete
878 if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) {
880 dprintf("first diff insert at %d...\r\n", nfd - new);
881 #endif /* DEBUG_UPDATE */
883 * Move to the first char to insert, where the first diff is.
885 MoveToChar(nfd - new);
887 * Check if we have stuff to keep at end
891 dprintf("with stuff to keep at end\r\n");
892 #endif /* DEBUG_UPDATE */
894 * insert fx chars of new starting at nfd
899 dprintf(" ERROR: cannot insert in early first diff\n");
900 #endif /* DEBUG_UPDATE */
901 Insert_write(nfd, fx);
902 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
905 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
907 so_write(nfd + fx, (nsb - nfd) - fx);
908 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
912 dprintf("without anything to save\r\n");
913 #endif /* DEBUG_UPDATE */
914 so_write(nfd, (nsb - nfd));
915 str_cp(ofd, nfd, (int) (nsb - nfd));
924 dprintf("first diff delete at %d...\r\n", ofd - old);
925 #endif /* DEBUG_UPDATE */
927 * move to the first char to delete where the first diff is
929 MoveToChar(ofd - old);
931 * Check if we have stuff to save
935 dprintf("with stuff to save at end\r\n");
936 #endif /* DEBUG_UPDATE */
938 * fx is less than zero *always* here but we check for code
944 dprintf(" ERROR: cannot delete in first diff\n");
945 #endif /* DEBUG_UPDATE */
947 str_delete(old, (int) (ofd - old), TermH, -fx);
950 * write (nsb-nfd) chars of new starting at nfd
952 so_write(nfd, (nsb - nfd));
953 str_cp(ofd, nfd, (int) (nsb - nfd));
958 dprintf("but with nothing left to save\r\n");
959 #endif /* DEBUG_UPDATE */
961 * write (nsb-nfd) chars of new starting at nfd
963 so_write(nfd, (nsb - nfd));
965 dprintf("cleareol %d\n", (oe - old) - (ne - new));
966 #endif /* DEBUG_UPDATE */
968 ClearEOL((oe - old) - (ne - new));
971 * The calculation above does not work too well on NT
973 ClearEOL(TermH - CursorH);
974 #endif /*WINNT_NATIVE*/
986 dprintf("second diff delete at %d...\r\n", (ose - old) + fx);
987 #endif /* DEBUG_UPDATE */
989 * Check if we have stuff to delete
992 * fx is the number of characters inserted (+) or deleted (-)
995 MoveToChar((ose - old) + fx);
997 * Check if we have stuff to save
1001 dprintf("with stuff to save at end\r\n");
1002 #endif /* DEBUG_UPDATE */
1004 * Again a duplicate test.
1009 dprintf(" ERROR: cannot delete in second diff\n");
1010 #endif /* DEBUG_UPDATE */
1015 * write (nls-nse) chars of new starting at nse
1017 so_write(nse, (nls - nse));
1020 int olen = (int) (oe - old + fx);
1024 dprintf("but with nothing left to save\r\n");
1025 #endif /* DEBUG_UPDATE */
1026 so_write(nse, (nls - nse));
1027 #ifdef DEBUG_REFRESH
1028 dprintf("cleareol %d\n", olen - (ne - new));
1029 #endif /* DEBUG_UPDATE */
1030 #ifndef WINNT_NATIVE
1031 ClearEOL(olen - (ne - new));
1034 * The calculation above does not work too well on NT
1036 ClearEOL(TermH - CursorH);
1037 #endif /*WINNT_NATIVE*/
1042 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
1044 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
1046 dprintf("late first diff insert at %d...\r\n", nfd - new);
1047 #endif /* DEBUG_UPDATE */
1049 MoveToChar(nfd - new);
1051 * Check if we have stuff to keep at the end
1055 dprintf("with stuff to keep at end\r\n");
1056 #endif /* DEBUG_UPDATE */
1058 * We have to recalculate fx here because we set it
1059 * to zero above as a flag saying that we hadn't done
1060 * an early first insert.
1062 fx = (int) ((nsb - nfd) - (osb - ofd));
1065 * insert fx chars of new starting at nfd
1069 dprintf(" ERROR: cannot insert in late first diff\n");
1070 #endif /* DEBUG_UPDATE */
1071 Insert_write(nfd, fx);
1072 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
1076 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1078 so_write(nfd + fx, (nsb - nfd) - fx);
1079 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
1083 dprintf("without anything to save\r\n");
1084 #endif /* DEBUG_UPDATE */
1085 so_write(nfd, (nsb - nfd));
1086 str_cp(ofd, nfd, (int) (nsb - nfd));
1091 * line is now NEW up to nse
1095 dprintf("second diff insert at %d...\r\n", nse - new);
1096 #endif /* DEBUG_UPDATE */
1097 MoveToChar(nse - new);
1100 dprintf("with stuff to keep at end\r\n");
1101 #endif /* DEBUG_UPDATE */
1103 /* insert sx chars of new starting at nse */
1106 dprintf(" ERROR: cannot insert in second diff\n");
1107 #endif /* DEBUG_UPDATE */
1108 Insert_write(nse, sx);
1112 * write (nls-nse) - sx chars of new starting at (nse + sx)
1114 so_write(nse + sx, (nls - nse) - sx);
1118 dprintf("without anything to save\r\n");
1119 #endif /* DEBUG_UPDATE */
1120 so_write(nse, (nls - nse));
1123 * No need to do a clear-to-end here because we were doing
1124 * a second insert, so we will have over written all of the
1130 dprintf("done.\r\n");
1131 #endif /* DEBUG_UPDATE */
1136 cpy_pad_spaces(dst, src, width)
1142 for (i = 0; i < width; i++) {
1143 if (*src == (Char) 0)
1157 { /* only move to new cursor pos */
1162 /* first we must find where the cursor is... */
1165 th = TermH; /* optimize for speed */
1167 for (cp = PromptBuf; *cp; ) { /* do prompt */
1168 if (*cp & LITERAL) {
1172 l = NLSFrom(cp, NLSZEROT, &c);
1173 w = NLSClassify(c, cp == PromptBuf);
1187 case NLSCLASS_ILLEGAL:
1190 case NLSCLASS_ILLEGAL2:
1191 case NLSCLASS_ILLEGAL3:
1192 case NLSCLASS_ILLEGAL4:
1193 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1198 if (h >= th) { /* check, extra long tabs picked up here also */
1204 for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */
1205 l = NLSFrom(cp, Cursor - cp, &c);
1206 w = NLSClassify(c, cp == InputBuf);
1220 case NLSCLASS_ILLEGAL:
1223 case NLSCLASS_ILLEGAL2:
1224 case NLSCLASS_ILLEGAL3:
1225 case NLSCLASS_ILLEGAL4:
1226 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1231 if (h >= th) { /* check, extra long tabs picked up here also */
1243 #ifndef WINTT_NATIVE
1245 PutPlusOne(c, width)
1249 while (width > 1 && CursorH + width > TermH)
1251 if ((c & LITERAL) != 0) {
1253 for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++)
1258 Display[CursorV][CursorH++] = (Char) c;
1260 Display[CursorV][CursorH++] = CHAR_DBWIDTH;
1261 if (CursorH >= TermH) { /* if we must overflow */
1265 if (T_Margin & MARGIN_AUTO) {
1266 if (T_Margin & MARGIN_MAGIC) {
1268 (void) putraw('\b');
1272 (void) putraw('\r');
1273 (void) putraw('\n');
1281 { /* we added just one char, handle it fast.
1282 * assumes that screen cursor == real cursor */
1287 if (Cursor != LastChar) {
1288 Refresh(); /* too hard to handle */
1291 if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) {
1292 Refresh(); /* clear out rprompt if less than one char gap*/
1296 NLSFrom(cp, (size_t)l, &c);
1297 w = NLSClassify(c, cp == InputBuf);
1301 if (c == CTL_ESC('\177')) {
1306 /* uncontrolify it; works only for iso8859-1 like sets */
1307 PutPlusOne((c | 0100), 1);
1309 PutPlusOne(_toebcdic[_toascii[c]|0100], 1);
1312 case NLSCLASS_ILLEGAL:
1313 PutPlusOne('\\', 1);
1314 PutPlusOne(((c >> 6) & 7) + '0', 1);
1315 PutPlusOne(((c >> 3) & 7) + '0', 1);
1316 PutPlusOne((c & 7) + '0', 1);
1320 PutPlusOne(MakeLiteral(cp, l, 0), 1);
1325 Refresh(); /* too hard to handle */
1331 /* clear the screen buffers so that new new prompt starts fresh. */
1338 CursorV = 0; /* clear the display buffer */
1340 for (i = 0; i < TermV; i++)
1341 (void) memset(Display[i], 0, TermH * sizeof(Display[0][0]));
1348 { /* Make sure all lines are *really* blank */
1353 * Clear the lines from the bottom up so that if we try moving
1354 * the cursor down by writing the character that is at the end
1355 * of the screen line, we won't rewrite a character that shouldn't
1358 for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */
1365 MoveToLine(OldvcV); /* go to last line */
1366 (void) putraw('\r'); /* go to BOL */
1367 (void) putraw('\n'); /* go to new line */