|
|
1.1 root 1: /*********************************************************************
2: * COPYRIGHT NOTICE *
3: **********************************************************************
4: * This software is copyright (C) 1982 by Pavel Curtis *
5: * *
6: * Permission is granted to reproduce and distribute *
7: * this file by any means so long as no fee is charged *
8: * above a nominal handling fee and so long as this *
9: * notice is always included in the copies. *
10: * *
11: * Other rights are reserved except as explicitly granted *
12: * by written permission of the author. *
13: * Pavel Curtis *
14: * Computer Science Dept. *
15: * 405 Upson Hall *
16: * Cornell University *
17: * Ithaca, NY 14853 *
18: * *
19: * Ph- (607) 256-4934 *
20: * *
21: * Pavel.Cornell@Udel-Relay (ARPAnet) *
22: * decvax!cornell!pavel (UUCPnet) *
23: *********************************************************************/
24:
25: /*
26: * lib_doupdate.c
27: *
28: * The routine doupdate() and its dependents
29: *
30: * $Log: lib_doupdate.c,v $
31: * Revision 3.4 93/04/10 00:18:56 munk
32: * color attributes added
33: *
34: * Revision 3.3 92/11/01 18:34:18 munk
35: * Switch attributes of in ClearScreen
36: *
37: * Revision 3.2 91/04/20 18:20:16 munk
38: * Usage of register variables
39: *
40: * Revision 3.1 84/12/13 11:20:28 john
41: * Revisions by Mark Horton
42: *
43: * Revision 2.1 82/10/25 14:47:05 pavel
44: * Added Copyright Notice
45: *
46: * Revision 2.0 82/10/25 13:44:33 pavel
47: * Beta-one Test Release
48: *
49: *
50: */
51:
52: #ifdef RCSHDR
53: static char RCSid[] =
54: "$Header: lib_doupdate.c,v 3.4 93/04/10 00:18:56 munk Exp $";
55: #endif
56:
57: #include <signal.h>
58: #include "curses.h"
59: #include "curses.priv.h"
60: #include "term.h"
61:
62: #define GoTo(row,col) mvcur(SP->_cursrow, SP->_curscol, row, col); \
63: SP->_cursrow = row; \
64: SP->_curscol = col;
65:
66: #define PutAttrChar(ch) if ((curscr->_attrs != (ch & A_ATTRIBUTES)) \
67: || (__pair_changed__ == TRUE)) \
68: { \
69: curscr->_attrs = ch & A_ATTRIBUTES; \
70: vidputs(curscr->_attrs, outc); \
71: __pair_changed__ = FALSE; \
72: } \
73: putc((int) (ch & A_CHARTEXT), SP->_ofp);
74:
75: #define PutChar(ch) if (!auto_right_margin || \
76: SP->_cursrow != lines - 1 || \
77: SP->_curscol != columns - 1) \
78: { \
79: PutAttrChar(ch); \
80: SP->_curscol++; \
81: if (SP->_curscol >= columns) \
82: if (auto_right_margin) \
83: { \
84: SP->_curscol = 0; \
85: SP->_cursrow++; \
86: } \
87: else \
88: SP->_curscol--; \
89: }
90:
91:
92:
93: outc(ch)
94: char ch;
95: {
96: putc(ch, SP->_ofp);
97: }
98:
99:
100: doupdate()
101: {
102: register int i;
103: int (*oldsig)();
104:
105: #ifdef TRACE
106: if (_tracing)
107: _tracef("doupdate() called");
108: #endif
109:
110: #ifdef SIGTSTP
111: oldsig = signal(SIGTSTP, SIG_IGN);
112: #endif
113:
114: if (curscr->_clear)
115: {
116: ClrUpdate(curscr);
117: curscr->_clear = FALSE;
118:
119: GoTo(curscr->_cury, curscr->_curx);
120: }
121: else
122: {
123: if (newscr->_clear)
124: {
125: ClrUpdate(newscr);
126: newscr->_clear = FALSE;
127: }
128: else if (curscr->_idlok)
129: IdlUpdate();
130: else
131: NoIdlUpdate();
132:
133: for (i = 0; i < lines; i++)
134: {
135: newscr->_firstchar[i] = _NOCHANGE;
136: newscr->_lastchar[i] = _NOCHANGE;
137: newscr->_numchngd[i] = 0;
138: }
139:
140: curscr->_curx = newscr->_curx;
141: curscr->_cury = newscr->_cury;
142:
143: GoTo(curscr->_cury, curscr->_curx);
144: }
145:
146:
147: fflush(SP->_ofp);
148:
149: #ifdef SIGTSTP
150: signal(SIGTSTP, oldsig);
151: #endif
152: }
153:
154:
155: /*
156: ** ClrUpdate(scr)
157: **
158: ** Update by clearing and redrawing the entire screen.
159: **
160: */
161:
162: static
163: ClrUpdate(scr)
164: register WINDOW *scr;
165: {
166: register int i, j;
167:
168: ClearScreen();
169:
170: for (i=0; i < lines; i++)
171: {
172: int lastNonBlank, lastCol;
173:
174: for (lastNonBlank = columns - 1;
175: lastNonBlank && scr->_line[i][lastNonBlank] == ' ';
176: lastNonBlank--)
177: ;
178:
179: if (!lastNonBlank)
180: continue;
181:
182: lastCol = lastNonBlank == (columns - 1);
183: if (lastCol && i == lines)
184: lastNonBlank--;
185:
186: for (j = 0; j <= lastNonBlank; j++) {
187: if (' ' != scr->_line[i][j]) {
188: GoTo(i, j);
189: break;
190: }
191: }
192:
193: for (;j <= lastNonBlank; j++) {
194: PutAttrChar(scr->_line[i][j]);
195: }
196:
197: if (auto_right_margin && lastCol) {
198: SP->_cursrow = i + 1;
199: SP->_curscol = 0;
200: }
201: else
202: SP->_curscol = j;
203: }
204:
205: if (scr != curscr)
206: for (i = 0; i < LINES; i++)
207: for (j = 0; j < COLS; j++)
208: curscr->_line[i][j] = scr->_line[i][j];
209: }
210:
211:
212: /*
213: ** NoIdlUpdate()
214: **
215: ** Update screen without using Insert/Delete Line capabilities
216: **
217: */
218:
219: static
220: NoIdlUpdate()
221: {
222: register int i;
223:
224: #ifdef TRACE
225: if (_tracing)
226: _tracef("NoIdlUpdate() called");
227: #endif
228:
229: for (i=0; i < lines; i++)
230: if (newscr->_numchngd[i])
231: TransformLine(i);
232: }
233:
234:
235: /*
236: ** IdlUpdate()
237: **
238: ** Update screen using Insert/Delete Line capabilities
239: **
240: */
241:
242: #define UNCHANGED(n) (newscr->_numchngd[n] <= columns/10 \
243: || newscr->_lastchar[n] \
244: - newscr->_firstchar[n] <= columns/10)
245:
246: static
247: IdlUpdate()
248: {
249: int firstLine, lastLine;
250: register int thisLine;
251:
252: #ifdef TRACE
253: if (_tracing)
254: _tracef("IdlUpdate() called");
255: #endif
256:
257: firstLine = -1;
258:
259: for (thisLine = 0; thisLine < lines; thisLine++)
260: {
261: if (UNCHANGED(thisLine))
262: {
263: if (firstLine != -1)
264: {
265: lastLine = thisLine - 1;
266: Gosling(firstLine, lastLine);
267: firstLine = -1;
268: }
269:
270: if (newscr->_firstchar[thisLine] != _NOCHANGE)
271: TransformLine(thisLine);
272: }
273: else if (firstLine == -1)
274: firstLine = thisLine;
275: }
276:
277: if (firstLine != -1)
278: Gosling(firstLine, lines - 1);
279: }
280:
281:
282: /*
283: ** TransformLine(lineno)
284: **
285: ** Call either IDcTransformLine or NoIDcTransformLine to do the
286: ** update, depending upon availability of insert/delete character.
287: */
288:
289: static
290: TransformLine(lineno)
291: int lineno;
292: {
293: if ( (insert_character || (enter_insert_mode && exit_insert_mode))
294: && delete_character)
295: IDcTransformLine(lineno);
296: else
297: NoIDcTransformLine(lineno);
298: }
299:
300:
301: /*
302: ** NoIDcTransformLine(lineno)
303: **
304: ** Transform the given line in curscr to the one in newscr, without
305: ** using Insert/Delete Character.
306: **
307: ** firstChar = position of first different character in line
308: ** lastChar = position of last different character in line
309: **
310: ** overwrite all characters between firstChar and lastChar.
311: **
312: */
313:
314: static
315: NoIDcTransformLine(lineno)
316: int lineno;
317: {
318: register int firstChar, lastChar;
319: register chtype *newLine = newscr->_line[lineno];
320: register chtype *oldLine = curscr->_line[lineno];
321: register int k;
322:
323: #ifdef TRACE
324: if (_tracing)
325: _tracef("NoIDcTransformLine(%d) called", lineno);
326: #endif
327:
328: firstChar = 0;
329: while (firstChar < columns
330: && newLine[firstChar] == oldLine[firstChar])
331: firstChar++;
332:
333: if (firstChar >= columns)
334: return;
335:
336: lastChar = columns - 1;
337: while (lastChar > firstChar && newLine[lastChar] == oldLine[lastChar])
338: lastChar--;
339:
340: GoTo(lineno, firstChar);
341:
342: for (k=firstChar; k <= lastChar; k++)
343: {
344: PutChar(newLine[k]);
345: oldLine[k] = newLine[k];
346: }
347: }
348:
349:
350: /*
351: ** IDcTransformLine(lineno)
352: **
353: ** Transform the given line in curscr to the one in newscr, using
354: ** Insert/Delete Character.
355: **
356: ** firstChar = position of first different character in line
357: ** oLastChar = position of last different character in old line
358: ** nLastChar = position of last different character in new line
359: **
360: ** move to firstChar
361: ** overwrite chars up to min(oLastChar, nLastChar)
362: ** if oLastChar < nLastChar
363: ** insert newLine[oLastChar+1..nLastChar]
364: ** else
365: ** delete oLastChar - nLastChar spaces
366: */
367:
368: static
369: IDcTransformLine(lineno)
370: int lineno;
371: {
372: int firstChar, oLastChar, nLastChar;
373: chtype *newLine = newscr->_line[lineno];
374: chtype *oldLine = curscr->_line[lineno];
375: register int k, n;
376:
377: #ifdef TRACE
378: if (_tracing)
379: _tracef("IDcTransformLine(%d) called", lineno);
380: #endif
381:
382: firstChar = 0;
383: while (firstChar < columns && newLine[firstChar] == oldLine[firstChar])
384: firstChar++;
385:
386: if (firstChar >= columns)
387: return;
388:
389: oLastChar = columns - 1;
390: while (oLastChar > firstChar && oldLine[oLastChar] == ' ')
391: oLastChar--;
392:
393: nLastChar = columns - 1;
394: while (nLastChar > firstChar && newLine[nLastChar] == ' ')
395: nLastChar--;
396:
397: while (newLine[nLastChar] == oldLine[oLastChar])
398: {
399: nLastChar--;
400: oLastChar--;
401: }
402:
403: n = min(oLastChar, nLastChar);
404: GoTo(lineno, firstChar);
405:
406: for (k=firstChar; k <= n; k++)
407: PutChar(newLine[k]);
408:
409: if (oLastChar < nLastChar)
410: InsStr(&newLine[k], nLastChar - oLastChar);
411: else if (oLastChar > nLastChar)
412: DelChar(oLastChar - nLastChar);
413:
414: for (k=firstChar; k < columns; k++)
415: oldLine[k] = newLine[k];
416: }
417:
418:
419: /*
420: ** Gosling(firstLine, lastLine)
421: **
422: ** Change the given range of lines on curscr into the same lines
423: ** on newscr, using Gosling's Algorithm.
424: */
425:
426: static short lineCost[MAXLINES][MAXLINES];
427: static short lineOps[MAXLINES][MAXLINES];
428: static short lineDels[MAXLINES];
429: static short lineIRs[MAXLINES];
430:
431: #define INSERT 1
432: #define DELETE 2
433: #define REPLACE 3
434:
435: static
436: Gosling(firstLine, lastLine)
437: int firstLine, lastLine;
438: {
439: register int i, count;
440:
441: #ifdef TRACE
442: if (_tracing)
443: _tracef("Gosling(%d,%d) called", firstLine, lastLine);
444: #endif
445:
446: Goscost(firstLine, lastLine - firstLine + 1);
447:
448: for (i=0; i <= lastLine - firstLine + 1; i++)
449: lineDels[i] = lineIRs[i] = 0;
450:
451: Gosdraw(lastLine - firstLine + 1, lastLine - firstLine + 1);
452:
453: count = 0;
454: for (i = lastLine - firstLine + 1; i > 0; i--)
455: {
456: if (lineDels[i] == DELETE)
457: count++;
458: else if (count)
459: {
460: DelLine(count, firstLine + i, lastLine);
461: count = 0;
462: }
463: }
464:
465: if (count)
466: DelLine(count, firstLine, lastLine);
467:
468:
469: for (i = 1; i <= lastLine - firstLine + 1; i++)
470: {
471: switch (lineIRs[i])
472: {
473: case REPLACE:
474: TransformLine(firstLine + i - 1);
475: break;
476:
477: case INSERT:
478: InsLine(firstLine + i - 1, lastLine);
479: break;
480:
481: default:
482: /* do nothing */
483: break;
484: }
485: }
486: }
487:
488:
489: #define RPLCOST(old,new) (oHash[old] == nHash[new] ? 0 : columns)
490:
491: static
492: Goscost(lineno, length)
493: int lineno, length;
494: {
495: register int i, j;
496: int cost, ILcost, DLcost;
497: long nHash[MAXLINES], oHash[MAXLINES];
498: long HashFn();
499:
500: #ifdef TRACE
501: if (_tracing)
502: _tracef("Goscost(lineno=%d,length=%d) called", lineno, length);
503: #endif
504:
505: ILcost = (insert_line ? strlen(insert_line) : 9999) + columns;
506: DLcost = (delete_line ? strlen(delete_line) : 9999);
507:
508: for (i=1; i <= length; i++)
509: {
510: nHash[i] = HashFn(newscr->_line[lineno + i - 1]);
511: oHash[i] = HashFn(curscr->_line[lineno + i - 1]);
512: }
513:
514: lineCost[0][0] = 0;
515:
516: for (i=1; i <= length; i++)
517: {
518: lineCost[i][0] = lineCost[i-1][0] + DLcost;
519: lineOps[i][0] = DELETE;
520:
521: lineCost[0][i] = lineCost[0][i-1] + ILcost;
522: lineOps[0][i] = INSERT;
523: }
524:
525: for (i=1; i <= length; i++)
526: {
527: for (j=1; j <= length; j++)
528: {
529: lineCost[i][j] = lineCost[i-1][j-1] + RPLCOST(i, j);
530: lineOps[i][j] = REPLACE;
531:
532: cost = lineCost[i][j-1] + ILcost;
533: if (cost < lineCost[i][j])
534: {
535: lineCost[i][j] = cost;
536: lineOps[i][j] = INSERT;
537: }
538:
539: cost = lineCost[i-1][j] + DLcost;
540: if (cost < lineCost[i][j])
541: {
542: lineCost[i][j] = cost;
543: lineOps[i][j] = DELETE;
544: }
545: }
546: }
547:
548: return(lineCost[columns][columns]);
549: }
550:
551:
552: /*
553: ** _PrintCosts(length)
554: **
555: ** Print out the cost matrix. Called only from sdb.
556: **
557: **
558: ** _DumpNewscr(first, last)
559: **
560: ** Print the specified range of lines from newscr. Called only from sdb.
561: **
562: **
563: ** _DumpCurscr(first, last)
564: **
565: ** Print the specified range of lines from curscr. Called only from sdb.
566: **
567: */
568:
569: _PrintCosts(length)
570: int length;
571: {
572: register int i, j;
573:
574: for (i=0; i <= length; i++)
575: {
576: for (j=0; j <= length; j++)
577: {
578: printf("%5d/%d", lineCost[i][j], lineOps[i][j]);
579: }
580:
581: putchar('\n');
582: }
583:
584: fflush(stdout);
585: }
586:
587:
588: _DumpNewscr(first, last)
589: int first, last;
590: {
591: register int i, j;
592:
593: for (i=first; i <= last; i++)
594: {
595: for (j=0; j < columns; j++)
596: putchar((int) (newscr->_line[i][j]));
597:
598: putchar('\n');
599: }
600: }
601:
602:
603: _DumpCurscr(first, last)
604: int first, last;
605: {
606: register int i, j;
607:
608: for (i=first; i <= last; i++)
609: {
610: for (j=0; j < columns; j++)
611: putchar((int) (curscr->_line[i][j]));
612:
613: putchar('\n');
614: }
615: }
616:
617:
618: long
619: HashFn(line)
620: register chtype *line;
621: {
622: register int i = 0;
623: long hash = 0;
624:
625: while(i < columns && (line[i] | A_CHARTEXT) == ' ')
626: i++;
627:
628: for (; i+1 < columns; i += 2)
629: hash += (line[i] << 8) + line[i+1];
630:
631: return (hash);
632: }
633:
634:
635: static
636: Gosdraw(i, j)
637: register int i, j;
638: {
639: if (i == 0 && j == 0)
640: return;
641:
642: switch (lineOps[i][j])
643: {
644: case INSERT:
645: Gosdraw(i, j-1);
646: lineIRs[j] = INSERT;
647: break;
648:
649: case DELETE:
650: lineDels[i] = DELETE;
651: Gosdraw(i-1, j);
652: break;
653:
654: case REPLACE:
655: Gosdraw(i-1, j-1);
656: lineIRs[j] = REPLACE;
657: break;
658: }
659: }
660:
661:
662: /*
663: ** ClearScreen()
664: **
665: ** Clear the physical screen and put cursor at home
666: **
667: */
668:
669: static
670: ClearScreen()
671: {
672: vidputs(A_NORMAL, outc);
673: if (clear_screen)
674: {
675: tputs(clear_screen, 1, outc);
676: SP->_cursrow = SP->_curscol = 0;
677: }
678: else if (clr_eos)
679: {
680: SP->_cursrow = SP->_curscol = -1;
681: GoTo(0,0);
682:
683: tputs(clr_eos, 1, outc);
684: }
685: else if (clr_eol)
686: {
687: SP->_cursrow = SP->_curscol = -1;
688:
689: while (SP->_cursrow < lines)
690: {
691: GoTo(SP->_cursrow, 0);
692: tputs(clr_eol, 1, outc);
693: }
694:
695: GoTo(0,0);
696: }
697: }
698:
699:
700: /*
701: ** InsStr(line, count)
702: **
703: ** Insert the count characters pointed to by line.
704: **
705: */
706:
707: InsStr(line, count)
708: register chtype *line;
709: register int count;
710: {
711: char *tparm();
712:
713: #ifdef TRACE
714: if (_tracing)
715: _tracef("InsStr(%o,%d) called", line, count);
716: #endif
717:
718: if (enter_insert_mode && exit_insert_mode)
719: {
720: tputs(enter_insert_mode, 1, outc);
721: while (count)
722: {
723: PutChar(*line);
724: line++;
725: count--;
726: }
727: tputs(exit_insert_mode, 1, outc);
728: }
729: else if (parm_ich)
730: {
731: tputs(tparm(parm_ich, count), 1, outc);
732: while (count)
733: {
734: PutChar(*line);
735: line++;
736: count--;
737: }
738: }
739: else
740: {
741: while (count)
742: {
743: tputs(insert_character, 1, outc);
744: PutChar(*line);
745: line++;
746: count--;
747: }
748: }
749: }
750:
751:
752: /*
753: ** DelChar(count)
754: **
755: ** Delete count characters at current position
756: **
757: */
758:
759: DelChar(count)
760: register int count;
761: {
762: char *tparm();
763:
764: #ifdef TRACE
765: if (_tracing)
766: _tracef("DelChar(%d) called", count);
767: #endif
768:
769: if (parm_dch)
770: {
771: tputs(tparm(parm_dch, count), 1, outc);
772: }
773: else
774: {
775: while (count--)
776: tputs(delete_character, 1, outc);
777: }
778: }
779:
780:
781: /*
782: ** InsLine(lineno, lastLine)
783: **
784: ** Insert line number lineno, affecting up to lastLine
785: **
786: */
787:
788: InsLine(lineno, lastLine)
789: int lineno, lastLine;
790: {
791: register int i, j, k;
792: chtype *temp;
793: chtype *line = newscr->_line[lineno];
794:
795: #ifdef TRACE
796: if (_tracing)
797: _tracef("InsLine(%d,%d) called", lineno, lastLine);
798: #endif
799:
800: GoTo(lineno, 0);
801:
802: tputs(insert_line, 1, outc);
803:
804: for (i=0; i < columns; i++)
805: PutChar(line[i]);
806:
807: temp = curscr->_line[lastLine];
808: for (k = lastLine; k > lineno; k--)
809: curscr->_line[k] = curscr->_line[k - 1];
810:
811: curscr->_line[k] = temp;
812:
813: for (j=0; j < columns; j++)
814: curscr->_line[k][j] = newscr->_line[k][j];
815: }
816:
817:
818: /*
819: ** DelLine(count, lineno, lastLine)
820: **
821: ** Delete count lines at lineno, affecting up to lastLine
822: **
823: */
824:
825: DelLine(count, lineno, lastLine)
826: int count, lineno, lastLine;
827: {
828: char *tparm();
829: register int j, k;
830: chtype *temp;
831:
832: #ifdef TRACE
833: if (_tracing)
834: _tracef("DelLine(%d,%d,%d) called", count, lineno, lastLine);
835: #endif
836:
837: GoTo(lineno, 0);
838:
839: if (parm_delete_line)
840: {
841: tputs(tparm(parm_delete_line, count), 1, outc);
842: }
843: else
844: {
845: while (count--)
846: tputs(delete_line, 1, outc);
847: }
848:
849: for (k = lineno; k + count <= lastLine; k++)
850: {
851: temp = curscr->_line[k];
852: curscr->_line[k] = curscr->_line[k + count];
853: curscr->_line[k + count] = temp;
854: }
855:
856: for (; k <= lastLine; k++)
857: for (j=0; j < columns; j++)
858: curscr->_line[k][j] = ' ';
859: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.