1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.refresh.c,v 3.46 2006/08/23 15:03:14 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.46 2006/08/23 15:03:14 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);
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 dprintf (char *, ...);
66 static void dprintstr (char *, const Char
*, const Char
*);
69 dprintstr(char *str
, const Char
*f
, const Char
*t
)
71 dprintf("%s:\"", str
);
74 dprintf("[%x]", *f
++);
76 dprintf("%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 dprintf(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
);
163 Draw(Char
*cp
, int nocomb
) /* draw char at cp, expand tabs, ctl chars */
170 w
= NLSClassify(c
, nocomb
);
173 Vdraw('\0', 0); /* assure end of line */
174 vcursor_h
= 0; /* reset cursor pos */
180 } while ((vcursor_h
& 07) != 0);
183 Vdraw('^' | attr
, 1);
184 if (c
== CTL_ESC('\177')) {
185 Vdraw('?' | attr
, 1);
188 /* uncontrolify it; works only for iso8859-1 like sets */
189 Vdraw(c
| 0100 | attr
, 1);
191 Vdraw(_toebcdic
[_toascii
[c
]|0100] | attr
, 1);
195 case NLSCLASS_ILLEGAL
:
196 Vdraw('\\' | attr
, 1);
197 Vdraw((((c
>> 6) & 7) + '0') | attr
, 1);
198 Vdraw((((c
>> 3) & 7) + '0') | attr
, 1);
199 Vdraw(((c
& 7) + '0') | attr
, 1);
201 case NLSCLASS_ILLEGAL2
:
202 case NLSCLASS_ILLEGAL3
:
203 case NLSCLASS_ILLEGAL4
:
204 Vdraw('\\' | attr
, 1);
205 Vdraw('U' | attr
, 1);
206 Vdraw('+' | attr
, 1);
207 for (i
= 8 * NLSCLASS_ILLEGAL_SIZE(w
) - 4; i
>= 0; i
-= 4)
208 Vdraw("0123456789ABCDEF"[(c
>> i
) & 15] | attr
, 1);
219 lh
= Strlen(Vdisplay
[lv
]) - 1;
221 if (Vdisplay
[lv
][lh
] != CHAR_DBWIDTH
)
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);
231 Vdisplay
[lv
][lh
] = MakeLiteral(cp
, 1, Vdisplay
[lv
][lh
]);
241 Vdraw(Char c
, int width
) /* draw char c onto V lines */
244 # ifdef SHORT_STRINGS
245 dprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c
, (int)(c
& ASCII
), width
);
247 dprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c
, (int)c
, width
);
248 # endif /* SHORT_STRNGS */
249 #endif /* DEBUG_REFRESH */
251 /* Hopefully this is what all the terminals do with multi-column characters
252 that "span line breaks". */
253 while (vcursor_h
+ width
> TermH
)
255 Vdisplay
[vcursor_v
][vcursor_h
] = c
;
257 vcursor_h
++; /* advance to next place */
259 Vdisplay
[vcursor_v
][vcursor_h
++] = CHAR_DBWIDTH
;
260 if (vcursor_h
>= TermH
) {
261 Vdisplay
[vcursor_v
][TermH
] = '\0'; /* assure end of line */
262 vcursor_h
= 0; /* reset it. */
265 if (vcursor_v
>= TermV
) { /* should NEVER happen. */
266 dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
270 #endif /* DEBUG_REFRESH */
275 * RefreshPromptpart()
276 * draws a prompt element, expanding literals (we know it's ASCIZ)
279 RefreshPromptpart(Char
*buf
)
286 for (cp
= buf
; *cp
; ) {
289 while (*cp
& LITERAL
)
292 w
= NLSWidth(*cp
& CHAR
);
293 Vdraw(MakeLiteral(litstart
, cp
+ 1 - litstart
, 0), w
);
298 * XXX: This is a bug, we lose the last literal, if it is not
299 * followed by a normal character, but it is too hard to fix
305 cp
+= Draw(cp
, cp
== buf
);
311 * draws the new virtual screen image from the current input
312 * line, then goes line-by-line changing the real image to the new
313 * virtual image. The routine to re-draw a line can be replaced
314 * easily in hopes of a smarter one being placed there.
326 int cur_h
, cur_v
= 0, new_vcv
;
331 dprintf("Prompt = :%s:\r\n", short2str(Prompt
));
332 dprintf("InputBuf = :%s:\r\n", short2str(InputBuf
));
333 #endif /* DEBUG_REFRESH */
334 oldgetting
= GettingInput
;
335 GettingInput
= 0; /* avoid re-entrance via SIGWINCH */
337 /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
340 RefreshPromptpart(RPrompt
);
341 rprompt_h
= vcursor_h
;
342 rprompt_v
= vcursor_v
;
344 /* reset the Vdraw cursor, draw prompt */
347 RefreshPromptpart(Prompt
);
348 cur_h
= -1; /* set flag in case I'm not set */
350 /* draw the current input buffer */
351 for (cp
= InputBuf
; (cp
< LastChar
); ) {
352 if (cp
>= Cursor
&& cur_h
== -1) {
353 cur_h
= vcursor_h
; /* save for later */
357 cp
+= Draw(cp
, cp
== InputBuf
);
360 if (cur_h
== -1) { /* if I haven't been set yet, I'm at the end */
365 rhdiff
= TermH
- vcursor_h
- rprompt_h
;
366 if (rprompt_h
!= 0 && rprompt_v
== 0 && vcursor_v
== 0 && rhdiff
> 1) {
368 * have a right-hand side prompt that will fit on
369 * the end of the first line with at least one
370 * character gap to the input buffer.
372 while (--rhdiff
> 0) /* pad out with spaces */
374 RefreshPromptpart(RPrompt
);
377 rprompt_h
= 0; /* flag "not using rprompt" */
381 new_vcv
= vcursor_v
; /* must be done BEFORE the NUL is written */
382 Vdraw('\0', 1); /* put NUL on end */
384 #if defined (DEBUG_REFRESH)
385 dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
386 TermH
, vcursor_h
, vcursor_v
, short2str(Vdisplay
[0]));
387 #endif /* DEBUG_REFRESH */
390 dprintf("updating %d lines.\r\n", new_vcv
);
391 #endif /* DEBUG_UPDATE */
392 for (cur_line
= 0; cur_line
<= new_vcv
; cur_line
++) {
393 /* NOTE THAT update_line MAY CHANGE Display[cur_line] */
394 update_line(Display
[cur_line
], Vdisplay
[cur_line
], cur_line
);
397 #endif /* WINNT_NATIVE */
400 * Copy the new line to be the current one, and pad out with spaces
401 * to the full width of the terminal so that if we try moving the
402 * cursor by writing the character that is at the end of the
403 * screen line, it won't be a NUL or some old leftover stuff.
405 cpy_pad_spaces(Display
[cur_line
], Vdisplay
[cur_line
], TermH
);
408 dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
409 vcursor_v
, OldvcV
, cur_line
);
410 #endif /* DEBUG_REFRESH */
411 if (OldvcV
> new_vcv
) {
412 for (; cur_line
<= OldvcV
; cur_line
++) {
413 update_line(Display
[cur_line
], STRNULL
, cur_line
);
414 *Display
[cur_line
] = '\0';
417 OldvcV
= new_vcv
; /* set for next time */
419 dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
420 CursorH
, CursorV
, cur_h
, cur_v
);
421 #endif /* DEBUG_REFRESH */
424 #endif /* WINNT_NATIVE */
425 MoveToLine(cur_v
); /* go to where the cursor is */
427 SetAttributes(0); /* Clear all attributes */
428 flush(); /* send the output... */
429 GettingInput
= oldgetting
; /* reset to old value */
434 { /* used to go to last used screen line */
442 { /* used to go to last used screen line */
451 /* insert num characters of s into d (in front of the character) at dat,
452 maximum length of d is dlen */
454 str_insert(Char
*d
, int dat
, int dlen
, Char
*s
, int num
)
460 if (num
> dlen
- dat
)
464 dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
465 num
, dat
, dlen
, short2str(d
));
466 dprintf("s == \"%s\"n", short2str(s
));
467 #endif /* DEBUG_REFRESH */
469 /* open up the space for num chars */
475 d
[dlen
] = '\0'; /* just in case */
478 dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
479 num
, dat
, dlen
, short2str(d
));
480 dprintf("s == \"%s\"n", short2str(s
));
481 #endif /* DEBUG_REFRESH */
483 /* copy the characters */
484 for (a
= d
+ dat
; (a
< d
+ dlen
) && (num
> 0); num
--)
488 dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
489 num
, dat
, dlen
, d
, short2str(s
));
490 dprintf("s == \"%s\"n", short2str(s
));
491 #endif /* DEBUG_REFRESH */
494 /* delete num characters d at dat, maximum length of d is dlen */
496 str_delete(Char
*d
, int dat
, int dlen
, int num
)
502 if (dat
+ num
>= dlen
) {
508 dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
509 num
, dat
, dlen
, short2str(d
));
510 #endif /* DEBUG_REFRESH */
512 /* open up the space for num chars */
518 d
[dlen
] = '\0'; /* just in case */
521 dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
522 num
, dat
, dlen
, short2str(d
));
523 #endif /* DEBUG_REFRESH */
527 str_cp(Char
*a
, Char
*b
, int n
)
534 /* ****************************************************************
535 update_line() is based on finding the middle difference of each line
538 /old first difference
539 /beginning of line | /old last same /old EOL
541 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
542 new: eddie> Oh, my little buggy says to me, as lurgid as
544 \beginning of line | \new last same \new end of line
545 \new first difference
547 all are character pointers for the sake of speed. Special cases for
548 no differences, as well as for end of line additions must be handled.
549 **************************************************************** */
551 /* Minimum at which doing an insert it "worth it". This should be about
552 * half the "cost" of going into insert mode, inserting a character, and
553 * going back out. This should really be calculated from the termcap
554 * data... For the moment, a good number for ANSI terminals.
556 #define MIN_END_KEEP 4
558 static void /* could be changed to make it smarter */
559 update_line(Char
*old
, Char
*new, int cur_line
)
562 Char
*ofd
, *ols
, *oe
, *nfd
, *nls
, *ne
;
563 Char
*osb
, *ose
, *nsb
, *nse
;
567 * find first diff (won't be CHAR_DBWIDTH in either line)
569 for (o
= old
, n
= new; *o
&& (*o
== *n
); o
++, n
++)
575 * Find the end of both old and new
580 * Remove any trailing blanks off of the end, being careful not to
581 * back up past the beginning.
583 if (!(adrof(STRhighlight
) && MarkIsSet
)) {
595 /* remove blanks from end of new */
596 if (!(adrof(STRhighlight
) && MarkIsSet
)) {
607 * if no diff, continue to next line of redraw
609 if (*ofd
== '\0' && *nfd
== '\0') {
611 dprintf("no difference.\r\n");
612 #endif /* DEBUG_UPDATE */
617 * find last same pointer
619 while ((o
> ofd
) && (n
> nfd
) && (*--o
== *--n
))
625 while (*o
== CHAR_DBWIDTH
) {
633 * find same begining and same end
641 * case 1: insert: scan from nfd to nls looking for *ofd
644 for (c
= *ofd
, n
= nfd
; n
< nls
; n
++) {
646 for (o
= ofd
, p
= n
; p
< nls
&& o
< ols
&& *o
== *p
; o
++, p
++)
649 * if the new match is longer and it's worth keeping, then we
652 if (((nse
- nsb
) < (p
- n
)) && (2 * (p
- n
) > n
- nfd
)) {
663 * case 2: delete: scan from ofd to ols looking for *nfd
666 for (c
= *nfd
, o
= ofd
; o
< ols
; o
++) {
668 for (n
= nfd
, p
= o
; p
< ols
&& n
< nls
&& *p
== *n
; p
++, n
++)
671 * if the new match is longer and it's worth keeping, then we
674 if (((ose
- osb
) < (p
- o
)) && (2 * (p
- o
) > o
- ofd
)) {
685 * If `last same' is before `same end' re-adjust
694 * Pragmatics I: If old trailing whitespace or not enough characters to
695 * save to be worth it, then don't save the last same info.
697 if ((oe
- ols
) < MIN_END_KEEP
) {
703 * Pragmatics II: if the terminal isn't smart enough, make the data dumber
704 * so the smart update doesn't try anything fancy
708 * fx is the number of characters we need to insert/delete: in the
709 * beginning to bring the two same begins together
711 fx
= (int) ((nsb
- nfd
) - (osb
- ofd
));
713 * sx is the number of characters we need to insert/delete: in the end to
714 * bring the two same last parts together
716 sx
= (int) ((nls
- nse
) - (ols
- ose
));
729 if ((ols
- ofd
) < (nls
- nfd
)) {
745 if ((ols
- ofd
) > (nls
- nfd
)) {
752 * Pragmatics III: make sure the middle shifted pointers are correct if
753 * they don't point to anything (we may have moved ols or nls).
755 /* if the change isn't worth it, don't bother */
756 /* was: if (osb == ose) */
757 if ((ose
- osb
) < MIN_END_KEEP
) {
765 * Now that we are done with pragmatics we recompute fx, sx
767 fx
= (int) ((nsb
- nfd
) - (osb
- ofd
));
768 sx
= (int) ((nls
- nse
) - (ols
- ose
));
772 dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
773 ofd
- old
, osb
- old
, ose
- old
, ols
- old
, oe
- old
);
774 dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
775 nfd
- new, nsb
- new, nse
- new, nls
- new, ne
- new);
776 dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
777 dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
778 dprintstr("old- oe", old
, oe
);
779 dprintstr("new- ne", new, ne
);
780 dprintstr("old-ofd", old
, ofd
);
781 dprintstr("new-nfd", new, nfd
);
782 dprintstr("ofd-osb", ofd
, osb
);
783 dprintstr("nfd-nsb", nfd
, nsb
);
784 dprintstr("osb-ose", osb
, ose
);
785 dprintstr("nsb-nse", nsb
, nse
);
786 dprintstr("ose-ols", ose
, ols
);
787 dprintstr("nse-nls", nse
, nls
);
788 dprintstr("ols- oe", ols
, oe
);
789 dprintstr("nls- ne", nls
, ne
);
790 #endif /* DEBUG_UPDATE */
793 * CursorV to this line cur_line MUST be in this routine so that if we
794 * don't have to change the line, we don't move to it. CursorH to first
797 MoveToLine(cur_line
);
800 * at this point we have something like this:
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
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).
814 * sx is the same for the second differences.
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
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
830 p
= (ols
!= oe
) ? oe
: ose
;
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
838 if ((nsb
!= nfd
) && fx
> 0 && ((p
- old
) + fx
< TermH
)) {
840 dprintf("first diff insert at %d...\r\n", nfd
- new);
841 #endif /* DEBUG_UPDATE */
843 * Move to the first char to insert, where the first diff is.
845 MoveToChar(nfd
- new);
847 * Check if we have stuff to keep at end
851 dprintf("with stuff to keep at end\r\n");
852 #endif /* DEBUG_UPDATE */
854 * insert fx chars of new starting at nfd
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
);
865 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
867 so_write(nfd
+ fx
, (nsb
- nfd
) - fx
);
868 str_cp(ofd
+ fx
, nfd
+ fx
, (int) ((nsb
- nfd
) - fx
));
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
));
884 dprintf("first diff delete at %d...\r\n", ofd
- old
);
885 #endif /* DEBUG_UPDATE */
887 * move to the first char to delete where the first diff is
889 MoveToChar(ofd
- old
);
891 * Check if we have stuff to save
895 dprintf("with stuff to save at end\r\n");
896 #endif /* DEBUG_UPDATE */
898 * fx is less than zero *always* here but we check for code
904 dprintf(" ERROR: cannot delete in first diff\n");
905 #endif /* DEBUG_UPDATE */
907 str_delete(old
, (int) (ofd
- old
), TermH
, -fx
);
910 * write (nsb-nfd) chars of new starting at nfd
912 so_write(nfd
, (nsb
- nfd
));
913 str_cp(ofd
, nfd
, (int) (nsb
- nfd
));
918 dprintf("but with nothing left to save\r\n");
919 #endif /* DEBUG_UPDATE */
921 * write (nsb-nfd) chars of new starting at nfd
923 so_write(nfd
, (nsb
- nfd
));
925 dprintf("cleareol %d\n", (oe
- old
) - (ne
- new));
926 #endif /* DEBUG_UPDATE */
928 ClearEOL((oe
- old
) - (ne
- new));
931 * The calculation above does not work too well on NT
933 ClearEOL(TermH
- CursorH
);
934 #endif /*WINNT_NATIVE*/
946 dprintf("second diff delete at %d...\r\n", (ose
- old
) + fx
);
947 #endif /* DEBUG_UPDATE */
949 * Check if we have stuff to delete
952 * fx is the number of characters inserted (+) or deleted (-)
955 MoveToChar((ose
- old
) + fx
);
957 * Check if we have stuff to save
961 dprintf("with stuff to save at end\r\n");
962 #endif /* DEBUG_UPDATE */
964 * Again a duplicate test.
969 dprintf(" ERROR: cannot delete in second diff\n");
970 #endif /* DEBUG_UPDATE */
975 * write (nls-nse) chars of new starting at nse
977 so_write(nse
, (nls
- nse
));
980 int olen
= (int) (oe
- old
+ fx
);
984 dprintf("but with nothing left to save\r\n");
985 #endif /* DEBUG_UPDATE */
986 so_write(nse
, (nls
- nse
));
988 dprintf("cleareol %d\n", olen
- (ne
- new));
989 #endif /* DEBUG_UPDATE */
991 ClearEOL(olen
- (ne
- new));
994 * The calculation above does not work too well on NT
996 ClearEOL(TermH
- CursorH
);
997 #endif /*WINNT_NATIVE*/
1002 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
1004 if ((nsb
!= nfd
) && (osb
- ofd
) <= (nsb
- nfd
) && (fx
== 0)) {
1006 dprintf("late first diff insert at %d...\r\n", nfd
- new);
1007 #endif /* DEBUG_UPDATE */
1009 MoveToChar(nfd
- new);
1011 * Check if we have stuff to keep at the end
1015 dprintf("with stuff to keep at end\r\n");
1016 #endif /* DEBUG_UPDATE */
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.
1022 fx
= (int) ((nsb
- nfd
) - (osb
- ofd
));
1025 * insert fx chars of new starting at nfd
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
);
1036 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1038 so_write(nfd
+ fx
, (nsb
- nfd
) - fx
);
1039 str_cp(ofd
+ fx
, nfd
+ fx
, (int) ((nsb
- nfd
) - fx
));
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
));
1051 * line is now NEW up to nse
1055 dprintf("second diff insert at %d...\r\n", nse
- new);
1056 #endif /* DEBUG_UPDATE */
1057 MoveToChar(nse
- new);
1060 dprintf("with stuff to keep at end\r\n");
1061 #endif /* DEBUG_UPDATE */
1063 /* insert sx chars of new starting at nse */
1066 dprintf(" ERROR: cannot insert in second diff\n");
1067 #endif /* DEBUG_UPDATE */
1068 Insert_write(nse
, sx
);
1072 * write (nls-nse) - sx chars of new starting at (nse + sx)
1074 so_write(nse
+ sx
, (nls
- nse
) - sx
);
1078 dprintf("without anything to save\r\n");
1079 #endif /* DEBUG_UPDATE */
1080 so_write(nse
, (nls
- nse
));
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
1090 dprintf("done.\r\n");
1091 #endif /* DEBUG_UPDATE */
1096 cpy_pad_spaces(Char
*dst
, Char
*src
, int width
)
1100 for (i
= 0; i
< width
; i
++) {
1101 if (*src
== (Char
) 0)
1115 { /* only move to new cursor pos */
1119 /* first we must find where the cursor is... */
1122 th
= TermH
; /* optimize for speed */
1124 for (cp
= Prompt
; cp
!= NULL
&& *cp
; ) { /* do prompt */
1125 if (*cp
& LITERAL
) {
1129 w
= NLSClassify(*cp
& CHAR
, cp
== Prompt
);
1143 case NLSCLASS_ILLEGAL
:
1146 case NLSCLASS_ILLEGAL2
:
1147 case NLSCLASS_ILLEGAL3
:
1148 case NLSCLASS_ILLEGAL4
:
1149 h
+= 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w
);
1154 if (h
>= th
) { /* check, extra long tabs picked up here also */
1160 for (cp
= InputBuf
; cp
< Cursor
;) { /* do input buffer to Cursor */
1161 w
= NLSClassify(*cp
& CHAR
, cp
== InputBuf
);
1175 case NLSCLASS_ILLEGAL
:
1178 case NLSCLASS_ILLEGAL2
:
1179 case NLSCLASS_ILLEGAL3
:
1180 case NLSCLASS_ILLEGAL4
:
1181 h
+= 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w
);
1186 if (h
>= th
) { /* check, extra long tabs picked up here also */
1195 if (adrof(STRhighlight
) && MarkIsSet
) {
1203 #ifndef WINTT_NATIVE
1205 PutPlusOne(Char c
, int width
)
1207 while (width
> 1 && CursorH
+ width
> TermH
)
1209 if ((c
& LITERAL
) != 0) {
1211 for (d
= litptr
+ (c
& ~LITERAL
) * LIT_FACTOR
; *d
; d
++)
1216 Display
[CursorV
][CursorH
++] = (Char
) c
;
1218 Display
[CursorV
][CursorH
++] = CHAR_DBWIDTH
;
1219 if (CursorH
>= TermH
) { /* if we must overflow */
1223 if (T_Margin
& MARGIN_AUTO
) {
1224 if (T_Margin
& MARGIN_MAGIC
) {
1226 (void) putraw('\b');
1230 (void) putraw('\r');
1231 (void) putraw('\n');
1239 { /* we added just one char, handle it fast.
1240 * assumes that screen cursor == real cursor */
1244 if (Cursor
!= LastChar
) {
1245 Refresh(); /* too hard to handle */
1248 if (rprompt_h
!= 0 && (TermH
- CursorH
- rprompt_h
< 3)) {
1249 Refresh(); /* clear out rprompt if less than one char gap*/
1254 w
= NLSClassify(c
, cp
== InputBuf
);
1258 if (c
== CTL_ESC('\177')) {
1263 /* uncontrolify it; works only for iso8859-1 like sets */
1264 PutPlusOne((c
| 0100), 1);
1266 PutPlusOne(_toebcdic
[_toascii
[c
]|0100], 1);
1269 case NLSCLASS_ILLEGAL
:
1270 PutPlusOne('\\', 1);
1271 PutPlusOne(((c
>> 6) & 7) + '0', 1);
1272 PutPlusOne(((c
>> 3) & 7) + '0', 1);
1273 PutPlusOne((c
& 7) + '0', 1);
1276 if (adrof(STRhighlight
) && MarkIsSet
)
1279 PutPlusOne(MakeLiteral(cp
, l
, 0), 1);
1282 if (adrof(STRhighlight
) && MarkIsSet
)
1286 Refresh(); /* too hard to handle */
1292 /* clear the screen buffers so that new new prompt starts fresh. */
1299 CursorV
= 0; /* clear the display buffer */
1301 for (i
= 0; i
< TermV
; i
++)
1302 (void) memset(Display
[i
], 0, TermH
* sizeof(Display
[0][0]));
1309 { /* Make sure all lines are *really* blank */
1314 * Clear the lines from the bottom up so that if we try moving
1315 * the cursor down by writing the character that is at the end
1316 * of the screen line, we won't rewrite a character that shouldn't
1319 for (i
= OldvcV
; i
>= 0; i
--) { /* for each line on the screen */
1326 MoveToLine(OldvcV
); /* go to last line */
1327 (void) putraw('\r'); /* go to BOL */
1328 (void) putraw('\n'); /* go to new line */