|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2: #include "ex.h"
3: #include "ex_tty.h"
4: #include "ex_vis.h"
5:
6: /*
7: * Deal with the screen, clearing, cursor positioning, putting characters
8: * into the screen image, and deleting characters.
9: * Really hard stuff here is utilizing insert character operations
10: * on intelligent terminals which differs widely from terminal to terminal.
11: */
12: vclear()
13: {
14:
15: #ifdef ADEBUG
16: if (trace)
17: tfixnl(), fprintf(trace, "------\nvclear\n");
18: #endif
19: tputs(CL, LINES, putch);
20: destcol = 0;
21: outcol = 0;
22: destline = 0;
23: outline = 0;
24: if (inopen)
25: vclrbyte(vtube0, WCOLS * (WECHO - ZERO + 1));
26: }
27:
28: /*
29: * Clear memory.
30: */
31: vclrbyte(cp, i)
32: register char *cp;
33: register int i;
34: {
35:
36: if (i > 0)
37: do
38: *cp++ = 0;
39: while (--i != 0);
40: }
41:
42: /*
43: * Clear a physical display line, high level.
44: */
45: vclrlin(l, tp)
46: int l;
47: line *tp;
48: {
49:
50: vigoto(l, 0);
51: if ((hold & HOLDAT) == 0)
52: putchar(tp > dol ? ((UPPERCASE || HZ) ? '^' : '~') : '@');
53: if (state == HARDOPEN)
54: sethard();
55: vclreol();
56: }
57:
58: /*
59: * Clear to the end of the current physical line
60: */
61: vclreol()
62: {
63: register int i, j;
64: register char *tp;
65:
66: if (destcol == WCOLS)
67: return;
68: destline += destcol / WCOLS;
69: destcol %= WCOLS;
70: if (destline < 0 || destline > WECHO)
71: error("Internal error: vclreol");
72: i = WCOLS - destcol;
73: tp = vtube[destline] + destcol;
74: if (CE) {
75: if (IN && *tp || !ateopr()) {
76: vcsync();
77: vputp(CE, 1);
78: }
79: vclrbyte(tp, i);
80: return;
81: }
82: if (*tp == 0)
83: return;
84: while (i > 0 && (j = *tp & (QUOTE|TRIM))) {
85: if (j != ' ' && (j & QUOTE) == 0) {
86: destcol = WCOLS - i;
87: vputchar(' ');
88: }
89: --i, *tp++ = 0;
90: }
91: }
92:
93: /*
94: * Clear the echo line.
95: * If didphys then its been cleared physically (as
96: * a side effect of a clear to end of display, e.g.)
97: * so just do it logically.
98: * If work here is being held off, just remember, in
99: * heldech, if work needs to be done, don't do anything.
100: */
101: vclrech(didphys)
102: bool didphys;
103: {
104:
105: if (Peekkey == ATTN)
106: return;
107: if (hold & HOLDECH) {
108: heldech = !didphys;
109: return;
110: }
111: if (!didphys && (CD || CE)) {
112: splitw++;
113: /*
114: * If display is retained below, then MUST use CD or CE
115: * since we don't really know whats out there.
116: * Vigoto might decide (incorrectly) to do nothing.
117: */
118: if (DB)
119: vgoto(WECHO, 0), vputp(CD ? CD : CE, 1);
120: else
121: vigoto(WECHO, 0), vclreol();
122: splitw = 0;
123: didphys = 1;
124: }
125: if (didphys)
126: vclrbyte(vtube[WECHO], WCOLS);
127: heldech = 0;
128: }
129:
130: /*
131: * Fix the echo area for use, setting
132: * the state variable splitw so we wont rollup
133: * when we move the cursor there.
134: */
135: fixech()
136: {
137:
138: splitw++;
139: if (state != VISUAL && state != CRTOPEN) {
140: vclean();
141: vcnt = 0;
142: }
143: vgoto(WECHO, 0); flusho();
144: }
145:
146: /*
147: * Put the cursor ``before'' cp.
148: */
149: vcursbef(cp)
150: register char *cp;
151: {
152:
153: if (cp <= linebuf)
154: vgotoCL(value(NUMBER) << 3);
155: else
156: vgotoCL(column(cp - 1) - 1);
157: }
158:
159: /*
160: * Put the cursor ``at'' cp.
161: */
162: vcursat(cp)
163: register char *cp;
164: {
165:
166: if (cp <= linebuf && linebuf[0] == 0)
167: vgotoCL(value(NUMBER) << 3);
168: else
169: vgotoCL(column(cp - 1));
170: }
171:
172: /*
173: * Put the cursor ``after'' cp.
174: */
175: vcursaft(cp)
176: register char *cp;
177: {
178:
179: vgotoCL(column(cp));
180: }
181:
182: /*
183: * Fix the cursor to be positioned in the correct place
184: * to accept a command.
185: */
186: vfixcurs()
187: {
188:
189: vsetcurs(cursor);
190: }
191:
192: /*
193: * Compute the column position implied by the cursor at ``nc'',
194: * and move the cursor there.
195: */
196: vsetcurs(nc)
197: register char *nc;
198: {
199: register int col;
200:
201: col = column(nc);
202: if (linebuf[0])
203: col--;
204: vgotoCL(col);
205: cursor = nc;
206: }
207:
208: /*
209: * Move the cursor invisibly, i.e. only remember to do it.
210: */
211: vigoto(y, x)
212: int y, x;
213: {
214:
215: destline = y;
216: destcol = x;
217: }
218:
219: /*
220: * Move the cursor to the position implied by any previous
221: * vigoto (or low level hacking with destcol/destline as in readecho).
222: */
223: vcsync()
224: {
225:
226: vgoto(destline, destcol);
227: }
228:
229: /*
230: * Goto column x of the current line.
231: */
232: vgotoCL(x)
233: register int x;
234: {
235:
236: if (splitw)
237: vgoto(WECHO, x);
238: else
239: vgoto(LINE(vcline), x);
240: }
241:
242: /*
243: * Invisible goto column x of current line.
244: */
245: vigotoCL(x)
246: register int x;
247: {
248:
249: if (splitw)
250: vigoto(WECHO, x);
251: else
252: vigoto(LINE(vcline), x);
253: }
254:
255: /*
256: * Move cursor to line y, column x, handling wraparound and scrolling.
257: */
258: vgoto(y, x)
259: register int y, x;
260: {
261: register char *tp;
262: register int c;
263:
264: /*
265: * Fold the possibly too large value of x.
266: */
267: if (x >= WCOLS) {
268: y += x / WCOLS;
269: x %= WCOLS;
270: }
271: if (y < 0)
272: error("Internal error: vgoto");
273: if (outcol >= WCOLS) {
274: if (AM) {
275: outline += outcol / WCOLS;
276: outcol %= WCOLS;
277: } else
278: outcol = WCOLS - 1;
279: }
280:
281: /*
282: * In a hardcopy or glass crt open, print the stuff
283: * implied by a motion, or backspace.
284: */
285: if (state == HARDOPEN || state == ONEOPEN) {
286: if (y != outline)
287: error("Line too long for open");
288: if (x + 1 < outcol - x || (outcol > x && !BS))
289: destcol = 0, fgoto();
290: tp = vtube[WBOT] + outcol;
291: while (outcol != x)
292: if (outcol < x) {
293: if (*tp == 0)
294: *tp = ' ';
295: c = *tp++ & TRIM;
296: vputc(c && (!OS || EO) ? c : ' '), outcol++;
297: } else {
298: if (BC)
299: vputp(BC, 0);
300: else
301: vputc('\b');
302: outcol--;
303: }
304: destcol = outcol = x;
305: destline = outline;
306: return;
307: }
308:
309: /*
310: * If the destination position implies a scroll, do it.
311: */
312: destline = y;
313: if (destline > WBOT && (!splitw || destline > WECHO)) {
314: endim();
315: vrollup(destline);
316: }
317:
318: /*
319: * If there really is a motion involved, do it.
320: * The check here is an optimization based on profiling.
321: */
322: destcol = x;
323: if ((destline - outline) * WCOLS != destcol - outcol) {
324: if (!MI)
325: endim();
326: fgoto();
327: }
328: }
329:
330: /*
331: * This is the hardest code in the editor, and deals with insert modes
332: * on different kinds of intelligent terminals. The complexity is due
333: * to the cross product of three factors:
334: *
335: * 1. Lines may display as more than one segment on the screen.
336: * 2. There are 2 kinds of intelligent terminal insert modes.
337: * 3. Tabs squash when you insert characters in front of them,
338: * in a way in which current intelligent terminals don't handle.
339: *
340: * The two kinds of terminals are typified by the DM2500 or HP2645 for
341: * one and the CONCEPT-100 or the FOX for the other.
342: *
343: * The first (HP2645) kind has an insert mode where the characters
344: * fall off the end of the line and the screen is shifted rigidly
345: * no matter how the display came about.
346: *
347: * The second (CONCEPT-100) kind comes from terminals which are designed
348: * for forms editing and which distinguish between blanks and ``spaces''
349: * on the screen, spaces being like blank, but never having had
350: * and data typed into that screen position (since, e.g. a clear operation
351: * like clear screen). On these terminals, when you insert a character,
352: * the characters from where you are to the end of the screen shift
353: * over till a ``space'' is found, and the null character there gets
354: * eaten up.
355: *
356: *
357: * The code here considers the line as consisting of several parts
358: * the first part is the ``doomed'' part, i.e. a part of the line
359: * which is being typed over. Next comes some text up to the first
360: * following tab. The tab is the next segment of the line, and finally
361: * text after the tab.
362: *
363: * We have to consider each of these segments and the effect of the
364: * insertion of a character on them. On terminals like HP2645's we
365: * must simulate a multi-line insert mode using the primitive one
366: * line insert mode. If we are inserting in front of a tab, we have
367: * to either delete characters from the tab or insert white space
368: * (when the tab reaches a new spot where it gets larger) before we
369: * insert the new character.
370: *
371: * On a terminal like a CONCEPT our strategy is to make all
372: * blanks be displayed, while trying to keep the screen having ``spaces''
373: * for portions of tabs. In this way the terminal hardward does some
374: * of the hacking for compression of tabs, although this tends to
375: * disappear as you work on the line and spaces change into blanks.
376: *
377: * There are a number of boundary conditions (like typing just before
378: * the first following tab) where we can avoid a lot of work. Most
379: * of them have to be dealt with explicitly because performance is
380: * much, much worse if we don't.
381: *
382: * A final thing which is hacked here is two flavors of insert mode.
383: * Datamedia's do this by an insert mode which you enter and leave
384: * and by having normal motion character operate differently in this
385: * mode, notably by having a newline insert a line on the screen in
386: * this mode. This generally means it is unsafe to move around
387: * the screen ignoring the fact that we are in this mode.
388: * This is possible on some terminals, and wins big (e.g. HP), so
389: * we encode this as a ``can move in insert capability'' mi,
390: * and terminals which have it can do insert mode with much less
391: * work when tabs are present following the cursor on the current line.
392: */
393:
394: /*
395: * Routine to expand a tab, calling the normal Outchar routine
396: * to put out each implied character. Note that we call outchar
397: * with a QUOTE. We use QUOTE internally to represent a position
398: * which is part of the expansion of a tab.
399: */
400: vgotab()
401: {
402: register int i = (LINE(vcline) - destline) * WCOLS + destcol;
403:
404: do
405: (*Outchar)(QUOTE);
406: while (++i % value(TABSTOP));
407: }
408:
409: /*
410: * Variables for insert mode.
411: */
412: int linend; /* The column position of end of line */
413: int tabstart; /* Column of start of first following tab */
414: int tabend; /* Column of end of following tabs */
415: int tabsize; /* Size of the following tabs */
416: int tabslack; /* Number of ``spaces'' in following tabs */
417: int inssiz; /* Number of characters to be inserted */
418: int inscol; /* Column where insertion is taking place */
419: int shft; /* Amount tab expansion shifted rest of line */
420: int slakused; /* This much of tabslack will be used up */
421:
422: /*
423: * This routine MUST be called before insert mode is run,
424: * and brings all segments of the current line to the top
425: * of the screen image buffer so it is easier for us to
426: * maniuplate them.
427: */
428: vprepins()
429: {
430: register int i;
431: register char *cp = vtube0;
432:
433: for (i = 0; i < DEPTH(vcline); i++) {
434: vmaktop(LINE(vcline) + i, cp);
435: cp += WCOLS;
436: }
437: }
438:
439: vmaktop(p, cp)
440: register int p;
441: char *cp;
442: {
443: register int i;
444: char temp[TUBECOLS];
445:
446: if (vtube[p] == cp)
447: return;
448: for (i = ZERO; i <= WECHO; i++)
449: if (vtube[i] == cp) {
450: copy(temp, vtube[i], WCOLS);
451: copy(vtube[i], vtube[p], WCOLS);
452: copy(vtube[p], temp, WCOLS);
453: vtube[i] = vtube[p];
454: vtube[p] = cp;
455: return;
456: }
457: error("Line too long");
458: }
459:
460: /*
461: * Insert character c at current cursor position.
462: * Multi-character inserts occur only as a result
463: * of expansion of tabs (i.e. inssize == 1 except
464: * for tabs) and code assumes this in several place
465: * to make life simpler.
466: */
467: vinschar(c)
468: char c;
469: {
470: register int i;
471: register char *tp;
472:
473: if ((!IM || !EI) && ((hold & HOLDQIK) || !value(REDRAW) || value(SLOWOPEN))) {
474: /*
475: * Don't want to try to use terminal
476: * insert mode, or to try to fake it.
477: * Just put the character out; the screen
478: * will probably be wrong but we will fix it later.
479: */
480: if (c == '\t') {
481: vgotab();
482: return;
483: }
484: vputchar(c);
485: if (DEPTH(vcline) * WCOLS + !value(REDRAW) >
486: (destline - LINE(vcline)) * WCOLS + destcol)
487: return;
488: /*
489: * The next line is about to be clobbered
490: * make space for another segment of this line
491: * (on an intelligent terminal) or just remember
492: * that next line was clobbered (on a dumb one
493: * if we don't care to redraw the tail.
494: */
495: if (AL) {
496: vnpins(0);
497: } else {
498: c = LINE(vcline) + DEPTH(vcline);
499: if (c < LINE(vcline + 1) || c > WBOT)
500: return;
501: i = destcol;
502: vinslin(c, 1, vcline);
503: DEPTH(vcline)++;
504: vigoto(c, i);
505: vprepins();
506: }
507: return;
508: }
509: /*
510: * Compute the number of positions in the line image of the
511: * current line. This is done from the physical image
512: * since that is faster. Note that we have no memory
513: * from insertion to insertion so that routines which use
514: * us don't have to worry about moving the cursor around.
515: */
516: if (*vtube0 == 0)
517: linend = 0;
518: else {
519: /*
520: * Search backwards for a non-null character
521: * from the end of the displayed line.
522: */
523: i = WCOLS * DEPTH(vcline);
524: if (i == 0)
525: i = WCOLS;
526: tp = vtube0 + i;
527: while (*--tp == 0)
528: if (--i == 0)
529: break;
530: linend = i;
531: }
532:
533: /*
534: * We insert at a position based on the physical location
535: * of the output cursor.
536: */
537: inscol = destcol + (destline - LINE(vcline)) * WCOLS;
538: if (c == '\t') {
539: /*
540: * Characters inserted from a tab must be
541: * remembered as being part of a tab, but we can't
542: * use QUOTE here since we really need to print blanks.
543: * QUOTE|' ' is the representation of this.
544: */
545: inssiz = value(TABSTOP) - inscol % value(TABSTOP);
546: c = ' ' | QUOTE;
547: } else
548: inssiz = 1;
549:
550: /*
551: * If the text to be inserted is less than the number
552: * of doomed positions, then we don't need insert mode,
553: * rather we can just typeover.
554: */
555: if (inssiz <= doomed) {
556: endim();
557: if (inscol != linend)
558: doomed -= inssiz;
559: do
560: vputchar(c);
561: while (--inssiz);
562: return;
563: }
564:
565: /*
566: * Have to really do some insertion, thus
567: * stake out the bounds of the first following
568: * group of tabs, computing starting position,
569: * ending position, and the number of ``spaces'' therein
570: * so we can tell how much it will squish.
571: */
572: tp = vtube0 + inscol;
573: for (i = inscol; i < linend; i++)
574: if (*tp++ & QUOTE) {
575: --tp;
576: break;
577: }
578: tabstart = tabend = i;
579: tabslack = 0;
580: while (tabend < linend) {
581: i = *tp++;
582: if ((i & QUOTE) == 0)
583: break;
584: if ((i & TRIM) == 0)
585: tabslack++;
586: tabsize++;
587: tabend++;
588: }
589: tabsize = tabend - tabstart;
590:
591: /*
592: * For HP's and DM's, e.g. tabslack has no meaning.
593: */
594: if (!IN)
595: tabslack = 0;
596: #ifdef IDEBUG
597: if (trace) {
598: fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ",
599: inscol, inssiz, tabstart);
600: fprintf(trace, "tabend %d, tabslack %d, linend %d\n",
601: tabend, tabslack, linend);
602: }
603: #endif
604:
605: /*
606: * The real work begins.
607: */
608: slakused = 0;
609: shft = 0;
610: if (tabsize) {
611: /*
612: * There are tabs on this line.
613: * If they need to expand, then the rest of the line
614: * will have to be shifted over. In this case,
615: * we will need to make sure there are no ``spaces''
616: * in the rest of the line (on e.g. CONCEPT-100)
617: * and then grab another segment on the screen if this
618: * line is now deeper. We then do the shift
619: * implied by the insertion.
620: */
621: if (inssiz >= doomed + value(TABSTOP) - tabstart % value(TABSTOP)) {
622: if (IN)
623: vrigid();
624: vneedpos(value(TABSTOP));
625: vishft();
626: }
627: } else if (inssiz > doomed)
628: /*
629: * No tabs, but line may still get deeper.
630: */
631: vneedpos(inssiz - doomed);
632: /*
633: * Now put in the inserted characters.
634: */
635: viin(c);
636:
637: /*
638: * Now put the cursor in its final resting place.
639: */
640: destline = LINE(vcline);
641: destcol = inscol + inssiz;
642: vcsync();
643: }
644:
645: /*
646: * Rigidify the rest of the line after the first
647: * group of following tabs, typing blanks over ``spaces''.
648: */
649: vrigid()
650: {
651: register int col;
652: register char *tp = vtube0 + tabend;
653:
654: for (col = tabend; col < linend; col++)
655: if ((*tp++ & TRIM) == 0) {
656: endim();
657: vgotoCL(col);
658: vputchar(' ' | QUOTE);
659: }
660: }
661:
662: /*
663: * We need cnt more positions on this line.
664: * Open up new space on the screen (this may in fact be a
665: * screen rollup).
666: *
667: * On a dumb terminal we may infact redisplay the rest of the
668: * screen here brute force to keep it pretty.
669: */
670: vneedpos(cnt)
671: int cnt;
672: {
673: register int d = DEPTH(vcline);
674: register int rmdr = d * WCOLS - linend;
675:
676: if (cnt <= rmdr - IN)
677: return;
678: endim();
679: vnpins(1);
680: }
681:
682: vnpins(dosync)
683: int dosync;
684: {
685: register int d = DEPTH(vcline);
686: register int e;
687:
688: e = LINE(vcline) + DEPTH(vcline);
689: if (e < LINE(vcline + 1)) {
690: vigoto(e, 0);
691: vclreol();
692: return;
693: }
694: DEPTH(vcline)++;
695: if (e < WECHO) {
696: e = vglitchup(vcline, d);
697: vigoto(e, 0); vclreol();
698: if (dosync) {
699: Outchar = vputchar;
700: vsync(e + 1);
701: Outchar = vinschar;
702: }
703: } else {
704: vup1();
705: vigoto(WBOT, 0);
706: vclreol();
707: }
708: vprepins();
709: }
710:
711: /*
712: * Do the shift of the next tabstop implied by
713: * insertion so it expands.
714: */
715: vishft()
716: {
717: int tshft = 0;
718: int j;
719: register int i;
720: register char *tp = vtube0;
721: register char *up;
722: short oldhold = hold;
723:
724: shft = value(TABSTOP);
725: hold |= HOLDPUPD;
726: if (!IM && !EI) {
727: /*
728: * Dumb terminals are easy, we just have
729: * to retype the text.
730: */
731: vigotoCL(tabend + shft);
732: up = tp + tabend;
733: for (i = tabend; i < linend; i++)
734: vputchar(*up++);
735: } else if (IN) {
736: /*
737: * CONCEPT-like terminals do most of the work for us,
738: * we don't have to muck with simulation of multi-line
739: * insert mode. Some of the shifting may come for free
740: * also if the tabs don't have enough slack to take up
741: * all the inserted characters.
742: */
743: i = shft;
744: slakused = inssiz - doomed;
745: if (slakused > tabslack) {
746: i -= slakused - tabslack;
747: slakused -= tabslack;
748: }
749: if (i > 0 && tabend != linend) {
750: tshft = i;
751: vgotoCL(tabend);
752: goim();
753: do
754: vputchar(' ' | QUOTE);
755: while (--i);
756: }
757: } else {
758: /*
759: * HP and Datamedia type terminals have to have multi-line
760: * insert faked. Hack each segment after where we are
761: * (going backwards to where we are.) We then can
762: * hack the segment where the end of the first following
763: * tab group is.
764: */
765: for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) {
766: vgotoCL(j * WCOLS);
767: goim();
768: up = tp + j * WCOLS - shft;
769: i = shft;
770: do
771: vputchar(*up++);
772: while (--i);
773: }
774: vigotoCL(tabstart);
775: i = shft - (inssiz - doomed);
776: if (i > 0) {
777: tabslack = inssiz - doomed;
778: vcsync();
779: goim();
780: do
781: vputchar(' ');
782: while (--i);
783: }
784: }
785: /*
786: * Now do the data moving in the internal screen
787: * image which is common to all three cases.
788: */
789: tp += linend;
790: up = tp + shft;
791: i = linend - tabend;
792: if (i > 0)
793: do
794: *--up = *--tp;
795: while (--i);
796: if (IN && tshft) {
797: i = tshft;
798: do
799: *--up = ' ' | QUOTE;
800: while (--i);
801: }
802: hold = oldhold;
803: }
804:
805: /*
806: * Now do the insert of the characters (finally).
807: */
808: viin(c)
809: char c;
810: {
811: register char *tp, *up;
812: register int i, j;
813: register bool noim = 0;
814: int remdoom;
815: short oldhold = hold;
816:
817: hold |= HOLDPUPD;
818: if (tabsize && (IM && EI) && inssiz - doomed > tabslack)
819: /*
820: * There is a tab out there which will be affected
821: * by the insertion since there aren't enough doomed
822: * characters to take up all the insertion and we do
823: * have insert mode capability.
824: */
825: if (inscol + doomed == tabstart) {
826: /*
827: * The end of the doomed characters sits right at the
828: * start of the tabs, then we don't need to use insert
829: * mode; unless the tab has already been expanded
830: * in which case we MUST use insert mode.
831: */
832: slakused = 0;
833: noim = !shft;
834: } else {
835: /*
836: * The last really special case to handle is case
837: * where the tab is just sitting there and doesn't
838: * have enough slack to let the insertion take
839: * place without shifting the rest of the line
840: * over. In this case we have to go out and
841: * delete some characters of the tab before we start
842: * or the answer will be wrong, as the rest of the
843: * line will have been shifted. This code means
844: * that terminals with only insert chracter (no
845: * delete character) won't work correctly.
846: */
847: i = inssiz - doomed - tabslack - slakused;
848: i %= value(TABSTOP);
849: if (i > 0) {
850: vgotoCL(tabstart);
851: godm();
852: for (i = inssiz - doomed - tabslack; i > 0; i--)
853: vputp(DC, DEPTH(vcline));
854: enddm();
855: }
856: }
857:
858: /*
859: * Now put out the characters of the actual insertion.
860: */
861: vigotoCL(inscol);
862: remdoom = doomed;
863: for (i = inssiz; i > 0; i--) {
864: if (remdoom > 0) {
865: remdoom--;
866: endim();
867: } else if (noim)
868: endim();
869: else if (IM && EI) {
870: vcsync();
871: goim();
872: }
873: vputchar(c);
874: }
875:
876: if (!IM || !EI) {
877: /*
878: * We are a dumb terminal; brute force update
879: * the rest of the line; this is very much an n^^2 process,
880: * and totally unreasonable at low speed.
881: *
882: * You asked for it, you get it.
883: */
884: tp = vtube0 + inscol + doomed;
885: for (i = inscol + doomed; i < tabstart; i++)
886: vputchar(*tp++);
887: hold = oldhold;
888: vigotoCL(tabstart + inssiz - doomed);
889: for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
890: vputchar(' ' | QUOTE);
891: } else {
892: if (!IN) {
893: /*
894: * On terminals without multi-line
895: * insert in the hardware, we must go fix the segments
896: * between the inserted text and the following
897: * tabs, if they are on different lines.
898: *
899: * Aaargh.
900: */
901: tp = vtube0;
902: for (j = (inscol + inssiz - 1) / WCOLS + 1;
903: j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) {
904: vgotoCL(j * WCOLS);
905: i = inssiz - doomed;
906: up = tp + j * WCOLS - i;
907: goim();
908: do
909: vputchar(*up++);
910: while (--i && *up);
911: }
912: } else {
913: /*
914: * On terminals with multi line inserts,
915: * life is simpler, just reflect eating of
916: * the slack.
917: */
918: tp = vtube0 + tabend;
919: for (i = tabsize - (inssiz - doomed); i >= 0; i--) {
920: if ((*--tp & (QUOTE|TRIM)) == QUOTE) {
921: --tabslack;
922: if (tabslack >= slakused)
923: continue;
924: }
925: *tp = ' ' | QUOTE;
926: }
927: }
928: /*
929: * Blank out the shifted positions to be tab positions.
930: */
931: if (shft) {
932: tp = vtube0 + tabend + shft;
933: for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--)
934: if ((*--tp & QUOTE) == 0)
935: *tp = ' ' | QUOTE;
936: }
937: }
938:
939: /*
940: * Finally, complete the screen image update
941: * to reflect the insertion.
942: */
943: hold = oldhold;
944: tp = vtube0 + tabstart; up = tp + inssiz - doomed;
945: for (i = tabstart; i > inscol + doomed; i--)
946: *--up = *--tp;
947: for (i = inssiz; i > 0; i--)
948: *--up = c;
949: doomed = 0;
950: }
951:
952: /*
953: * Go into ``delete mode''. If the
954: * sequence which goes into delete mode
955: * is the same as that which goes into insert
956: * mode, then we are in delete mode already.
957: */
958: godm()
959: {
960:
961: if (insmode) {
962: if (eq(DM, IM))
963: return;
964: endim();
965: }
966: vputp(DM, 0);
967: }
968:
969: /*
970: * If we are coming out of delete mode, but
971: * delete and insert mode end with the same sequence,
972: * it wins to pretend we are now in insert mode,
973: * since we will likely want to be there again soon
974: * if we just moved over to delete space from part of
975: * a tab (above).
976: */
977: enddm()
978: {
979:
980: if (eq(DM, IM)) {
981: insmode = 1;
982: return;
983: }
984: vputp(ED, 0);
985: }
986:
987: /*
988: * In and out of insert mode.
989: * Note that the code here demands that there be
990: * a string for insert mode (the null string) even
991: * if the terminal does all insertions a single character
992: * at a time, since it branches based on whether IM is null.
993: */
994: goim()
995: {
996:
997: if (!insmode)
998: vputp(IM, 0);
999: insmode = 1;
1000: }
1001:
1002: endim()
1003: {
1004:
1005: if (insmode) {
1006: vputp(EI, 0);
1007: insmode = 0;
1008: }
1009: }
1010:
1011: /*
1012: * Put the character c on the screen at the current cursor position.
1013: * This routine handles wraparound and scrolling and understands not
1014: * to roll when splitw is set, i.e. we are working in the echo area.
1015: * There is a bunch of hacking here dealing with the difference between
1016: * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also
1017: * code to deal with terminals which overstrike, including CRT's where
1018: * you can erase overstrikes with some work. CRT's which do underlining
1019: * implicitly which has to be erased (like CONCEPTS) are also handled.
1020: */
1021: vputchar(c)
1022: register int c;
1023: {
1024: register char *tp;
1025: register int d;
1026:
1027: c &= (QUOTE|TRIM);
1028: #ifdef TRACE
1029: if (trace)
1030: tracec(c);
1031: #endif
1032: /* Patch to fix problem of >79 chars on echo line: don't echo extras */
1033: if (destcol >= WCOLS-1 && splitw && destline == WECHO)
1034: return;
1035: if (destcol >= WCOLS) {
1036: destline += destcol / WCOLS;
1037: destcol %= WCOLS;
1038: }
1039: if (destline > WBOT && (!splitw || destline > WECHO))
1040: vrollup(destline);
1041: tp = vtube[destline] + destcol;
1042: switch (c) {
1043:
1044: case '\t':
1045: vgotab();
1046: return;
1047:
1048: case ' ':
1049: /*
1050: * We can get away without printing a space in a number
1051: * of cases, but not always. We get away with doing nothing
1052: * if we are not in insert mode, and not on a CONCEPT-100
1053: * like terminal, and either not in hardcopy open or in hardcopy
1054: * open on a terminal with no overstriking, provided,
1055: * in all cases, that nothing has ever been displayed
1056: * at this position. Ugh.
1057: */
1058: if (!insmode && !IN && (state != HARDOPEN || OS) && (*tp&TRIM) == 0) {
1059: *tp = ' ';
1060: destcol++;
1061: return;
1062: }
1063: goto def;
1064:
1065: case QUOTE:
1066: if (insmode) {
1067: /*
1068: * When in insert mode, tabs have to expand
1069: * to real, printed blanks.
1070: */
1071: c = ' ' | QUOTE;
1072: goto def;
1073: }
1074: if (*tp == 0) {
1075: /*
1076: * A ``space''.
1077: */
1078: if ((hold & HOLDPUPD) == 0)
1079: *tp = QUOTE;
1080: destcol++;
1081: return;
1082: }
1083: /*
1084: * A ``space'' ontop of a part of a tab.
1085: */
1086: if (*tp & QUOTE) {
1087: destcol++;
1088: return;
1089: }
1090: c = ' ' | QUOTE;
1091: /* fall into ... */
1092:
1093: def:
1094: default:
1095: d = *tp & TRIM;
1096: /*
1097: * Now get away with doing nothing if the characters
1098: * are the same, provided we are not in insert mode
1099: * and if we are in hardopen, that the terminal has overstrike.
1100: */
1101: if (d == (c & TRIM) && !insmode && (state != HARDOPEN || OS)) {
1102: if ((hold & HOLDPUPD) == 0)
1103: *tp = c;
1104: destcol++;
1105: return;
1106: }
1107: /*
1108: * Backwards looking optimization.
1109: * The low level cursor motion routines will use
1110: * a cursor motion right sequence to step 1 character
1111: * right. On, e.g., a DM3025A this is 2 characters
1112: * and printing is noticeably slower at 300 baud.
1113: * Since the low level routines are not allowed to use
1114: * spaces for positioning, we discover the common
1115: * case of a single space here and force a space
1116: * to be printed.
1117: */
1118: if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) {
1119: vputc(' ');
1120: outcol++;
1121: }
1122:
1123: /*
1124: * This is an inline expansion a call to vcsync() dictated
1125: * by high frequency in a profile.
1126: */
1127: if (outcol != destcol || outline != destline)
1128: vgoto(destline, destcol);
1129:
1130: /*
1131: * Deal with terminals which have overstrike.
1132: * We handle erasing general overstrikes, erasing
1133: * underlines on terminals (such as CONCEPTS) which
1134: * do underlining correctly automatically (e.g. on nroff
1135: * output), and remembering, in hardcopy mode,
1136: * that we have overstruct something.
1137: */
1138: if (!insmode && d && d != ' ' && d != (c & TRIM)) {
1139: if (EO && (OS || UL && (c == '_' || d == '_'))) {
1140: vputc(' ');
1141: outcol++, destcol++;
1142: back1();
1143: } else
1144: rubble = 1;
1145: }
1146:
1147: /*
1148: * Unless we are just bashing characters around for
1149: * inner working of insert mode, update the display.
1150: */
1151: if ((hold & HOLDPUPD) == 0)
1152: *tp = c;
1153:
1154: /*
1155: * In insert mode, put out the IC sequence, padded
1156: * based on the depth of the current line.
1157: * A terminal which had no real insert mode, rather
1158: * opening a character position at a time could do this.
1159: * Actually should use depth to end of current line
1160: * but this rarely matters.
1161: */
1162: if (insmode)
1163: vputp(IC, DEPTH(vcline));
1164: vputc(c & TRIM);
1165:
1166: /*
1167: * In insert mode, IP is a post insert pad.
1168: */
1169: if (insmode)
1170: vputp(IP, DEPTH(vcline));
1171: destcol++, outcol++;
1172:
1173: /*
1174: * CONCEPT braindamage in early models: after a wraparound
1175: * the next newline is eaten. It's hungry so we just
1176: * feed it now rather than worrying about it.
1177: */
1178: if (XN && outcol % WCOLS == 0)
1179: vputc('\n');
1180: }
1181: }
1182:
1183: /*
1184: * Delete display positions stcol through endcol.
1185: * Amount of use of special terminal features here is limited.
1186: */
1187: physdc(stcol, endcol)
1188: int stcol, endcol;
1189: {
1190: register char *tp, *up;
1191: char *tpe;
1192: register int i;
1193: register int nc = endcol - stcol;
1194:
1195: #ifdef IDEBUG
1196: if (trace)
1197: tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol);
1198: #endif
1199: if (!DC || nc <= 0)
1200: return;
1201: if (IN) {
1202: /*
1203: * CONCEPT-100 like terminal.
1204: * If there are any ``spaces'' in the material to be
1205: * deleted, then this is too hard, just retype.
1206: */
1207: vprepins();
1208: up = vtube0 + stcol;
1209: i = nc;
1210: do
1211: if ((*up++ & (QUOTE|TRIM)) == QUOTE)
1212: return;
1213: while (--i);
1214: i = 2 * nc;
1215: do
1216: if (*up == 0 || (*up++ & QUOTE) == QUOTE)
1217: return;
1218: while (--i);
1219: vgotoCL(stcol);
1220: } else {
1221: /*
1222: * HP like delete mode.
1223: * Compute how much text we are moving over by deleting.
1224: * If it appears to be faster to just retype
1225: * the line, do nothing and that will be done later.
1226: * We are assuming 2 output characters per deleted
1227: * characters and that clear to end of line is available.
1228: */
1229: i = stcol / WCOLS;
1230: if (i != endcol / WCOLS)
1231: return;
1232: i += LINE(vcline);
1233: stcol %= WCOLS;
1234: endcol %= WCOLS;
1235: up = vtube[i]; tp = up + endcol; tpe = up + WCOLS;
1236: while (tp < tpe && *tp)
1237: tp++;
1238: if (tp - (up + stcol) < 2 * nc)
1239: return;
1240: vgoto(i, stcol);
1241: }
1242:
1243: /*
1244: * Go into delete mode and do the actual delete.
1245: * Padding is on DC itself.
1246: */
1247: godm();
1248: for (i = nc; i > 0; i--)
1249: vputp(DC, DEPTH(vcline));
1250: vputp(ED, 0);
1251:
1252: /*
1253: * Straighten up.
1254: * With CONCEPT like terminals, characters are pulled left
1255: * from first following null. HP like terminals shift rest of
1256: * this (single physical) line rigidly.
1257: */
1258: if (IN) {
1259: up = vtube0 + stcol;
1260: tp = vtube0 + endcol;
1261: while (i = *tp++) {
1262: if ((i & (QUOTE|TRIM)) == QUOTE)
1263: break;
1264: *up++ = i;
1265: }
1266: do
1267: *up++ = i;
1268: while (--nc);
1269: } else {
1270: copy(up + stcol, up + endcol, WCOLS - endcol);
1271: vclrbyte(tpe - nc, nc);
1272: }
1273: }
1274:
1275: #ifdef TRACE
1276: tfixnl()
1277: {
1278:
1279: if (trubble || techoin)
1280: fprintf(trace, "\n");
1281: trubble = 0, techoin = 0;
1282: }
1283:
1284: tvliny()
1285: {
1286: register int i;
1287:
1288: if (!trace)
1289: return;
1290: tfixnl();
1291: fprintf(trace, "vcnt = %d, vcline = %d, vliny = ", vcnt, vcline);
1292: for (i = 0; i <= vcnt; i++) {
1293: fprintf(trace, "%d", LINE(i));
1294: if (FLAGS(i) & VDIRT)
1295: fprintf(trace, "*");
1296: if (DEPTH(i) != 1)
1297: fprintf(trace, "<%d>", DEPTH(i));
1298: if (i < vcnt)
1299: fprintf(trace, " ");
1300: }
1301: fprintf(trace, "\n");
1302: }
1303:
1304: tracec(c)
1305: char c;
1306: {
1307:
1308: if (!techoin)
1309: trubble = 1;
1310: if (c == ESCAPE)
1311: fprintf(trace, "$");
1312: else if (c < ' ' || c == DELETE)
1313: fprintf(trace, "^%c", ctlof(c));
1314: else
1315: fprintf(trace, "%c", c);
1316: }
1317: #endif
1318:
1319: /*
1320: * Put a character with possible tracing.
1321: */
1322: vputch(c)
1323: int c;
1324: {
1325:
1326: #ifdef TRACE
1327: if (trace)
1328: tracec(c);
1329: #endif
1330: vputc(c);
1331: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.