+/* 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();
+}
+