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