|
|
1.1 root 1: /*
2: * Modify current screen line 'old' to match desired line 'new'.
3: * The old line is at position ln. Each line is divided into 4 regions:
4: *
5: * nlws, olws - amount of leading white space on new/old line
6: * com_head - length of common head
7: * nchanged, ochanged - length of the parts changed
8: * com_tail - length of a common tail
9: */
10:
11: /* @(#) _id_char.c: 1.1 10/15/83 (1.20 3/6/83) */
12:
13: #include "curses.ext"
14:
15: #define min(a,b) (a<b ? a : b)
16:
17: _id_char (old, new, ln)
18: register struct line *old, * new;
19: {
20: register chtype *oc_beg, *nc_beg,/* Beginning of changed part */
21: *oc_end, *nc_end;/* End of changed part */
22: chtype *p, *q; /* scratch */
23: int olws, nlws; /* old/new leading white space */
24: int com_head, com_tail; /* size of common head/tail */
25: int ochanged, nchanged; /* size of changed part */
26: int samelen; /* both lines are same length */
27: int nbl; /* # blanks in new line replacing nonblanks in old */
28: int nms; /* # chars same in new and old in middle part */
29: int cw_idc; /* cost of update with insert/delete character */
30: int cwo_idc; /* cost of update without insert/delete character */
31: int i, j, n; /* scratch */
32: int len, diff;
33: static chtype nullline[] = {0, 0};
34:
35: #ifdef DEBUG
36: if(outf) fprintf(outf, "_id_char(%x, %x, %d)\n", old, new, ln);
37: if(outf) fprintf(outf, "old: ");
38: if(outf) fprintf(outf, "%8x: ", old);
39: if (old == NULL) {
40: if(outf) fprintf(outf, "()\n");
41: } else {
42: if(outf) fprintf(outf, "%4d ", old->length);
43: for (j=0; j<old->length; j++) {
44: n = old->body[j];
45: if (n & A_ATTRIBUTES)
46: putc('\'', outf);
47: n &= 0177;
48: if(outf) fprintf(outf, "%c", n>=' ' ? n : '.');
49: }
50: if(outf) fprintf(outf, "\n");
51: }
52: if(outf) fprintf(outf, "new: ");
53: if(outf) fprintf(outf, "%8x: ", new);
54: if (new == NULL) {
55: if(outf) fprintf(outf, "()\n");
56: } else {
57: if(outf) fprintf(outf, "%4d ", new->length);
58: for (j=0; j<new->length; j++) {
59: n = new->body[j];
60: if (n & A_ATTRIBUTES)
61: putc('\'', outf);
62: n &= 0177;
63: if(outf) fprintf(outf, "%c", n>=' ' ? n : '.');
64: }
65: if(outf) fprintf(outf, "\n");
66: }
67: #endif DEBUG
68:
69: if (old == new)
70: {
71: return;
72: }
73:
74: /* Start at the ends of the lines */
75: if( old )
76: {
77: oc_beg = old -> body;
78: oc_end = &old -> body[old -> length];
79: }
80: else
81: {
82: oc_beg = nullline;
83: oc_end = oc_beg;
84: }
85: if( new )
86: {
87: nc_beg = new -> body;
88: nc_end = &new -> body[new -> length];
89: }
90: else
91: {
92: nc_beg = nullline;
93: nc_end = nc_beg;
94: }
95:
96: /* Find leading and trailing blanks */
97: olws = nlws = com_head = com_tail = 0;
98: while (*--oc_end == ' ' && oc_end >= oc_beg)
99: ;
100: while (*--nc_end == ' ' && nc_end >= nc_beg)
101: ;
102: samelen = (nc_end-nc_beg) == (oc_end-oc_beg)
103: ;
104: while( *oc_beg == ' ' && oc_beg <= oc_end )
105: {
106: oc_beg++;
107: olws++;
108: }
109: while( *nc_beg == ' ' && nc_beg <= nc_end )
110: {
111: nc_beg++;
112: nlws++;
113: }
114:
115: /*
116: * Now find common heads and tails (com_head & com_tail). If the
117: * lengths are the same, the change was probably at the beginning,
118: * so count common tail first. This only matters if it could match
119: * both ways, for example, when changing
120: * " ####"
121: * to
122: * "#### ####"
123: */
124: if( samelen )
125: {
126: while( *oc_end==*nc_end && oc_beg<=oc_end && nc_beg<=nc_end )
127: {
128: oc_end--;
129: nc_end--;
130: com_tail++;
131: }
132: while( *oc_beg==*nc_beg && oc_beg<=oc_end && nc_beg<=nc_end )
133: {
134: oc_beg++;
135: nc_beg++;
136: com_head++;
137: }
138: }
139: else
140: {
141: while( *oc_beg==*nc_beg && oc_beg<=oc_end && nc_beg<=nc_end )
142: {
143: oc_beg++;
144: nc_beg++;
145: com_head++;
146: }
147: while( *oc_end==*nc_end && oc_beg<=oc_end && nc_beg<=nc_end )
148: {
149: oc_end--;
150: nc_end--;
151: com_tail++;
152: }
153: }
154: ochanged = oc_end - oc_beg + 1;
155: nchanged = nc_end - nc_beg + 1;
156:
157: /* Optimization: lines are identical, so return now */
158: if( ochanged==0 && nchanged==0 && nlws==olws )
159: {
160: #ifdef DEBUG
161: if(outf) fprintf(outf, "identical lines, returning early\n");
162: #endif
163: return;
164: }
165:
166: #ifdef DEBUG
167: if(outf) fprintf (outf, "Before costs: nlws=%2d olws=%2d\
168: com_head=%2d nchanged=%2d ochanged=%2d com_tail=%2d, icfixed %d,\
169: icvar %d/32\n", nlws, olws, com_head, nchanged, ochanged, com_tail,
170: SP->term_costs.icfixed, SP->term_costs.icvar);
171: if(outf) fprintf (outf, "samelen %d, *oc_beg %o *nc_beg %o\
172: *oc_end %o *nc_end %o\n", samelen, *oc_beg, *nc_beg, *oc_end, *nc_end);
173: #endif DEBUG
174:
175: /* Decide whether to use insert/delete character */
176: #define costic(nchars) (SP->term_costs.icfixed + \
177: (((nchars)*SP->term_costs.icvar)>>5) )
178:
179: /* #define costic(nchars) (fprintf(outf,"costic %d, add %g\n", nchars, SP->term_costs.icfixed + (nchars)*SP->term_costs.icvar),(SP->term_costs.icfixed + (nchars)*SP->term_costs.icvar)) */
180:
181: cw_idc = cwo_idc = nchanged;
182: if( olws > nlws ) /* delete char */
183: {
184: cw_idc += costic(olws-nlws);
185: }
186: else
187: {
188: if( nlws > olws ) /* insert char */
189: {
190: cw_idc += costic(nlws-olws);
191: }
192: }
193: if( ochanged > nchanged ) /* delete char */
194: {
195: cw_idc += costic(ochanged-nchanged);
196: }
197: else
198: {
199: if( nchanged > ochanged ) /* insert char */
200: {
201: cw_idc += costic(nchanged-ochanged);
202: }
203: }
204: if( olws != nlws )
205: {
206: cwo_idc += com_head;
207: }
208: if( olws+ochanged != nlws+nchanged )
209: {
210: cwo_idc += com_tail;
211: }
212:
213: if( cw_idc > cwo_idc )
214: {
215: /*
216: * It's cheaper to NOT use insert/delete character!
217: * This may be because the gain from saving the common head
218: * and tail is not worth the cost of doing the insert and
219: * delete chars (some terminals are slow at this, or the
220: * tails may be really short) or because the cost is
221: * infinite (i.e. the terminal does not have ins/del char).
222: * We note this fact by forgetting about the common heads
223: * and tails.
224: */
225: ochanged += com_head+com_tail;
226: nchanged += com_head+com_tail;
227: oc_end += com_tail;
228: nc_end += com_tail;
229: oc_beg -= com_head;
230: nc_beg -= com_head;
231: com_head = 0;
232: com_tail = 0;
233: }
234:
235: /*
236: * On magic cookie terminals, we have to check for the possibility
237: * that there is a cookie that we must overwrite. This is only
238: * necessary because a "go normal" cookie looks like an ordinary
239: * blank but must compare differently.
240: */
241: if( magic_cookie_glitch >= 0 && com_tail > 0 && nc_end[1] == ' ' &&
242: oc_end[0]&A_ATTRIBUTES && oc_end[1] == ' ' )
243: {
244: #ifdef DEBUG
245: if (outf) fprintf(outf, "adding one because of magic cookie\n");
246: #endif
247: oc_end++;
248: nc_end++;
249: ochanged++;
250: nchanged++;
251: com_tail--;
252: }
253:
254: #ifdef DEBUG
255: if(outf) fprintf (outf, "After costs: nlws=%2d olws=%2d com_head=%2d nchanged=%2d ochanged=%2d com_tail=%2d, cost w/idc %d, cost wo/idc %d\n",
256: nlws, olws, com_head, nchanged, ochanged, com_tail, cw_idc, cwo_idc);
257: #endif DEBUG
258:
259: /*
260: * Now actually go fix up the line.
261: * There are several cases to consider.
262: * The most important thing to keep in mind is
263: * that deletions need to be done before insertions
264: * to prevent shifting good text off the end of the line.
265: */
266:
267: if( com_head == 0 && com_tail == 0 )
268: {
269: /* No common text - must redraw entire line */
270: if( ochanged == 0 && nchanged == 0 )
271: {
272: /* Empty lines - do nothing */
273: _chk_typeahead();
274: return;
275: }
276: /* If empty old line, pretend leading blanks */
277: if( ochanged == 0 && !insert_null_glitch )
278: {
279: olws = nlws;
280: }
281:
282: /* Make sure changed parts start at same column */
283: j = nlws - olws;
284: if( j > 0 )
285: {
286: nc_beg -= j;
287: nchanged += j;
288: nlws = olws;
289: }
290: else
291: {
292: if( j < 0 )
293: {
294: oc_beg += j;
295: ochanged -= j;
296: olws = nlws;
297: }
298: }
299:
300: for(nbl=nms=0,p=oc_beg,q=nc_beg;p<=oc_end && q<=nc_end;p++,q++)
301: {
302: if( *q==' ' && *p != ' ' )
303: {
304: nbl++;
305: }
306: if( *q == *p )
307: {
308: nms++;
309: }
310: #ifdef FULLDEBUG
311: if (outf) fprintf(outf, "*p '%c', *q '%c', nms %d, nbl %d\n", *p, *q, nms, nbl);
312: #endif
313: }
314: if( !clr_eol || insert_null_glitch || nms>=nbl )
315: {
316: _showstring(ln, min(nlws, olws), nc_beg, nc_end, old);
317: if( nlws + nchanged < olws + ochanged )
318: {
319: _pos(ln, nlws + nchanged);
320: _clreol();
321: }
322: }
323: else
324: {
325: if( ochanged > 0 )
326: {
327: _pos(ln, olws);
328: _clreol();
329: for (p=oc_beg; p<=oc_end; p++)
330: *p = ' ';
331: }
332: _showstring(ln, nlws, nc_beg, nc_end, old);
333: }
334: _chk_typeahead();
335: return;
336: }
337:
338: if( com_head==0 )
339: {
340: /* We have only a common tail. */
341: if( nchanged == 0 && ochanged == 0 )
342: {
343: _chk_typeahead();
344: return;
345: }
346: i = (nlws + nchanged) - (olws + ochanged);
347: /* Simplify things - force olws == nlws */
348: j = nlws - olws;
349: if( j > 0 )
350: {
351: nc_beg -= j;
352: nchanged += j;
353: nlws = olws;
354: }
355: else
356: {
357: if( j < 0 )
358: {
359: oc_beg += j;
360: ochanged -= j;
361: olws = nlws;
362: }
363: }
364: if( i >= 0 )
365: {
366: _showstring(ln, nlws, nc_beg, nc_end-i, old);
367: if( i > 0 )
368: {
369: _ins_string(ln, nlws+nchanged-i, nc_end-i+1, nc_end);
370: }
371: }
372: else
373: {
374: _showstring(ln, nlws, nc_beg, nc_end, old);
375: _delchars(-i);
376: }
377: _chk_typeahead();
378: return;
379: }
380:
381: /* At this point, we know there is a common head (com_head != 0) */
382: if( nlws < olws )
383: {
384: /* Do the leading delete chars right away */
385: _pos(ln, 0);
386: _delchars(diff = olws - nlws);
387: olws = nlws;
388: len = old->length;
389: for( i=0; i<len; i++ )
390: {
391: old->body[i] = old->body[i]+diff;
392: }
393: }
394: if (com_tail == 0)
395: {
396: if( nchanged == 0 && ochanged == 0 )
397: {
398: if( nlws > olws )
399: {
400: _ins_blanks(ln, 0, nlws - olws);
401: }
402: _chk_typeahead();
403: return;
404: }
405: _showstring(ln, olws+com_head, nc_beg, nc_end, old);
406: if( nchanged < ochanged )
407: {
408: _pos(ln, olws + com_head + nchanged);
409: _clreol();
410: }
411: if( nlws > olws )
412: {
413: _ins_blanks(ln, 0, nlws - olws);
414: }
415: }
416: else
417: {
418: if( nchanged > 0 && ochanged > 0 )
419: {
420: i = min(nchanged, ochanged);
421: _showstring(ln, olws+com_head, nc_beg, nc_beg+i-1, old);
422: }
423: if( nchanged < ochanged )
424: {
425: _pos(ln, nlws + com_head + nchanged);
426: _delchars(ochanged - nchanged);
427: }
428: else
429: {
430: if( nchanged > ochanged )
431: {
432: _ins_string(ln, olws+com_head+ochanged,
433: nc_beg + ochanged, nc_end);
434: }
435: }
436: if( nlws > olws )
437: {
438: _ins_blanks(ln, 0, nlws-olws);
439: }
440: }
441: _chk_typeahead();
442: return;
443: }
444:
445: /*
446: * Insert nblanks blanks at position (sline, scol).
447: */
448: static int
449: _ins_blanks(sline, scol, nblanks)
450: int sline, scol, nblanks;
451: {
452: #ifdef DEBUG
453: if (outf) fprintf(outf, "_ins_blanks at (%d, %d) %d blanks\n",
454: sline, scol, nblanks);
455: #endif
456: _pos(sline, scol);
457: if( nblanks > 1 && parm_ich )
458: {
459: /* Insert the characters and then draw on the blanks */
460: _inschars(nblanks);
461: }
462: else
463: {
464: /*
465: * Type the blanks in "insert mode". This includes
466: * having to send insert_character before each character
467: * is output.
468: */
469: _insmode(1);
470: _blanks(nblanks);
471: }
472: _insmode(0);
473: }
474:
475: /*
476: * Insert the given string on the screen.
477: * This is like _showstring but you know you're in insert mode.
478: */
479: static
480: _ins_string(sline, scol, first, last)
481: int sline, scol;
482: chtype *first, *last;
483: {
484: int len = last-first+1;
485:
486: #ifdef DEBUG
487: if (outf) fprintf(outf, "_ins_string at (%d, %d) %d chars\n",
488: sline, scol, len);
489: #endif
490: _pos(sline, scol);
491: if( len > 1 && parm_ich )
492: {
493: /* Insert the characters and then draw on the blanks */
494: _inschars(len);
495: _showstring(sline, scol, first, last, NULL);
496: }
497: else
498: {
499: /*
500: * Type the characters in "insert mode". This includes
501: * having to send insert_character before each character
502: * is output.
503: */
504: _insmode(1);
505: _showstring(sline, scol, first, last, NULL);
506: }
507: _insmode(0);
508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.