date and time created 80/08/01 00:41:11 by mark
[unix-history] / usr / src / usr.bin / ex / ex_subr.c
/* 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));
}
/*
* Ignore a comment to the end of the line.
* This routine eats the trailing newline so don't call newline().
*/
comment()
{
register int c;
do {
c = getchar();
} while (c != '\n' && c != EOF);
if (c == EOF)
ungetchar(c);
}
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);
else if (c=='"')
comment();
}
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 VMUNIX
char *seekpt;
#else
# ifdef lint
char *seekpt;
# else
int seekpt;
# endif
#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 VMUNIX
char *seekpt;
#else
# ifdef lint
char *seekpt;
# else
int seekpt;
# endif
#endif
{
#ifdef VMUNIX
strcpy(linebuf, seekpt);
#else
lseek(erfile, (long) seekpt, 0);
if (read(erfile, linebuf, 128) < 2)
CP(linebuf, "ERROR");
#endif
}
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;
register oldglobmk;
oldglobmk = *addr & 1;
*addr &= ~1;
for (markp = (anymarks ? names : &names['z'-'a'+1]);
markp <= &names['z'-'a'+1]; markp++)
if (*markp == *addr)
*markp = n;
*addr = n | oldglobmk;
}
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;
if (!FIXUNDO)
return;
#ifdef TRACE
if (trace)
vudump("before save");
#endif
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;
#ifdef TRACE
if (trace)
vudump("after save");
#endif
}
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
# ifdef VMUNIX
char *std_errlist[] = {
# else
short std_errlist[] = {
# endif
#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);
}
/*
* Return the column number that results from being in column col and
* hitting a tab, where tabs are set every ts columns. Work right for
* the case where col > COLUMNS, even if ts does not divide COLUMNS.
*/
tabcol(col, ts)
int col, ts;
{
int offset, result;
if (col >= COLUMNS) {
offset = COLUMNS * (col/COLUMNS);
col -= offset;
} else
offset = 0;
result = col + ts - (col % ts) + offset;
return (result);
}
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();
}