/* * Clear to the end of the current physical line */ void vclreol(void) { register int i, j; register cell *tp; if (destcol == WCOLS) return; destline += destcol / WCOLS; destcol %= WCOLS; if (destline < 0 || destline > WECHO) error(catgets(catd, 1, 237, "Internal error: vclreol")); i = WCOLS - destcol; tp = vtube[destline] + destcol; if (CE) { if (IN && *tp || !ateopr()) { vcsync(); vputp(CE, 1); } vclrcell(tp, i); return; } if (*tp == 0) return; while (i > 0 && (j = *tp & (QUOTE|TRIM|MULTICOL))) { if ((j != ' ' && (j & QUOTE) == 0)) { destcol = WCOLS - i; vputchar(' '); } --i, *tp++ = 0; } }
/* * Scroll the screen up cnt lines physically. * If doclr is true, do a clear eol if the terminal * has standout (to prevent it from scrolling up) */ void vmoveitup(register int cnt, int doclr) { if (cnt == 0) return; #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vmoveitup(%d)\n", cnt); #endif if (doclr && (SO || SE)) vclrech(0); if (SF) { destline = WECHO; destcol = (NONL ? 0 : outcol % WCOLS); fgoto(); while (cnt > 0) vputp(SF, 0), cnt--; return; } destline = WECHO + cnt; destcol = (NONL ? 0 : outcol % WCOLS); fgoto(); if (state == ONEOPEN || state == HARDOPEN) { outline = destline = 0; vclrcell(vtube[0], WCOLS); } }
/* * 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. */ void vclrech(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) vclrcell(vtube[WECHO], WCOLS); heldech = 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. */ void goim(void) { if (!insmode) vputp(IM, 0); insmode = 1; }
/* * Rrrrringgggggg. * If possible, use flash (VB). */ void beep(void) { if (VB) vputp(VB, 0); else vputc(CTRL('g')); }
void endim(void) { if (insmode) { vputp(EI, 0); insmode = 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). */ void enddm(void) { if (eq(DM, IM)) { insmode = 1; return; } vputp(ED, 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. */ void godm(void) { if (insmode) { if (eq(DM, IM)) return; endim(); } vputp(DM, 0); }
/* * 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. */ void vneedpos(int npcnt) { register int d = DEPTH(vcline); register int rmdr = d * WCOLS - linend; /* * Delete the showmode string on wraparound to last line. Cannot use * vclrech() since the mode string is printed on the echo area, but * not actually a part of it. */ if (value(SHOWMODE) && (value(REDRAW) || (IM && EI)) && npcnt == rmdr - IN && LINE(vcline) + d == WECHO) { int sdc, sdl; char *ocurs; endim(); sdc = destcol, sdl = destline, ocurs = cursor; splitw++; vgoto(WECHO, 0); if (CD) { vputp(CD, 1); } else if (CE) { vputp(CE, 1); } else { int i; for (i = 1; i < WCOLS; i++) vputchar(' '); } destcol = sdc, destline = sdl; cursor = ocurs; splitw = 0; } if (npcnt <= rmdr - IN) return; endim(); vnpins(1); }
/* * Do the real work in deleting cnt lines starting at line p from * the display. First affected line is line l. */ void vdellin(int p, int cnt, int l) { register int i; if (cnt == 0) return; if (DL == NOSTR || cnt < 0) { /* * Can't do it; just remember that line l is munged. */ FLAGS(l) |= VDIRT; return; } #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l); #endif /* * Send the deletes to the screen and then adjust logical * and physical internal data structures. */ vgoto(p, 0); if (DL_PARM && (cnt>1 || *DL==0)) { vputp(tgoto(DL_PARM, p, cnt), WECHO-p); } else if (xCS && *DL==0) { /* vt100: fake DL by changing scrolling region */ vputp(SC, 1); /* Save since xCS homes stupid cursor */ vputp(tgoto(xCS, TLINES-1, p), 1); vputp(tgoto(CM, 0, TLINES-1), 1);/* Go to lower left corner */ for (i=0; i<cnt; i++) /* .. and scroll cnt times */ putch('\n'); /* should check NL too */ vputp(tgoto(xCS, TLINES-1, 0), 1);/* restore scrolling region */ vputp(RC, 1); /* put cursor back */ } else { for (i = 0; i < cnt; i++) vputp(DL, WECHO - p); } vadjDL(p, cnt); vcloseup(l, cnt); }
/* * Clear to the end of the current physical line */ void vclreol(void) { int i; wchar_t *tp, j; #ifdef TRACE if (trace) fprintf(trace, "vclreol(), destcol %d, ateopr() %d\n", destcol, ateopr()); #endif if (destcol == WCOLS) return; destline += destcol / WCOLS; destcol %= WCOLS; if (destline < 0 || destline > WECHO) error(gettext("Internal error: vclreol")); i = WCOLS - destcol; tp = vtube[destline] + destcol; if (clr_eol) { if (insert_null_glitch && *tp || !ateopr()) { vcsync(); vputp(clr_eol, 1); } vclrbyte(tp, i); return; } if (*tp == 0) return; while (i > 0 && (j = *tp & (QUOTE|TRIM))) { if (j != ' ' && (j & QUOTE) == 0) { destcol = WCOLS - i; (void) vputchar(' '); } --i, *tp++ = 0; } }
/* * Insert cnt blank lines before line p, * logically and (if supported) physically. */ void vinslin(register int p, register int cnt, int l) { register int i; bool could = 1; #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l); #endif if (p + cnt > WBOT && CD) { /* * Really quick -- clear to end of screen. */ cnt = WECHO + 1 - p; vgoto(p, 0), vputp(CD, cnt); vclrech(1); vadjAL(p, cnt); } else if (SR && p == WTOP && costSR < costAL) { /* * Use reverse scroll mode of the terminal, at * the top of the window. Reverse linefeed works * too, since we only use it from line WTOP. */ for (i = cnt; i > 0; i--) { vgoto(p, 0), vputp(SR, 0); if (i > 1 && (hold & HOLDAT) == 0) putchar('@'); /* * If we are at the top of the screen, and the * terminal retains display above, then we * should try to clear to end of line. * Have to use CE since we don't remember what is * actually on the line. */ if (CE && (DA || p != 0)) vputp(CE, 1); } vadjAL(p, cnt); } else if (AL) { /* * Use insert line. */ vgoto(p, 0); if (AL_PARM && (cnt>1 || *AL==0)) { /* insert cnt lines. Should do @'s too. */ vputp(tgoto(AL_PARM, p, cnt), WECHO+1-p); } else if (xCS && *AL==0) { /* vt100 change scrolling region to fake AL */ vputp(SC, 1); vputp(tgoto(xCS, TLINES-1,p), 1); vputp(RC, 1); /* xCS homes stupid cursor */ for (i=cnt; i>0; i--) vputp(SR, 1); /* should do @'s */ vputp(tgoto(xCS, TLINES-1,0), 1); vputp(RC, 1); /* Once again put it back */ } else { vputp(AL, WECHO + 1 - p); for (i = cnt - 1; i > 0; i--) { vgoto(outline+1, 0); vputp(AL, WECHO + 1 - outline); if ((hold & HOLDAT) == 0) putchar('@'); } } vadjAL(p, cnt); } else could = 0; vopenup(cnt, could, l); }
/* * Move cursor to line y, column x, handling wraparound and scrolling. */ void vgoto(register int y, register int x) { register cell *tp; register int c; /* * Fold the possibly too large value of x. */ if (x >= WCOLS) { y += x / WCOLS; x %= WCOLS; } #ifdef MB if (y >= 0 && y <= WLINES && mb_cur_max > 1 && !insmode) { while (x > 0 && (vtube[y][x]&(MULTICOL|TRIM)) == MULTICOL && vtube[y][x-1] & MULTICOL && (vtube[y][x-1]&(MULTICOL|TRIM)) != MULTICOL) x--; } #endif /* MB */ if (y < 0) error(catgets(catd, 1, 238, "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(catgets(catd, 1, 239, "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 = ' '; c = *tp++ & TRIM; 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(); } }
/* * Delete display positions stcol through endcol. * Amount of use of special terminal features here is limited. */ void physdc(int stcol, int endcol) { register cell *tp, *up; cell *tpe = NULL; 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) * sizeof *up); vclrcell(tpe - nc, nc); } }
/* * 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. */ int vputchar(register int c) { register cell *tp; register int d, m, n; #ifndef BIT8 c &= (QUOTE|TRIM); #endif #ifdef TRACE if (trace) tracec(c); #endif /* Fix problem of >79 chars on echo line. */ if (destcol >= WCOLS-1 && splitw && destline == WECHO) pofix(); #ifdef MB if (mb_cur_max > 1) { if (c == MULTICOL) return c; /* * If a multicolumn character extends beyond the screen * width, it must be put on the next line. A tilde is * printed as an indicator but must disappear when the * text is moved at a later time. */ if (c == ('~'|INVBIT|QUOTE)) c = '~'|INVBIT; else if (c == ('~'|INVBIT)) return c; else if (destcol < WCOLS && destcol + colsc(c==QUOTE ? ' ' : c&TRIM&~MULTICOL) - 1 >= WCOLS) vputchar('~'|INVBIT|QUOTE); } #endif /* MB */ if (destcol >= WCOLS) { destline += destcol / WCOLS; destcol %= WCOLS; } if (destline > WBOT && (!splitw || destline > WECHO)) vrollup(destline); tp = vtube[destline] + destcol; if (c == QUOTE) { if (insmode) { /* * When in insert mode, tabs have to expand * to real, printed blanks. */ c = ' ' | QUOTE; goto def; } if (*tp == 0) { /* * A ``space''. */ if ((hold & HOLDPUPD) == 0) *tp = QUOTE; destcol++; return c; } /* * A ``space'' ontop of a part of a tab. */ if (*tp & QUOTE) { destcol++; return c; } c = ' ' | QUOTE; goto def; } #ifdef notdef #ifdef BIT8 if (c == ' ' | QUOTE) { c = ' '; goto def; } #endif #endif switch (c) { case '\t': vgotab(); return c; 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) && (*tp"E)) { *tp = ' '; destcol++; return c; } goto def; def: default: d = *tp & TRIM; /* * 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. */ if ((d & ~MULTICOL) == (c & TRIM & ~MULTICOL) && !insmode && (state != HARDOPEN || OS) && c != MULTICOL) { n = colsc(d); for (m = 1; m < n; m++) if ((tp[m] & (MULTICOL|TRIM)) != MULTICOL) break; if (m == n) { if ((hold & HOLDPUPD) == 0) *tp = c | (n > 1 ? MULTICOL : 0); destcol += n; return c; } } /* * 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. */ if (!insmode && d && d != ' ' && d != (c & TRIM)) { 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. */ #ifdef notdef if (insmode) #else /* * It seems today's termcap writers consider this * an either-or situation; if both im and ic * are used vi puts out additional spaces. * * SVR4 ex does not include this change. If it hits * your terminal, change back to the old way and * mail me a description. * * GR July 2000 */ if (insmode && (!IM || !*IM)) #endif /* !notdef */ { n = colsc(c&TRIM); for (m = 0; m < n; m++) vputp(IC, DEPTH(vcline)); } vputc(c & TRIM); /* * 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'); } } #ifdef MB if (mb_cur_max > 1 && (d = colsc(c&TRIM&~MULTICOL)) > 1) { if ((hold & HOLDPUPD) == 0) *tp |= MULTICOL; while (--d) { if ((hold & HOLDPUPD) == 0) *++tp = MULTICOL; destcol++; outcol++; } } #endif /* MB */ return c; }
/* * Now do the insert of the characters (finally). */ void viin(int c) /* int c; /\* mjm: char --> int */ { register cell *tp, *up; 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 + insmc0 + 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 > insmc1) { remdoom--; endim(); } else if (noim || insmc1 && remdoom == insmc1) endim(); else if (IM && EI) { vcsync(); goim(); } vputchar(c); } if (!IM || !EI || remdoom && remdoom == insmc1) { /* * 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 + insmc0 - doomed); for (i = tabsize - (inssiz - insmc0 - doomed) + shft; i > 0; i--) vputchar(' ' | QUOTE); } 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 + insmc0 + inssiz - 1) / WCOLS + 1; j <= (tabstart + inssiz - doomed - 1) / WCOLS; j++) { vgotoCL(j * WCOLS); i = inssiz - doomed + insmc1; 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 + insmc1 - doomed); i >= 0; i--) { if ((*--tp & (QUOTE|TRIM)) == QUOTE) { --tabslack; if (tabslack >= slakused) continue; } *tp = ' ' | QUOTE; } } /* * Blank out the shifted positions to be tab positions. */ if (shft) { tp = vtube0 + tabend + shft; for (i = tabsize - (inssiz - doomed) + shft; i > 0; i--) if ((*--tp & QUOTE) == 0) *tp = ' ' | QUOTE; } } /* * Finally, complete the screen image update * to reflect the insertion. */ hold = oldhold; tp = vtube0 + tabstart; up = tp + insmc1 + inssiz - doomed; for (i = tabstart; i > inscol + doomed; i--) *--up = *--tp; #ifdef MB for (i = insmc1; i > 0; i--) *--up = MULTICOL; #endif for (i = inssiz; i > 0; i--) *--up = c | (insmc1 ? MULTICOL : 0); doomed = 0; }