1 | /* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/ed.refresh.c,v 1.1.1.3 2005-06-03 14:35:26 ghudson 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. |
---|
8 | * |
---|
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. |
---|
20 | * |
---|
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. |
---|
32 | */ |
---|
33 | #include "sh.h" |
---|
34 | |
---|
35 | RCSID("$Id: ed.refresh.c,v 1.1.1.3 2005-06-03 14:35:26 ghudson Exp $") |
---|
36 | |
---|
37 | #include "ed.h" |
---|
38 | /* #define DEBUG_UPDATE */ |
---|
39 | /* #define DEBUG_REFRESH */ |
---|
40 | /* #define DEBUG_LITERAL */ |
---|
41 | |
---|
42 | /* refresh.c -- refresh the current set of lines on the screen */ |
---|
43 | |
---|
44 | Char *litptr; |
---|
45 | static int vcursor_h, vcursor_v; |
---|
46 | static int rprompt_h, rprompt_v; |
---|
47 | |
---|
48 | static int MakeLiteral __P((Char *, int, Char)); |
---|
49 | static int Draw __P((Char *, int)); |
---|
50 | static void Vdraw __P((Char, int)); |
---|
51 | static void RefreshPromptpart __P((Char *)); |
---|
52 | static void update_line __P((Char *, Char *, int)); |
---|
53 | static void str_insert __P((Char *, int, int, Char *, int)); |
---|
54 | static void str_delete __P((Char *, int, int, int)); |
---|
55 | static void str_cp __P((Char *, Char *, int)); |
---|
56 | #ifndef WINNT_NATIVE |
---|
57 | static |
---|
58 | #else |
---|
59 | extern |
---|
60 | #endif |
---|
61 | void PutPlusOne __P((Char, int)); |
---|
62 | static void cpy_pad_spaces __P((Char *, Char *, int)); |
---|
63 | #if defined(DEBUG_UPDATE) || defined(DEBUG_REFRESH) || defined(DEBUG_LITERAL) |
---|
64 | static void dprintf __P((char *, ...)); |
---|
65 | #ifdef DEBUG_UPDATE |
---|
66 | static void dprintstr __P((char *, const Char *, const Char *)); |
---|
67 | |
---|
68 | static void |
---|
69 | dprintstr(str, f, t) |
---|
70 | char *str; |
---|
71 | const Char *f, *t; |
---|
72 | { |
---|
73 | dprintf("%s:\"", str); |
---|
74 | while (f < t) { |
---|
75 | if (*f & ~ASCII) |
---|
76 | dprintf("[%x]", *f++); |
---|
77 | else |
---|
78 | dprintf("%c", *f++ & ASCII); |
---|
79 | } |
---|
80 | dprintf("\"\r\n"); |
---|
81 | } |
---|
82 | #endif /* DEBUG_UPDATE */ |
---|
83 | |
---|
84 | /* dprintf(): |
---|
85 | * Print to $DEBUGTTY, so that we can test editing on one pty, and |
---|
86 | * print debugging stuff on another. Don't interrupt the shell while |
---|
87 | * debugging cause you'll mangle up the file descriptors! |
---|
88 | */ |
---|
89 | static void |
---|
90 | #ifdef PROTOTYPES |
---|
91 | dprintf(char *fmt, ...) |
---|
92 | #else |
---|
93 | dprintf(va_list) |
---|
94 | va_dcl |
---|
95 | #endif /* __STDC__ */ |
---|
96 | { |
---|
97 | static int fd = -1; |
---|
98 | char *dtty; |
---|
99 | |
---|
100 | if ((dtty = getenv("DEBUGTTY"))) { |
---|
101 | int o; |
---|
102 | va_list va; |
---|
103 | #ifdef PROTOTYPES |
---|
104 | va_start(va, fmt); |
---|
105 | #else |
---|
106 | char *fmt; |
---|
107 | va_start(va); |
---|
108 | fmt = va_arg(va, char *); |
---|
109 | #endif /* __STDC__ */ |
---|
110 | |
---|
111 | if (fd == -1) |
---|
112 | fd = open(dtty, O_RDWR); |
---|
113 | o = SHOUT; |
---|
114 | flush(); |
---|
115 | SHOUT = fd; |
---|
116 | xvprintf(fmt, va); |
---|
117 | va_end(va); |
---|
118 | flush(); |
---|
119 | SHOUT = o; |
---|
120 | } |
---|
121 | } |
---|
122 | #endif /* DEBUG_UPDATE || DEBUG_REFRESH || DEBUG_LITERAL */ |
---|
123 | |
---|
124 | static int litlen = 0, litalloc = 0; |
---|
125 | |
---|
126 | static int MakeLiteral(str, len, addlit) |
---|
127 | Char *str; |
---|
128 | int len; |
---|
129 | Char addlit; |
---|
130 | { |
---|
131 | int i, addlitlen = 0; |
---|
132 | Char *addlitptr = 0; |
---|
133 | if (addlit) { |
---|
134 | if ((addlit & LITERAL) != 0) { |
---|
135 | addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; |
---|
136 | addlitlen = Strlen(addlitptr); |
---|
137 | } else { |
---|
138 | addlitptr = &addlit; |
---|
139 | addlitlen = 1; |
---|
140 | } |
---|
141 | for (i = 0; i < litlen; i += LIT_FACTOR) |
---|
142 | if (!Strncmp(addlitptr, litptr + i, addlitlen) && !Strncmp(str, litptr + i + addlitlen, len) && litptr[i + addlitlen + len] == 0) |
---|
143 | return (i / LIT_FACTOR) | LITERAL; |
---|
144 | } else { |
---|
145 | addlitlen = 0; |
---|
146 | for (i = 0; i < litlen; i += LIT_FACTOR) |
---|
147 | if (!Strncmp(str, litptr + i, len) && litptr[i + len] == 0) |
---|
148 | return (i / LIT_FACTOR) | LITERAL; |
---|
149 | } |
---|
150 | if (litlen + addlitlen + len + 1 + (LIT_FACTOR - 1) > litalloc) { |
---|
151 | Char *newlitptr; |
---|
152 | int add = 256; |
---|
153 | while (len + addlitlen + 1 + (LIT_FACTOR - 1) > add) |
---|
154 | add *= 2; |
---|
155 | if (litptr) |
---|
156 | newlitptr = (Char *)xrealloc(litptr, (litalloc + add) * sizeof(Char)); |
---|
157 | else |
---|
158 | newlitptr = (Char *)xmalloc((litalloc + add) * sizeof(Char)); |
---|
159 | if (!newlitptr) |
---|
160 | return '?'; |
---|
161 | litptr = newlitptr; |
---|
162 | litalloc += add; |
---|
163 | if (addlitptr && addlitptr != &addlit) |
---|
164 | addlitptr = litptr + (addlit & ~LITERAL) * LIT_FACTOR; |
---|
165 | } |
---|
166 | i = litlen / LIT_FACTOR; |
---|
167 | if (i >= LITERAL || i == CHAR_DBWIDTH) |
---|
168 | return '?'; |
---|
169 | if (addlitptr) { |
---|
170 | Strncpy(litptr + litlen, addlitptr, addlitlen); |
---|
171 | litlen += addlitlen; |
---|
172 | } |
---|
173 | Strncpy(litptr + litlen, str, len); |
---|
174 | litlen += len; |
---|
175 | do |
---|
176 | litptr[litlen++] = 0; |
---|
177 | while (litlen % LIT_FACTOR); |
---|
178 | return i | LITERAL; |
---|
179 | } |
---|
180 | |
---|
181 | static int |
---|
182 | Draw(cp, nocomb) /* draw char at cp, expand tabs, ctl chars */ |
---|
183 | Char *cp; |
---|
184 | int nocomb; |
---|
185 | { |
---|
186 | int l, w, i, lv, lh; |
---|
187 | Char ch, attr; |
---|
188 | NLSChar c; |
---|
189 | |
---|
190 | attr = *cp & ~CHAR; |
---|
191 | l = NLSFrom(cp, NLSZEROT, &c); |
---|
192 | w = NLSClassify(c, nocomb); |
---|
193 | switch (w) { |
---|
194 | case NLSCLASS_NL: |
---|
195 | Vdraw('\0', 0); /* assure end of line */ |
---|
196 | vcursor_h = 0; /* reset cursor pos */ |
---|
197 | vcursor_v++; |
---|
198 | break; |
---|
199 | case NLSCLASS_TAB: |
---|
200 | do { |
---|
201 | Vdraw(' ', 1); |
---|
202 | } while ((vcursor_h & 07) != 0); |
---|
203 | break; |
---|
204 | case NLSCLASS_CTRL: |
---|
205 | Vdraw('^' | attr, 1); |
---|
206 | if (c == CTL_ESC('\177')) { |
---|
207 | Vdraw('?' | attr, 1); |
---|
208 | } else { |
---|
209 | #ifdef IS_ASCII |
---|
210 | /* uncontrolify it; works only for iso8859-1 like sets */ |
---|
211 | Vdraw(c | 0100 | attr, 1); |
---|
212 | #else |
---|
213 | Vdraw(_toebcdic[_toascii[c]|0100] | attr, 1); |
---|
214 | #endif |
---|
215 | } |
---|
216 | break; |
---|
217 | case NLSCLASS_ILLEGAL: |
---|
218 | ch = *cp & CHAR; |
---|
219 | Vdraw('\\' | attr, 1); |
---|
220 | Vdraw((((ch >> 6) & 7) + '0') | attr, 1); |
---|
221 | Vdraw((((ch >> 3) & 7) + '0') | attr, 1); |
---|
222 | Vdraw(((ch & 7) + '0') | attr, 1); |
---|
223 | break; |
---|
224 | case NLSCLASS_ILLEGAL2: |
---|
225 | case NLSCLASS_ILLEGAL3: |
---|
226 | case NLSCLASS_ILLEGAL4: |
---|
227 | Vdraw('\\' | attr, 1); |
---|
228 | Vdraw('U' | attr, 1); |
---|
229 | Vdraw('+' | attr, 1); |
---|
230 | for (i = 8 * NLSCLASS_ILLEGAL_SIZE(w) - 4; i >= 0; i -= 4) |
---|
231 | Vdraw("0123456789ABCDEF"[(c >> i) & 15] | attr, 1); |
---|
232 | break; |
---|
233 | case 0: |
---|
234 | lv = vcursor_v; |
---|
235 | lh = vcursor_h; |
---|
236 | for (;;) { |
---|
237 | lh--; |
---|
238 | if (lh < 0) { |
---|
239 | lv--; |
---|
240 | if (lv < 0) |
---|
241 | break; |
---|
242 | lh = Strlen(Vdisplay[lv]) - 1; |
---|
243 | } |
---|
244 | if (Vdisplay[lv][lh] != CHAR_DBWIDTH) |
---|
245 | break; |
---|
246 | } |
---|
247 | if (lv < 0) { |
---|
248 | int l2 = l; |
---|
249 | for (; l2-- > 0; cp++) { |
---|
250 | ch = *cp & CHAR; |
---|
251 | Vdraw('\\' | attr, 1); |
---|
252 | Vdraw((((ch >> 6) & 7) + '0') | attr, 1); |
---|
253 | Vdraw((((ch >> 3) & 7) + '0') | attr, 1); |
---|
254 | Vdraw(((ch & 7) + '0') | attr, 1); |
---|
255 | } |
---|
256 | return l; |
---|
257 | } |
---|
258 | Vdisplay[lv][lh] = MakeLiteral(cp, l, Vdisplay[lv][lh]); |
---|
259 | break; |
---|
260 | default: |
---|
261 | if (l > 1) |
---|
262 | Vdraw(MakeLiteral(cp, l, 0), w); |
---|
263 | else |
---|
264 | Vdraw(*cp, w); |
---|
265 | break; |
---|
266 | } |
---|
267 | return l; |
---|
268 | } |
---|
269 | |
---|
270 | static void |
---|
271 | Vdraw(c, width) /* draw char c onto V lines */ |
---|
272 | Char c; |
---|
273 | int width; |
---|
274 | { |
---|
275 | #ifdef DEBUG_REFRESH |
---|
276 | # ifdef SHORT_STRINGS |
---|
277 | dprintf("Vdrawing %6.6o '%c' %d\r\n", (unsigned)c, (int)(c & ASCII), width); |
---|
278 | # else |
---|
279 | dprintf("Vdrawing %3.3o '%c' %d\r\n", (unsigned)c, (int)c, width); |
---|
280 | # endif /* SHORT_STRNGS */ |
---|
281 | #endif /* DEBUG_REFRESH */ |
---|
282 | |
---|
283 | /* Hopefully this is what all the terminals do with multi-column characters |
---|
284 | that "span line breaks". */ |
---|
285 | while (vcursor_h + width > TermH) |
---|
286 | Vdraw(' ', 1); |
---|
287 | Vdisplay[vcursor_v][vcursor_h] = (Char) c; |
---|
288 | if (width) |
---|
289 | vcursor_h++; /* advance to next place */ |
---|
290 | while (--width > 0) |
---|
291 | Vdisplay[vcursor_v][vcursor_h++] = CHAR_DBWIDTH; |
---|
292 | if (vcursor_h >= TermH) { |
---|
293 | Vdisplay[vcursor_v][TermH] = '\0'; /* assure end of line */ |
---|
294 | vcursor_h = 0; /* reset it. */ |
---|
295 | vcursor_v++; |
---|
296 | #ifdef DEBUG_REFRESH |
---|
297 | if (vcursor_v >= TermV) { /* should NEVER happen. */ |
---|
298 | dprintf("\r\nVdraw: vcursor_v overflow! Vcursor_v == %d > %d\r\n", |
---|
299 | vcursor_v, TermV); |
---|
300 | abort(); |
---|
301 | } |
---|
302 | #endif /* DEBUG_REFRESH */ |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | /* |
---|
307 | * RefreshPromptpart() |
---|
308 | * draws a prompt element, expanding literals (we know it's ASCIZ) |
---|
309 | */ |
---|
310 | static void |
---|
311 | RefreshPromptpart(buf) |
---|
312 | Char *buf; |
---|
313 | { |
---|
314 | Char *cp; |
---|
315 | NLSChar c; |
---|
316 | int l, w; |
---|
317 | |
---|
318 | for (cp = buf; *cp; ) { |
---|
319 | if (*cp & LITERAL) { |
---|
320 | Char *litstart = cp; |
---|
321 | while (*cp & LITERAL) |
---|
322 | cp++; |
---|
323 | if (*cp) { |
---|
324 | l = NLSFrom(cp, NLSZEROT, &c); |
---|
325 | w = NLSWidth(c); |
---|
326 | Vdraw(MakeLiteral(litstart, cp + l - litstart, 0), w); |
---|
327 | cp += l; |
---|
328 | } |
---|
329 | else { |
---|
330 | /* |
---|
331 | * XXX: This is a bug, we lose the last literal, if it is not |
---|
332 | * followed by a normal character, but it is too hard to fix |
---|
333 | */ |
---|
334 | break; |
---|
335 | } |
---|
336 | } |
---|
337 | else |
---|
338 | cp += Draw(cp, cp == buf); |
---|
339 | } |
---|
340 | } |
---|
341 | |
---|
342 | /* |
---|
343 | * Refresh() |
---|
344 | * draws the new virtual screen image from the current input |
---|
345 | * line, then goes line-by-line changing the real image to the new |
---|
346 | * virtual image. The routine to re-draw a line can be replaced |
---|
347 | * easily in hopes of a smarter one being placed there. |
---|
348 | */ |
---|
349 | #ifndef WINNT_NATIVE |
---|
350 | static |
---|
351 | #endif |
---|
352 | int OldvcV = 0; |
---|
353 | |
---|
354 | void |
---|
355 | Refresh() |
---|
356 | { |
---|
357 | int cur_line; |
---|
358 | Char *cp; |
---|
359 | int cur_h, cur_v = 0, new_vcv; |
---|
360 | int rhdiff; |
---|
361 | Char oldgetting; |
---|
362 | |
---|
363 | #ifdef DEBUG_REFRESH |
---|
364 | dprintf("PromptBuf = :%s:\r\n", short2str(PromptBuf)); |
---|
365 | dprintf("InputBuf = :%s:\r\n", short2str(InputBuf)); |
---|
366 | #endif /* DEBUG_REFRESH */ |
---|
367 | oldgetting = GettingInput; |
---|
368 | GettingInput = 0; /* avoid re-entrance via SIGWINCH */ |
---|
369 | |
---|
370 | /* reset the Vdraw cursor, temporarily draw rprompt to calculate its size */ |
---|
371 | vcursor_h = 0; |
---|
372 | vcursor_v = 0; |
---|
373 | RefreshPromptpart(RPromptBuf); |
---|
374 | rprompt_h = vcursor_h; |
---|
375 | rprompt_v = vcursor_v; |
---|
376 | |
---|
377 | /* reset the Vdraw cursor, draw prompt */ |
---|
378 | vcursor_h = 0; |
---|
379 | vcursor_v = 0; |
---|
380 | RefreshPromptpart(PromptBuf); |
---|
381 | cur_h = -1; /* set flag in case I'm not set */ |
---|
382 | |
---|
383 | /* draw the current input buffer */ |
---|
384 | for (cp = InputBuf; (cp < LastChar); ) { |
---|
385 | if (cp >= Cursor && cur_h == -1) { |
---|
386 | cur_h = vcursor_h; /* save for later */ |
---|
387 | cur_v = vcursor_v; |
---|
388 | Cursor = cp; |
---|
389 | } |
---|
390 | cp += Draw(cp, cp == InputBuf); |
---|
391 | } |
---|
392 | |
---|
393 | if (cur_h == -1) { /* if I haven't been set yet, I'm at the end */ |
---|
394 | cur_h = vcursor_h; |
---|
395 | cur_v = vcursor_v; |
---|
396 | } |
---|
397 | |
---|
398 | rhdiff = TermH - vcursor_h - rprompt_h; |
---|
399 | if (rprompt_h != 0 && rprompt_v == 0 && vcursor_v == 0 && rhdiff > 1) { |
---|
400 | /* |
---|
401 | * have a right-hand side prompt that will fit on |
---|
402 | * the end of the first line with at least one |
---|
403 | * character gap to the input buffer. |
---|
404 | */ |
---|
405 | while (--rhdiff > 0) /* pad out with spaces */ |
---|
406 | Vdraw(' ', 1); |
---|
407 | RefreshPromptpart(RPromptBuf); |
---|
408 | } |
---|
409 | else { |
---|
410 | rprompt_h = 0; /* flag "not using rprompt" */ |
---|
411 | rprompt_v = 0; |
---|
412 | } |
---|
413 | |
---|
414 | new_vcv = vcursor_v; /* must be done BEFORE the NUL is written */ |
---|
415 | Vdraw('\0', 1); /* put NUL on end */ |
---|
416 | |
---|
417 | #if defined (DEBUG_REFRESH) |
---|
418 | dprintf("TermH=%d, vcur_h=%d, vcur_v=%d, Vdisplay[0]=\r\n:%80.80s:\r\n", |
---|
419 | TermH, vcursor_h, vcursor_v, short2str(Vdisplay[0])); |
---|
420 | #endif /* DEBUG_REFRESH */ |
---|
421 | |
---|
422 | #ifdef DEBUG_UPDATE |
---|
423 | dprintf("updating %d lines.\r\n", new_vcv); |
---|
424 | #endif /* DEBUG_UPDATE */ |
---|
425 | for (cur_line = 0; cur_line <= new_vcv; cur_line++) { |
---|
426 | /* NOTE THAT update_line MAY CHANGE Display[cur_line] */ |
---|
427 | update_line(Display[cur_line], Vdisplay[cur_line], cur_line); |
---|
428 | #ifdef WINNT_NATIVE |
---|
429 | flush(); |
---|
430 | #endif /* WINNT_NATIVE */ |
---|
431 | |
---|
432 | /* |
---|
433 | * Copy the new line to be the current one, and pad out with spaces |
---|
434 | * to the full width of the terminal so that if we try moving the |
---|
435 | * cursor by writing the character that is at the end of the |
---|
436 | * screen line, it won't be a NUL or some old leftover stuff. |
---|
437 | */ |
---|
438 | cpy_pad_spaces(Display[cur_line], Vdisplay[cur_line], TermH); |
---|
439 | } |
---|
440 | #ifdef DEBUG_REFRESH |
---|
441 | dprintf("\r\nvcursor_v = %d, OldvcV = %d, cur_line = %d\r\n", |
---|
442 | vcursor_v, OldvcV, cur_line); |
---|
443 | #endif /* DEBUG_REFRESH */ |
---|
444 | if (OldvcV > new_vcv) { |
---|
445 | for (; cur_line <= OldvcV; cur_line++) { |
---|
446 | update_line(Display[cur_line], STRNULL, cur_line); |
---|
447 | *Display[cur_line] = '\0'; |
---|
448 | } |
---|
449 | } |
---|
450 | OldvcV = new_vcv; /* set for next time */ |
---|
451 | #ifdef DEBUG_REFRESH |
---|
452 | dprintf("\r\nCursorH = %d, CursorV = %d, cur_h = %d, cur_v = %d\r\n", |
---|
453 | CursorH, CursorV, cur_h, cur_v); |
---|
454 | #endif /* DEBUG_REFRESH */ |
---|
455 | #ifdef WINNT_NATIVE |
---|
456 | flush(); |
---|
457 | #endif /* WINNT_NATIVE */ |
---|
458 | MoveToLine(cur_v); /* go to where the cursor is */ |
---|
459 | MoveToChar(cur_h); |
---|
460 | SetAttributes(0); /* Clear all attributes */ |
---|
461 | flush(); /* send the output... */ |
---|
462 | GettingInput = oldgetting; /* reset to old value */ |
---|
463 | } |
---|
464 | |
---|
465 | #ifdef notdef |
---|
466 | GotoBottom() |
---|
467 | { /* used to go to last used screen line */ |
---|
468 | MoveToLine(OldvcV); |
---|
469 | } |
---|
470 | |
---|
471 | #endif |
---|
472 | |
---|
473 | void |
---|
474 | PastBottom() |
---|
475 | { /* used to go to last used screen line */ |
---|
476 | MoveToLine(OldvcV); |
---|
477 | (void) putraw('\r'); |
---|
478 | (void) putraw('\n'); |
---|
479 | ClearDisp(); |
---|
480 | flush(); |
---|
481 | } |
---|
482 | |
---|
483 | |
---|
484 | /* insert num characters of s into d (in front of the character) at dat, |
---|
485 | maximum length of d is dlen */ |
---|
486 | static void |
---|
487 | str_insert(d, dat, dlen, s, num) |
---|
488 | Char *d; |
---|
489 | int dat, dlen; |
---|
490 | Char *s; |
---|
491 | int num; |
---|
492 | { |
---|
493 | Char *a, *b; |
---|
494 | |
---|
495 | if (num <= 0) |
---|
496 | return; |
---|
497 | if (num > dlen - dat) |
---|
498 | num = dlen - dat; |
---|
499 | |
---|
500 | #ifdef DEBUG_REFRESH |
---|
501 | dprintf("str_insert() starting: %d at %d max %d, d == \"%s\"\n", |
---|
502 | num, dat, dlen, short2str(d)); |
---|
503 | dprintf("s == \"%s\"n", short2str(s)); |
---|
504 | #endif /* DEBUG_REFRESH */ |
---|
505 | |
---|
506 | /* open up the space for num chars */ |
---|
507 | if (num > 0) { |
---|
508 | b = d + dlen - 1; |
---|
509 | a = b - num; |
---|
510 | while (a >= &d[dat]) |
---|
511 | *b-- = *a--; |
---|
512 | d[dlen] = '\0'; /* just in case */ |
---|
513 | } |
---|
514 | #ifdef DEBUG_REFRESH |
---|
515 | dprintf("str_insert() after insert: %d at %d max %d, d == \"%s\"\n", |
---|
516 | num, dat, dlen, short2str(d)); |
---|
517 | dprintf("s == \"%s\"n", short2str(s)); |
---|
518 | #endif /* DEBUG_REFRESH */ |
---|
519 | |
---|
520 | /* copy the characters */ |
---|
521 | for (a = d + dat; (a < d + dlen) && (num > 0); num--) |
---|
522 | *a++ = *s++; |
---|
523 | |
---|
524 | #ifdef DEBUG_REFRESH |
---|
525 | dprintf("str_insert() after copy: %d at %d max %d, d == \"%s\"\n", |
---|
526 | num, dat, dlen, d, short2str(s)); |
---|
527 | dprintf("s == \"%s\"n", short2str(s)); |
---|
528 | #endif /* DEBUG_REFRESH */ |
---|
529 | } |
---|
530 | |
---|
531 | /* delete num characters d at dat, maximum length of d is dlen */ |
---|
532 | static void |
---|
533 | str_delete(d, dat, dlen, num) |
---|
534 | Char *d; |
---|
535 | int dat, dlen, num; |
---|
536 | { |
---|
537 | Char *a, *b; |
---|
538 | |
---|
539 | if (num <= 0) |
---|
540 | return; |
---|
541 | if (dat + num >= dlen) { |
---|
542 | d[dat] = '\0'; |
---|
543 | return; |
---|
544 | } |
---|
545 | |
---|
546 | #ifdef DEBUG_REFRESH |
---|
547 | dprintf("str_delete() starting: %d at %d max %d, d == \"%s\"\n", |
---|
548 | num, dat, dlen, short2str(d)); |
---|
549 | #endif /* DEBUG_REFRESH */ |
---|
550 | |
---|
551 | /* open up the space for num chars */ |
---|
552 | if (num > 0) { |
---|
553 | b = d + dat; |
---|
554 | a = b + num; |
---|
555 | while (a < &d[dlen]) |
---|
556 | *b++ = *a++; |
---|
557 | d[dlen] = '\0'; /* just in case */ |
---|
558 | } |
---|
559 | #ifdef DEBUG_REFRESH |
---|
560 | dprintf("str_delete() after delete: %d at %d max %d, d == \"%s\"\n", |
---|
561 | num, dat, dlen, short2str(d)); |
---|
562 | #endif /* DEBUG_REFRESH */ |
---|
563 | } |
---|
564 | |
---|
565 | static void |
---|
566 | str_cp(a, b, n) |
---|
567 | Char *a, *b; |
---|
568 | int n; |
---|
569 | { |
---|
570 | while (n-- && *b) |
---|
571 | *a++ = *b++; |
---|
572 | } |
---|
573 | |
---|
574 | |
---|
575 | /* **************************************************************** |
---|
576 | update_line() is based on finding the middle difference of each line |
---|
577 | on the screen; vis: |
---|
578 | |
---|
579 | /old first difference |
---|
580 | /beginning of line | /old last same /old EOL |
---|
581 | v v v v |
---|
582 | old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as |
---|
583 | new: eddie> Oh, my little buggy says to me, as lurgid as |
---|
584 | ^ ^ ^ ^ |
---|
585 | \beginning of line | \new last same \new end of line |
---|
586 | \new first difference |
---|
587 | |
---|
588 | all are character pointers for the sake of speed. Special cases for |
---|
589 | no differences, as well as for end of line additions must be handled. |
---|
590 | **************************************************************** */ |
---|
591 | |
---|
592 | /* Minimum at which doing an insert it "worth it". This should be about |
---|
593 | * half the "cost" of going into insert mode, inserting a character, and |
---|
594 | * going back out. This should really be calculated from the termcap |
---|
595 | * data... For the moment, a good number for ANSI terminals. |
---|
596 | */ |
---|
597 | #define MIN_END_KEEP 4 |
---|
598 | |
---|
599 | static void /* could be changed to make it smarter */ |
---|
600 | update_line(old, new, cur_line) |
---|
601 | Char *old, *new; |
---|
602 | int cur_line; |
---|
603 | { |
---|
604 | Char *o, *n, *p, c; |
---|
605 | Char *ofd, *ols, *oe, *nfd, *nls, *ne; |
---|
606 | Char *osb, *ose, *nsb, *nse; |
---|
607 | int fx, sx; |
---|
608 | |
---|
609 | /* |
---|
610 | * find first diff (won't be CHAR_DBWIDTH in either line) |
---|
611 | */ |
---|
612 | for (o = old, n = new; *o && (*o == *n); o++, n++) |
---|
613 | continue; |
---|
614 | ofd = o; |
---|
615 | nfd = n; |
---|
616 | |
---|
617 | /* |
---|
618 | * Find the end of both old and new |
---|
619 | */ |
---|
620 | while (*o) |
---|
621 | o++; |
---|
622 | /* |
---|
623 | * Remove any trailing blanks off of the end, being careful not to |
---|
624 | * back up past the beginning. |
---|
625 | */ |
---|
626 | while (ofd < o) { |
---|
627 | if (o[-1] != ' ') |
---|
628 | break; |
---|
629 | o--; |
---|
630 | } |
---|
631 | oe = o; |
---|
632 | *oe = (Char) 0; |
---|
633 | |
---|
634 | while (*n) |
---|
635 | n++; |
---|
636 | |
---|
637 | /* remove blanks from end of new */ |
---|
638 | while (nfd < n) { |
---|
639 | if (n[-1] != ' ') |
---|
640 | break; |
---|
641 | n--; |
---|
642 | } |
---|
643 | ne = n; |
---|
644 | *ne = (Char) 0; |
---|
645 | |
---|
646 | /* |
---|
647 | * if no diff, continue to next line of redraw |
---|
648 | */ |
---|
649 | if (*ofd == '\0' && *nfd == '\0') { |
---|
650 | #ifdef DEBUG_UPDATE |
---|
651 | dprintf("no difference.\r\n"); |
---|
652 | #endif /* DEBUG_UPDATE */ |
---|
653 | return; |
---|
654 | } |
---|
655 | |
---|
656 | /* |
---|
657 | * find last same pointer |
---|
658 | */ |
---|
659 | while ((o > ofd) && (n > nfd) && (*--o == *--n)) |
---|
660 | continue; |
---|
661 | if (*o != *n) { |
---|
662 | o++; |
---|
663 | n++; |
---|
664 | } |
---|
665 | while (*o == CHAR_DBWIDTH) { |
---|
666 | o++; |
---|
667 | n++; |
---|
668 | } |
---|
669 | ols = o; |
---|
670 | nls = n; |
---|
671 | |
---|
672 | /* |
---|
673 | * find same begining and same end |
---|
674 | */ |
---|
675 | osb = ols; |
---|
676 | nsb = nls; |
---|
677 | ose = ols; |
---|
678 | nse = nls; |
---|
679 | |
---|
680 | /* |
---|
681 | * case 1: insert: scan from nfd to nls looking for *ofd |
---|
682 | */ |
---|
683 | if (*ofd) { |
---|
684 | for (c = *ofd, n = nfd; n < nls; n++) { |
---|
685 | if (c == *n) { |
---|
686 | for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++) |
---|
687 | continue; |
---|
688 | /* |
---|
689 | * if the new match is longer and it's worth keeping, then we |
---|
690 | * take it |
---|
691 | */ |
---|
692 | if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { |
---|
693 | nsb = n; |
---|
694 | nse = p; |
---|
695 | osb = ofd; |
---|
696 | ose = o; |
---|
697 | } |
---|
698 | } |
---|
699 | } |
---|
700 | } |
---|
701 | |
---|
702 | /* |
---|
703 | * case 2: delete: scan from ofd to ols looking for *nfd |
---|
704 | */ |
---|
705 | if (*nfd) { |
---|
706 | for (c = *nfd, o = ofd; o < ols; o++) { |
---|
707 | if (c == *o) { |
---|
708 | for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++) |
---|
709 | continue; |
---|
710 | /* |
---|
711 | * if the new match is longer and it's worth keeping, then we |
---|
712 | * take it |
---|
713 | */ |
---|
714 | if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { |
---|
715 | nsb = nfd; |
---|
716 | nse = n; |
---|
717 | osb = o; |
---|
718 | ose = p; |
---|
719 | } |
---|
720 | } |
---|
721 | } |
---|
722 | } |
---|
723 | #ifdef notdef |
---|
724 | /* |
---|
725 | * If `last same' is before `same end' re-adjust |
---|
726 | */ |
---|
727 | if (ols < ose) |
---|
728 | ols = ose; |
---|
729 | if (nls < nse) |
---|
730 | nls = nse; |
---|
731 | #endif |
---|
732 | |
---|
733 | /* |
---|
734 | * Pragmatics I: If old trailing whitespace or not enough characters to |
---|
735 | * save to be worth it, then don't save the last same info. |
---|
736 | */ |
---|
737 | if ((oe - ols) < MIN_END_KEEP) { |
---|
738 | ols = oe; |
---|
739 | nls = ne; |
---|
740 | } |
---|
741 | |
---|
742 | /* |
---|
743 | * Pragmatics II: if the terminal isn't smart enough, make the data dumber |
---|
744 | * so the smart update doesn't try anything fancy |
---|
745 | */ |
---|
746 | |
---|
747 | /* |
---|
748 | * fx is the number of characters we need to insert/delete: in the |
---|
749 | * beginning to bring the two same begins together |
---|
750 | */ |
---|
751 | fx = (int) ((nsb - nfd) - (osb - ofd)); |
---|
752 | /* |
---|
753 | * sx is the number of characters we need to insert/delete: in the end to |
---|
754 | * bring the two same last parts together |
---|
755 | */ |
---|
756 | sx = (int) ((nls - nse) - (ols - ose)); |
---|
757 | |
---|
758 | if (!T_CanIns) { |
---|
759 | if (fx > 0) { |
---|
760 | osb = ols; |
---|
761 | ose = ols; |
---|
762 | nsb = nls; |
---|
763 | nse = nls; |
---|
764 | } |
---|
765 | if (sx > 0) { |
---|
766 | ols = oe; |
---|
767 | nls = ne; |
---|
768 | } |
---|
769 | if ((ols - ofd) < (nls - nfd)) { |
---|
770 | ols = oe; |
---|
771 | nls = ne; |
---|
772 | } |
---|
773 | } |
---|
774 | if (!T_CanDel) { |
---|
775 | if (fx < 0) { |
---|
776 | osb = ols; |
---|
777 | ose = ols; |
---|
778 | nsb = nls; |
---|
779 | nse = nls; |
---|
780 | } |
---|
781 | if (sx < 0) { |
---|
782 | ols = oe; |
---|
783 | nls = ne; |
---|
784 | } |
---|
785 | if ((ols - ofd) > (nls - nfd)) { |
---|
786 | ols = oe; |
---|
787 | nls = ne; |
---|
788 | } |
---|
789 | } |
---|
790 | |
---|
791 | /* |
---|
792 | * Pragmatics III: make sure the middle shifted pointers are correct if |
---|
793 | * they don't point to anything (we may have moved ols or nls). |
---|
794 | */ |
---|
795 | /* if the change isn't worth it, don't bother */ |
---|
796 | /* was: if (osb == ose) */ |
---|
797 | if ((ose - osb) < MIN_END_KEEP) { |
---|
798 | osb = ols; |
---|
799 | ose = ols; |
---|
800 | nsb = nls; |
---|
801 | nse = nls; |
---|
802 | } |
---|
803 | |
---|
804 | /* |
---|
805 | * Now that we are done with pragmatics we recompute fx, sx |
---|
806 | */ |
---|
807 | fx = (int) ((nsb - nfd) - (osb - ofd)); |
---|
808 | sx = (int) ((nls - nse) - (ols - ose)); |
---|
809 | |
---|
810 | #ifdef DEBUG_UPDATE |
---|
811 | dprintf("\n"); |
---|
812 | dprintf("ofd %d, osb %d, ose %d, ols %d, oe %d\n", |
---|
813 | ofd - old, osb - old, ose - old, ols - old, oe - old); |
---|
814 | dprintf("nfd %d, nsb %d, nse %d, nls %d, ne %d\n", |
---|
815 | nfd - new, nsb - new, nse - new, nls - new, ne - new); |
---|
816 | dprintf("xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"); |
---|
817 | dprintf("xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"); |
---|
818 | dprintstr("old- oe", old, oe); |
---|
819 | dprintstr("new- ne", new, ne); |
---|
820 | dprintstr("old-ofd", old, ofd); |
---|
821 | dprintstr("new-nfd", new, nfd); |
---|
822 | dprintstr("ofd-osb", ofd, osb); |
---|
823 | dprintstr("nfd-nsb", nfd, nsb); |
---|
824 | dprintstr("osb-ose", osb, ose); |
---|
825 | dprintstr("nsb-nse", nsb, nse); |
---|
826 | dprintstr("ose-ols", ose, ols); |
---|
827 | dprintstr("nse-nls", nse, nls); |
---|
828 | dprintstr("ols- oe", ols, oe); |
---|
829 | dprintstr("nls- ne", nls, ne); |
---|
830 | #endif /* DEBUG_UPDATE */ |
---|
831 | |
---|
832 | /* |
---|
833 | * CursorV to this line cur_line MUST be in this routine so that if we |
---|
834 | * don't have to change the line, we don't move to it. CursorH to first |
---|
835 | * diff char |
---|
836 | */ |
---|
837 | MoveToLine(cur_line); |
---|
838 | |
---|
839 | /* |
---|
840 | * at this point we have something like this: |
---|
841 | * |
---|
842 | * /old /ofd /osb /ose /ols /oe |
---|
843 | * v.....................v v..................v v........v |
---|
844 | * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as |
---|
845 | * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as |
---|
846 | * ^.....................^ ^..................^ ^........^ |
---|
847 | * \new \nfd \nsb \nse \nls \ne |
---|
848 | * |
---|
849 | * fx is the difference in length between the the chars between nfd and |
---|
850 | * nsb, and the chars between ofd and osb, and is thus the number of |
---|
851 | * characters to delete if < 0 (new is shorter than old, as above), |
---|
852 | * or insert (new is longer than short). |
---|
853 | * |
---|
854 | * sx is the same for the second differences. |
---|
855 | */ |
---|
856 | |
---|
857 | /* |
---|
858 | * if we have a net insert on the first difference, AND inserting the net |
---|
859 | * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character |
---|
860 | * (which is ne if nls != ne, otherwise is nse) off the edge of the screen |
---|
861 | * (TermH - 1) else we do the deletes first so that we keep everything we |
---|
862 | * need to. |
---|
863 | */ |
---|
864 | |
---|
865 | /* |
---|
866 | * if the last same is the same like the end, there is no last same part, |
---|
867 | * otherwise we want to keep the last same part set p to the last useful |
---|
868 | * old character |
---|
869 | */ |
---|
870 | p = (ols != oe) ? oe : ose; |
---|
871 | |
---|
872 | /* |
---|
873 | * if (There is a diffence in the beginning) && (we need to insert |
---|
874 | * characters) && (the number of characters to insert is less than the term |
---|
875 | * width) We need to do an insert! else if (we need to delete characters) |
---|
876 | * We need to delete characters! else No insert or delete |
---|
877 | */ |
---|
878 | if ((nsb != nfd) && fx > 0 && ((p - old) + fx < TermH)) { |
---|
879 | #ifdef DEBUG_UPDATE |
---|
880 | dprintf("first diff insert at %d...\r\n", nfd - new); |
---|
881 | #endif /* DEBUG_UPDATE */ |
---|
882 | /* |
---|
883 | * Move to the first char to insert, where the first diff is. |
---|
884 | */ |
---|
885 | MoveToChar(nfd - new); |
---|
886 | /* |
---|
887 | * Check if we have stuff to keep at end |
---|
888 | */ |
---|
889 | if (nsb != ne) { |
---|
890 | #ifdef DEBUG_UPDATE |
---|
891 | dprintf("with stuff to keep at end\r\n"); |
---|
892 | #endif /* DEBUG_UPDATE */ |
---|
893 | /* |
---|
894 | * insert fx chars of new starting at nfd |
---|
895 | */ |
---|
896 | if (fx > 0) { |
---|
897 | #ifdef DEBUG_UPDATE |
---|
898 | if (!T_CanIns) |
---|
899 | dprintf(" ERROR: cannot insert in early first diff\n"); |
---|
900 | #endif /* DEBUG_UPDATE */ |
---|
901 | Insert_write(nfd, fx); |
---|
902 | str_insert(old, (int) (ofd - old), TermH, nfd, fx); |
---|
903 | } |
---|
904 | /* |
---|
905 | * write (nsb-nfd) - fx chars of new starting at (nfd + fx) |
---|
906 | */ |
---|
907 | so_write(nfd + fx, (nsb - nfd) - fx); |
---|
908 | str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); |
---|
909 | } |
---|
910 | else { |
---|
911 | #ifdef DEBUG_UPDATE |
---|
912 | dprintf("without anything to save\r\n"); |
---|
913 | #endif /* DEBUG_UPDATE */ |
---|
914 | so_write(nfd, (nsb - nfd)); |
---|
915 | str_cp(ofd, nfd, (int) (nsb - nfd)); |
---|
916 | /* |
---|
917 | * Done |
---|
918 | */ |
---|
919 | return; |
---|
920 | } |
---|
921 | } |
---|
922 | else if (fx < 0) { |
---|
923 | #ifdef DEBUG_UPDATE |
---|
924 | dprintf("first diff delete at %d...\r\n", ofd - old); |
---|
925 | #endif /* DEBUG_UPDATE */ |
---|
926 | /* |
---|
927 | * move to the first char to delete where the first diff is |
---|
928 | */ |
---|
929 | MoveToChar(ofd - old); |
---|
930 | /* |
---|
931 | * Check if we have stuff to save |
---|
932 | */ |
---|
933 | if (osb != oe) { |
---|
934 | #ifdef DEBUG_UPDATE |
---|
935 | dprintf("with stuff to save at end\r\n"); |
---|
936 | #endif /* DEBUG_UPDATE */ |
---|
937 | /* |
---|
938 | * fx is less than zero *always* here but we check for code |
---|
939 | * symmetry |
---|
940 | */ |
---|
941 | if (fx < 0) { |
---|
942 | #ifdef DEBUG_UPDATE |
---|
943 | if (!T_CanDel) |
---|
944 | dprintf(" ERROR: cannot delete in first diff\n"); |
---|
945 | #endif /* DEBUG_UPDATE */ |
---|
946 | DeleteChars(-fx); |
---|
947 | str_delete(old, (int) (ofd - old), TermH, -fx); |
---|
948 | } |
---|
949 | /* |
---|
950 | * write (nsb-nfd) chars of new starting at nfd |
---|
951 | */ |
---|
952 | so_write(nfd, (nsb - nfd)); |
---|
953 | str_cp(ofd, nfd, (int) (nsb - nfd)); |
---|
954 | |
---|
955 | } |
---|
956 | else { |
---|
957 | #ifdef DEBUG_UPDATE |
---|
958 | dprintf("but with nothing left to save\r\n"); |
---|
959 | #endif /* DEBUG_UPDATE */ |
---|
960 | /* |
---|
961 | * write (nsb-nfd) chars of new starting at nfd |
---|
962 | */ |
---|
963 | so_write(nfd, (nsb - nfd)); |
---|
964 | #ifdef DEBUG_REFRESH |
---|
965 | dprintf("cleareol %d\n", (oe - old) - (ne - new)); |
---|
966 | #endif /* DEBUG_UPDATE */ |
---|
967 | #ifndef WINNT_NATIVE |
---|
968 | ClearEOL((oe - old) - (ne - new)); |
---|
969 | #else |
---|
970 | /* |
---|
971 | * The calculation above does not work too well on NT |
---|
972 | */ |
---|
973 | ClearEOL(TermH - CursorH); |
---|
974 | #endif /*WINNT_NATIVE*/ |
---|
975 | /* |
---|
976 | * Done |
---|
977 | */ |
---|
978 | return; |
---|
979 | } |
---|
980 | } |
---|
981 | else |
---|
982 | fx = 0; |
---|
983 | |
---|
984 | if (sx < 0) { |
---|
985 | #ifdef DEBUG_UPDATE |
---|
986 | dprintf("second diff delete at %d...\r\n", (ose - old) + fx); |
---|
987 | #endif /* DEBUG_UPDATE */ |
---|
988 | /* |
---|
989 | * Check if we have stuff to delete |
---|
990 | */ |
---|
991 | /* |
---|
992 | * fx is the number of characters inserted (+) or deleted (-) |
---|
993 | */ |
---|
994 | |
---|
995 | MoveToChar((ose - old) + fx); |
---|
996 | /* |
---|
997 | * Check if we have stuff to save |
---|
998 | */ |
---|
999 | if (ols != oe) { |
---|
1000 | #ifdef DEBUG_UPDATE |
---|
1001 | dprintf("with stuff to save at end\r\n"); |
---|
1002 | #endif /* DEBUG_UPDATE */ |
---|
1003 | /* |
---|
1004 | * Again a duplicate test. |
---|
1005 | */ |
---|
1006 | if (sx < 0) { |
---|
1007 | #ifdef DEBUG_UPDATE |
---|
1008 | if (!T_CanDel) |
---|
1009 | dprintf(" ERROR: cannot delete in second diff\n"); |
---|
1010 | #endif /* DEBUG_UPDATE */ |
---|
1011 | DeleteChars(-sx); |
---|
1012 | } |
---|
1013 | |
---|
1014 | /* |
---|
1015 | * write (nls-nse) chars of new starting at nse |
---|
1016 | */ |
---|
1017 | so_write(nse, (nls - nse)); |
---|
1018 | } |
---|
1019 | else { |
---|
1020 | int olen = (int) (oe - old + fx); |
---|
1021 | if (olen > TermH) |
---|
1022 | olen = TermH; |
---|
1023 | #ifdef DEBUG_UPDATE |
---|
1024 | dprintf("but with nothing left to save\r\n"); |
---|
1025 | #endif /* DEBUG_UPDATE */ |
---|
1026 | so_write(nse, (nls - nse)); |
---|
1027 | #ifdef DEBUG_REFRESH |
---|
1028 | dprintf("cleareol %d\n", olen - (ne - new)); |
---|
1029 | #endif /* DEBUG_UPDATE */ |
---|
1030 | #ifndef WINNT_NATIVE |
---|
1031 | ClearEOL(olen - (ne - new)); |
---|
1032 | #else |
---|
1033 | /* |
---|
1034 | * The calculation above does not work too well on NT |
---|
1035 | */ |
---|
1036 | ClearEOL(TermH - CursorH); |
---|
1037 | #endif /*WINNT_NATIVE*/ |
---|
1038 | } |
---|
1039 | } |
---|
1040 | |
---|
1041 | /* |
---|
1042 | * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... |
---|
1043 | */ |
---|
1044 | if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { |
---|
1045 | #ifdef DEBUG_UPDATE |
---|
1046 | dprintf("late first diff insert at %d...\r\n", nfd - new); |
---|
1047 | #endif /* DEBUG_UPDATE */ |
---|
1048 | |
---|
1049 | MoveToChar(nfd - new); |
---|
1050 | /* |
---|
1051 | * Check if we have stuff to keep at the end |
---|
1052 | */ |
---|
1053 | if (nsb != ne) { |
---|
1054 | #ifdef DEBUG_UPDATE |
---|
1055 | dprintf("with stuff to keep at end\r\n"); |
---|
1056 | #endif /* DEBUG_UPDATE */ |
---|
1057 | /* |
---|
1058 | * We have to recalculate fx here because we set it |
---|
1059 | * to zero above as a flag saying that we hadn't done |
---|
1060 | * an early first insert. |
---|
1061 | */ |
---|
1062 | fx = (int) ((nsb - nfd) - (osb - ofd)); |
---|
1063 | if (fx > 0) { |
---|
1064 | /* |
---|
1065 | * insert fx chars of new starting at nfd |
---|
1066 | */ |
---|
1067 | #ifdef DEBUG_UPDATE |
---|
1068 | if (!T_CanIns) |
---|
1069 | dprintf(" ERROR: cannot insert in late first diff\n"); |
---|
1070 | #endif /* DEBUG_UPDATE */ |
---|
1071 | Insert_write(nfd, fx); |
---|
1072 | str_insert(old, (int) (ofd - old), TermH, nfd, fx); |
---|
1073 | } |
---|
1074 | |
---|
1075 | /* |
---|
1076 | * write (nsb-nfd) - fx chars of new starting at (nfd + fx) |
---|
1077 | */ |
---|
1078 | so_write(nfd + fx, (nsb - nfd) - fx); |
---|
1079 | str_cp(ofd + fx, nfd + fx, (int) ((nsb - nfd) - fx)); |
---|
1080 | } |
---|
1081 | else { |
---|
1082 | #ifdef DEBUG_UPDATE |
---|
1083 | dprintf("without anything to save\r\n"); |
---|
1084 | #endif /* DEBUG_UPDATE */ |
---|
1085 | so_write(nfd, (nsb - nfd)); |
---|
1086 | str_cp(ofd, nfd, (int) (nsb - nfd)); |
---|
1087 | } |
---|
1088 | } |
---|
1089 | |
---|
1090 | /* |
---|
1091 | * line is now NEW up to nse |
---|
1092 | */ |
---|
1093 | if (sx >= 0) { |
---|
1094 | #ifdef DEBUG_UPDATE |
---|
1095 | dprintf("second diff insert at %d...\r\n", nse - new); |
---|
1096 | #endif /* DEBUG_UPDATE */ |
---|
1097 | MoveToChar(nse - new); |
---|
1098 | if (ols != oe) { |
---|
1099 | #ifdef DEBUG_UPDATE |
---|
1100 | dprintf("with stuff to keep at end\r\n"); |
---|
1101 | #endif /* DEBUG_UPDATE */ |
---|
1102 | if (sx > 0) { |
---|
1103 | /* insert sx chars of new starting at nse */ |
---|
1104 | #ifdef DEBUG_UPDATE |
---|
1105 | if (!T_CanIns) |
---|
1106 | dprintf(" ERROR: cannot insert in second diff\n"); |
---|
1107 | #endif /* DEBUG_UPDATE */ |
---|
1108 | Insert_write(nse, sx); |
---|
1109 | } |
---|
1110 | |
---|
1111 | /* |
---|
1112 | * write (nls-nse) - sx chars of new starting at (nse + sx) |
---|
1113 | */ |
---|
1114 | so_write(nse + sx, (nls - nse) - sx); |
---|
1115 | } |
---|
1116 | else { |
---|
1117 | #ifdef DEBUG_UPDATE |
---|
1118 | dprintf("without anything to save\r\n"); |
---|
1119 | #endif /* DEBUG_UPDATE */ |
---|
1120 | so_write(nse, (nls - nse)); |
---|
1121 | |
---|
1122 | /* |
---|
1123 | * No need to do a clear-to-end here because we were doing |
---|
1124 | * a second insert, so we will have over written all of the |
---|
1125 | * old string. |
---|
1126 | */ |
---|
1127 | } |
---|
1128 | } |
---|
1129 | #ifdef DEBUG_UPDATE |
---|
1130 | dprintf("done.\r\n"); |
---|
1131 | #endif /* DEBUG_UPDATE */ |
---|
1132 | } |
---|
1133 | |
---|
1134 | |
---|
1135 | static void |
---|
1136 | cpy_pad_spaces(dst, src, width) |
---|
1137 | Char *dst, *src; |
---|
1138 | int width; |
---|
1139 | { |
---|
1140 | int i; |
---|
1141 | |
---|
1142 | for (i = 0; i < width; i++) { |
---|
1143 | if (*src == (Char) 0) |
---|
1144 | break; |
---|
1145 | *dst++ = *src++; |
---|
1146 | } |
---|
1147 | |
---|
1148 | while (i < width) { |
---|
1149 | *dst++ = ' '; |
---|
1150 | i++; |
---|
1151 | } |
---|
1152 | *dst = (Char) 0; |
---|
1153 | } |
---|
1154 | |
---|
1155 | void |
---|
1156 | RefCursor() |
---|
1157 | { /* only move to new cursor pos */ |
---|
1158 | Char *cp; |
---|
1159 | NLSChar c; |
---|
1160 | int l, w, h, th, v; |
---|
1161 | |
---|
1162 | /* first we must find where the cursor is... */ |
---|
1163 | h = 0; |
---|
1164 | v = 0; |
---|
1165 | th = TermH; /* optimize for speed */ |
---|
1166 | |
---|
1167 | for (cp = PromptBuf; *cp; ) { /* do prompt */ |
---|
1168 | if (*cp & LITERAL) { |
---|
1169 | cp++; |
---|
1170 | continue; |
---|
1171 | } |
---|
1172 | l = NLSFrom(cp, NLSZEROT, &c); |
---|
1173 | w = NLSClassify(c, cp == PromptBuf); |
---|
1174 | cp += l; |
---|
1175 | switch(w) { |
---|
1176 | case NLSCLASS_NL: |
---|
1177 | h = 0; |
---|
1178 | v++; |
---|
1179 | break; |
---|
1180 | case NLSCLASS_TAB: |
---|
1181 | while (++h & 07) |
---|
1182 | ; |
---|
1183 | break; |
---|
1184 | case NLSCLASS_CTRL: |
---|
1185 | h += 2; |
---|
1186 | break; |
---|
1187 | case NLSCLASS_ILLEGAL: |
---|
1188 | h += 4; |
---|
1189 | break; |
---|
1190 | case NLSCLASS_ILLEGAL2: |
---|
1191 | case NLSCLASS_ILLEGAL3: |
---|
1192 | case NLSCLASS_ILLEGAL4: |
---|
1193 | h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); |
---|
1194 | break; |
---|
1195 | default: |
---|
1196 | h += w; |
---|
1197 | } |
---|
1198 | if (h >= th) { /* check, extra long tabs picked up here also */ |
---|
1199 | h -= th; |
---|
1200 | v++; |
---|
1201 | } |
---|
1202 | } |
---|
1203 | |
---|
1204 | for (cp = InputBuf; cp < Cursor;) { /* do input buffer to Cursor */ |
---|
1205 | l = NLSFrom(cp, Cursor - cp, &c); |
---|
1206 | w = NLSClassify(c, cp == InputBuf); |
---|
1207 | cp += l; |
---|
1208 | switch(w) { |
---|
1209 | case NLSCLASS_NL: |
---|
1210 | h = 0; |
---|
1211 | v++; |
---|
1212 | break; |
---|
1213 | case NLSCLASS_TAB: |
---|
1214 | while (++h & 07) |
---|
1215 | ; |
---|
1216 | break; |
---|
1217 | case NLSCLASS_CTRL: |
---|
1218 | h += 2; |
---|
1219 | break; |
---|
1220 | case NLSCLASS_ILLEGAL: |
---|
1221 | h += 4; |
---|
1222 | break; |
---|
1223 | case NLSCLASS_ILLEGAL2: |
---|
1224 | case NLSCLASS_ILLEGAL3: |
---|
1225 | case NLSCLASS_ILLEGAL4: |
---|
1226 | h += 3 + 2 * NLSCLASS_ILLEGAL_SIZE(w); |
---|
1227 | break; |
---|
1228 | default: |
---|
1229 | h += w; |
---|
1230 | } |
---|
1231 | if (h >= th) { /* check, extra long tabs picked up here also */ |
---|
1232 | h -= th; |
---|
1233 | v++; |
---|
1234 | } |
---|
1235 | } |
---|
1236 | |
---|
1237 | /* now go there */ |
---|
1238 | MoveToLine(v); |
---|
1239 | MoveToChar(h); |
---|
1240 | flush(); |
---|
1241 | } |
---|
1242 | |
---|
1243 | #ifndef WINTT_NATIVE |
---|
1244 | static void |
---|
1245 | PutPlusOne(c, width) |
---|
1246 | Char c; |
---|
1247 | int width; |
---|
1248 | { |
---|
1249 | while (width > 1 && CursorH + width > TermH) |
---|
1250 | PutPlusOne(' ', 1); |
---|
1251 | if ((c & LITERAL) != 0) { |
---|
1252 | Char *d; |
---|
1253 | for (d = litptr + (c & ~LITERAL) * LIT_FACTOR; *d; d++) |
---|
1254 | (void) putwraw(*d); |
---|
1255 | } else { |
---|
1256 | (void) putwraw(c); |
---|
1257 | } |
---|
1258 | Display[CursorV][CursorH++] = (Char) c; |
---|
1259 | while (--width > 0) |
---|
1260 | Display[CursorV][CursorH++] = CHAR_DBWIDTH; |
---|
1261 | if (CursorH >= TermH) { /* if we must overflow */ |
---|
1262 | CursorH = 0; |
---|
1263 | CursorV++; |
---|
1264 | OldvcV++; |
---|
1265 | if (T_Margin & MARGIN_AUTO) { |
---|
1266 | if (T_Margin & MARGIN_MAGIC) { |
---|
1267 | (void) putraw(' '); |
---|
1268 | (void) putraw('\b'); |
---|
1269 | } |
---|
1270 | } |
---|
1271 | else { |
---|
1272 | (void) putraw('\r'); |
---|
1273 | (void) putraw('\n'); |
---|
1274 | } |
---|
1275 | } |
---|
1276 | } |
---|
1277 | #endif |
---|
1278 | |
---|
1279 | void |
---|
1280 | RefPlusOne(int l) |
---|
1281 | { /* we added just one char, handle it fast. |
---|
1282 | * assumes that screen cursor == real cursor */ |
---|
1283 | Char *cp; |
---|
1284 | int w; |
---|
1285 | NLSChar c; |
---|
1286 | |
---|
1287 | if (Cursor != LastChar) { |
---|
1288 | Refresh(); /* too hard to handle */ |
---|
1289 | return; |
---|
1290 | } |
---|
1291 | if (rprompt_h != 0 && (TermH - CursorH - rprompt_h < 3)) { |
---|
1292 | Refresh(); /* clear out rprompt if less than one char gap*/ |
---|
1293 | return; |
---|
1294 | } |
---|
1295 | cp = Cursor - l; |
---|
1296 | NLSFrom(cp, (size_t)l, &c); |
---|
1297 | w = NLSClassify(c, cp == InputBuf); |
---|
1298 | switch(w) { |
---|
1299 | case NLSCLASS_CTRL: |
---|
1300 | PutPlusOne('^', 1); |
---|
1301 | if (c == CTL_ESC('\177')) { |
---|
1302 | PutPlusOne('?', 1); |
---|
1303 | break; |
---|
1304 | } |
---|
1305 | #ifdef IS_ASCII |
---|
1306 | /* uncontrolify it; works only for iso8859-1 like sets */ |
---|
1307 | PutPlusOne((c | 0100), 1); |
---|
1308 | #else |
---|
1309 | PutPlusOne(_toebcdic[_toascii[c]|0100], 1); |
---|
1310 | #endif |
---|
1311 | break; |
---|
1312 | case NLSCLASS_ILLEGAL: |
---|
1313 | PutPlusOne('\\', 1); |
---|
1314 | PutPlusOne(((c >> 6) & 7) + '0', 1); |
---|
1315 | PutPlusOne(((c >> 3) & 7) + '0', 1); |
---|
1316 | PutPlusOne((c & 7) + '0', 1); |
---|
1317 | break; |
---|
1318 | case 1: |
---|
1319 | if (l > 1) |
---|
1320 | PutPlusOne(MakeLiteral(cp, l, 0), 1); |
---|
1321 | else |
---|
1322 | PutPlusOne(*cp, 1); |
---|
1323 | break; |
---|
1324 | default: |
---|
1325 | Refresh(); /* too hard to handle */ |
---|
1326 | return; |
---|
1327 | } |
---|
1328 | flush(); |
---|
1329 | } |
---|
1330 | |
---|
1331 | /* clear the screen buffers so that new new prompt starts fresh. */ |
---|
1332 | |
---|
1333 | void |
---|
1334 | ClearDisp() |
---|
1335 | { |
---|
1336 | int i; |
---|
1337 | |
---|
1338 | CursorV = 0; /* clear the display buffer */ |
---|
1339 | CursorH = 0; |
---|
1340 | for (i = 0; i < TermV; i++) |
---|
1341 | (void) memset(Display[i], 0, TermH * sizeof(Display[0][0])); |
---|
1342 | OldvcV = 0; |
---|
1343 | litlen = 0; |
---|
1344 | } |
---|
1345 | |
---|
1346 | void |
---|
1347 | ClearLines() |
---|
1348 | { /* Make sure all lines are *really* blank */ |
---|
1349 | int i; |
---|
1350 | |
---|
1351 | if (T_CanCEOL) { |
---|
1352 | /* |
---|
1353 | * Clear the lines from the bottom up so that if we try moving |
---|
1354 | * the cursor down by writing the character that is at the end |
---|
1355 | * of the screen line, we won't rewrite a character that shouldn't |
---|
1356 | * be there. |
---|
1357 | */ |
---|
1358 | for (i = OldvcV; i >= 0; i--) { /* for each line on the screen */ |
---|
1359 | MoveToLine(i); |
---|
1360 | MoveToChar(0); |
---|
1361 | ClearEOL(TermH); |
---|
1362 | } |
---|
1363 | } |
---|
1364 | else { |
---|
1365 | MoveToLine(OldvcV); /* go to last line */ |
---|
1366 | (void) putraw('\r'); /* go to BOL */ |
---|
1367 | (void) putraw('\n'); /* go to new line */ |
---|
1368 | } |
---|
1369 | } |
---|