2 * ed.refresh.c: Lower level screen refreshing functions
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 /* #define DEBUG_UPDATE */
35 /* #define DEBUG_REFRESH */
36 /* #define DEBUG_LITERAL */
38 /* refresh.c -- refresh the current set of lines on the screen */
41 static int vcursor_h, vcursor_v;
42 static int rprompt_h, rprompt_v;
44 static int MakeLiteral (Char *, int, Char);
45 static int Draw (Char *, int, int);
46 static void Vdraw (Char, int);
47 static void RefreshPromptpart (Char *);
48 static void update_line (Char *, Char *, int);
49 static void str_insert (Char *, int, int, Char *, int);
50 static void str_delete (Char *, int, int, int);
51 static void str_cp (Char *, Char *, int);
57 void PutPlusOne (Char, int);
58 static void cpy_pad_spaces (Char *, Char *, int);
59 #if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL)
60 static void reprintf (char *, ...);
62 static void dprintstr (char *, const Char *, const Char *);
65 dprintstr(char *str, const Char *f, const Char *t)
67 reprintf("%s:\"", str);
70 reprintf("[%x]", *f++);
72 reprintf("%c", CTL_ESC(ASCII & ASC(*f++)));
76 #endif /* DEBUG_UPDATE */
79 * Print to $DEBUGTTY, so that we can test editing on one pty, and
80 * print debugging stuff on another. Don't interrupt the shell while
81 * debugging cause you'll mangle up the file descriptors!
84 reprintf(char *fmt, ...)
89 if ((dtty = getenv("DEBUGTTY"))) {
95 fd = xopen(dtty, O_RDWR);
105 #endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */
107 static int litlen = 0, litalloc = 0;
109 static int MakeLiteral(Char *str, int len, Char addlit)
111 int i, addlitlen = 0;
114 if ((addlit & LITERAL) != 0) {
115 addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
116 addlitlen = Strlen(addlitptr);
121 for (i = 0; i < litlen; i += LIT_FACTOR)
122 if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0)
123 return (i / LIT_FACTOR) | LITERAL;
126 for (i = 0; i < litlen; i += LIT_FACTOR)
127 if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0)
128 return (i / LIT_FACTOR) | LITERAL;
130 if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) {
133 while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add)
135 newlitptr = xrealloc(litptr, (litalloc + add) * sizeof(Char));
140 if (addlitptr && addlitptr != &addlit)
141 addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
143 i = litlen / LIT_FACTOR;
144 if (i >= LITERAL || i == CHAR_DBWIDTH)
147 Strncpy(litptr + litlen, addlitptr, addlitlen);
150 Strncpy(litptr + litlen, str, len);
153 litptr[litlen++] = 0;
154 while (litlen % LIT_FACTOR);
158 /* draw char at cp, expand tabs, ctl chars */
160 Draw(Char *cp, int nocomb, int drawPrompt)
166 if (!drawPrompt) { /* draw command-line */
169 } else { /* draw prompt */
170 /* prompt with attributes(UNDER,BOLD,STANDOUT) */
171 if (*cp & (UNDER | BOLD | STANDOUT)) { /* *cp >= STANDOUT */
174 * We can't distinguish whether (*cp=)0x02ffffff is
175 * U+02FFFFFF or U+00FFFFFF|STANDOUT.
176 * We handle as U+00FFFFFF|STANDOUT, only when drawing prompt. */
177 attr = (*cp & ATTRIBUTES);
178 /* ~(UNDER | BOLD | STANDOUT) = 0xf1ffffff */
179 c = *cp & ~(UNDER | BOLD | STANDOUT);
181 /* if c is ctrl code, we handle *cp as havnig no attributes */
182 if ((c < 0x20 && c >= 0) || c == 0x7f) {
186 } else { /* prompt without attributes */
195 w = NLSClassify(c, nocomb, drawPrompt);
198 Vdraw('\0', 0); /* assure end of line */
199 vcursor_h = 0; /* reset cursor pos */
205 } while ((vcursor_h & 07) != 0);
208 Vdraw('^' | attr, 1);
209 if (c == CTL_ESC('\177')) {
210 Vdraw('?' | attr, 1);
213 /* uncontrolify it; works only for iso8859-1 like sets */
214 Vdraw(c | 0100 | attr, 1);
216 Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1);
220 case NLSCLASS_ILLEGAL:
221 Vdraw('\\' | attr, 1);
222 Vdraw((((c >> 6) & 7) + '0') | attr, 1);
223 Vdraw((((c >> 3) & 7) + '0') | attr, 1);
224 Vdraw(((c & 7) + '0') | attr, 1);
226 case NLSCLASS_ILLEGAL2:
227 case NLSCLASS_ILLEGAL3:
228 case NLSCLASS_ILLEGAL4:
229 case NLSCLASS_ILLEGAL5:
233 for (i = 16 + 4 * (-w-5); i >= 0; i -= 4)
234 Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1);
245 lh = Strlen(Vdisplay[lv]) - 1;
247 if (Vdisplay[lv][lh] != CHAR_DBWIDTH)
251 Vdraw('\\' | attr, 1);
252 Vdraw((((c >> 6) & 7) + '0') | attr, 1);
253 Vdraw((((c >> 3) & 7) + '0') | attr, 1);
254 Vdraw(((c & 7) + '0') | attr, 1);
257 Vdisplay[lv][lh] = MakeLiteral(cp, 1, Vdisplay[lv][lh]);
267 Vdraw(Char c, int width) /* draw char c onto V lines */
270 # ifdef SHORT_STRINGS
271 reprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width);
273 reprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width);
274 # endif /* SHORT_STRNGS */
275 #endif /* DEBUG_REFRESH */
277 /* Hopefully this is what all the terminals do with multi-column characters
278 that "span line breaks". */
279 while (vcursor_h + width > TermH)
281 Vdisplay[vcursor_v][vcursor_h] = c;
283 vcursor_h++; /* advance to next place */
285 Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH;
286 if (vcursor_h >= TermH) {
287 Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */
288 vcursor_h = 0; /* reset it. */
291 if (vcursor_v >= TermV) { /* should NEVER happen. */
292 reprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
296 #endif /* DEBUG_REFRESH */
301 * RefreshPromptpart()
302 * draws a prompt element, expanding literals (we know it's ASCIZ)
305 RefreshPromptpart(Char *buf)
312 for (cp = buf; *cp; ) {
315 while (*cp & LITERAL)
318 w = NLSWidth(*cp & CHAR);
319 Vdraw(MakeLiteral(litstart, cp + 1 - litstart, 0), w);
324 * XXX: This is a bug, we lose the last literal, if it is not
325 * followed by a normal character, but it is too hard to fix
331 cp += Draw(cp, cp == buf, 1);
337 * draws the new virtual screen image from the current input
338 * line, then goes line-by-line changing the real image to the new
339 * virtual image. The routine to re-draw a line can be replaced
340 * easily in hopes of a smarter one being placed there.
352 int cur_h, cur_v = 0, new_vcv;
357 reprintf("Prompt = :%s:\r\n", short2str(Prompt));
358 reprintf("InputBuf = :%s:\r\n", short2str(InputBuf));
359 #endif /* DEBUG_REFRESH */
360 oldgetting = GettingInput;
361 GettingInput = 0; /* avoid re-entrance via SIGWINCH */
363 /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
366 RefreshPromptpart(RPrompt);
367 rprompt_h = vcursor_h;
368 rprompt_v = vcursor_v;
370 /* reset the Vdraw cursor, draw prompt */
373 RefreshPromptpart(Prompt);
374 cur_h = -1; /* set flag in case I'm not set */
376 /* draw the current input buffer */
377 for (cp = InputBuf; (cp < LastChar); ) {
378 if (cp >= Cursor && cur_h == -1) {
379 cur_h = vcursor_h; /* save for later */
383 cp += Draw(cp, cp == InputBuf, 0);
386 if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */
391 rhdiff = TermH - vcursor_h - rprompt_h;
392 if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) {
394 * have a right-hand side prompt that will fit on
395 * the end of the first line with at least one
396 * character gap to the input buffer.
398 while (--rhdiff > 0) /* pad out with spaces */
400 RefreshPromptpart(RPrompt);
403 rprompt_h = 0; /* flag "not using rprompt" */
407 new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */
408 Vdraw('\0', 1); /* put NUL on end */
410 #if defined (DEBUG_REFRESH)
411 reprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
412 TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0]));
413 #endif /* DEBUG_REFRESH */
416 reprintf("updating %d lines.\r\n", new_vcv);
417 #endif /* DEBUG_UPDATE */
418 for (cur_line = 0; cur_line <= new_vcv; cur_line++) {
419 /* NOTE THAT update_line MAY CHANGE Display[cur_line] */
420 update_line(Display[cur_line], Vdisplay[cur_line], cur_line);
423 #endif /* WINNT_NATIVE */
426 * Copy the new line to be the current one, and pad out with spaces
427 * to the full width of the terminal so that if we try moving the
428 * cursor by writing the character that is at the end of the
429 * screen line, it won't be a NUL or some old leftover stuff.
431 cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH);
434 reprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
435 vcursor_v, OldvcV, cur_line);
436 #endif /* DEBUG_REFRESH */
437 if (OldvcV > new_vcv) {
438 for (; cur_line <= OldvcV; cur_line++) {
439 update_line(Display[cur_line], STRNULL, cur_line);
440 *Display[cur_line] = '\0';
443 OldvcV = new_vcv; /* set for next time */
445 reprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
446 CursorH, CursorV, cur_h, cur_v);
447 #endif /* DEBUG_REFRESH */
450 #endif /* WINNT_NATIVE */
451 MoveToLine(cur_v); /* go to where the cursor is */
453 SetAttributes(0); /* Clear all attributes */
454 flush(); /* send the output... */
455 GettingInput = oldgetting; /* reset to old value */
460 { /* used to go to last used screen line */
468 { /* used to go to last used screen line */
477 /* insert num characters of s into d (in front of the character) at dat,
478 maximum length of d is dlen */
480 str_insert(Char *d, int dat, int dlen, Char *s, int num)
486 if (num > dlen - dat)
490 reprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
491 num, dat, dlen, short2str(d));
492 reprintf("s == \"%s\"n", short2str(s));
493 #endif /* DEBUG_REFRESH */
495 /* open up the space for num chars */
501 d[dlen] = '\0'; /* just in case */
504 reprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
505 num, dat, dlen, short2str(d));
506 reprintf("s == \"%s\"n", short2str(s));
507 #endif /* DEBUG_REFRESH */
509 /* copy the characters */
510 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
514 reprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
515 num, dat, dlen, d, short2str(s));
516 reprintf("s == \"%s\"n", short2str(s));
517 #endif /* DEBUG_REFRESH */
520 /* delete num characters d at dat, maximum length of d is dlen */
522 str_delete(Char *d, int dat, int dlen, int num)
528 if (dat + num >= dlen) {
534 reprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
535 num, dat, dlen, short2str(d));
536 #endif /* DEBUG_REFRESH */
538 /* open up the space for num chars */
544 d[dlen] = '\0'; /* just in case */
547 reprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
548 num, dat, dlen, short2str(d));
549 #endif /* DEBUG_REFRESH */
553 str_cp(Char *a, Char *b, int n)
560 /* ****************************************************************
561 update_line() is based on finding the middle difference of each line
564 /old first difference
565 /beginning of line | /old last same /old EOL
567 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
568 new: eddie> Oh, my little buggy says to me, as lurgid as
570 \beginning of line | \new last same \new end of line
571 \new first difference
573 all are character pointers for the sake of speed. Special cases for
574 no differences, as well as for end of line additions must be handled.
575 **************************************************************** */
577 /* Minimum at which doing an insert it "worth it". This should be about
578 * half the "cost" of going into insert mode, inserting a character, and
579 * going back out. This should really be calculated from the termcap
580 * data... For the moment, a good number for ANSI terminals.
582 #define MIN_END_KEEP 4
584 static void /* could be changed to make it smarter */
585 update_line(Char *old, Char *new, int cur_line)
588 Char *ofd, *ols, *oe, *nfd, *nls, *ne;
589 Char *osb, *ose, *nsb, *nse;
593 * find first diff (won't be CHAR_DBWIDTH in either line)
595 for (o = old, n = new; *o && (*o == *n); o++, n++)
601 * Find the end of both old and new
606 * Remove any trailing blanks off of the end, being careful not to
607 * back up past the beginning.
609 if (!(adrof(STRhighlight) && MarkIsSet)) {
621 /* remove blanks from end of new */
622 if (!(adrof(STRhighlight) && MarkIsSet)) {
633 * if no diff, continue to next line of redraw
635 if (*ofd == '\0' && *nfd == '\0') {
637 reprintf("no difference.\r\n");
638 #endif /* DEBUG_UPDATE */
643 * find last same pointer
645 while ((o > ofd) && (n > nfd) && (*--o == *--n))
651 while (*o == CHAR_DBWIDTH) {
659 * find same begining and same end
667 * case 1: insert: scan from nfd to nls looking for *ofd
670 for (c = *ofd, n = nfd; n < nls; n++) {
672 for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
675 * if the new match is longer and it's worth keeping, then we
678 if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
689 * case 2: delete: scan from ofd to ols looking for *nfd
692 for (c = *nfd, o = ofd; o < ols; o++) {
694 for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
697 * if the new match is longer and it's worth keeping, then we
700 if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
711 * If `last same' is before `same end' re-adjust
720 * Pragmatics I: If old trailing whitespace or not enough characters to
721 * save to be worth it, then don't save the last same info.
723 if ((oe - ols) < MIN_END_KEEP) {
729 * Pragmatics II: if the terminal isn't smart enough, make the data dumber
730 * so the smart update doesn't try anything fancy
734 * fx is the number of characters we need to insert/delete: in the
735 * beginning to bring the two same begins together
737 fx = (int) ((nsb - nfd) - (osb - ofd));
739 * sx is the number of characters we need to insert/delete: in the end to
740 * bring the two same last parts together
742 sx = (int) ((nls - nse) - (ols - ose));
755 if ((ols - ofd) < (nls - nfd)) {
771 if ((ols - ofd) > (nls - nfd)) {
778 * Pragmatics III: make sure the middle shifted pointers are correct if
779 * they don't point to anything (we may have moved ols or nls).
781 /* if the change isn't worth it, don't bother */
782 /* was: if (osb == ose) */
783 if ((ose - osb) < MIN_END_KEEP) {
791 * Now that we are done with pragmatics we recompute fx, sx
793 fx = (int) ((nsb - nfd) - (osb - ofd));
794 sx = (int) ((nls - nse) - (ols - ose));
798 reprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
799 ofd - old, osb - old, ose - old, ols - old, oe - old);
800 reprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
801 nfd - new, nsb - new, nse - new, nls - new, ne - new);
802 reprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
803 reprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
804 dprintstr("old- oe", old, oe);
805 dprintstr("new- ne", new, ne);
806 dprintstr("old-ofd", old, ofd);
807 dprintstr("new-nfd", new, nfd);
808 dprintstr("ofd-osb", ofd, osb);
809 dprintstr("nfd-nsb", nfd, nsb);
810 dprintstr("osb-ose", osb, ose);
811 dprintstr("nsb-nse", nsb, nse);
812 dprintstr("ose-ols", ose, ols);
813 dprintstr("nse-nls", nse, nls);
814 dprintstr("ols- oe", ols, oe);
815 dprintstr("nls- ne", nls, ne);
816 #endif /* DEBUG_UPDATE */
819 * CursorV to this line cur_line MUST be in this routine so that if we
820 * don't have to change the line, we don't move to it. CursorH to first
823 MoveToLine(cur_line);
826 * at this point we have something like this:
828 * /old /ofd /osb /ose /ols /oe
829 * v.....................v v..................v v........v
830 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
831 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
832 * ^.....................^ ^..................^ ^........^
833 * \new \nfd \nsb \nse \nls \ne
835 * fx is the difference in length between the the chars between nfd and
836 * nsb, and the chars between ofd and osb, and is thus the number of
837 * characters to delete if < 0 (new is shorter than old, as above),
838 * or insert (new is longer than short).
840 * sx is the same for the second differences.
844 * if we have a net insert on the first difference, AND inserting the net
845 * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
846 * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
847 * (TermH - 1) else we do the deletes first so that we keep everything we
852 * if the last same is the same like the end, there is no last same part,
853 * otherwise we want to keep the last same part set p to the last useful
856 p = (ols != oe) ? oe : ose;
859 * if (There is a diffence in the beginning) && (we need to insert
860 * characters) && (the number of characters to insert is less than the term
861 * width) We need to do an insert! else if (we need to delete characters)
862 * We need to delete characters! else No insert or delete
864 if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) {
866 reprintf("first diff insert at %d...\r\n", nfd - new);
867 #endif /* DEBUG_UPDATE */
869 * Move to the first char to insert, where the first diff is.
871 MoveToChar(nfd - new);
873 * Check if we have stuff to keep at end
877 reprintf("with stuff to keep at end\r\n");
878 #endif /* DEBUG_UPDATE */
880 * insert fx chars of new starting at nfd
885 reprintf(" ERROR: cannot insert in early first diff\n");
886 #endif /* DEBUG_UPDATE */
887 Insert_write(nfd, fx);
888 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
891 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
893 so_write(nfd + fx, (nsb - nfd) - fx);
894 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
898 reprintf("without anything to save\r\n");
899 #endif /* DEBUG_UPDATE */
900 so_write(nfd, (nsb - nfd));
901 str_cp(ofd, nfd, (int) (nsb - nfd));
910 reprintf("first diff delete at %d...\r\n", ofd - old);
911 #endif /* DEBUG_UPDATE */
913 * move to the first char to delete where the first diff is
915 MoveToChar(ofd - old);
917 * Check if we have stuff to save
921 reprintf("with stuff to save at end\r\n");
922 #endif /* DEBUG_UPDATE */
924 * fx is less than zero *always* here but we check for code
930 reprintf(" ERROR: cannot delete in first diff\n");
931 #endif /* DEBUG_UPDATE */
933 str_delete(old, (int) (ofd - old), TermH, -fx);
936 * write (nsb-nfd) chars of new starting at nfd
938 so_write(nfd, (nsb - nfd));
939 str_cp(ofd, nfd, (int) (nsb - nfd));
944 reprintf("but with nothing left to save\r\n");
945 #endif /* DEBUG_UPDATE */
947 * write (nsb-nfd) chars of new starting at nfd
949 so_write(nfd, (nsb - nfd));
951 reprintf("cleareol %d\n", (oe - old) - (ne - new));
952 #endif /* DEBUG_UPDATE */
954 ClearEOL((oe - old) - (ne - new));
957 * The calculation above does not work too well on NT
959 ClearEOL(TermH - CursorH);
960 #endif /*WINNT_NATIVE*/
972 reprintf("second diff delete at %d...\r\n", (ose - old) + fx);
973 #endif /* DEBUG_UPDATE */
975 * Check if we have stuff to delete
978 * fx is the number of characters inserted (+) or deleted (-)
981 MoveToChar((ose - old) + fx);
983 * Check if we have stuff to save
987 reprintf("with stuff to save at end\r\n");
988 #endif /* DEBUG_UPDATE */
990 * Again a duplicate test.
995 reprintf(" ERROR: cannot delete in second diff\n");
996 #endif /* DEBUG_UPDATE */
1001 * write (nls-nse) chars of new starting at nse
1003 so_write(nse, (nls - nse));
1006 int olen = (int) (oe - old + fx);
1010 reprintf("but with nothing left to save\r\n");
1011 #endif /* DEBUG_UPDATE */
1012 so_write(nse, (nls - nse));
1013 #ifdef DEBUG_REFRESH
1014 reprintf("cleareol %d\n", olen - (ne - new));
1015 #endif /* DEBUG_UPDATE */
1016 #ifndef WINNT_NATIVE
1017 ClearEOL(olen - (ne - new));
1020 * The calculation above does not work too well on NT
1022 ClearEOL(TermH - CursorH);
1023 #endif /*WINNT_NATIVE*/
1028 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
1030 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
1032 reprintf("late first diff insert at %d...\r\n", nfd - new);
1033 #endif /* DEBUG_UPDATE */
1035 MoveToChar(nfd - new);
1037 * Check if we have stuff to keep at the end
1041 reprintf("with stuff to keep at end\r\n");
1042 #endif /* DEBUG_UPDATE */
1044 * We have to recalculate fx here because we set it
1045 * to zero above as a flag saying that we hadn't done
1046 * an early first insert.
1048 fx = (int) ((nsb - nfd) - (osb - ofd));
1051 * insert fx chars of new starting at nfd
1055 reprintf(" ERROR: cannot insert in late first diff\n");
1056 #endif /* DEBUG_UPDATE */
1057 Insert_write(nfd, fx);
1058 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
1062 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1064 so_write(nfd + fx, (nsb - nfd) - fx);
1065 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
1069 reprintf("without anything to save\r\n");
1070 #endif /* DEBUG_UPDATE */
1071 so_write(nfd, (nsb - nfd));
1072 str_cp(ofd, nfd, (int) (nsb - nfd));
1077 * line is now NEW up to nse
1081 reprintf("second diff insert at %d...\r\n", nse - new);
1082 #endif /* DEBUG_UPDATE */
1083 MoveToChar(nse - new);
1086 reprintf("with stuff to keep at end\r\n");
1087 #endif /* DEBUG_UPDATE */
1089 /* insert sx chars of new starting at nse */
1092 reprintf(" ERROR: cannot insert in second diff\n");
1093 #endif /* DEBUG_UPDATE */
1094 Insert_write(nse, sx);
1098 * write (nls-nse) - sx chars of new starting at (nse + sx)
1100 so_write(nse + sx, (nls - nse) - sx);
1104 reprintf("without anything to save\r\n");
1105 #endif /* DEBUG_UPDATE */
1106 so_write(nse, (nls - nse));
1109 * No need to do a clear-to-end here because we were doing
1110 * a second insert, so we will have over written all of the
1116 reprintf("done.\r\n");
1117 #endif /* DEBUG_UPDATE */
1122 cpy_pad_spaces(Char *dst, Char *src, int width)
1126 for (i = 0; i < width; i++) {
1127 if (*src == (Char) 0)
1141 { /* only move to new cursor pos */
1145 /* first we must find where the cursor is... */
1148 th = TermH; /* optimize for speed */
1150 for (cp = Prompt; cp != NULL && *cp; ) { /* do prompt */
1151 if (*cp & LITERAL) {
1155 w = NLSClassify(*cp & CHAR, cp == Prompt, 0);
1169 case NLSCLASS_ILLEGAL:
1172 case NLSCLASS_ILLEGAL2:
1173 case NLSCLASS_ILLEGAL3:
1174 case NLSCLASS_ILLEGAL4:
1175 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1180 if (h >= th) { /* check, extra long tabs picked up here also */
1186 for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */
1187 w = NLSClassify(*cp & CHAR, cp == InputBuf, 0);
1201 case NLSCLASS_ILLEGAL:
1204 case NLSCLASS_ILLEGAL2:
1205 case NLSCLASS_ILLEGAL3:
1206 case NLSCLASS_ILLEGAL4:
1207 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1212 if (h >= th) { /* check, extra long tabs picked up here also */
1221 if (adrof(STRhighlight) && MarkIsSet) {
1229 #ifndef WINTT_NATIVE
1231 PutPlusOne(Char c, int width)
1233 while (width > 1 && CursorH + width > TermH)
1235 if ((c & LITERAL) != 0) {
1237 for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++)
1242 Display[CursorV][CursorH++] = (Char) c;
1244 Display[CursorV][CursorH++] = CHAR_DBWIDTH;
1245 if (CursorH >= TermH) { /* if we must overflow */
1249 if (T_Margin & MARGIN_AUTO) {
1250 if (T_Margin & MARGIN_MAGIC) {
1252 (void) putraw('\b');
1256 (void) putraw('\r');
1257 (void) putraw('\n');
1265 { /* we added just one char, handle it fast.
1266 * assumes that screen cursor == real cursor */
1270 if (Cursor != LastChar) {
1271 Refresh(); /* too hard to handle */
1274 if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) {
1275 Refresh(); /* clear out rprompt if less than one char gap*/
1280 w = NLSClassify(c, cp == InputBuf, 0);
1284 if (c == CTL_ESC('\177')) {
1289 /* uncontrolify it; works only for iso8859-1 like sets */
1290 PutPlusOne((c | 0100), 1);
1292 PutPlusOne(_toebcdic[_toascii[c]|0100], 1);
1295 case NLSCLASS_ILLEGAL:
1296 PutPlusOne('\\', 1);
1297 PutPlusOne(((c >> 6) & 7) + '0', 1);
1298 PutPlusOne(((c >> 3) & 7) + '0', 1);
1299 PutPlusOne((c & 7) + '0', 1);
1302 if (adrof(STRhighlight) && MarkIsSet)
1305 PutPlusOne(MakeLiteral(cp, l, 0), 1);
1308 if (adrof(STRhighlight) && MarkIsSet)
1312 Refresh(); /* too hard to handle */
1318 /* clear the screen buffers so that new new prompt starts fresh. */
1325 CursorV = 0; /* clear the display buffer */
1327 for (i = 0; i < TermV; i++)
1328 (void) memset(Display[i], 0, (TermH + 1) * sizeof(Display[0][0]));
1335 { /* Make sure all lines are *really* blank */
1340 * Clear the lines from the bottom up so that if we try moving
1341 * the cursor down by writing the character that is at the end
1342 * of the screen line, we won't rewrite a character that shouldn't
1345 for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */
1352 MoveToLine(OldvcV); /* go to last line */
1353 (void) putraw('\r'); /* go to BOL */
1354 (void) putraw('\n'); /* go to new line */