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