From 851aa263951321c759f2cf561cb6cddb77f4362f Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Tue, 8 May 1979 23:19:53 -0800 Subject: [PATCH] BSD 2 development Work on file src/ex/ex_re.c Work on file src/ex/ex_re.h Work on file src/ex/ex_set.c Work on file src/ex/ex_subr.c Synthesized-from: 2bsd --- src/ex/ex_re.c | 845 +++++++++++++++++++++++++++++++++++++++++++++++ src/ex/ex_re.h | 66 ++++ src/ex/ex_set.c | 178 ++++++++++ src/ex/ex_subr.c | 743 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1832 insertions(+) create mode 100644 src/ex/ex_re.c create mode 100644 src/ex/ex_re.h create mode 100644 src/ex/ex_set.c create mode 100644 src/ex/ex_subr.c diff --git a/src/ex/ex_re.c b/src/ex/ex_re.c new file mode 100644 index 0000000000..114a7cc137 --- /dev/null +++ b/src/ex/ex_re.c @@ -0,0 +1,845 @@ +/* Copyright (c) 1979 Regents of the University of California */ +#include "ex.h" +#include "ex_re.h" + +/* + * Global, substitute and regular expressions. + * Very similar to ed, with some re extensions and + * confirmed substitute. + */ +global(k) + bool k; +{ + register char *gp; + register int c; + register line *a1; + char globuf[GBSIZE], *Cwas; + int lines = lineDOL(); + char *oglobp = globp; + + Cwas = Command; + if (inglobal) + error("Global within global@not allowed"); + markDOT(); + setall(); + nonzero(); + if (skipend()) + error("Global needs re|Missing regular expression for global"); + c = getchar(); + ignore(compile(c, 0)); + savere(scanre); + gp = globuf; + while ((c = getchar()) != '\n') { + switch (c) { + + case EOF: + c = '\n'; + goto brkwh; + + case '\\': + c = getchar(); + switch (c) { + + case '\\': + ungetchar(c); + break; + + case '\n': + break; + + default: + *gp++ = '\\'; + break; + } + break; + } + *gp++ = c; + if (gp >= &globuf[GBSIZE - 2]) + error("Global command too long"); + } +brkwh: + ungetchar(c); +out: + newline(); + *gp++ = c; + *gp++ = 0; + inglobal = 1; + for (a1 = one; a1 <= dol; a1++) { + *a1 &= ~01; + if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k) + *a1 |= 01; + } + /* should use gdelete from ed to avoid n**2 here on g/.../d */ + saveall(); + if (inopen) + inopen = -1; + for (a1 = one; a1 <= dol; a1++) { + if (*a1 & 01) { + *a1 &= ~01; + dot = a1; + globp = globuf; + commands(1, 1); + a1 = zero; + } + } + globp = oglobp; + inglobal = 0; + endline = 1; + Command = Cwas; + netchHAD(lines); + setlastchar(EOF); + if (inopen) { + ungetchar(EOF); + inopen = 1; + } +} + +bool xflag; +int scount, slines, stotal; + +substitute(c) + int c; +{ + register line *addr; + register int n; + int gsubf; + + gsubf = compsub(c); + if (!inglobal) + save12(), undkind = UNDCHANGE; + stotal = 0; + slines = 0; + for (addr = addr1; addr <= addr2; addr++) { + scount = 0; + if (dosubcon(0, addr) == 0) + continue; + if (gsubf) + while (*loc2) + if (dosubcon(1, addr) == 0) + break; + if (scount) { + stotal += scount; + slines++; + putmark(addr); + n = append(getsub, addr); + addr += n; + addr2 += n; + } + } + if (stotal == 0 && !inglobal && !xflag) + error("Fail|Substitute pattern match failed"); + snote(stotal, slines); + return (stotal); +} + +compsub(ch) +{ + register int seof, c; + int gsubf; + + gsubf = 0; + xflag = 0; + switch (ch) { + + case 's': + ignore(skipwh()); + seof = getchar(); + if (endcmd(seof)) + error("Substitute needs re|Missing regular expression for substitute"); + seof = compile(seof, 1); + savere(subre); + comprhs(seof); + break; + + case '&': + if (subre.Expbuf[0] == 0) + error("No previous substitute re|No previous substitute to repeat"); + resre(subre); + break; + + case '~': + if (re.Expbuf[0] == 0) + error("No previous re|No previous regular expression"); + savere(subre); + break; + } + for (;;) { + c = getchar(); + switch (c) { + + case 'g': + gsubf++; + continue; + + case 'c': + xflag++; + continue; + + default: + ungetchar(c); + setcount(); + newline(); + return (gsubf); + } + } +} + +comprhs(seof) + int seof; +{ + register char *rp, *orp; + register int c; + char orhsbuf[LBSIZE / 2]; + + rp = rhsbuf; + CP(orhsbuf, rp); + for (;;) { + c = getchar(); + if (c == seof) + break; + switch (c) { + + case '\\': + c = getchar(); + if (c == EOF) { + ungetchar(c); + break; + } + if (value(MAGIC)) { + /* + * When "magic", \& turns into a plain &, + * and all other chars work fine quoted. + */ + if (c != '&') + c |= QUOTE; + break; + } +magic: + if (c == '~') { + for (orp = orhsbuf; *orp; *rp++ = *orp++) + if (rp >= &rhsbuf[LBSIZE / 2 + 1]) + goto toobig; + continue; + } + c |= QUOTE; + break; + + case '\n': + case EOF: + ungetchar(c); + goto endrhs; + + case '~': + case '&': + if (value(MAGIC)) + goto magic; + break; + } + if (rp >= &rhsbuf[LBSIZE / 2 - 1]) +toobig: + error("Replacement pattern too long@- limit 256 characters"); + *rp++ = c; + } +endrhs: + *rp++ = 0; +} + +getsub() +{ + register char *p; + + if ((p = linebp) == 0) + return (EOF); + strcLIN(p); + linebp = 0; + return (0); +} + +dosubcon(f, a) + bool f; + line *a; +{ + + if (execute(f, a) == 0) + return (0); + if (confirmed(a)) { + dosub(); + scount++; + } + return (1); +} + +confirmed(a) + line *a; +{ + register int c, ch; + + if (xflag == 0) + return (1); + pofix(); + pline(lineno(a)); + if (inopen) + putchar('\n' | QUOTE); + c = column(loc1 - 1); + ugo(c - 1 + (inopen ? 1 : 0), ' '); + ugo(column(loc2 - 1) - c, '^'); + flush(); + ch = c = getkey(); +again: + if (c == '\r') + c = '\n'; + if (inopen) + putchar(c), flush(); + if (c != '\n' && c != EOF) { + c = getkey(); + goto again; + } + noteinp(); + return (ch == 'y'); +} + +getch() +{ + char c; + + if (read(2, &c, 1) != 1) + return (EOF); + return (c & TRIM); +} + +ugo(cnt, with) + int with; + int cnt; +{ + + if (cnt > 0) + do + putchar(with); + while (--cnt > 0); +} + +int casecnt; +bool destuc; + +dosub() +{ + register char *lp, *sp, *rp; + int c; + + lp = linebuf; + sp = genbuf; + rp = rhsbuf; + while (lp < loc1) + *sp++ = *lp++; + casecnt = 0; + while (c = *rp++) { + if (c & QUOTE) + switch (c & TRIM) { + + case '&': + sp = place(sp, loc1, loc2); + if (sp == 0) + goto ovflo; + continue; + + case 'l': + casecnt = 1; + destuc = 0; + continue; + + case 'L': + casecnt = LBSIZE; + destuc = 0; + continue; + + case 'u': + casecnt = 1; + destuc = 1; + continue; + + case 'U': + casecnt = LBSIZE; + destuc = 1; + continue; + + case 'E': + case 'e': + casecnt = 0; + continue; + } + if (c < 0 && (c &= TRIM) >= '1' && c < nbra + '1') { + sp = place(sp, braslist[c - '1'], braelist[c - '1']); + if (sp == 0) + goto ovflo; + continue; + } + if (casecnt) + *sp++ = fixcase(c & TRIM); + else + *sp++ = c & TRIM; + if (sp >= &genbuf[LBSIZE]) +ovflo: + error("Line overflow@in substitute - limit 512 chars"); + } + lp = loc2; + loc2 = sp + (linebuf - genbuf) + (loc1 == loc2); + while (*sp++ = *lp++) + if (sp >= &genbuf[LBSIZE]) + goto ovflo; + strcLIN(genbuf); +} + +fixcase(c) + register int c; +{ + + if (casecnt == 0) + return (c); + casecnt--; + if (destuc) { + if (islower(c)) + c = toupper(c); + } else + if (isupper(c)) + c = tolower(c); + return (c); +} + +char * +place(sp, l1, l2) + register char *sp, *l1, *l2; +{ + + while (l1 < l2) { + *sp++ = fixcase(*l1++); + if (sp >= &genbuf[LBSIZE]) + return (0); + } + return (sp); +} + +snote(total, lines) + register int total, lines; +{ + + if (!notable(total)) + return; + printf(mesg("%d subs|%d substitutions"), total); + if (lines != 1 && lines != total) + printf(" on %d lines", lines); + noonl(); + flush(); +} + +compile(eof, oknl) + int eof; + int oknl; +{ + register int c; + register char *ep; + char *lastep; + char bracket[NBRA], *bracketp, *rhsp; + int cclcnt; + + if (isalpha(eof) || isdigit(eof)) + error("Re delimiter must not be letter or digit|Regular expressions cannot be delimited by letters or digits"); + ep = expbuf; + c = getchar(); + if (eof == '\\') + switch (c) { + + case '/': + case '?': + if (scanre.Expbuf[0] == 0) + error("No previous scan re|No previous scanning regular expression"); + resre(scanre); + return (c); + + case '&': + if (subre.Expbuf[0] == 0) + error("No previous substitute re|No previous substitute regular expression"); + resre(subre); + return (c); + + default: + error("Badly formed re|Regular expression \ must be followed by / or ?"); + } + if (c == eof || c == '\n' || c == EOF) { + if (*ep == 0) + error("No previous re|No previous regular expression"); + if (c == '\n' && oknl == 0) + error("Missing closing delimiter@for regular expression"); + if (c != eof) + ungetchar(c); + return (eof); + } + bracketp = bracket; + nbra = 0; + circfl = 0; + if (c == '^') { + c = getchar(); + circfl++; + } + ungetchar(c); + for (;;) { + if (ep >= &expbuf[ESIZE - 2]) +complex: + cerror("Re too complex|Regular expression too complicated"); + c = getchar(); + if (c == eof || c == EOF) { + if (bracketp != bracket) + cerror("Unmatched \\(|More \\('s than \\)'s in regular expression"); + *ep++ = CEOF; + if (c == EOF) + ungetchar(c); + return (eof); + } + if (value(MAGIC)) { + if (c != '*' || ep == expbuf) + lastep = ep; + } else + if (c != '\\' || peekchar() != '*' || ep == expbuf) + lastep = ep; + switch (c) { + + case '\\': + if (!intag) + c = getchar(); + switch (c) { + + case '(': + if (nbra >= NBRA) + cerror("Awash in \\('s!|Too many \\('d subexressions in a regular expression"); + *bracketp++ = nbra; + *ep++ = CBRA; + *ep++ = nbra++; + continue; + + case ')': + if (bracketp <= bracket) + cerror("Extra \\)|More \\)'s than \\('s in regular expression"); + *ep++ = CKET; + *ep++ = *--bracketp; + continue; + + case '<': + *ep++ = CBRC; + continue; + + case '>': + *ep++ = CLET; + continue; + } + if (value(MAGIC) == 0 && !intag) +magic: + switch (c) { + + case '.': + *ep++ = CDOT; + continue; + + case '~': + rhsp = rhsbuf; + while (*rhsp) { + if (*rhsp & QUOTE) { + c = *rhsp & TRIM; + if (c == '&') + error("Replacement pattern contains &@- cannot use in re"); + if (c >= '1' && c <= '9') + error("Replacement pattern contains \\d@- cannot use in re"); + } + if (ep >= &expbuf[ESIZE-2]) + goto complex; + *ep++ = CCHR; + *ep++ = *rhsp++ & TRIM; + } + continue; + + case '*': + if (ep == expbuf) + break; + if (*lastep == CBRA || *lastep == CKET) + cerror("Illegal *|Can't * a \\( ... \\) in regular expression"); + if (*lastep == CCHR && (lastep[1] & QUOTE)) + cerror("Illegal *|Can't * a \\n in regular expression"); + *lastep |= STAR; + continue; + + case '[': + *ep++ = CCL; + *ep++ = 0; + cclcnt = 1; + c = getchar(); + if (c == '^') { + c = getchar(); + ep[-2] = NCCL; + } + if (c == ']') + cerror("Bad character class|Empty character class '[]' or '[^]' cannot match"); + while (c != ']') { + if (c == '\\' && any(peekchar(), "]-^\\")) + c = getchar() | QUOTE; + if (c == '\n' || c == EOF) + cerror("Missing ]"); + *ep++ = c; + cclcnt++; + if (ep >= &expbuf[ESIZE]) + goto complex; + c = getchar(); + } + lastep[1] = cclcnt; + continue; + } + if (c == EOF) { + ungetchar(EOF); + c = '\\'; + goto defchar; + } + *ep++ = CCHR; + if (c == '\n') + cerror("No newlines in re's|Can't escape newlines into regular expressions"); +/* + if (c < '1' || c > NBRA + '1') { +*/ + *ep++ = c; + continue; +/* + } + c -= '1'; + if (c >= nbra) + cerror("Bad \\n|\\n in regular expression with n greater than the number of \\('s"); + *ep++ = c | QUOTE; + continue; +*/ + + case '\n': + if (oknl) { + ungetchar(c); + *ep++ = CEOF; + return (eof); + } + cerror("Badly formed re|Missing closing delimiter for regular expression"); + + case '$': + if (peekchar() == eof || peekchar() == EOF || oknl && peekchar() == '\n') { + *ep++ = CDOL; + continue; + } + goto defchar; + + case '.': + case '~': + case '*': + case '[': + if (value(MAGIC) && !intag) + goto magic; +defchar: + default: + *ep++ = CCHR; + *ep++ = c; + continue; + } + } +} + +cerror(s) + char *s; +{ + + expbuf[0] = 0; + error(s); +} + +same(a, b) + register int a, b; +{ + + return (a == b || value(IGNORECASE) && + ((islower(a) && toupper(a) == b) || (islower(b) && toupper(b) == a))); +} + +char *locs; + +execute(gf, addr) + line *addr; +{ + register char *p1, *p2; + register int c; + + if (gf) { + if (circfl) + return (0); + locs = p1 = loc2; + } else { + if (addr == zero) + return (0); + p1 = linebuf; + getline(*addr); + locs = 0; + } + p2 = expbuf; + if (circfl) { + loc1 = p1; + return (advance(p1, p2)); + } + /* fast check for first character */ + if (*p2 == CCHR) { + c = p2[1]; + do { + if (c != *p1 && (!value(IGNORECASE) || + !((islower(c) && toupper(c) == *p1) || (islower(*p1) && toupper(*p1) == c)))) + continue; + if (advance(p1, p2)) { + loc1 = p1; + return (1); + } + } while (*p1++); + return (0); + } + /* regular algorithm */ + do { + if (advance(p1, p2)) { + loc1 = p1; + return (1); + } + } while (*p1++); + return (0); +} + +#define uletter(c) (isalpha(c) || c == '_') + +advance(lp, ep) + register char *lp, *ep; +{ + register char *curlp; + char *sp, *sp1; + int c; + + for (;;) switch (*ep++) { + + case CCHR: +/* useless + if (*ep & QUOTE) { + c = *ep++ & TRIM; + sp = braslist[c]; + sp1 = braelist[c]; + while (sp < sp1) { + if (!same(*sp, *lp)) + return (0); + sp++, lp++; + } + continue; + } +*/ + if (!same(*ep, *lp)) + return (0); + ep++, lp++; + continue; + + case CDOT: + if (*lp++) + continue; + return (0); + + case CDOL: + if (*lp == 0) + continue; + return (0); + + case CEOF: + loc2 = lp; + return (1); + + case CCL: + if (cclass(ep, *lp++, 1)) { + ep += *ep; + continue; + } + return (0); + + case NCCL: + if (cclass(ep, *lp++, 0)) { + ep += *ep; + continue; + } + return (0); + + case CBRA: + braslist[*ep++] = lp; + continue; + + case CKET: + braelist[*ep++] = lp; + continue; + + case CDOT|STAR: + curlp = lp; + while (*lp++) + continue; + goto star; + + case CCHR|STAR: + curlp = lp; + while (same(*lp, *ep)) + lp++; + lp++; + ep++; + goto star; + + case CCL|STAR: + case NCCL|STAR: + curlp = lp; + while (cclass(ep, *lp++, ep[-1] == (CCL|STAR))) + continue; + ep += *ep; + goto star; +star: + do { + lp--; + if (lp == locs) + break; + if (advance(lp, ep)) + return (1); + } while (lp > curlp); + return (0); + + case CBRC: + if (lp == expbuf) + continue; + if ((isdigit(*lp) || uletter(*lp)) && !uletter(lp[-1]) && !isdigit(lp[-1])) + continue; + return (0); + + case CLET: + if (!uletter(*lp) && !isdigit(*lp)) + continue; + return (0); + + default: + error("Re internal error"); + } +} + +cclass(set, c, af) + register char *set; + register int c; + int af; +{ + register int n; + + if (c == 0) + return (0); + if (value(IGNORECASE) && isupper(c)) + c = tolower(c); + n = *set++; + while (--n) + if (n > 2 && set[1] == '-') { + if (c >= (set[0] & TRIM) && c <= (set[2] & TRIM)) + return (af); + set += 3; + n -= 2; + } else + if ((*set++ & TRIM) == c) + return (af); + return (!af); +} diff --git a/src/ex/ex_re.h b/src/ex/ex_re.h new file mode 100644 index 0000000000..2f88c74f26 --- /dev/null +++ b/src/ex/ex_re.h @@ -0,0 +1,66 @@ +/* Copyright (c) 1979 Regents of the University of California */ +/* + * Regular expression definitions. + * The regular expressions in ex are similar to those in ed, + * with the addition of the word boundaries from Toronto ed + * and allowing character classes to have [a-b] as in the shell. + * The numbers for the nodes below are spaced further apart then + * necessary because I at one time partially put in + and | (one or + * more and alternation.) + */ +struct regexp { + char Expbuf[ESIZE + 2]; + bool Circfl; + short Nbra; +}; + +/* + * There are three regular expressions here, the previous (in re), + * the previous substitute (in subre) and the previous scanning (in scanre). + * It would be possible to get rid of "re" by making it a stack parameter + * to the appropriate routines. + */ +struct regexp re; /* Last re */ +struct regexp scanre; /* Last scanning re */ +struct regexp subre; /* Last substitute re */ + +/* + * Defining circfl and expbuf like this saves us from having to change + * old code in the ex_re.c stuff. + */ +#define expbuf re.Expbuf +#define circfl re.Circfl +#define nbra re.Nbra + +/* + * Since the phototypesetter v7-epsilon + * C compiler doesn't have structure assignment... + */ +#define savere(a) copy(&a, &re, sizeof (struct regexp)); +#define resre(a) copy(&re, &a, sizeof (struct regexp)); + +/* + * Definitions for substitute + */ +char *braslist[NBRA]; /* Starts of \(\)'ed text in lhs */ +char *braelist[NBRA]; /* Ends... */ +char rhsbuf[RHSSIZE]; /* Rhs of last substitute */ + +/* + * Definitions of codes for the compiled re's. + * The re algorithm is described in a paper + * by K. Thompson in the CACM about 10 years ago + * and is the same as in ed. + */ +#define STAR 1 + +#define CBRA 1 +#define CDOT 4 +#define CCL 8 +#define NCCL 12 +#define CDOL 16 +#define CEOF 17 +#define CKET 18 +#define CCHR 20 +#define CBRC 24 +#define CLET 25 diff --git a/src/ex/ex_set.c b/src/ex/ex_set.c new file mode 100644 index 0000000000..7724742a50 --- /dev/null +++ b/src/ex/ex_set.c @@ -0,0 +1,178 @@ +/* Copyright (c) 1979 Regents of the University of California */ +#include "ex.h" +#include "ex_temp.h" + +/* + * Set command. + */ +char optname[ONMSZ]; + +set() +{ + register char *cp; + register struct option *op; + register int c; + bool no; + + setnoaddr(); + if (skipend()) { + if (peekchar() != EOF) + ignchar(); + propts(); + return; + } + do { + cp = optname; + do { + if (cp < &optname[ONMSZ - 2]) + *cp++ = getchar(); + } while (isalpha(peekchar())); + *cp = 0; + cp = optname; + if (eq("all", cp)) { + if (inopen) + pofix(); + prall(); + goto next; + } + no = 0; + if (cp[0] == 'n' && cp[1] == 'o') { + cp += 2; + no++; + } + for (op = options; op < &options[NOPTS]; op++) + if (eq(op->oname, cp) || op->oabbrev && eq(op->oabbrev, cp)) + break; + if (op->oname == 0) + serror("%s: No such option@- 'set all' gives all option values", cp); + c = skipwh(); + if (peekchar() == '?') { + ignchar(); +printone: + propt(op); + noonl(); + goto next; + } + if (op->otype == ONOFF) { + op->ovalue = 1 - no; + goto next; + } + if (no) + serror("Option %s is not a toggle", op->oname); + if (c != 0 || setend()) + goto printone; + if (getchar() != '=') + serror("Missing =@in assignment to option %s", op->oname); + switch (op->otype) { + + case NUMERIC: + if (!isdigit(peekchar())) + error("Digits required@after = when assigning numeric option"); + op->ovalue = getnum(); + if (value(TABSTOP) <= 0) + value(TABSTOP) = TABS; + break; + + case STRING: + case OTERM: + cp = optname; + while (!setend()) { + if (cp >= &optname[ONMSZ]) + error("String too long@in option assignment"); + *cp++ = getchar(); + } + *cp = 0; + if (op->otype == OTERM) { + if (inopen) + error("Can't change type of terminal from within open/visual"); + setterm(optname); + } else { + CP(op->osvalue, optname); + op->odefault = 1; + } + break; + } +next: + flush(); + } while (!skipend()); + eol(); +} + +setend() +{ + + return (iswhite(peekchar()) || endcmd(peekchar())); +} + +prall() +{ + register int incr = (NOPTS + 2) / 3; + register int rows = incr; + register struct option *op = options; + + for (; rows; rows--, op++) { + propt(op); + tab(24); + propt(&op[incr]); + if (&op[2*incr] < &options[NOPTS]) { + tab(48); + propt(&op[2 * incr]); + } + putNFL(); + } +} + +propts() +{ + register struct option *op; + + for (op = options; op < &options[NOPTS]; op++) { +#ifdef V6 + if (op == &options[TERM]) +#else + if (op == &options[TTYTYPE]) +#endif + continue; + switch (op->otype) { + + case ONOFF: + case NUMERIC: + if (op->ovalue == op->odefault) + continue; + break; + + case STRING: + if (op->odefault == 0) + continue; + break; + } + propt(op); + putchar(' '); + } + noonl(); + flush(); +} + +propt(op) + register struct option *op; +{ + register char *name; + + name = op->oname; + + switch (op->otype) { + + case ONOFF: + printf("%s%s", op->ovalue ? "" : "no", name); + break; + + case NUMERIC: + printf("%s=%d", name, op->ovalue); + break; + + case STRING: + case OTERM: + printf("%s=%s", name, op->osvalue); + break; + } +} diff --git a/src/ex/ex_subr.c b/src/ex/ex_subr.c new file mode 100644 index 0000000000..318cc9e910 --- /dev/null +++ b/src/ex/ex_subr.c @@ -0,0 +1,743 @@ +/* Copyright (c) 1979 Regents of the University of California */ +#include "ex.h" +#include "ex_re.h" +#include "ex_tty.h" +#include "ex_vis.h" + +/* + * Random routines, in alphabetical order. + */ + +any(c, s) + int c; + register char *s; +{ + register int x; + + while (x = *s++) + if (x == c) + return (1); + return (0); +} + +backtab(i) + register int i; +{ + register int j; + + j = i % value(SHIFTWIDTH); + if (j == 0) + j = value(SHIFTWIDTH); + i -= j; + if (i < 0) + i = 0; + return (i); +} + +change() +{ + + tchng++; + chng = tchng; +} + +/* + * Column returns the number of + * columns occupied by printing the + * characters through position cp of the + * current line. + */ +column(cp) + register char *cp; +{ + + if (cp == 0) + cp = &linebuf[LBSIZE - 2]; + return (qcolumn(cp, (char *) 0)); +} + +Copy(to, from, size) + register char *from, *to; + register int size; +{ + + if (size > 0) + do + *to++ = *from++; + while (--size > 0); +} + +copyw(to, from, size) + register line *from, *to; + register int size; +{ + + if (size > 0) + do + *to++ = *from++; + while (--size > 0); +} + +copywR(to, from, size) + register line *from, *to; + register int size; +{ + + while (--size >= 0) + to[size] = from[size]; +} + +ctlof(c) + int c; +{ + + return (c == TRIM ? '?' : c | ('A' - 1)); +} + +dingdong() +{ + + if (VB) + putpad(VB); + else if (value(ERRORBELLS)) + putch('\207'); +} + +fixindent(indent) + int indent; +{ + register int i; + register char *cp; + + i = whitecnt(genbuf); + cp = vpastwh(genbuf); + if (*cp == 0 && i == indent && linebuf[0] == 0) { + genbuf[0] = 0; + return (i); + } + CP(genindent(i), cp); + return (i); +} + +filioerr(cp) + char *cp; +{ + register int oerrno = errno; + + lprintf("\"%s\"", cp); + errno = oerrno; + syserror(); +} + +char * +genindent(indent) + register int indent; +{ + register char *cp; + + for (cp = genbuf; indent >= value(TABSTOP); indent -= value(TABSTOP)) + *cp++ = '\t'; + for (; indent > 0; indent--) + *cp++ = ' '; + return (cp); +} + +getDOT() +{ + + getline(*dot); +} + +line * +getmark(c) + register int c; +{ + register line *addr; + + for (addr = one; addr <= dol; addr++) + if (names[c - 'a'] == (*addr &~ 01)) { + return (addr); + } + return (0); +} + +getn(cp) + register char *cp; +{ + register int i = 0; + + while (isdigit(*cp)) + i = i * 10 + *cp++ - '0'; + if (*cp) + return (0); + return (i); +} + +ignnEOF() +{ + register int c = getchar(); + + if (c == EOF) + ungetchar(c); +} + +iswhite(c) + int c; +{ + + return (c == ' ' || c == '\t'); +} + +junk(c) + register int c; +{ + + if (c && !value(BEAUTIFY)) + return (0); + if (c >= ' ' && c != TRIM) + return (0); + switch (c) { + + case '\t': + case '\n': + case '\f': + return (0); + + default: + return (1); + } +} + +killed() +{ + + killcnt(addr2 - addr1 + 1); +} + +killcnt(cnt) + register int cnt; +{ + + if (inopen) { + notecnt = cnt; + notenam = notesgn = ""; + return; + } + if (!notable(cnt)) + return; + printf("%d lines", cnt); + if (value(TERSE) == 0) { + printf(" %c%s", Command[0] | ' ', Command + 1); + if (Command[strlen(Command) - 1] != 'e') + putchar('e'); + putchar('d'); + } + putNFL(); +} + +lineno(a) + line *a; +{ + + return (a - zero); +} + +lineDOL() +{ + + return (lineno(dol)); +} + +lineDOT() +{ + + return (lineno(dot)); +} + +markDOT() +{ + + markpr(dot); +} + +markpr(which) + line *which; +{ + + if ((inglobal == 0 || inopen) && which <= endcore) { + names['z'-'a'+1] = *which & ~01; + if (inopen) + ncols['z'-'a'+1] = cursor; + } +} + +markreg(c) + register int c; +{ + + if (c == '\'' || c == '`') + return ('z' + 1); + if (c >= 'a' && c <= 'z') + return (c); + return (0); +} + +/* + * Mesg decodes the terse/verbose strings. Thus + * 'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy' + * 'xxx|yyy' -> 'xxx' if terse, else 'yyy' + * All others map to themselves. + */ +char * +mesg(str) + register char *str; +{ + register char *cp; + + str = strcpy(genbuf, str); + for (cp = str; *cp; cp++) + switch (*cp) { + + case '@': + if (value(TERSE)) + *cp = 0; + else + *cp = ' '; + break; + + case '|': + if (value(TERSE) == 0) + return (cp + 1); + *cp = 0; + break; + } + return (str); +} + +/*VARARGS2*/ +merror(seekpt, i) +#ifdef lint + char *seekpt; +#else + int seekpt; +#endif + int i; +{ + register char *cp = linebuf; + + if (seekpt == 0) + return; + merror1(seekpt); + if (*cp == '\n') + putnl(), cp++; + if (inopen && CE) + vclreol(); + if (SO && SE) + putpad(SO); + printf(mesg(cp), i); + if (SO && SE) + putpad(SE); +} + +merror1(seekpt) +#ifdef lint + char *seekpt; +#else + int seekpt; +#endif +{ + + lseek(erfile, (long) seekpt, 0); + if (read(erfile, linebuf, 128) < 2) + CP(linebuf, "ERROR"); +} + +morelines() +{ + + if ((int) sbrk(1024 * sizeof (line)) == -1) + return (-1); + endcore += 1024; + return (0); +} + +nonzero() +{ + + if (addr1 == zero) { + notempty(); + error("Nonzero address required@on this command"); + } +} + +notable(i) + int i; +{ + + return (hush == 0 && !inglobal && i > value(REPORT)); +} + + +notempty() +{ + + if (dol == zero) + error("No lines@in the buffer"); +} + + +netchHAD(cnt) + int cnt; +{ + + netchange(lineDOL() - cnt); +} + +netchange(i) + register int i; +{ + register char *cp; + + if (i > 0) + notesgn = cp = "more "; + else + notesgn = cp = "fewer ", i = -i; + if (inopen) { + notecnt = i; + notenam = ""; + return; + } + if (!notable(i)) + return; + printf(mesg("%d %slines@in file after %s"), i, cp, Command); + putNFL(); +} + +putmark(addr) + line *addr; +{ + + putmk1(addr, putline()); +} + +putmk1(addr, n) + register line *addr; + int n; +{ + register line *markp; + + *addr &= ~1; + for (markp = (anymarks ? names : &names['z'-'a'+1]); markp <= &names['z'-'a'+1]; markp++) + if (*markp == *addr) + *markp = n; + *addr = n; +} + +char * +plural(i) + long i; +{ + + return (i == 1 ? "" : "s"); +} + +int qcount(); +short vcntcol; + +qcolumn(lim, gp) + register char *lim, *gp; +{ + register int x; + int (*OO)(); + + OO = Outchar; + Outchar = qcount; + vcntcol = 0; + if (lim != NULL) + x = lim[1], lim[1] = 0; + pline(0); + if (lim != NULL) + lim[1] = x; + if (gp) + while (*gp) + putchar(*gp++); + Outchar = OO; + return (vcntcol); +} + +int +qcount(c) + int c; +{ + + if (c == '\t') { + vcntcol += value(TABSTOP) - vcntcol % value(TABSTOP); + return; + } + vcntcol++; +} + +reverse(a1, a2) + register line *a1, *a2; +{ + register line t; + + for (;;) { + t = *--a2; + if (a2 <= a1) + return; + *a2 = *a1; + *a1++ = t; + } +} + +save(a1, a2) + line *a1; + register line *a2; +{ + register int more; + + undkind = UNDNONE; + undadot = dot; + more = (a2 - a1 + 1) - (unddol - dol); + while (more > (endcore - truedol)) + if (morelines() < 0) + error("Out of memory@saving lines for undo - try using ed or re"); + if (more) + (*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1, + (truedol - unddol)); + unddol += more; + truedol += more; + copyw(dol + 1, a1, a2 - a1 + 1); + undkind = UNDALL; + unddel = a1 - 1; + undap1 = a1; + undap2 = a2 + 1; +} + +save12() +{ + + save(addr1, addr2); +} + +saveall() +{ + + save(one, dol); +} + +span() +{ + + return (addr2 - addr1 + 1); +} + +sync() +{ + + chng = 0; + tchng = 0; + xchng = 0; +} + + +skipwh() +{ + register int wh; + + wh = 0; + while (iswhite(peekchar())) { + wh++; + ignchar(); + } + return (wh); +} + +/*VARARGS2*/ +smerror(seekpt, cp) +#ifdef lint + char *seekpt; +#else + int seekpt; +#endif + char *cp; +{ + + if (seekpt == 0) + return; + merror1(seekpt); + if (inopen && CE) + vclreol(); + if (SO && SE) + putpad(SO); + lprintf(mesg(linebuf), cp); + if (SO && SE) + putpad(SE); +} + +#define std_nerrs (sizeof std_errlist / sizeof std_errlist[0]) + +#define error(i) i + +#ifdef lint +char *std_errlist[] = { +#else +short std_errlist[] = { +#endif + error("Error 0"), + error("Not super-user"), + error("No such file or directory"), + error("No such process"), + error("Interrupted system call"), + error("Physical I/O error"), + error("No such device or address"), + error("Argument list too long"), + error("Exec format error"), + error("Bad file number"), + error("No children"), + error("No more processes"), + error("Not enough core"), + error("Permission denied"), + error("Bad address"), + error("Block device required"), + error("Mount device busy"), + error("File exists"), + error("Cross-device link"), + error("No such device"), + error("Not a directory"), + error("Is a directory"), + error("Invalid argument"), + error("File table overflow"), + error("Too many open files"), + error("Not a typewriter"), + error("Text file busy"), + error("File too large"), + error("No space left on device"), + error("Illegal seek"), + error("Read-only file system"), + error("Too many links"), + error("Broken pipe") +#ifndef QUOTA + , error("Math argument") + , error("Result too large") +#else + , error("Quota exceeded") +#endif +}; + +#undef error + +char * +strend(cp) + register char *cp; +{ + + while (*cp) + cp++; + return (cp); +} + +strcLIN(dp) + char *dp; +{ + + CP(linebuf, dp); +} + +syserror() +{ + register int e = errno; + + dirtcnt = 0; + putchar(' '); + if (e >= 0 && errno <= std_nerrs) + error(std_errlist[e]); + else + error("System error %d", e); +} + +char * +vfindcol(i) + int i; +{ + register char *cp; + register int (*OO)() = Outchar; + + Outchar = qcount; + ignore(qcolumn(linebuf - 1, NOSTR)); + for (cp = linebuf; *cp && vcntcol < i; cp++) + putchar(*cp); + if (cp != linebuf) + cp--; + Outchar = OO; + return (cp); +} + +char * +vskipwh(cp) + register char *cp; +{ + + while (iswhite(*cp) && cp[1]) + cp++; + return (cp); +} + + +char * +vpastwh(cp) + register char *cp; +{ + + while (iswhite(*cp)) + cp++; + return (cp); +} + +whitecnt(cp) + register char *cp; +{ + register int i; + + i = 0; + for (;;) + switch (*cp++) { + + case '\t': + i += value(TABSTOP) - i % value(TABSTOP); + break; + + case ' ': + i++; + break; + + default: + return (i); + } +} + +#ifdef lint +Ignore(a) + char *a; +{ + + a = a; +} + +Ignorf(a) + int (*a)(); +{ + + a = a; +} +#endif + +markit(addr) + line *addr; +{ + + if (addr != dot && addr >= one && addr <= dol) + markDOT(); +} + -- 2.20.1