1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.refresh.c,v 3.51 2015/06/06 21:19:07 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("$tcsh: ed.refresh.c,v 3.51 2015/06/06 21:19:07 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 (Char *, int, Char);
49 static int Draw (Char *, int, int);
50 static void Vdraw (Char, int);
51 static void RefreshPromptpart (Char *);
52 static void update_line (Char *, Char *, int);
53 static void str_insert (Char *, int, int, Char *, int);
54 static void str_delete (Char *, int, int, int);
55 static void str_cp (Char *, Char *, int);
61 void PutPlusOne (Char, int);
62 static void cpy_pad_spaces (Char *, Char *, int);
63 #if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL)
64 static void reprintf (char *, ...);
66 static void dprintstr (char *, const Char *, const Char *);
69 dprintstr(char *str, const Char *f, const Char *t)
71 reprintf("%s:\"", str);
74 reprintf("[%x]", *f++);
76 reprintf("%c", CTL_ESC(ASCII & ASC(*f++)));
80 #endif /* DEBUG_UPDATE */
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!
88 reprintf(char *fmt, ...)
93 if ((dtty = getenv("DEBUGTTY"))) {
99 fd = xopen(dtty, O_RDWR);
109 #endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */
111 static int litlen = 0, litalloc = 0;
113 static int MakeLiteral(Char *str, int len, Char addlit)
115 int i, addlitlen = 0;
118 if ((addlit & LITERAL) != 0) {
119 addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
120 addlitlen = Strlen(addlitptr);
125 for (i = 0; i < litlen; i += LIT_FACTOR)
126 if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0)
127 return (i / LIT_FACTOR) | LITERAL;
130 for (i = 0; i < litlen; i += LIT_FACTOR)
131 if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0)
132 return (i / LIT_FACTOR) | LITERAL;
134 if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) {
137 while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add)
139 newlitptr = xrealloc(litptr, (litalloc + add) * sizeof(Char));
144 if (addlitptr && addlitptr != &addlit)
145 addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR;
147 i = litlen / LIT_FACTOR;
148 if (i >= LITERAL || i == CHAR_DBWIDTH)
151 Strncpy(litptr + litlen, addlitptr, addlitlen);
154 Strncpy(litptr + litlen, str, len);
157 litptr[litlen++] = 0;
158 while (litlen % LIT_FACTOR);
162 /* draw char at cp, expand tabs, ctl chars */
164 Draw(Char *cp, int nocomb, int drawPrompt)
170 if (!drawPrompt) { /* draw command-line */
173 } else { /* draw prompt */
174 /* prompt with attributes(UNDER,BOLD,STANDOUT) */
175 if (*cp & (UNDER | BOLD | STANDOUT)) { /* *cp >= STANDOUT */
178 * We can't distinguish whether (*cp=)0x02ffffff is
179 * U+02FFFFFF or U+00FFFFFF|STANDOUT.
180 * We handle as U+00FFFFFF|STANDOUT, only when drawing prompt. */
181 attr = (*cp & ATTRIBUTES);
182 /* ~(UNDER | BOLD | STANDOUT) = 0xf1ffffff */
183 c = *cp & ~(UNDER | BOLD | STANDOUT);
185 /* if c is ctrl code, we handle *cp as havnig no attributes */
186 if ((c < 0x20 && c >= 0) || c == 0x7f) {
190 } else { /* prompt without attributes */
199 w = NLSClassify(c, nocomb, drawPrompt);
202 Vdraw('\0', 0); /* assure end of line */
203 vcursor_h = 0; /* reset cursor pos */
209 } while ((vcursor_h & 07) != 0);
212 Vdraw('^' | attr, 1);
213 if (c == CTL_ESC('\177')) {
214 Vdraw('?' | attr, 1);
217 /* uncontrolify it; works only for iso8859-1 like sets */
218 Vdraw(c | 0100 | attr, 1);
220 Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1);
224 case NLSCLASS_ILLEGAL:
225 Vdraw('\\' | attr, 1);
226 Vdraw((((c >> 6) & 7) + '0') | attr, 1);
227 Vdraw((((c >> 3) & 7) + '0') | attr, 1);
228 Vdraw(((c & 7) + '0') | attr, 1);
230 case NLSCLASS_ILLEGAL2:
231 case NLSCLASS_ILLEGAL3:
232 case NLSCLASS_ILLEGAL4:
233 case NLSCLASS_ILLEGAL5:
237 for (i = 16 + 4 * (-w-5); i >= 0; i -= 4)
238 Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1);
249 lh = Strlen(Vdisplay[lv]) - 1;
251 if (Vdisplay[lv][lh] != CHAR_DBWIDTH)
255 Vdraw('\\' | attr, 1);
256 Vdraw((((c >> 6) & 7) + '0') | attr, 1);
257 Vdraw((((c >> 3) & 7) + '0') | attr, 1);
258 Vdraw(((c & 7) + '0') | attr, 1);
261 Vdisplay[lv][lh] = MakeLiteral(cp, 1, Vdisplay[lv][lh]);
271 Vdraw(Char c, int width) /* draw char c onto V lines */
274 # ifdef SHORT_STRINGS
275 reprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width);
277 reprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width);
278 # endif /* SHORT_STRNGS */
279 #endif /* DEBUG_REFRESH */
281 /* Hopefully this is what all the terminals do with multi-column characters
282 that "span line breaks". */
283 while (vcursor_h + width > TermH)
285 Vdisplay[vcursor_v][vcursor_h] = c;
287 vcursor_h++; /* advance to next place */
289 Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH;
290 if (vcursor_h >= TermH) {
291 Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */
292 vcursor_h = 0; /* reset it. */
295 if (vcursor_v >= TermV) { /* should NEVER happen. */
296 reprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
300 #endif /* DEBUG_REFRESH */
305 * RefreshPromptpart()
306 * draws a prompt element, expanding literals (we know it's ASCIZ)
309 RefreshPromptpart(Char *buf)
316 for (cp = buf; *cp; ) {
319 while (*cp & LITERAL)
322 w = NLSWidth(*cp & CHAR);
323 Vdraw(MakeLiteral(litstart, cp + 1 - litstart, 0), w);
328 * XXX: This is a bug, we lose the last literal, if it is not
329 * followed by a normal character, but it is too hard to fix
335 cp += Draw(cp, cp == buf, 1);
341 * draws the new virtual screen image from the current input
342 * line, then goes line-by-line changing the real image to the new
343 * virtual image. The routine to re-draw a line can be replaced
344 * easily in hopes of a smarter one being placed there.
356 int cur_h, cur_v = 0, new_vcv;
361 reprintf("Prompt = :%s:\r\n", short2str(Prompt));
362 reprintf("InputBuf = :%s:\r\n", short2str(InputBuf));
363 #endif /* DEBUG_REFRESH */
364 oldgetting = GettingInput;
365 GettingInput = 0; /* avoid re-entrance via SIGWINCH */
367 /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
370 RefreshPromptpart(RPrompt);
371 rprompt_h = vcursor_h;
372 rprompt_v = vcursor_v;
374 /* reset the Vdraw cursor, draw prompt */
377 RefreshPromptpart(Prompt);
378 cur_h = -1; /* set flag in case I'm not set */
380 /* draw the current input buffer */
381 for (cp = InputBuf; (cp < LastChar); ) {
382 if (cp >= Cursor && cur_h == -1) {
383 cur_h = vcursor_h; /* save for later */
387 cp += Draw(cp, cp == InputBuf, 0);
390 if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */
395 rhdiff = TermH - vcursor_h - rprompt_h;
396 if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) {
398 * have a right-hand side prompt that will fit on
399 * the end of the first line with at least one
400 * character gap to the input buffer.
402 while (--rhdiff > 0) /* pad out with spaces */
404 RefreshPromptpart(RPrompt);
407 rprompt_h = 0; /* flag "not using rprompt" */
411 new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */
412 Vdraw('\0', 1); /* put NUL on end */
414 #if defined (DEBUG_REFRESH)
415 reprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
416 TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0]));
417 #endif /* DEBUG_REFRESH */
420 reprintf("updating %d lines.\r\n", new_vcv);
421 #endif /* DEBUG_UPDATE */
422 for (cur_line = 0; cur_line <= new_vcv; cur_line++) {
423 /* NOTE THAT update_line MAY CHANGE Display[cur_line] */
424 update_line(Display[cur_line], Vdisplay[cur_line], cur_line);
427 #endif /* WINNT_NATIVE */
430 * Copy the new line to be the current one, and pad out with spaces
431 * to the full width of the terminal so that if we try moving the
432 * cursor by writing the character that is at the end of the
433 * screen line, it won't be a NUL or some old leftover stuff.
435 cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH);
438 reprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
439 vcursor_v, OldvcV, cur_line);
440 #endif /* DEBUG_REFRESH */
441 if (OldvcV > new_vcv) {
442 for (; cur_line <= OldvcV; cur_line++) {
443 update_line(Display[cur_line], STRNULL, cur_line);
444 *Display[cur_line] = '\0';
447 OldvcV = new_vcv; /* set for next time */
449 reprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
450 CursorH, CursorV, cur_h, cur_v);
451 #endif /* DEBUG_REFRESH */
454 #endif /* WINNT_NATIVE */
455 MoveToLine(cur_v); /* go to where the cursor is */
457 SetAttributes(0); /* Clear all attributes */
458 flush(); /* send the output... */
459 GettingInput = oldgetting; /* reset to old value */
464 { /* used to go to last used screen line */
472 { /* used to go to last used screen line */
481 /* insert num characters of s into d (in front of the character) at dat,
482 maximum length of d is dlen */
484 str_insert(Char *d, int dat, int dlen, Char *s, int num)
490 if (num > dlen - dat)
494 reprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
495 num, dat, dlen, short2str(d));
496 reprintf("s == \"%s\"n", short2str(s));
497 #endif /* DEBUG_REFRESH */
499 /* open up the space for num chars */
505 d[dlen] = '\0'; /* just in case */
508 reprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
509 num, dat, dlen, short2str(d));
510 reprintf("s == \"%s\"n", short2str(s));
511 #endif /* DEBUG_REFRESH */
513 /* copy the characters */
514 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
518 reprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
519 num, dat, dlen, d, short2str(s));
520 reprintf("s == \"%s\"n", short2str(s));
521 #endif /* DEBUG_REFRESH */
524 /* delete num characters d at dat, maximum length of d is dlen */
526 str_delete(Char *d, int dat, int dlen, int num)
532 if (dat + num >= dlen) {
538 reprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
539 num, dat, dlen, short2str(d));
540 #endif /* DEBUG_REFRESH */
542 /* open up the space for num chars */
548 d[dlen] = '\0'; /* just in case */
551 reprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
552 num, dat, dlen, short2str(d));
553 #endif /* DEBUG_REFRESH */
557 str_cp(Char *a, Char *b, int n)
564 /* ****************************************************************
565 update_line() is based on finding the middle difference of each line
568 /old first difference
569 /beginning of line | /old last same /old EOL
571 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
572 new: eddie> Oh, my little buggy says to me, as lurgid as
574 \beginning of line | \new last same \new end of line
575 \new first difference
577 all are character pointers for the sake of speed. Special cases for
578 no differences, as well as for end of line additions must be handled.
579 **************************************************************** */
581 /* Minimum at which doing an insert it "worth it". This should be about
582 * half the "cost" of going into insert mode, inserting a character, and
583 * going back out. This should really be calculated from the termcap
584 * data... For the moment, a good number for ANSI terminals.
586 #define MIN_END_KEEP 4
588 static void /* could be changed to make it smarter */
589 update_line(Char *old, Char *new, int cur_line)
592 Char *ofd, *ols, *oe, *nfd, *nls, *ne;
593 Char *osb, *ose, *nsb, *nse;
597 * find first diff (won't be CHAR_DBWIDTH in either line)
599 for (o = old, n = new; *o && (*o == *n); o++, n++)
605 * Find the end of both old and new
610 * Remove any trailing blanks off of the end, being careful not to
611 * back up past the beginning.
613 if (!(adrof(STRhighlight) && MarkIsSet)) {
625 /* remove blanks from end of new */
626 if (!(adrof(STRhighlight) && MarkIsSet)) {
637 * if no diff, continue to next line of redraw
639 if (*ofd == '\0' && *nfd == '\0') {
641 reprintf("no difference.\r\n");
642 #endif /* DEBUG_UPDATE */
647 * find last same pointer
649 while ((o > ofd) && (n > nfd) && (*--o == *--n))
655 while (*o == CHAR_DBWIDTH) {
663 * find same begining and same end
671 * case 1: insert: scan from nfd to nls looking for *ofd
674 for (c = *ofd, n = nfd; n < nls; n++) {
676 for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
679 * if the new match is longer and it's worth keeping, then we
682 if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
693 * case 2: delete: scan from ofd to ols looking for *nfd
696 for (c = *nfd, o = ofd; o < ols; o++) {
698 for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
701 * if the new match is longer and it's worth keeping, then we
704 if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
715 * If `last same' is before `same end' re-adjust
724 * Pragmatics I: If old trailing whitespace or not enough characters to
725 * save to be worth it, then don't save the last same info.
727 if ((oe - ols) < MIN_END_KEEP) {
733 * Pragmatics II: if the terminal isn't smart enough, make the data dumber
734 * so the smart update doesn't try anything fancy
738 * fx is the number of characters we need to insert/delete: in the
739 * beginning to bring the two same begins together
741 fx = (int) ((nsb - nfd) - (osb - ofd));
743 * sx is the number of characters we need to insert/delete: in the end to
744 * bring the two same last parts together
746 sx = (int) ((nls - nse) - (ols - ose));
759 if ((ols - ofd) < (nls - nfd)) {
775 if ((ols - ofd) > (nls - nfd)) {
782 * Pragmatics III: make sure the middle shifted pointers are correct if
783 * they don't point to anything (we may have moved ols or nls).
785 /* if the change isn't worth it, don't bother */
786 /* was: if (osb == ose) */
787 if ((ose - osb) < MIN_END_KEEP) {
795 * Now that we are done with pragmatics we recompute fx, sx
797 fx = (int) ((nsb - nfd) - (osb - ofd));
798 sx = (int) ((nls - nse) - (ols - ose));
802 reprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
803 ofd - old, osb - old, ose - old, ols - old, oe - old);
804 reprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
805 nfd - new, nsb - new, nse - new, nls - new, ne - new);
806 reprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
807 reprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
808 dprintstr("old- oe", old, oe);
809 dprintstr("new- ne", new, ne);
810 dprintstr("old-ofd", old, ofd);
811 dprintstr("new-nfd", new, nfd);
812 dprintstr("ofd-osb", ofd, osb);
813 dprintstr("nfd-nsb", nfd, nsb);
814 dprintstr("osb-ose", osb, ose);
815 dprintstr("nsb-nse", nsb, nse);
816 dprintstr("ose-ols", ose, ols);
817 dprintstr("nse-nls", nse, nls);
818 dprintstr("ols- oe", ols, oe);
819 dprintstr("nls- ne", nls, ne);
820 #endif /* DEBUG_UPDATE */
823 * CursorV to this line cur_line MUST be in this routine so that if we
824 * don't have to change the line, we don't move to it. CursorH to first
827 MoveToLine(cur_line);
830 * at this point we have something like this:
832 * /old /ofd /osb /ose /ols /oe
833 * v.....................v v..................v v........v
834 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
835 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
836 * ^.....................^ ^..................^ ^........^
837 * \new \nfd \nsb \nse \nls \ne
839 * fx is the difference in length between the the chars between nfd and
840 * nsb, and the chars between ofd and osb, and is thus the number of
841 * characters to delete if < 0 (new is shorter than old, as above),
842 * or insert (new is longer than short).
844 * sx is the same for the second differences.
848 * if we have a net insert on the first difference, AND inserting the net
849 * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
850 * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
851 * (TermH - 1) else we do the deletes first so that we keep everything we
856 * if the last same is the same like the end, there is no last same part,
857 * otherwise we want to keep the last same part set p to the last useful
860 p = (ols != oe) ? oe : ose;
863 * if (There is a diffence in the beginning) && (we need to insert
864 * characters) && (the number of characters to insert is less than the term
865 * width) We need to do an insert! else if (we need to delete characters)
866 * We need to delete characters! else No insert or delete
868 if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) {
870 reprintf("first diff insert at %d...\r\n", nfd - new);
871 #endif /* DEBUG_UPDATE */
873 * Move to the first char to insert, where the first diff is.
875 MoveToChar(nfd - new);
877 * Check if we have stuff to keep at end
881 reprintf("with stuff to keep at end\r\n");
882 #endif /* DEBUG_UPDATE */
884 * insert fx chars of new starting at nfd
889 reprintf(" ERROR: cannot insert in early first diff\n");
890 #endif /* DEBUG_UPDATE */
891 Insert_write(nfd, fx);
892 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
895 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
897 so_write(nfd + fx, (nsb - nfd) - fx);
898 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
902 reprintf("without anything to save\r\n");
903 #endif /* DEBUG_UPDATE */
904 so_write(nfd, (nsb - nfd));
905 str_cp(ofd, nfd, (int) (nsb - nfd));
914 reprintf("first diff delete at %d...\r\n", ofd - old);
915 #endif /* DEBUG_UPDATE */
917 * move to the first char to delete where the first diff is
919 MoveToChar(ofd - old);
921 * Check if we have stuff to save
925 reprintf("with stuff to save at end\r\n");
926 #endif /* DEBUG_UPDATE */
928 * fx is less than zero *always* here but we check for code
934 reprintf(" ERROR: cannot delete in first diff\n");
935 #endif /* DEBUG_UPDATE */
937 str_delete(old, (int) (ofd - old), TermH, -fx);
940 * write (nsb-nfd) chars of new starting at nfd
942 so_write(nfd, (nsb - nfd));
943 str_cp(ofd, nfd, (int) (nsb - nfd));
948 reprintf("but with nothing left to save\r\n");
949 #endif /* DEBUG_UPDATE */
951 * write (nsb-nfd) chars of new starting at nfd
953 so_write(nfd, (nsb - nfd));
955 reprintf("cleareol %d\n", (oe - old) - (ne - new));
956 #endif /* DEBUG_UPDATE */
958 ClearEOL((oe - old) - (ne - new));
961 * The calculation above does not work too well on NT
963 ClearEOL(TermH - CursorH);
964 #endif /*WINNT_NATIVE*/
976 reprintf("second diff delete at %d...\r\n", (ose - old) + fx);
977 #endif /* DEBUG_UPDATE */
979 * Check if we have stuff to delete
982 * fx is the number of characters inserted (+) or deleted (-)
985 MoveToChar((ose - old) + fx);
987 * Check if we have stuff to save
991 reprintf("with stuff to save at end\r\n");
992 #endif /* DEBUG_UPDATE */
994 * Again a duplicate test.
999 reprintf(" ERROR: cannot delete in second diff\n");
1000 #endif /* DEBUG_UPDATE */
1005 * write (nls-nse) chars of new starting at nse
1007 so_write(nse, (nls - nse));
1010 int olen = (int) (oe - old + fx);
1014 reprintf("but with nothing left to save\r\n");
1015 #endif /* DEBUG_UPDATE */
1016 so_write(nse, (nls - nse));
1017 #ifdef DEBUG_REFRESH
1018 reprintf("cleareol %d\n", olen - (ne - new));
1019 #endif /* DEBUG_UPDATE */
1020 #ifndef WINNT_NATIVE
1021 ClearEOL(olen - (ne - new));
1024 * The calculation above does not work too well on NT
1026 ClearEOL(TermH - CursorH);
1027 #endif /*WINNT_NATIVE*/
1032 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
1034 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
1036 reprintf("late first diff insert at %d...\r\n", nfd - new);
1037 #endif /* DEBUG_UPDATE */
1039 MoveToChar(nfd - new);
1041 * Check if we have stuff to keep at the end
1045 reprintf("with stuff to keep at end\r\n");
1046 #endif /* DEBUG_UPDATE */
1048 * We have to recalculate fx here because we set it
1049 * to zero above as a flag saying that we hadn't done
1050 * an early first insert.
1052 fx = (int) ((nsb - nfd) - (osb - ofd));
1055 * insert fx chars of new starting at nfd
1059 reprintf(" ERROR: cannot insert in late first diff\n");
1060 #endif /* DEBUG_UPDATE */
1061 Insert_write(nfd, fx);
1062 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
1066 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1068 so_write(nfd + fx, (nsb - nfd) - fx);
1069 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
1073 reprintf("without anything to save\r\n");
1074 #endif /* DEBUG_UPDATE */
1075 so_write(nfd, (nsb - nfd));
1076 str_cp(ofd, nfd, (int) (nsb - nfd));
1081 * line is now NEW up to nse
1085 reprintf("second diff insert at %d...\r\n", nse - new);
1086 #endif /* DEBUG_UPDATE */
1087 MoveToChar(nse - new);
1090 reprintf("with stuff to keep at end\r\n");
1091 #endif /* DEBUG_UPDATE */
1093 /* insert sx chars of new starting at nse */
1096 reprintf(" ERROR: cannot insert in second diff\n");
1097 #endif /* DEBUG_UPDATE */
1098 Insert_write(nse, sx);
1102 * write (nls-nse) - sx chars of new starting at (nse + sx)
1104 so_write(nse + sx, (nls - nse) - sx);
1108 reprintf("without anything to save\r\n");
1109 #endif /* DEBUG_UPDATE */
1110 so_write(nse, (nls - nse));
1113 * No need to do a clear-to-end here because we were doing
1114 * a second insert, so we will have over written all of the
1120 reprintf("done.\r\n");
1121 #endif /* DEBUG_UPDATE */
1126 cpy_pad_spaces(Char *dst, Char *src, int width)
1130 for (i = 0; i < width; i++) {
1131 if (*src == (Char) 0)
1145 { /* only move to new cursor pos */
1149 /* first we must find where the cursor is... */
1152 th = TermH; /* optimize for speed */
1154 for (cp = Prompt; cp != NULL && *cp; ) { /* do prompt */
1155 if (*cp & LITERAL) {
1159 w = NLSClassify(*cp & CHAR, cp == Prompt, 0);
1173 case NLSCLASS_ILLEGAL:
1176 case NLSCLASS_ILLEGAL2:
1177 case NLSCLASS_ILLEGAL3:
1178 case NLSCLASS_ILLEGAL4:
1179 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1184 if (h >= th) { /* check, extra long tabs picked up here also */
1190 for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */
1191 w = NLSClassify(*cp & CHAR, cp == InputBuf, 0);
1205 case NLSCLASS_ILLEGAL:
1208 case NLSCLASS_ILLEGAL2:
1209 case NLSCLASS_ILLEGAL3:
1210 case NLSCLASS_ILLEGAL4:
1211 h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w);
1216 if (h >= th) { /* check, extra long tabs picked up here also */
1225 if (adrof(STRhighlight) && MarkIsSet) {
1233 #ifndef WINTT_NATIVE
1235 PutPlusOne(Char c, int width)
1237 while (width > 1 && CursorH + width > TermH)
1239 if ((c & LITERAL) != 0) {
1241 for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++)
1246 Display[CursorV][CursorH++] = (Char) c;
1248 Display[CursorV][CursorH++] = CHAR_DBWIDTH;
1249 if (CursorH >= TermH) { /* if we must overflow */
1253 if (T_Margin & MARGIN_AUTO) {
1254 if (T_Margin & MARGIN_MAGIC) {
1256 (void) putraw('\b');
1260 (void) putraw('\r');
1261 (void) putraw('\n');
1269 { /* we added just one char, handle it fast.
1270 * assumes that screen cursor == real cursor */
1274 if (Cursor != LastChar) {
1275 Refresh(); /* too hard to handle */
1278 if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) {
1279 Refresh(); /* clear out rprompt if less than one char gap*/
1284 w = NLSClassify(c, cp == InputBuf, 0);
1288 if (c == CTL_ESC('\177')) {
1293 /* uncontrolify it; works only for iso8859-1 like sets */
1294 PutPlusOne((c | 0100), 1);
1296 PutPlusOne(_toebcdic[_toascii[c]|0100], 1);
1299 case NLSCLASS_ILLEGAL:
1300 PutPlusOne('\\', 1);
1301 PutPlusOne(((c >> 6) & 7) + '0', 1);
1302 PutPlusOne(((c >> 3) & 7) + '0', 1);
1303 PutPlusOne((c & 7) + '0', 1);
1306 if (adrof(STRhighlight) && MarkIsSet)
1309 PutPlusOne(MakeLiteral(cp, l, 0), 1);
1312 if (adrof(STRhighlight) && MarkIsSet)
1316 Refresh(); /* too hard to handle */
1322 /* clear the screen buffers so that new new prompt starts fresh. */
1329 CursorV = 0; /* clear the display buffer */
1331 for (i = 0; i < TermV; i++)
1332 (void) memset(Display[i], 0, (TermH + 1) * sizeof(Display[0][0]));
1339 { /* Make sure all lines are *really* blank */
1344 * Clear the lines from the bottom up so that if we try moving
1345 * the cursor down by writing the character that is at the end
1346 * of the screen line, we won't rewrite a character that shouldn't
1349 for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */
1356 MoveToLine(OldvcV); /* go to last line */
1357 (void) putraw('\r'); /* go to BOL */
1358 (void) putraw('\n'); /* go to new line */