From e45f2c96f7829df1cb6efdf87c32d506e385791b Mon Sep 17 00:00:00 2001 From: Mark Horton Date: Fri, 1 Aug 1980 06:00:18 -0800 Subject: [PATCH] date and time created 80/07/31 23:00:18 by mark SCCS-vsn: usr.bin/ex/ex_put.c 1.1 --- usr/src/usr.bin/ex/ex_put.c | 888 ++++++++++++++++++++++++++++++++++++ 1 file changed, 888 insertions(+) create mode 100644 usr/src/usr.bin/ex/ex_put.c diff --git a/usr/src/usr.bin/ex/ex_put.c b/usr/src/usr.bin/ex/ex_put.c new file mode 100644 index 0000000000..c184d883e5 --- /dev/null +++ b/usr/src/usr.bin/ex/ex_put.c @@ -0,0 +1,888 @@ +/* Copyright (c) 1979 Regents of the University of California */ +#include "ex.h" +#include "ex_tty.h" +#include "ex_vis.h" + +/* + * Terminal driving and line formatting routines. + * Basic motion optimizations are done here as well + * as formatting of lines (printing of control characters, + * line numbering and the like). + */ + +/* + * The routines outchar, putchar and pline are actually + * variables, and these variables point at the current definitions + * of the routines. See the routine setflav. + * We sometimes make outchar be routines which catch the characters + * to be printed, e.g. if we want to see how long a line is. + * During open/visual, outchar and putchar will be set to + * routines in the file ex_vput.c (vputchar, vinschar, etc.). + */ +int (*Outchar)() = termchar; +int (*Putchar)() = normchar; +int (*Pline)() = normline; + +int (* +setlist(t))() + bool t; +{ + register int (*P)(); + + listf = t; + P = Putchar; + Putchar = t ? listchar : normchar; + return (P); +} + +int (* +setnumb(t))() + bool t; +{ + register int (*P)(); + + numberf = t; + P = Pline; + Pline = t ? numbline : normline; + return (P); +} + +/* + * Format c for list mode; leave things in common + * with normal print mode to be done by normchar. + */ +listchar(c) + register short c; +{ + + c &= (TRIM|QUOTE); + switch (c) { + + case '\t': + case '\b': + outchar('^'); + c = ctlof(c); + break; + + case '\n': + break; + + case '\n' | QUOTE: + outchar('$'); + break; + + default: + if (c & QUOTE) + break; + if (c < ' ' && c != '\n' || c == DELETE) + outchar('^'), c = ctlof(c); + break; + } + normchar(c); +} + +/* + * Format c for printing. Handle funnies of upper case terminals + * and crocky hazeltines which don't have ~. + */ +normchar(c) + register short c; +{ + register char *colp; + + c &= (TRIM|QUOTE); + if (c == '~' && HZ) { + normchar('\\'); + c = '^'; + } + if (c & QUOTE) + switch (c) { + + case ' ' | QUOTE: + case '\b' | QUOTE: + break; + + case QUOTE: + return; + + default: + c &= TRIM; + } + else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t' || c == DELETE) + putchar('^'), c = ctlof(c); + else if (UPPERCASE) + if (isupper(c)) { + outchar('\\'); + c = tolower(c); + } else { + colp = "({)}!|^~'`"; + while (*colp++) + if (c == *colp++) { + outchar('\\'); + c = colp[-2]; + break; + } + } + outchar(c); +} + +/* + * Print a line with a number. + */ +numbline(i) + int i; +{ + + if (shudclob) + slobber(' '); + printf("%6d ", i); + normline(); +} + +/* + * Normal line output, no numbering. + */ +normline() +{ + register char *cp; + + if (shudclob) + slobber(linebuf[0]); + /* pdp-11 doprnt is not reentrant so can't use "printf" here + in case we are tracing */ + for (cp = linebuf; *cp;) + putchar(*cp++); + if (!inopen) + putchar('\n' | QUOTE); +} + +/* + * Given c at the beginning of a line, determine whether + * the printing of the line will erase or otherwise obliterate + * the prompt which was printed before. If it won't, do it now. + */ +slobber(c) + int c; +{ + + shudclob = 0; + switch (c) { + + case '\t': + if (Putchar == listchar) + return; + break; + + default: + return; + + case ' ': + case 0: + break; + } + if (OS) + return; + flush(); + putch(' '); + if (BC) + tputs(BC, 0, putch); + else + putch('\b'); +} + +/* + * The output buffer is initialized with a useful error + * message so we don't have to keep it in data space. + */ +static char linb[66] = { + 'E', 'r', 'r', 'o', 'r', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', ' ', + 'f', 'i', 'l', 'e', ' ', 'n', 'o', 't', ' ', + 'a', 'v', 'a', 'i', 'l', 'a', 'b', 'l', 'e', '\n', 0 +}; +static char *linp = linb + 33; + +/* + * Phadnl records when we have already had a complete line ending with \n. + * If another line starts without a flush, and the terminal suggests it, + * we switch into -nl mode so that we can send lineffeeds to avoid + * a lot of spacing. + */ +static bool phadnl; + +/* + * Indirect to current definition of putchar. + */ +putchar(c) + int c; +{ + + (*Putchar)(c); +} + +/* + * Termchar routine for command mode. + * Watch for possible switching to -nl mode. + * Otherwise flush into next level of buffering when + * small buffer fills or at a newline. + */ +termchar(c) + int c; +{ + + if (pfast == 0 && phadnl) + pstart(); + if (c == '\n') + phadnl = 1; + else if (linp >= &linb[63]) + flush1(); + *linp++ = c; + if (linp >= &linb[63]) { + fgoto(); + flush1(); + } +} + +flush() +{ + + flush1(); + flush2(); +} + +/* + * Flush from small line buffer into output buffer. + * Work here is destroying motion into positions, and then + * letting fgoto do the optimized motion. + */ +flush1() +{ + register char *lp; + register short c; + + *linp = 0; + lp = linb; + while (*lp) + switch (c = *lp++) { + + case '\r': + destline += destcol / COLUMNS; + destcol = 0; + continue; + + case '\b': + if (destcol) + destcol--; + continue; + + case ' ': + destcol++; + continue; + + case '\t': + destcol += value(TABSTOP) - destcol % value(TABSTOP); + continue; + + case '\n': + destline += destcol / COLUMNS + 1; + if (destcol != 0 && destcol % COLUMNS == 0) + destline--; + destcol = 0; + continue; + + default: + fgoto(); + for (;;) { + if (AM == 0 && outcol == COLUMNS) + fgoto(); + c &= TRIM; + putch(c); + if (c == '\b') { + outcol--; + destcol--; + } else if (c >= ' ' && c != DELETE) { + outcol++; + destcol++; + if (XN && outcol % COLUMNS == 0) + putch('\n'); + } + c = *lp++; + if (c <= ' ') + break; + } + --lp; + continue; + } + linp = linb; +} + +flush2() +{ + + fgoto(); + flusho(); + pstop(); +} + +/* + * Sync the position of the output cursor. + * Most work here is rounding for terminal boundaries getting the + * column position implied by wraparound or the lack thereof and + * rolling up the screen to get destline on the screen. + */ +fgoto() +{ + register int l, c; + + if (destcol > COLUMNS - 1) { + destline += destcol / COLUMNS; + destcol %= COLUMNS; + } + if (outcol > COLUMNS - 1) { + l = (outcol + 1) / COLUMNS; + outline += l; + outcol %= COLUMNS; + if (AM == 0) { + while (l > 0) { + if (pfast) + putch('\r'); + putch('\n'); + l--; + } + outcol = 0; + } + if (outline > LINES - 1) { + destline -= outline - (LINES - 1); + outline = LINES - 1; + } + } + if (destline > LINES - 1) { + l = destline; + destline = LINES - 1; + if (outline < LINES - 1) { + c = destcol; + if (pfast == 0 && (!CA || holdcm)) + destcol = 0; + fgoto(); + destcol = c; + } + while (l > LINES - 1) { + putch('\n'); + l--; + if (pfast == 0) + outcol = 0; + } + } + if (destline < outline && !(CA && !holdcm || UP != NOSTR)) + destline = outline; + if (CA && !holdcm) + if (plod(costCM) > 0) + plod(0); + else + tputs(tgoto(CM, destcol, destline), 0, putch); + else + plod(0); + outline = destline; + outcol = destcol; +} + +/* + * Tab to column col by flushing and then setting destcol. + * Used by "set all". + */ +tab(col) + int col; +{ + + flush1(); + destcol = col; +} + +/* + * Move (slowly) to destination. + * Hard thing here is using home cursor on really deficient terminals. + * Otherwise just use cursor motions, hacking use of tabs and overtabbing + * and backspace. + */ + +static int plodcnt, plodflg; + +plodput(c) +{ + + if (plodflg) + plodcnt--; + else + putch(c); +} + +plod(cnt) +{ + register int i, j, k; + register int soutcol, soutline; + + plodcnt = plodflg = cnt; + soutcol = outcol; + soutline = outline; + if (HO) { + if (GT) + i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS)); + else + i = destcol; + if (destcol >= outcol) { + j = destcol / value(HARDTABS) - outcol / value(HARDTABS); + if (GT && j) + j += destcol % value(HARDTABS); + else + j = destcol - outcol; + } else + if (outcol - destcol <= i && (BS || BC)) + i = j = outcol - destcol; + else + j = i + 1; + k = outline - destline; + if (k < 0) + k = -k; + j += k; + if (i + destline < j) { + tputs(HO, 0, plodput); + outcol = outline = 0; + } else if (LL) { + k = (LINES - 1) - destline; + if (i + k + 2 < j) { + tputs(LL, 0, plodput); + outcol = 0; + outline = LINES - 1; + } + } + } + if (GT) + i = destcol % value(HARDTABS) + destcol / value(HARDTABS); + else + i = destcol; +/* + if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) { + j *= (k = strlen(BT)); + if ((k += (destcol&7)) > 4) + j += 8 - (destcol&7); + else + j += k; + } else +*/ + j = outcol - destcol; + /* + * If we will later need a \n which will turn into a \r\n by + * the system or the terminal, then don't bother to try to \r. + */ + if ((NONL || !pfast) && outline < destline) + goto dontcr; + /* + * If the terminal will do a \r\n and there isn't room for it, + * then we can't afford a \r. + */ + if (NC && outline >= destline) + goto dontcr; + /* + * If it will be cheaper, or if we can't back up, then send + * a return preliminarily. + */ + if (j > i + 1 || outcol > destcol && !BS && !BC) { + plodput('\r'); + if (NC) { + plodput('\n'); + outline++; + } + outcol = 0; + } +dontcr: + while (outline < destline) { + outline++; + plodput('\n'); + if (plodcnt < 0) + goto out; + if (NONL || pfast == 0) + outcol = 0; + } + if (BT) + k = strlen(BT); + while (outcol > destcol) { + if (plodcnt < 0) + goto out; +/* + if (BT && !insmode && outcol - destcol > 4+k) { + tputs(BT, 0, plodput); + outcol--; + outcol &= ~7; + continue; + } +*/ + outcol--; + if (BC) + tputs(BC, 0, plodput); + else + plodput('\b'); + } + while (outline > destline) { + outline--; + tputs(UP, 0, plodput); + if (plodcnt < 0) + goto out; + } + if (GT && !insmode && destcol - outcol > 1) { + for (;;) { + i = (outcol / value(HARDTABS) + 1) * value(HARDTABS); + if (i > destcol) + break; + if (TA) + tputs(TA, 0, plodput); + else + plodput('\t'); + outcol = i; + } + if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) { + if (TA) + tputs(TA, 0, plodput); + else + plodput('\t'); + outcol = i; + while (outcol > destcol) { + outcol--; + if (BC) + tputs(BC, 0, plodput); + else + plodput('\b'); + } + } + } + while (outcol < destcol) { + if (inopen && ND) + tputs(ND, 0, plodput); + else + plodput(' '); + outcol++; + if (plodcnt < 0) + goto out; + } +out: + if (plodflg) { + outcol = soutcol; + outline = soutline; + } + return(plodcnt); +} + +/* + * An input line arrived. + * Calculate new (approximate) screen line position. + * Approximate because kill character echoes newline with + * no feedback and also because of long input lines. + */ +noteinp() +{ + + outline++; + if (outline > LINES - 1) + outline = LINES - 1; + destline = outline; + destcol = outcol = 0; +} + +/* + * Something weird just happened and we + * lost track of whats happening out there. + * Since we cant, in general, read where we are + * we just reset to some known state. + * On cursor addressible terminals setting to unknown + * will force a cursor address soon. + */ +termreset() +{ + + endim(); + if (TI) /* otherwise it flushes anyway, and 'set tty=dumb' vomits */ + putpad(TI); /*adb change -- emit terminal initial sequence */ + destcol = 0; + destline = LINES - 1; + if (CA) { + outcol = UKCOL; + outline = UKCOL; + } else { + outcol = destcol; + outline = destline; + } +} + +/* + * Low level buffering, with the ability to drain + * buffered output without printing it. + */ +char *obp = obuf; + +draino() +{ + + obp = obuf; +} + +flusho() +{ + + if (obp != obuf) { + write(1, obuf, obp - obuf); + obp = obuf; + } +} + +putnl() +{ + + putchar('\n'); +} + +putS(cp) + char *cp; +{ + + if (cp == NULL) + return; + while (*cp) + putch(*cp++); +} + + +putch(c) + int c; +{ + + *obp++ = c; + if (obp >= &obuf[sizeof obuf]) + flusho(); +} + +/* + * Miscellaneous routines related to output. + */ + +/* + * Cursor motion. + */ +char * +cgoto() +{ + + return (tgoto(CM, destcol, destline)); +} + +/* + * Put with padding + */ +putpad(cp) + char *cp; +{ + + flush(); + tputs(cp, 0, putch); +} + +/* + * Set output through normal command mode routine. + */ +setoutt() +{ + + Outchar = termchar; +} + +/* + * Printf (temporarily) in list mode. + */ +/*VARARGS2*/ +lprintf(cp, dp) + char *cp, *dp; +{ + register int (*P)(); + + P = setlist(1); + printf(cp, dp); + Putchar = P; +} + +/* + * Newline + flush. + */ +putNFL() +{ + + putnl(); + flush(); +} + +/* + * Try to start -nl mode. + */ +pstart() +{ + + if (NONL) + return; + if (!value(OPTIMIZE)) + return; + if (ruptible == 0 || pfast) + return; + fgoto(); + flusho(); + pfast = 1; + normtty++; + tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD); + sTTY(1); +} + +/* + * Stop -nl mode. + */ +pstop() +{ + + if (inopen) + return; + phadnl = 0; + linp = linb; + draino(); + normal(normf); + pfast &= ~1; +} + +/* + * Prep tty for open mode. + */ +ostart() +{ + int f; + + if (!intty) + error("Open and visual must be used interactively"); + gTTY(1); + normtty++; + f = tty.sg_flags; +#ifdef CBREAK + tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) | CBREAK; +#else + tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) | RAW; +#endif +#ifdef TIOCGETC + nttyc.t_quitc = nttyc.t_startc = nttyc.t_stopc = '\377'; +#endif + sTTY(1); + putpad(VS); + putpad(KS); + pfast |= 2; + return (f); +} + +/* + * Stop open, restoring tty modes. + */ +ostop(f) + int f; +{ + + pfast = (f & CRMOD) == 0; + termreset(), fgoto(), flusho(); + normal(f); + putpad(VE); + putpad(KE); +} + +#ifndef CBREAK +/* + * Into cooked mode for interruptibility. + */ +vcook() +{ + + tty.sg_flags &= ~RAW; + sTTY(1); +} + +/* + * Back into raw mode. + */ +vraw() +{ + + tty.sg_flags |= RAW; + sTTY(1); +} +#endif + +/* + * Restore flags to normal state f. + */ +normal(f) + int f; +{ + + if (normtty > 0) { + setty(f); + normtty--; + } +} + +/* + * Straight set of flags to state f. + */ +setty(f) + int f; +{ + register int ot = tty.sg_flags; + +#ifdef TIOCGETC + if (f == normf) + nttyc = ottyc; + else + nttyc.t_quitc = nttyc.t_startc = nttyc.t_stopc = '\377'; +#endif + tty.sg_flags = f; + sTTY(1); + return (ot); +} + +gTTY(i) + int i; +{ + + ignore(gtty(i, &tty)); +#ifdef TIOCGETC + ioctl(i, TIOCGETC, &ottyc); + nttyc = ottyc; +#endif +} + +sTTY(i) + int i; +{ + +/* + * Bug in USG tty driver, put out a null char as a patch. + */ +#ifdef USG + if (tty.sg_ospeed == B1200) + write(1, "", 1); +#endif +#ifdef TIOCSETN + ioctl(i, TIOCSETN, &tty); +#else + stty(i, &tty); +#endif +#ifdef TIOCSETC + ioctl(i, TIOCSETC, &nttyc); +#endif +} + +/* + * Print newline, or blank if in open/visual + */ +noonl() +{ + + putchar(Outchar != termchar ? ' ' : '\n'); +} -- 2.20.1