Make vinum use libedit instead of libreadline.
[dragonfly.git] / contrib / tcsh / ed.refresh.c
blobed05b8b214f078eca9620809c5de70ab81567ed3
1 /* $Header: /src/pub/tcsh/ed.refresh.c,v 3.29 2002/03/08 17:36:45 christos Exp $ */
2 /*
3 * ed.refresh.c: Lower level screen refreshing functions
4 */
5 /*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 #include "sh.h"
35 RCSID("$Id: ed.refresh.c,v 3.29 2002/03/08 17:36:45 christos Exp $")
37 #include "ed.h"
38 /* #define DEBUG_UPDATE */
39 /* #define DEBUG_REFRESH */
40 /* #define DEBUG_LITERAL */
42 /* refresh.c -- refresh the current set of lines on the screen */
44 Char *litptr[256];
45 static int vcursor_h, vcursor_v;
46 static int rprompt_h, rprompt_v;
48 static void Draw __P((int));
49 static void Vdraw __P((int));
50 static void RefreshPromptpart __P((Char *));
51 static void update_line __P((Char *, Char *, int));
52 static void str_insert __P((Char *, int, int, Char *, int));
53 static void str_delete __P((Char *, int, int, int));
54 static void str_cp __P((Char *, Char *, int));
55 static void PutPlusOne __P((int));
56 static void cpy_pad_spaces __P((Char *, Char *, int));
57 #if defined(DSPMBYTE)
58 static Char *update_line_fix_mbyte_point __P((Char *, Char *, int));
59 #endif
60 #if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL)
61 static void dprintf __P((char *, ...));
62 #ifdef DEBUG_UPDATE
63 static void dprintstr __P((char *, Char *, Char *));
65 static void
66 dprintstr(str, f, t)
67 char *str;
68 Char *f, *t;
70 dprintf("%s:\"", str);
71 while (f < t)
72 dprintf("%c", *f++ & ASCII);
73 dprintf("\"\r\n");
75 #endif /* DEBUG_UPDATE */
77 /* dprintf():
78 * Print to $DEBUGTTY, so that we can test editing on one pty, and
79 * print debugging stuff on another. Don't interrupt the shell while
80 * debugging cause you'll mangle up the file descriptors!
82 static void
83 #ifdef FUNCPROTO
84 dprintf(char *fmt, ...)
85 #else
86 dprintf(va_list)
87 va_dcl
88 #endif /* __STDC__ */
90 static int fd = -1;
91 char *dtty;
93 if ((dtty = getenv("DEBUGTTY"))) {
94 int o;
95 va_list va;
96 #ifdef FUNCPROTO
97 va_start(va, fmt);
98 #else
99 char *fmt;
100 va_start(va);
101 fmt = va_arg(va, char *);
102 #endif /* __STDC__ */
104 if (fd == -1)
105 fd = open(dtty, O_RDWR);
106 o = SHOUT;
107 flush();
108 SHOUT = fd;
109 xvprintf(fmt, va);
110 va_end(va);
111 flush();
112 SHOUT = o;
115 #endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */
117 static void
118 Draw(c) /* draw c, expand tabs, ctl chars */
119 register int c;
121 register Char ch = c & CHAR;
123 if (Isprint(ch)) {
124 Vdraw(c);
125 return;
127 /* from wolman%crltrx.DEC@decwrl.dec.com (Alec Wolman) */
128 if (ch == '\n') { /* expand the newline */
130 * Don't force a newline if Vdraw does it (i.e. we're at end of line)
131 * - or we will get two newlines and possibly garbage in between
133 int oldv = vcursor_v;
135 Vdraw('\0'); /* assure end of line */
136 if (oldv == vcursor_v) {
137 vcursor_h = 0; /* reset cursor pos */
138 vcursor_v++;
140 return;
142 if (ch == '\t') { /* expand the tab */
143 for (;;) {
144 Vdraw(' ');
145 if ((vcursor_h & 07) == 0)
146 break; /* go until tab stop */
149 else if (Iscntrl(ch)) {
150 #ifdef IS_ASCII
151 Vdraw('^');
152 if (ch == CTL_ESC('\177')) {
153 Vdraw('?');
155 else {
156 /* uncontrolify it; works only for iso8859-1 like sets */
157 Vdraw((c | 0100));
158 #else
159 if (ch == CTL_ESC('\177')) {
160 Vdraw('^');
161 Vdraw('?');
163 else {
164 if (Isupper(_toebcdic[_toascii[c]|0100])
165 || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL)
167 Vdraw('^');
168 Vdraw(_toebcdic[_toascii[c]|0100]);
170 else
172 Vdraw('\\');
173 Vdraw(((c >> 6) & 7) + '0');
174 Vdraw(((c >> 3) & 7) + '0');
175 Vdraw((c & 7) + '0');
177 #endif
180 #ifdef KANJI
181 else if (
182 #ifdef DSPMBYTE
183 _enable_mbdisp &&
184 #endif
185 !adrof(STRnokanji)) {
186 Vdraw(c);
187 return;
189 #endif
190 else {
191 Vdraw('\\');
192 Vdraw(((c >> 6) & 7) + '0');
193 Vdraw(((c >> 3) & 7) + '0');
194 Vdraw((c & 7) + '0');
198 static void
199 Vdraw(c) /* draw char c onto V lines */
200 register int c;
202 #ifdef DEBUG_REFRESH
203 # ifdef SHORT_STRINGS
204 dprintf("Vdrawing %6.6o '%c'\r\n", c, c & ASCII);
205 # else
206 dprintf("Vdrawing %3.3o '%c'\r\n", c, c);
207 # endif /* SHORT_STRNGS */
208 #endif /* DEBUG_REFRESH */
210 Vdisplay[vcursor_v][vcursor_h] = (Char) c;
211 vcursor_h++; /* advance to next place */
212 if (vcursor_h >= TermH) {
213 Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */
214 vcursor_h = 0; /* reset it. */
215 vcursor_v++;
216 #ifdef DEBUG_REFRESH
217 if (vcursor_v >= TermV) { /* should NEVER happen. */
218 dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n",
219 vcursor_v, TermV);
220 abort();
222 #endif /* DEBUG_REFRESH */
227 * RefreshPromptpart()
228 * draws a prompt element, expanding literals (we know it's ASCIZ)
230 static void
231 RefreshPromptpart(buf)
232 Char *buf;
234 register Char *cp;
235 static unsigned int litnum = 0;
236 if (buf == NULL)
238 litnum = 0;
239 return;
242 for (cp = buf; *cp; cp++) {
243 if (*cp & LITERAL) {
244 if (litnum < (sizeof(litptr) / sizeof(litptr[0]))) {
245 litptr[litnum] = cp;
246 #ifdef DEBUG_LITERAL
247 dprintf("litnum = %d, litptr = %x:\r\n",
248 litnum, litptr[litnum]);
249 #endif /* DEBUG_LITERAL */
251 while (*cp & LITERAL)
252 cp++;
253 if (*cp)
254 Vdraw((int) (litnum++ | LITERAL));
255 else {
257 * XXX: This is a bug, we lose the last literal, if it is not
258 * followed by a normal character, but it is too hard to fix
260 break;
263 else
264 Draw(*cp);
269 * Refresh()
270 * draws the new virtual screen image from the current input
271 * line, then goes line-by-line changing the real image to the new
272 * virtual image. The routine to re-draw a line can be replaced
273 * easily in hopes of a smarter one being placed there.
275 static int OldvcV = 0;
276 void
277 Refresh()
279 register int cur_line;
280 register Char *cp;
281 int cur_h, cur_v = 0, new_vcv;
282 int rhdiff;
283 Char oldgetting;
285 #ifdef DEBUG_REFRESH
286 dprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf));
287 dprintf("InputBuf = :%s:\r\n", short2str(InputBuf));
288 #endif /* DEBUG_REFRESH */
289 oldgetting = GettingInput;
290 GettingInput = 0; /* avoid re-entrance via SIGWINCH */
292 /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */
293 vcursor_h = 0;
294 vcursor_v = 0;
295 RefreshPromptpart(NULL);
296 RefreshPromptpart(RPromptBuf);
297 rprompt_h = vcursor_h;
298 rprompt_v = vcursor_v;
300 /* reset the Vdraw cursor, draw prompt */
301 vcursor_h = 0;
302 vcursor_v = 0;
303 RefreshPromptpart(NULL);
304 RefreshPromptpart(PromptBuf);
305 cur_h = -1; /* set flag in case I'm not set */
307 /* draw the current input buffer */
308 for (cp = InputBuf; (cp < LastChar); cp++) {
309 if (cp == Cursor) {
310 cur_h = vcursor_h; /* save for later */
311 cur_v = vcursor_v;
313 Draw(*cp);
316 if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */
317 cur_h = vcursor_h;
318 cur_v = vcursor_v;
321 rhdiff = TermH - vcursor_h - rprompt_h;
322 if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) {
324 * have a right-hand side prompt that will fit on
325 * the end of the first line with at least one
326 * character gap to the input buffer.
328 while (--rhdiff > 0) /* pad out with spaces */
329 Draw(' ');
330 RefreshPromptpart(RPromptBuf);
332 else {
333 rprompt_h = 0; /* flag "not using rprompt" */
334 rprompt_v = 0;
337 new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */
338 Vdraw('\0'); /* put NUL on end */
340 #ifdef DEBUG_REFRESH
341 dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n",
342 TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0]));
343 #endif /* DEBUG_REFRESH */
345 #ifdef DEBUG_UPDATE
346 dprintf("updating %d lines.\r\n", new_vcv);
347 #endif /* DEBUG_UPDATE */
348 for (cur_line = 0; cur_line <= new_vcv; cur_line++) {
349 /* NOTE THAT update_line MAY CHANGE Display[cur_line] */
350 update_line(Display[cur_line], Vdisplay[cur_line], cur_line);
351 #ifdef WINNT_NATIVE
352 flush();
353 #endif /* WINNT_NATIVE */
356 * Copy the new line to be the current one, and pad out with spaces
357 * to the full width of the terminal so that if we try moving the
358 * cursor by writing the character that is at the end of the
359 * screen line, it won't be a NUL or some old leftover stuff.
361 cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH);
362 #ifdef notdef
363 (void) Strncpy(Display[cur_line], Vdisplay[cur_line], (size_t) TermH);
364 Display[cur_line][TermH] = '\0'; /* just in case */
365 #endif
367 #ifdef DEBUG_REFRESH
368 dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n",
369 vcursor_v, OldvcV, cur_line);
370 #endif /* DEBUG_REFRESH */
371 if (OldvcV > new_vcv) {
372 for (; cur_line <= OldvcV; cur_line++) {
373 update_line(Display[cur_line], STRNULL, cur_line);
374 *Display[cur_line] = '\0';
377 OldvcV = new_vcv; /* set for next time */
378 #ifdef DEBUG_REFRESH
379 dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n",
380 CursorH, CursorV, cur_h, cur_v);
381 #endif /* DEBUG_REFRESH */
382 #ifdef WINNT_NATIVE
383 flush();
384 #endif /* WINNT_NATIVE */
385 MoveToLine(cur_v); /* go to where the cursor is */
386 MoveToChar(cur_h);
387 SetAttributes(0); /* Clear all attributes */
388 flush(); /* send the output... */
389 GettingInput = oldgetting; /* reset to old value */
392 #ifdef notdef
393 GotoBottom()
394 { /* used to go to last used screen line */
395 MoveToLine(OldvcV);
398 #endif
400 void
401 PastBottom()
402 { /* used to go to last used screen line */
403 MoveToLine(OldvcV);
404 (void) putraw('\r');
405 (void) putraw('\n');
406 ClearDisp();
407 flush();
411 /* insert num characters of s into d (in front of the character) at dat,
412 maximum length of d is dlen */
413 static void
414 str_insert(d, dat, dlen, s, num)
415 register Char *d;
416 register int dat, dlen;
417 register Char *s;
418 register int num;
420 register Char *a, *b;
422 if (num <= 0)
423 return;
424 if (num > dlen - dat)
425 num = dlen - dat;
427 #ifdef DEBUG_REFRESH
428 dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n",
429 num, dat, dlen, short2str(d));
430 dprintf("s == \"%s\"n", short2str(s));
431 #endif /* DEBUG_REFRESH */
433 /* open up the space for num chars */
434 if (num > 0) {
435 b = d + dlen - 1;
436 a = b - num;
437 while (a >= &d[dat])
438 *b-- = *a--;
439 d[dlen] = '\0'; /* just in case */
441 #ifdef DEBUG_REFRESH
442 dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n",
443 num, dat, dlen, short2str(d));
444 dprintf("s == \"%s\"n", short2str(s));
445 #endif /* DEBUG_REFRESH */
447 /* copy the characters */
448 for (a = d + dat; (a < d + dlen) && (num > 0); num--)
449 *a++ = *s++;
451 #ifdef DEBUG_REFRESH
452 dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n",
453 num, dat, dlen, d, short2str(s));
454 dprintf("s == \"%s\"n", short2str(s));
455 #endif /* DEBUG_REFRESH */
458 /* delete num characters d at dat, maximum length of d is dlen */
459 static void
460 str_delete(d, dat, dlen, num)
461 register Char *d;
462 register int dat, dlen, num;
464 register Char *a, *b;
466 if (num <= 0)
467 return;
468 if (dat + num >= dlen) {
469 d[dat] = '\0';
470 return;
473 #ifdef DEBUG_REFRESH
474 dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n",
475 num, dat, dlen, short2str(d));
476 #endif /* DEBUG_REFRESH */
478 /* open up the space for num chars */
479 if (num > 0) {
480 b = d + dat;
481 a = b + num;
482 while (a < &d[dlen])
483 *b++ = *a++;
484 d[dlen] = '\0'; /* just in case */
486 #ifdef DEBUG_REFRESH
487 dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n",
488 num, dat, dlen, short2str(d));
489 #endif /* DEBUG_REFRESH */
492 static void
493 str_cp(a, b, n)
494 register Char *a, *b;
495 register int n;
497 while (n-- && *b)
498 *a++ = *b++;
502 #if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
503 static Char *
504 update_line_fix_mbyte_point(start, target, d)
505 Char *start, *target;
506 int d;
508 if (_enable_mbdisp) {
509 while (*start) {
510 if (target == start)
511 break;
512 if (target < start)
513 return target + d;
514 if (Ismbyte1(*start) && Ismbyte2(*(start + 1)))
515 start++;
516 start++;
519 return target;
521 #endif
523 /* ****************************************************************
524 update_line() is based on finding the middle difference of each line
525 on the screen; vis:
527 /old first difference
528 /beginning of line | /old last same /old EOL
529 v v v v
530 old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
531 new: eddie> Oh, my little buggy says to me, as lurgid as
532 ^ ^ ^ ^
533 \beginning of line | \new last same \new end of line
534 \new first difference
536 all are character pointers for the sake of speed. Special cases for
537 no differences, as well as for end of line additions must be handled.
538 **************************************************************** */
540 /* Minimum at which doing an insert it "worth it". This should be about
541 * half the "cost" of going into insert mode, inserting a character, and
542 * going back out. This should really be calculated from the termcap
543 * data... For the moment, a good number for ANSI terminals.
545 #define MIN_END_KEEP 4
547 static void /* could be changed to make it smarter */
548 update_line(old, new, cur_line)
549 register Char *old, *new;
550 int cur_line;
552 register Char *o, *n, *p, c;
553 Char *ofd, *ols, *oe, *nfd, *nls, *ne;
554 Char *osb, *ose, *nsb, *nse;
555 int fx, sx;
558 * find first diff
560 for (o = old, n = new; *o && (*o == *n); o++, n++)
561 continue;
562 ofd = o;
563 nfd = n;
566 * Find the end of both old and new
568 while (*o)
569 o++;
571 * Remove any trailing blanks off of the end, being careful not to
572 * back up past the beginning.
574 while (ofd < o) {
575 if (o[-1] != ' ')
576 break;
577 o--;
579 oe = o;
580 *oe = (Char) 0;
582 while (*n)
583 n++;
585 /* remove blanks from end of new */
586 while (nfd < n) {
587 if (n[-1] != ' ')
588 break;
589 n--;
591 ne = n;
592 *ne = (Char) 0;
595 * if no diff, continue to next line of redraw
597 if (*ofd == '\0' && *nfd == '\0') {
598 #ifdef DEBUG_UPDATE
599 dprintf("no difference.\r\n");
600 #endif /* DEBUG_UPDATE */
601 return;
605 * find last same pointer
607 while ((o > ofd) && (n > nfd) && (*--o == *--n))
608 continue;
609 ols = ++o;
610 nls = ++n;
613 * find same begining and same end
615 osb = ols;
616 nsb = nls;
617 ose = ols;
618 nse = nls;
621 * case 1: insert: scan from nfd to nls looking for *ofd
623 if (*ofd) {
624 for (c = *ofd, n = nfd; n < nls; n++) {
625 if (c == *n) {
626 for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
627 continue;
629 * if the new match is longer and it's worth keeping, then we
630 * take it
632 if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
633 nsb = n;
634 nse = p;
635 osb = ofd;
636 ose = o;
643 * case 2: delete: scan from ofd to ols looking for *nfd
645 if (*nfd) {
646 for (c = *nfd, o = ofd; o < ols; o++) {
647 if (c == *o) {
648 for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
649 continue;
651 * if the new match is longer and it's worth keeping, then we
652 * take it
654 if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
655 nsb = nfd;
656 nse = n;
657 osb = o;
658 ose = p;
663 #ifdef notdef
665 * If `last same' is before `same end' re-adjust
667 if (ols < ose)
668 ols = ose;
669 if (nls < nse)
670 nls = nse;
671 #endif
674 * Pragmatics I: If old trailing whitespace or not enough characters to
675 * save to be worth it, then don't save the last same info.
677 if ((oe - ols) < MIN_END_KEEP) {
678 ols = oe;
679 nls = ne;
683 * Pragmatics II: if the terminal isn't smart enough, make the data dumber
684 * so the smart update doesn't try anything fancy
688 * fx is the number of characters we need to insert/delete: in the
689 * beginning to bring the two same begins together
691 fx = (int) ((nsb - nfd) - (osb - ofd));
693 * sx is the number of characters we need to insert/delete: in the end to
694 * bring the two same last parts together
696 sx = (int) ((nls - nse) - (ols - ose));
698 if (!T_CanIns) {
699 if (fx > 0) {
700 osb = ols;
701 ose = ols;
702 nsb = nls;
703 nse = nls;
705 if (sx > 0) {
706 ols = oe;
707 nls = ne;
709 if ((ols - ofd) < (nls - nfd)) {
710 ols = oe;
711 nls = ne;
714 if (!T_CanDel) {
715 if (fx < 0) {
716 osb = ols;
717 ose = ols;
718 nsb = nls;
719 nse = nls;
721 if (sx < 0) {
722 ols = oe;
723 nls = ne;
725 if ((ols - ofd) > (nls - nfd)) {
726 ols = oe;
727 nls = ne;
732 * Pragmatics III: make sure the middle shifted pointers are correct if
733 * they don't point to anything (we may have moved ols or nls).
735 /* if the change isn't worth it, don't bother */
736 /* was: if (osb == ose) */
737 if ((ose - osb) < MIN_END_KEEP) {
738 osb = ols;
739 ose = ols;
740 nsb = nls;
741 nse = nls;
745 * Now that we are done with pragmatics we recompute fx, sx
747 fx = (int) ((nsb - nfd) - (osb - ofd));
748 sx = (int) ((nls - nse) - (ols - ose));
750 #ifdef DEBUG_UPDATE
751 dprintf("\n");
752 dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n",
753 ofd - old, osb - old, ose - old, ols - old, oe - old);
754 dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
755 nfd - new, nsb - new, nse - new, nls - new, ne - new);
756 dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n");
757 dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n");
758 dprintstr("old- oe", old, oe);
759 dprintstr("new- ne", new, ne);
760 dprintstr("old-ofd", old, ofd);
761 dprintstr("new-nfd", new, nfd);
762 dprintstr("ofd-osb", ofd, osb);
763 dprintstr("nfd-nsb", nfd, nsb);
764 dprintstr("osb-ose", osb, ose);
765 dprintstr("nsb-nse", nsb, nse);
766 dprintstr("ose-ols", ose, ols);
767 dprintstr("nse-nls", nse, nls);
768 dprintstr("ols- oe", ols, oe);
769 dprintstr("nls- ne", nls, ne);
770 #endif /* DEBUG_UPDATE */
773 * CursorV to this line cur_line MUST be in this routine so that if we
774 * don't have to change the line, we don't move to it. CursorH to first
775 * diff char
777 MoveToLine(cur_line);
779 #if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
780 ofd = update_line_fix_mbyte_point(old, ofd, -1);
781 osb = update_line_fix_mbyte_point(old, osb, 1);
782 ose = update_line_fix_mbyte_point(old, ose, -1);
783 ols = update_line_fix_mbyte_point(old, ols, 1);
784 nfd = update_line_fix_mbyte_point(new, nfd, -1);
785 nsb = update_line_fix_mbyte_point(new, nsb, 1);
786 nse = update_line_fix_mbyte_point(new, nse, -1);
787 nls = update_line_fix_mbyte_point(new, nls, 1);
788 #endif
791 * at this point we have something like this:
793 * /old /ofd /osb /ose /ols /oe
794 * v.....................v v..................v v........v
795 * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
796 * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
797 * ^.....................^ ^..................^ ^........^
798 * \new \nfd \nsb \nse \nls \ne
800 * fx is the difference in length between the the chars between nfd and
801 * nsb, and the chars between ofd and osb, and is thus the number of
802 * characters to delete if < 0 (new is shorter than old, as above),
803 * or insert (new is longer than short).
805 * sx is the same for the second differences.
809 * if we have a net insert on the first difference, AND inserting the net
810 * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
811 * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
812 * (TermH - 1) else we do the deletes first so that we keep everything we
813 * need to.
817 * if the last same is the same like the end, there is no last same part,
818 * otherwise we want to keep the last same part set p to the last useful
819 * old character
821 p = (ols != oe) ? oe : ose;
824 * if (There is a diffence in the beginning) && (we need to insert
825 * characters) && (the number of characters to insert is less than the term
826 * width) We need to do an insert! else if (we need to delete characters)
827 * We need to delete characters! else No insert or delete
829 if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) {
830 #ifdef DEBUG_UPDATE
831 dprintf("first diff insert at %d...\r\n", nfd - new);
832 #endif /* DEBUG_UPDATE */
834 * Move to the first char to insert, where the first diff is.
836 MoveToChar(nfd - new);
838 * Check if we have stuff to keep at end
840 if (nsb != ne) {
841 #ifdef DEBUG_UPDATE
842 dprintf("with stuff to keep at end\r\n");
843 #endif /* DEBUG_UPDATE */
845 * insert fx chars of new starting at nfd
847 if (fx > 0) {
848 #ifdef DEBUG_UPDATE
849 if (!T_CanIns)
850 dprintf(" ERROR: cannot insert in early first diff\n");
851 #endif /* DEBUG_UPDATE */
852 Insert_write(nfd, fx);
853 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
856 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
858 so_write(nfd + fx, (nsb - nfd) - fx);
859 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
861 else {
862 #ifdef DEBUG_UPDATE
863 dprintf("without anything to save\r\n");
864 #endif /* DEBUG_UPDATE */
865 so_write(nfd, (nsb - nfd));
866 str_cp(ofd, nfd, (int) (nsb - nfd));
868 * Done
870 return;
873 else if (fx < 0) {
874 #ifdef DEBUG_UPDATE
875 dprintf("first diff delete at %d...\r\n", ofd - old);
876 #endif /* DEBUG_UPDATE */
878 * move to the first char to delete where the first diff is
880 MoveToChar(ofd - old);
882 * Check if we have stuff to save
884 if (osb != oe) {
885 #ifdef DEBUG_UPDATE
886 dprintf("with stuff to save at end\r\n");
887 #endif /* DEBUG_UPDATE */
889 * fx is less than zero *always* here but we check for code
890 * symmetry
892 if (fx < 0) {
893 #ifdef DEBUG_UPDATE
894 if (!T_CanDel)
895 dprintf(" ERROR: cannot delete in first diff\n");
896 #endif /* DEBUG_UPDATE */
897 DeleteChars(-fx);
898 str_delete(old, (int) (ofd - old), TermH, -fx);
901 * write (nsb-nfd) chars of new starting at nfd
903 so_write(nfd, (nsb - nfd));
904 str_cp(ofd, nfd, (int) (nsb - nfd));
907 else {
908 #ifdef DEBUG_UPDATE
909 dprintf("but with nothing left to save\r\n");
910 #endif /* DEBUG_UPDATE */
912 * write (nsb-nfd) chars of new starting at nfd
914 so_write(nfd, (nsb - nfd));
915 #ifdef DEBUG_REFRESH
916 dprintf("cleareol %d\n", (oe - old) - (ne - new));
917 #endif /* DEBUG_UPDATE */
918 #ifndef WINNT_NATIVE
919 ClearEOL((oe - old) - (ne - new));
920 #else
922 * The calculation above does not work too well on NT
924 ClearEOL(TermH - CursorH);
925 #endif /*WINNT_NATIVE*/
927 * Done
929 return;
932 else
933 fx = 0;
935 if (sx < 0) {
936 #ifdef DEBUG_UPDATE
937 dprintf("second diff delete at %d...\r\n", (ose - old) + fx);
938 #endif /* DEBUG_UPDATE */
940 * Check if we have stuff to delete
943 * fx is the number of characters inserted (+) or deleted (-)
946 MoveToChar((ose - old) + fx);
948 * Check if we have stuff to save
950 if (ols != oe) {
951 #ifdef DEBUG_UPDATE
952 dprintf("with stuff to save at end\r\n");
953 #endif /* DEBUG_UPDATE */
955 * Again a duplicate test.
957 if (sx < 0) {
958 #ifdef DEBUG_UPDATE
959 if (!T_CanDel)
960 dprintf(" ERROR: cannot delete in second diff\n");
961 #endif /* DEBUG_UPDATE */
962 DeleteChars(-sx);
966 * write (nls-nse) chars of new starting at nse
968 so_write(nse, (nls - nse));
970 else {
971 int olen = (int) (oe - old + fx);
972 if (olen > TermH)
973 olen = TermH;
974 #ifdef DEBUG_UPDATE
975 dprintf("but with nothing left to save\r\n");
976 #endif /* DEBUG_UPDATE */
977 so_write(nse, (nls - nse));
978 #ifdef DEBUG_REFRESH
979 dprintf("cleareol %d\n", olen - (ne - new));
980 #endif /* DEBUG_UPDATE */
981 #ifndef WINNT_NATIVE
982 ClearEOL(olen - (ne - new));
983 #else
985 * The calculation above does not work too well on NT
987 ClearEOL(TermH - CursorH);
988 #endif /*WINNT_NATIVE*/
993 * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
995 if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
996 #ifdef DEBUG_UPDATE
997 dprintf("late first diff insert at %d...\r\n", nfd - new);
998 #endif /* DEBUG_UPDATE */
1000 MoveToChar(nfd - new);
1002 * Check if we have stuff to keep at the end
1004 if (nsb != ne) {
1005 #ifdef DEBUG_UPDATE
1006 dprintf("with stuff to keep at end\r\n");
1007 #endif /* DEBUG_UPDATE */
1009 * We have to recalculate fx here because we set it
1010 * to zero above as a flag saying that we hadn't done
1011 * an early first insert.
1013 fx = (int) ((nsb - nfd) - (osb - ofd));
1014 if (fx > 0) {
1016 * insert fx chars of new starting at nfd
1018 #ifdef DEBUG_UPDATE
1019 if (!T_CanIns)
1020 dprintf(" ERROR: cannot insert in late first diff\n");
1021 #endif /* DEBUG_UPDATE */
1022 Insert_write(nfd, fx);
1023 str_insert(old, (int) (ofd - old), TermH, nfd, fx);
1027 * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
1029 so_write(nfd + fx, (nsb - nfd) - fx);
1030 str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx));
1032 else {
1033 #ifdef DEBUG_UPDATE
1034 dprintf("without anything to save\r\n");
1035 #endif /* DEBUG_UPDATE */
1036 so_write(nfd, (nsb - nfd));
1037 str_cp(ofd, nfd, (int) (nsb - nfd));
1042 * line is now NEW up to nse
1044 if (sx >= 0) {
1045 #ifdef DEBUG_UPDATE
1046 dprintf("second diff insert at %d...\r\n", nse - new);
1047 #endif /* DEBUG_UPDATE */
1048 MoveToChar(nse - new);
1049 if (ols != oe) {
1050 #ifdef DEBUG_UPDATE
1051 dprintf("with stuff to keep at end\r\n");
1052 #endif /* DEBUG_UPDATE */
1053 if (sx > 0) {
1054 /* insert sx chars of new starting at nse */
1055 #ifdef DEBUG_UPDATE
1056 if (!T_CanIns)
1057 dprintf(" ERROR: cannot insert in second diff\n");
1058 #endif /* DEBUG_UPDATE */
1059 Insert_write(nse, sx);
1063 * write (nls-nse) - sx chars of new starting at (nse + sx)
1065 so_write(nse + sx, (nls - nse) - sx);
1067 else {
1068 #ifdef DEBUG_UPDATE
1069 dprintf("without anything to save\r\n");
1070 #endif /* DEBUG_UPDATE */
1071 so_write(nse, (nls - nse));
1074 * No need to do a clear-to-end here because we were doing
1075 * a second insert, so we will have over written all of the
1076 * old string.
1080 #ifdef DEBUG_UPDATE
1081 dprintf("done.\r\n");
1082 #endif /* DEBUG_UPDATE */
1086 static void
1087 cpy_pad_spaces(dst, src, width)
1088 register Char *dst, *src;
1089 register int width;
1091 register int i;
1093 for (i = 0; i < width; i++) {
1094 if (*src == (Char) 0)
1095 break;
1096 *dst++ = *src++;
1099 while (i < width) {
1100 *dst++ = ' ';
1101 i++;
1103 *dst = (Char) 0;
1106 void
1107 RefCursor()
1108 { /* only move to new cursor pos */
1109 register Char *cp, c;
1110 register int h, th, v;
1112 /* first we must find where the cursor is... */
1113 h = 0;
1114 v = 0;
1115 th = TermH; /* optimize for speed */
1117 for (cp = PromptBuf; *cp; cp++) { /* do prompt */
1118 if (*cp & LITERAL)
1119 continue;
1120 c = *cp & CHAR; /* extra speed plus strip the inverse */
1121 h++; /* all chars at least this long */
1123 /* from wolman%crltrx.DEC@decwrl.dec.com (Alec Wolman) */
1124 /* lets handle newline as part of the prompt */
1126 if (c == '\n') {
1127 h = 0;
1128 v++;
1130 else {
1131 if (c == '\t') { /* if a tab, to next tab stop */
1132 while (h & 07) {
1133 h++;
1136 else if (Iscntrl(c)) { /* if control char */
1137 h++;
1138 if (h > th) { /* if overflow, compensate */
1139 h = 1;
1140 v++;
1143 else if (!Isprint(c)) {
1144 h += 3;
1145 if (h > th) { /* if overflow, compensate */
1146 h = h - th;
1147 v++;
1152 if (h >= th) { /* check, extra long tabs picked up here also */
1153 h = 0;
1154 v++;
1158 for (cp = InputBuf; cp < Cursor; cp++) { /* do input buffer to Cursor */
1159 c = *cp & CHAR; /* extra speed plus strip the inverse */
1160 h++; /* all chars at least this long */
1162 if (c == '\n') { /* handle newline in data part too */
1163 h = 0;
1164 v++;
1166 else {
1167 if (c == '\t') { /* if a tab, to next tab stop */
1168 while (h & 07) {
1169 h++;
1172 else if (Iscntrl(c)) { /* if control char */
1173 h++;
1174 if (h > th) { /* if overflow, compensate */
1175 h = 1;
1176 v++;
1179 else if (!Isprint(c)) {
1180 h += 3;
1181 if (h > th) { /* if overflow, compensate */
1182 h = h - th;
1183 v++;
1188 if (h >= th) { /* check, extra long tabs picked up here also */
1189 h = 0;
1190 v++;
1194 /* now go there */
1195 MoveToLine(v);
1196 MoveToChar(h);
1197 flush();
1200 static void
1201 PutPlusOne(c)
1202 int c;
1204 (void) putraw(c);
1205 Display[CursorV][CursorH++] = (Char) c;
1206 if (CursorH >= TermH) { /* if we must overflow */
1207 CursorH = 0;
1208 CursorV++;
1209 OldvcV++;
1210 if (T_Margin & MARGIN_AUTO) {
1211 if (T_Margin & MARGIN_MAGIC) {
1212 (void) putraw(' ');
1213 (void) putraw('\b');
1216 else {
1217 (void) putraw('\r');
1218 (void) putraw('\n');
1223 void
1224 RefPlusOne()
1225 { /* we added just one char, handle it fast.
1226 * assumes that screen cursor == real cursor */
1227 register Char c, mc;
1229 c = Cursor[-1] & CHAR; /* the char we just added */
1231 if (c == '\t' || Cursor != LastChar) {
1232 Refresh(); /* too hard to handle */
1233 return;
1236 if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) {
1237 Refresh(); /* clear out rprompt if less than one char gap*/
1238 return;
1239 } /* else (only do at end of line, no TAB) */
1241 if (Iscntrl(c)) { /* if control char, do caret */
1242 #ifdef IS_ASCII
1243 mc = (c == '\177') ? '?' : (c | 0100);
1244 PutPlusOne('^');
1245 PutPlusOne(mc);
1246 #else
1247 if (_toascii[c] == '\177' || Isupper(_toebcdic[_toascii[c]|0100])
1248 || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL)
1250 mc = (_toascii[c] == '\177') ? '?' : _toebcdic[_toascii[c]|0100];
1251 PutPlusOne('^');
1252 PutPlusOne(mc);
1254 else
1256 PutPlusOne('\\');
1257 PutPlusOne(((c >> 6) & 7) + '0');
1258 PutPlusOne(((c >> 3) & 7) + '0');
1259 PutPlusOne((c & 7) + '0');
1261 #endif
1263 else if (Isprint(c)) { /* normal char */
1264 PutPlusOne(c);
1266 #ifdef KANJI
1267 else if (
1268 #ifdef DSPMBYTE
1269 _enable_mbdisp &&
1270 #endif
1271 !adrof(STRnokanji)) {
1272 PutPlusOne(c);
1274 #endif
1275 else {
1276 PutPlusOne('\\');
1277 PutPlusOne(((c >> 6) & 7) + '0');
1278 PutPlusOne(((c >> 3) & 7) + '0');
1279 PutPlusOne((c & 7) + '0');
1281 flush();
1284 /* clear the screen buffers so that new new prompt starts fresh. */
1286 void
1287 ClearDisp()
1289 register int i;
1291 CursorV = 0; /* clear the display buffer */
1292 CursorH = 0;
1293 for (i = 0; i < TermV; i++)
1294 (void) memset(Display[i], 0, TermH * sizeof(Display[0][0]));
1295 OldvcV = 0;
1298 void
1299 ClearLines()
1300 { /* Make sure all lines are *really* blank */
1301 register int i;
1303 if (T_CanCEOL) {
1305 * Clear the lines from the bottom up so that if we try moving
1306 * the cursor down by writing the character that is at the end
1307 * of the screen line, we won't rewrite a character that shouldn't
1308 * be there.
1310 for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */
1311 MoveToLine(i);
1312 MoveToChar(0);
1313 ClearEOL(TermH);
1316 else {
1317 MoveToLine(OldvcV); /* go to last line */
1318 (void) putraw('\r'); /* go to BOL */
1319 (void) putraw('\n'); /* go to new line */