/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #if !defined(lint) && defined(DOSCCS) static char *sccsid = "@(#)ex_vput.c 7.4.1 (2.11BSD GTE) 12/9/94"; #endif #include "ex.h" #include "ex_tty.h" #include "ex_vis.h" /* * Deal with the screen, clearing, cursor positioning, putting characters * into the screen image, and deleting characters. * Really hard stuff here is utilizing insert character operations * on intelligent terminals which differs widely from terminal to terminal. */ vclear() { #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "------\nvclear\n"); #endif tputs(CL, LINES, putch); destcol = 0; outcol = 0; destline = 0; outline = 0; if (inopen) vclrbyte(vtube0, WCOLS * (WECHO - ZERO + 1)); } /* * Clear memory. */ vclrbyte(cp, i) register char *cp; register int i; { if (i > 0) do *cp++ = 0; while (--i != 0); } /* * Clear a physical display line, high level. */ vclrlin(l, tp) int l; line *tp; { vigoto(l, 0); if ((hold & HOLDAT) == 0) putchar(tp > dol ? '~' : '@'); if (state == HARDOPEN) sethard(); vclreol(); } /* * Clear to the end of the current physical line */ vclreol() { register int i, j; #ifndef BIT8 register char *tp; #else register short *tp; #endif if (destcol == WCOLS) return; destline += destcol / WCOLS; destcol %= WCOLS; if (destline < 0 || destline > WECHO) error("Internal error: vclreol"); i = WCOLS - destcol; tp = vtube[destline] + destcol; if (CE) { if (IN && *tp || !ateopr()) { vcsync(); vputp(CE, 1); } vclrbyte(tp, i); return; } if (*tp == 0) return; while (i > 0 && (j = *tp & (QUOTE|TRIM))) { if ((j != ' ' && (j & QUOTE) == 0) #ifdef ISO || (j & QUOTE && !niso(j)) #endif ) { destcol = WCOLS - i; vputchar(' '); } --i, *tp++ = 0; } } /* * Clear the echo line. * If didphys then its been cleared physically (as * a side effect of a clear to end of display, e.g.) * so just do it logically. * If work here is being held off, just remember, in * heldech, if work needs to be done, don't do anything. */ vclrech(didphys) bool didphys; { if (Peekkey == ATTN) return; if (hold & HOLDECH) { heldech = !didphys; return; } if (!didphys && (CD || CE)) { splitw++; /* * If display is retained below, then MUST use CD or CE * since we don't really know whats out there. * Vigoto might decide (incorrectly) to do nothing. */ if (DB) { vgoto(WECHO, 0); vputp(CD ? CD : CE, 1); } else { if (XT) { /* * This code basically handles the t1061 * where positioning at (0, 0) won't work * because the terminal won't let you put * the cursor on it's magic cookie. * * Should probably be XS above, or even a * new X? glitch, but right now t1061 is the * only terminal with XT. */ vgoto(WECHO, 0); vputp(DL, 1); } else { vigoto(WECHO, 0); vclreol(); } } splitw = 0; didphys = 1; } if (didphys) vclrbyte(vtube[WECHO], WCOLS); heldech = 0; } /* * Fix the echo area for use, setting * the state variable splitw so we wont rollup * when we move the cursor there. */ fixech() { splitw++; if (state != VISUAL && state != CRTOPEN) { vclean(); vcnt = 0; } vgoto(WECHO, 0); flusho(); } /* * Put the cursor ``before'' cp. */ vcursbef(cp) register char *cp; { if (cp <= linebuf) vgotoCL(value(NUMBER) << 3); else vgotoCL(column(cp - 1) - 1); } /* * Put the cursor ``at'' cp. */ vcursat(cp) register char *cp; { if (cp <= linebuf && linebuf[0] == 0) vgotoCL(value(NUMBER) << 3); else vgotoCL(column(cp - 1)); } /* * Put the cursor ``after'' cp. */ vcursaft(cp) register char *cp; { vgotoCL(column(cp)); } /* * Fix the cursor to be positioned in the correct place * to accept a command. */ vfixcurs() { vsetcurs(cursor); } /* * Compute the column position implied by the cursor at ``nc'', * and move the cursor there. */ vsetcurs(nc) register char *nc; { register int col; col = column(nc); if (linebuf[0]) col--; vgotoCL(col); cursor = nc; } /* * Move the cursor invisibly, i.e. only remember to do it. */ vigoto(y, x) int y, x; { destline = y; destcol = x; } /* * Move the cursor to the position implied by any previous * vigoto (or low level hacking with destcol/destline as in readecho). */ vcsync() { vgoto(destline, destcol); } /* * Goto column x of the current line. */ vgotoCL(x) register int x; { if (splitw) vgoto(WECHO, x); else vgoto(LINE(vcline), x); } /* * Invisible goto column x of current line. */ vigotoCL(x) register int x; { if (splitw) vigoto(WECHO, x); else vigoto(LINE(vcline), x); } /* * Move cursor to line y, column x, handling wraparound and scrolling. */ vgoto(y, x) register int y, x; { #ifndef BIT8 register char *tp; #else register short *tp; #endif register int c; /* * Fold the possibly too large value of x. */ if (x >= WCOLS) { y += x / WCOLS; x %= WCOLS; } if (y < 0) error("Internal error: vgoto"); if (outcol >= WCOLS) { if (AM) { outline += outcol / WCOLS; outcol %= WCOLS; } else outcol = WCOLS - 1; } /* * In a hardcopy or glass crt open, print the stuff * implied by a motion, or backspace. */ if (state == HARDOPEN || state == ONEOPEN) { if (y != outline) error("Line too long for open"); if (x + 1 < outcol - x || (outcol > x && !BS)) destcol = 0, fgoto(); tp = vtube[WBOT] + outcol; while (outcol != x) if (outcol < x) { if (*tp == 0) *tp = ' '; #ifndef ISO c = *tp++ & TRIM; #else if (niso(*tp)) c = *tp++ & TRIM; else c = *tp++; #endif vputc(c && (!OS || EO) ? c : ' '), outcol++; } else { if (BC) vputp(BC, 0); else vputc('\b'); outcol--; } destcol = outcol = x; destline = outline; return; } /* * If the destination position implies a scroll, do it. */ destline = y; if (destline > WBOT && (!splitw || destline > WECHO)) { endim(); vrollup(destline); } /* * If there really is a motion involved, do it. * The check here is an optimization based on profiling. */ destcol = x; if ((destline - outline) * WCOLS != destcol - outcol) { if (!MI) endim(); fgoto(); } } /* * This is the hardest code in the editor, and deals with insert modes * on different kinds of intelligent terminals. The complexity is due * to the cross product of three factors: * * 1. Lines may display as more than one segment on the screen. * 2. There are 2 kinds of intelligent terminal insert modes. * 3. Tabs squash when you insert characters in front of them, * in a way in which current intelligent terminals don't handle. * * The two kinds of terminals are typified by the DM2500 or HP2645 for * one and the CONCEPT-100 or the FOX for the other. * * The first (HP2645) kind has an insert mode where the characters * fall off the end of the line and the screen is shifted rigidly * no matter how the display came about. * * The second (CONCEPT-100) kind comes from terminals which are designed * for forms editing and which distinguish between blanks and ``spaces'' * on the screen, spaces being like blank, but never having had * and data typed into that screen position (since, e.g. a clear operation * like clear screen). On these terminals, when you insert a character, * the characters from where you are to the end of the screen shift * over till a ``space'' is found, and the null character there gets * eaten up. * * * The code here considers the line as consisting of several parts * the first part is the ``doomed'' part, i.e. a part of the line * which is being typed over. Next comes some text up to the first * following tab. The tab is the next segment of the line, and finally * text after the tab. * * We have to consider each of these segments and the effect of the * insertion of a character on them. On terminals like HP2645's we * must simulate a multi-line insert mode using the primitive one * line insert mode. If we are inserting in front of a tab, we have * to either delete characters from the tab or insert white space * (when the tab reaches a new spot where it gets larger) before we * insert the new character. * * On a terminal like a CONCEPT our strategy is to make all * blanks be displayed, while trying to keep the screen having ``spaces'' * for portions of tabs. In this way the terminal hardward does some * of the hacking for compression of tabs, although this tends to * disappear as you work on the line and spaces change into blanks. * * There are a number of boundary conditions (like typing just before * the first following tab) where we can avoid a lot of work. Most * of them have to be dealt with explicitly because performance is * much, much worse if we don't. * * A final thing which is hacked here is two flavors of insert mode. * Datamedia's do this by an insert mode which you enter and leave * and by having normal motion character operate differently in this * mode, notably by having a newline insert a line on the screen in * this mode. This generally means it is unsafe to move around * the screen ignoring the fact that we are in this mode. * This is possible on some terminals, and wins big (e.g. HP), so * we encode this as a ``can move in insert capability'' mi, * and terminals which have it can do insert mode with much less * work when tabs are present following the cursor on the current line. */ /* * Routine to expand a tab, calling the normal Outchar routine * to put out each implied character. Note that we call outchar * with a QUOTE. We use QUOTE internally to represent a position * which is part of the expansion of a tab. */ vgotab() { register int i = tabcol(destcol, value(TABSTOP)) - destcol; do (*Outchar)(QUOTE); while (--i); } /* * Variables for insert mode. */ int linend; /* The column position of end of line */ int tabstart; /* Column of start of first following tab */ int tabend; /* Column of end of following tabs */ int tabsize; /* Size of the following tabs */ int tabslack; /* Number of ``spaces'' in following tabs */ int inssiz; /* Number of characters to be inserted */ int inscol; /* Column where insertion is taking place */ int shft; /* Amount tab expansion shifted rest of line */ int slakused; /* This much of tabslack will be used up */ /* * This routine MUST be called before insert mode is run, * and brings all segments of the current line to the top * of the screen image buffer so it is easier for us to * maniuplate them. */ vprepins() { register int i; #ifndef BIT8 register char *cp = vtube0; #else register short *cp = vtube0; #endif for (i = 0; i < DEPTH(vcline); i++) { vmaktop(LINE(vcline) + i, cp); cp += WCOLS; } } vmaktop(p, cp) register int p; #ifndef BIT8 char *cp; #else short *cp; #endif { register int i; char temp[TUBECOLS]; if (p < 0 || vtube[p] == cp) return; for (i = ZERO; i <= WECHO; i++) if (vtube[i] == cp) { copy(temp, vtube[i], WCOLS); copy(vtube[i], vtube[p], WCOLS); copy(vtube[p], temp, WCOLS); vtube[i] = vtube[p]; vtube[p] = cp; return; } error("Line too long"); } /* * Insert character c at current cursor position. * Multi-character inserts occur only as a result * of expansion of tabs (i.e. inssize == 1 except * for tabs) and code assumes this in several place * to make life simpler. */ vinschar(c) int c; /* mjm: char --> int */ { register int i; #ifndef BIT8 register char *tp; #else register short *tp; #endif if ((!IM || !EI) && ((hold & HOLDQIK) || !value(REDRAW) || value(SLOWOPEN))) { /* * Don't want to try to use terminal * insert mode, or to try to fake it. * Just put the character out; the screen * will probably be wrong but we will fix it later. */ if (c == '\t') { vgotab(); return; } vputchar(c); if (DEPTH(vcline) * WCOLS + !value(REDRAW) > (destline - LINE(vcline)) * WCOLS + destcol) return; /* * The next line is about to be clobbered * make space for another segment of this line * (on an intelligent terminal) or just remember * that next line was clobbered (on a dumb one * if we don't care to redraw the tail. */ if (AL) { vnpins(0); } else { c = LINE(vcline) + DEPTH(vcline); if (c < LINE(vcline + 1) || c > WBOT) return; i = destcol; vinslin(c, 1, vcline); DEPTH(vcline)++; vigoto(c, i); vprepins(); } return; } /* * Compute the number of positions in the line image of the * current line. This is done from the physical image * since that is faster. Note that we have no memory * from insertion to insertion so that routines which use * us don't have to worry about moving the cursor around. */ if (*vtube0 == 0) linend = 0; else { /* * Search backwards for a non-null character * from the end of the displayed line. */ i = WCOLS * DEPTH(vcline); if (i == 0) i = WCOLS; tp = vtube0 + i; while (*--tp == 0) if (--i == 0) break; linend = i; } /* * We insert at a position based on the physical location * of the output cursor. */ inscol = destcol + (destline - LINE(vcline)) * WCOLS; if (c == '\t') { /* * Characters inserted from a tab must be * remembered as being part of a tab, but we can't * use QUOTE here since we really need to print blanks. * QUOTE|' ' is the representation of this. */ inssiz = tabcol(inscol, value(TABSTOP)) - inscol; #ifdef ISO c = '\a' | QUOTE; #else c = ' ' | QUOTE; #endif } else inssiz = 1; /* * If the text to be inserted is less than the number * of doomed positions, then we don't need insert mode, * rather we can just typeover. */ if (inssiz <= doomed) { endim(); if (inscol != linend) doomed -= inssiz; do vputchar(c); while (--inssiz); return; } /* * Have to really do some insertion, thus * stake out the bounds of the first following * group of tabs, computing starting position, * ending position, and the number of ``spaces'' therein * so we can tell how much it will squish. */ tp = vtube0 + inscol; for (i = inscol; i < linend; i++) #ifndef ISO if (*tp++ & QUOTE) { #else if (niso(*tp++)) { #endif --tp; break; } tabstart = tabend = i; tabslack = 0; while (tabend < linend) { i = *tp++; if ((i & QUOTE) == 0) break; #ifdef ISO if (!niso(i)) break; #endif if ((i & TRIM) == 0) tabslack++; tabsize++; tabend++; } tabsize = tabend - tabstart; /* * For HP's and DM's, e.g. tabslack has no meaning. */ if (!IN) tabslack = 0; #ifdef IDEBUG if (trace) { fprintf(trace, "inscol %d, inssiz %d, tabstart %d, ", inscol, inssiz, tabstart); fprintf(trace, "tabend %d, tabslack %d, linend %d\n", tabend, tabslack, linend); } #endif /* * The real work begins. */ slakused = 0; shft = 0; if (tabsize) { /* * There are tabs on this line. * If they need to expand, then the rest of the line * will have to be shifted over. In this case, * we will need to make sure there are no ``spaces'' * in the rest of the line (on e.g. CONCEPT-100) * and then grab another segment on the screen if this * line is now deeper. We then do the shift * implied by the insertion. */ if (inssiz >= doomed + tabcol(tabstart, value(TABSTOP)) - tabstart) { if (IN) vrigid(); vneedpos(value(TABSTOP)); vishft(); } } else if (inssiz > doomed) /* * No tabs, but line may still get deeper. */ vneedpos(inssiz - doomed); /* * Now put in the inserted characters. */ viin(c); /* * Now put the cursor in its final resting place. */ destline = LINE(vcline); destcol = inscol + inssiz; vcsync(); } /* * Rigidify the rest of the line after the first * group of following tabs, typing blanks over ``spaces''. */ vrigid() { register int col; #ifndef BIT8 register char *tp = vtube0 + tabend; #else register short *tp = vtube0 + tabend; #endif #ifdef ISO char e; #endif for (col = tabend; col < linend; col++) { #ifndef ISO if ((*tp++ & TRIM) == 0) { #else e = *tp++; if ((e & TRIM) == 0 && niso(e)) { #endif endim(); vgotoCL(col); #ifdef ISO vputchar('\a' | QUOTE); #else vputchar(' ' | QUOTE); #endif } } } /* * We need cnt more positions on this line. * Open up new space on the screen (this may in fact be a * screen rollup). * * On a dumb terminal we may infact redisplay the rest of the * screen here brute force to keep it pretty. */ vneedpos(cnt) int cnt; { register int d = DEPTH(vcline); register int rmdr = d * WCOLS - linend; if (cnt <= rmdr - IN) return; endim(); vnpins(1); } vnpins(dosync) int dosync; { register int d = DEPTH(vcline); register int e; e = LINE(vcline) + DEPTH(vcline); if (e < LINE(vcline + 1)) { vigoto(e, 0); vclreol(); return; } DEPTH(vcline)++; if (e < WECHO) { e = vglitchup(vcline, d); vigoto(e, 0); vclreol(); if (dosync) { int (*Ooutchar)() = Outchar; Outchar = vputchar; vsync(e + 1); Outchar = Ooutchar; } } else { vup1(); vigoto(WBOT, 0); vclreol(); } vprepins(); } /* * Do the shift of the next tabstop implied by * insertion so it expands. */ vishft() { int tshft = 0; int j; register int i; #ifndef BIT8 register char *tp = vtube0; register char *up; #else register short *tp = vtube0; register short *up; #endif short oldhold = hold; shft = value(TABSTOP); hold |= HOLDPUPD; if (!IM && !EI) { /* * Dumb terminals are easy, we just have * to retype the text. */ vigotoCL(tabend + shft); up = tp + tabend; for (i = tabend; i < linend; i++) vputchar(*up++); } else if (IN) { /* * CONCEPT-like terminals do most of the work for us, * we don't have to muck with simulation of multi-line * insert mode. Some of the shifting may come for free * also if the tabs don't have enough slack to take up * all the inserted characters. */ i = shft; slakused = inssiz - doomed; if (slakused > tabslack) { i -= slakused - tabslack; slakused -= tabslack; } if (i > 0 && tabend != linend) { tshft = i; vgotoCL(tabend); goim(); do #ifdef ISO vputchar('\a' | QUOTE); #else vputchar(' ' | QUOTE); #endif while (--i); } } else { /* * HP and Datamedia type terminals have to have multi-line * insert faked. Hack each segment after where we are * (going backwards to where we are.) We then can * hack the segment where the end of the first following * tab group is. */ for (j = DEPTH(vcline) - 1; j > (tabend + shft) / WCOLS; j--) { vgotoCL(j * WCOLS); goim(); up = tp + j * WCOLS - shft; i = shft; do { if (*up) vputchar(*up++); else break; } while (--i); } vigotoCL(tabstart); i = shft - (inssiz - doomed); if (i > 0) { tabslack = inssiz - doomed; vcsync(); goim(); do vputchar(' '); while (--i); } } /* * Now do the data moving in the internal screen * image which is common to all three cases. */ tp += linend; up = tp + shft; i = linend - tabend; if (i > 0) do *--up = *--tp; while (--i); if (IN && tshft) { i = tshft; do #ifdef ISO *--up = '\a' | QUOTE; #else *--up = ' ' | QUOTE; #endif while (--i); } hold = oldhold; } /* * Now do the insert of the characters (finally). */ viin(c) int c; /* mjm: char --> int */ { #ifndef BIT8 register char *tp, *up; #else register short *tp, *up; #endif register int i, j; register bool noim = 0; int remdoom; short oldhold = hold; hold |= HOLDPUPD; if (tabsize && (IM && EI) && inssiz - doomed > tabslack) /* * There is a tab out there which will be affected * by the insertion since there aren't enough doomed * characters to take up all the insertion and we do * have insert mode capability. */ if (inscol + doomed == tabstart) { /* * The end of the doomed characters sits right at the * start of the tabs, then we don't need to use insert * mode; unless the tab has already been expanded * in which case we MUST use insert mode. */ slakused = 0; noim = !shft; } else { /* * The last really special case to handle is case * where the tab is just sitting there and doesn't * have enough slack to let the insertion take * place without shifting the rest of the line * over. In this case we have to go out and * delete some characters of the tab before we start * or the answer will be wrong, as the rest of the * line will have been shifted. This code means * that terminals with only insert chracter (no * delete character) won't work correctly. */ i = inssiz - doomed - tabslack - slakused; i %= value(TABSTOP); if (i > 0) { vgotoCL(tabstart); godm(); for (i = inssiz - doomed - tabslack; i > 0; i--) vputp(DC, DEPTH(vcline)); enddm(); } } /* * Now put out the characters of the actual insertion. */ vigotoCL(inscol); remdoom = doomed; for (i = inssiz; i > 0; i--) { if (remdoom > 0) { remdoom--; endim(); } else if (noim) endim(); else if (IM && EI) { vcsync(); goim(); } vputchar(c); } #ifndef BIT8 if (!IM || !EI) { #endif /* * We are a dumb terminal; brute force update * the rest of the line; this is very much an n^^2 process, * and totally unreasonable at low speed. * * You asked for it, you get it. */ tp = vtube0 + inscol + doomed; for (i = inscol + doomed; i < tabstart; i++) vputchar(*tp++); hold = oldhold; vigotoCL(tabstart + inssiz - doomed); for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--) #ifdef ISO vputchar('\a' | QUOTE); #else vputchar(' ' | QUOTE); #endif #ifndef BIT8 } else { if (!IN) { /* * On terminals without multi-line * insert in the hardware, we must go fix the segments * between the inserted text and the following * tabs, if they are on different lines. * * Aaargh. */ tp = vtube0; for (j = (inscol + inssiz - 1) / WCOLS + 1; j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) { vgotoCL(j * WCOLS); i = inssiz - doomed; up = tp + j * WCOLS - i; goim(); do vputchar(*up++); while (--i && *up); } } else { /* * On terminals with multi line inserts, * life is simpler, just reflect eating of * the slack. */ tp = vtube0 + tabend; for (i = tabsize - (inssiz - doomed); i >= 0; i--) { if ((*--tp & (QUOTE|TRIM)) == QUOTE) { --tabslack; if (tabslack >= slakused) continue; } #ifdef ISO *tp = '\a' | QUOTE; #else *tp = ' ' | QUOTE; #endif } } /* * Blank out the shifted positions to be tab positions. */ if (shft) { tp = vtube0 + tabend + shft; for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--) #ifdef ISO { tp--; if (*tp & QUOTE == 0 || !niso(*tp)) *tp = '\a' | QUOTE; } #else if ((*--tp & QUOTE) == 0) *tp = ' ' | QUOTE; #endif } } #endif /* !BIT8 */ /* * Finally, complete the screen image update * to reflect the insertion. */ hold = oldhold; tp = vtube0 + tabstart; up = tp + inssiz - doomed; for (i = tabstart; i > inscol + doomed; i--) *--up = *--tp; for (i = inssiz; i > 0; i--) *--up = c; doomed = 0; } /* * Go into ``delete mode''. If the * sequence which goes into delete mode * is the same as that which goes into insert * mode, then we are in delete mode already. */ godm() { if (insmode) { if (eq(DM, IM)) return; endim(); } vputp(DM, 0); } /* * If we are coming out of delete mode, but * delete and insert mode end with the same sequence, * it wins to pretend we are now in insert mode, * since we will likely want to be there again soon * if we just moved over to delete space from part of * a tab (above). */ enddm() { if (eq(DM, IM)) { insmode = 1; return; } vputp(ED, 0); } /* * In and out of insert mode. * Note that the code here demands that there be * a string for insert mode (the null string) even * if the terminal does all insertions a single character * at a time, since it branches based on whether IM is null. */ goim() { if (!insmode) vputp(IM, 0); insmode = 1; } endim() { if (insmode) { vputp(EI, 0); insmode = 0; } } /* * Put the character c on the screen at the current cursor position. * This routine handles wraparound and scrolling and understands not * to roll when splitw is set, i.e. we are working in the echo area. * There is a bunch of hacking here dealing with the difference between * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also * code to deal with terminals which overstrike, including CRT's where * you can erase overstrikes with some work. CRT's which do underlining * implicitly which has to be erased (like CONCEPTS) are also handled. */ vputchar(c) register int c; { #ifndef BIT8 register char *tp; #else register short *tp; #endif register int d; #ifdef ISO int e; #endif c &= (QUOTE|TRIM); #ifdef TRACE if (trace) tracec(c); #endif /* Fix problem of >79 chars on echo line. */ if (destcol >= WCOLS-1 && splitw && destline == WECHO) pofix(); if (destcol >= WCOLS) { destline += destcol / WCOLS; destcol %= WCOLS; } if (destline > WBOT && (!splitw || destline > WECHO)) vrollup(destline); tp = vtube[destline] + destcol; switch (c) { case '\t': vgotab(); return; case ' ': /* * We can get away without printing a space in a number * of cases, but not always. We get away with doing nothing * if we are not in insert mode, and not on a CONCEPT-100 * like terminal, and either not in hardcopy open or in hardcopy * open on a terminal with no overstriking, provided, * in all cases, that nothing has ever been displayed * at this position. Ugh. */ if (!insmode && !IN && (state != HARDOPEN || OS) #ifndef ISO && (*tp&TRIM) == 0 #else && (*tp & TRIM == 0) && (!niso(c)) #endif ) { *tp = ' '; destcol++; return; } goto def; #ifdef ISO case '\a' | QUOTE: c = ' '; goto def; #endif case QUOTE: if (insmode) { /* * When in insert mode, tabs have to expand * to real, printed blanks. */ #ifndef ISO c = ' ' | QUOTE; #else c = ' '; #endif goto def; } if (*tp == 0) { /* * A ``space''. */ if ((hold & HOLDPUPD) == 0) *tp = QUOTE; destcol++; return; } /* * A ``space'' ontop of a part of a tab. */ #ifndef ISO if (*tp & QUOTE) { #else if (niso(*tp)) { #endif destcol++; return; } #ifndef ISO c = ' ' | QUOTE; #else c = ' '; #endif /* fall into ... */ def: default: #ifndef ISO d = *tp & TRIM; #else if (niso(*tp)) d = *tp & TRIM; else d = *tp; #endif /* * Now get away with doing nothing if the characters * are the same, provided we are not in insert mode * and if we are in hardopen, that the terminal has overstrike. */ #ifndef ISO if (d == (c & TRIM) && !insmode && (state != HARDOPEN || OS)) { #else if (niso(c)) e = c & TRIM; else e = c; if (d == e && !insmode && (state != HARDOPEN || OS)) { #endif if ((hold & HOLDPUPD) == 0) *tp = c; destcol++; return; } /* * Backwards looking optimization. * The low level cursor motion routines will use * a cursor motion right sequence to step 1 character * right. On, e.g., a DM3025A this is 2 characters * and printing is noticeably slower at 300 baud. * Since the low level routines are not allowed to use * spaces for positioning, we discover the common * case of a single space here and force a space * to be printed. */ if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) { vputc(' '); outcol++; } /* * This is an inline expansion a call to vcsync() dictated * by high frequency in a profile. */ if (outcol != destcol || outline != destline) vgoto(destline, destcol); /* * Deal with terminals which have overstrike. * We handle erasing general overstrikes, erasing * underlines on terminals (such as CONCEPTS) which * do underlining correctly automatically (e.g. on nroff * output), and remembering, in hardcopy mode, * that we have overstruct something. */ #ifndef ISO if (!insmode && d && d != ' ' && d != (c & TRIM)) { #else if (niso(c)) e = c & TRIM; else e = c; if (!insmode && d && d != ' ' && d != e) { #endif if (EO && (OS || UL && (c == '_' || d == '_'))) { vputc(' '); outcol++, destcol++; back1(); } else rubble = 1; } /* * Unless we are just bashing characters around for * inner working of insert mode, update the display. */ if ((hold & HOLDPUPD) == 0) *tp = c; /* * In insert mode, put out the IC sequence, padded * based on the depth of the current line. * A terminal which had no real insert mode, rather * opening a character position at a time could do this. * Actually should use depth to end of current line * but this rarely matters. */ if (insmode) vputp(IC, DEPTH(vcline)); #ifndef ISO vputc(c & TRIM); #else if (niso(c)) vputc(c & TRIM); else vputc(c); #endif /* * In insert mode, IP is a post insert pad. */ if (insmode) vputp(IP, DEPTH(vcline)); destcol++, outcol++; /* * CONCEPT braindamage in early models: after a wraparound * the next newline is eaten. It's hungry so we just * feed it now rather than worrying about it. * Fixed to use return linefeed to work right * on vt100/tab132 as well as concept. */ if (XN && outcol % WCOLS == 0) { vputc('\r'); vputc('\n'); } } } /* * Delete display positions stcol through endcol. * Amount of use of special terminal features here is limited. */ physdc(stcol, endcol) int stcol, endcol; { #ifndef BIT8 register char *tp, *up; char *tpe; #else register short *tp, *up; short *tpe; #endif register int i; register int nc = endcol - stcol; #ifdef IDEBUG if (trace) tfixnl(), fprintf(trace, "physdc(%d, %d)\n", stcol, endcol); #endif if (!DC || nc <= 0) return; if (IN) { /* * CONCEPT-100 like terminal. * If there are any ``spaces'' in the material to be * deleted, then this is too hard, just retype. */ vprepins(); up = vtube0 + stcol; i = nc; do if ((*up++ & (QUOTE|TRIM)) == QUOTE) return; while (--i); i = 2 * nc; do if (*up == 0 || (*up++ & QUOTE) == QUOTE) return; while (--i); vgotoCL(stcol); } else { /* * HP like delete mode. * Compute how much text we are moving over by deleting. * If it appears to be faster to just retype * the line, do nothing and that will be done later. * We are assuming 2 output characters per deleted * characters and that clear to end of line is available. */ i = stcol / WCOLS; if (i != endcol / WCOLS) return; i += LINE(vcline); stcol %= WCOLS; endcol %= WCOLS; up = vtube[i]; tp = up + endcol; tpe = up + WCOLS; while (tp < tpe && *tp) tp++; if (tp - (up + stcol) < 2 * nc) return; vgoto(i, stcol); } /* * Go into delete mode and do the actual delete. * Padding is on DC itself. */ godm(); for (i = nc; i > 0; i--) vputp(DC, DEPTH(vcline)); vputp(ED, 0); /* * Straighten up. * With CONCEPT like terminals, characters are pulled left * from first following null. HP like terminals shift rest of * this (single physical) line rigidly. */ if (IN) { up = vtube0 + stcol; tp = vtube0 + endcol; while (i = *tp++) { if ((i & (QUOTE|TRIM)) == QUOTE) break; *up++ = i; } do *up++ = i; while (--nc); } else { copy(up + stcol, up + endcol, WCOLS - endcol); vclrbyte(tpe - nc, nc); } } #ifdef TRACE tfixnl() { if (trubble || techoin) fprintf(trace, "\n"); trubble = 0, techoin = 0; } tvliny() { register int i; if (!trace) return; tfixnl(); fprintf(trace, "vcnt = %d, vcline = %d, vliny = ", vcnt, vcline); for (i = 0; i <= vcnt; i++) { fprintf(trace, "%d", LINE(i)); if (FLAGS(i) & VDIRT) fprintf(trace, "*"); if (DEPTH(i) != 1) fprintf(trace, "<%d>", DEPTH(i)); if (i < vcnt) fprintf(trace, " "); } fprintf(trace, "\n"); } tracec(c) int c; /* mjm: char --> int */ { if (!techoin) trubble = 1; if (c == ESCAPE) fprintf(trace, "$"); else if (c & QUOTE) /* mjm: for 3B (no sign extension) */ #ifndef ISO fprintf(trace, "~%c", ctlof(c&TRIM)); #else { if (niso(c)) fprintf(trace, "~%c", ctlof(c&TRIM)); else fprintf(trace, "~%c", ctlof(c)); } #endif else if (c < ' ' || c == DELETE) fprintf(trace, "^%c", ctlof(c)); else fprintf(trace, "%c", c); } #endif /* * Put a character with possible tracing. */ vputch(c) int c; { #ifdef TRACE if (trace) tracec(c); #endif vputc(c); }