file reorg, pathnames.h, paths.h
[unix-history] / usr / src / usr.bin / ex / ex_subr.c
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char *sccsid = "@(#)ex_subr.c 7.12 (Berkeley) %G%";
#endif not lint
#include "ex.h"
#include "ex_re.h"
#include "ex_tty.h"
#include "ex_vis.h"
#include "pathnames.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 = ex_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 = ex_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;
ex_printf("%d lines", cnt);
if (value(TERSE) == 0) {
ex_printf(" %c%s", Command[0] | ' ', Command + 1);
if (Command[strlen(Command) - 1] != 'e')
ex_putchar('e');
ex_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)
#ifndef EXSTRINGS
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 > 0 && CE)
vclreol();
if (SO && SE)
putpad(SO);
ex_printf(mesg(cp), i);
if (SO && SE)
putpad(SE);
}
merror1(seekpt)
#ifndef EXSTRINGS
char *seekpt;
#else
# ifdef lint
char *seekpt;
# else
int seekpt;
# endif
#endif
{
#ifndef EXSTRINGS
strcpy(linebuf, seekpt);
#else
lseek(erfile, (long) seekpt, 0);
if (read(erfile, linebuf, 128) < 2)
CP(linebuf, "ERROR");
#endif
}
morelines()
{
#ifdef UNIX_SBRK
char *sbrk();
if ((int) sbrk(1024 * sizeof (line)) == -1)
return (-1);
endcore += 1024;
return (0);
#else
/*
* We can never be guaranteed that we can get more memory
* beyond "endcore". So we just punt every time.
*/
return -1;
#endif
}
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;
ex_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)
ex_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)
#ifdef UNIX_SBRK
error("Out of memory@saving lines for undo - try using ed");
#else
error("Out of memory@saving lines for undo - try increasing linelimit");
#endif
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);
}
ex_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);
}
char *
strend(cp)
register char *cp;
{
while (*cp)
cp++;
return (cp);
}
strcLIN(dp)
char *dp;
{
CP(linebuf, dp);
}
syserror()
{
register int e = errno;
#ifndef vms
extern int sys_nerr;
extern char *sys_errlist[];
#else
extern noshare int sys_nerr;
extern noshare char *sys_errlist[];
#endif
dirtcnt = 0;
ex_putchar(' ');
if (e >= 0 && e <= sys_nerr)
error(sys_errlist[e]);
else
#ifdef vms
if (e == EVMSERR) {
error("VMS system error %d", vaxc$errno);
perror("vmserror");
}
else
#endif
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++)
ex_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();
}
/*
* The following code is defensive programming against a bug in the
* pdp-11 overlay implementation. Sometimes it goes nuts and asks
* for an overlay with some garbage number, which generates an emt
* trap. This is a less than elegant solution, but it is somewhat
* better than core dumping and losing your work, leaving your tty
* in a weird state, etc.
*/
int _ovno;
onemt()
{
signal(SIGEMT, onemt);
/* 2 and 3 are valid on 11/40 type vi, so */
if (_ovno < 0 || _ovno > 3)
_ovno = 0;
error("emt trap, _ovno is %d @ - try again");
}
/*
* When a hangup occurs our actions are similar to a preserve
* command. If the buffer has not been [Modified], then we do
* nothing but remove the temporary files and exit.
* Otherwise, we sync the temp file and then attempt a preserve.
* If the preserve succeeds, we unlink our temp files.
* If the preserve fails, we leave the temp files as they are
* as they are a backup even without preservation if they
* are not removed.
*/
onhup()
{
/*
* USG tty driver can send multiple HUP's!!
*/
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
if (chng == 0) {
cleanup(1);
ex_exit(0);
}
if (setexit() == 0) {
if (preserve()) {
cleanup(1);
ex_exit(0);
}
}
ex_exit(1);
}
/*
* An interrupt occurred. Drain any output which
* is still in the output buffering pipeline.
* Catch interrupts again. Unless we are in visual
* reset the output state (out of -nl mode, e.g).
* Then like a normal error (with the \n before Interrupt
* suppressed in visual mode).
*/
onintr()
{
#ifndef CBREAK
signal(SIGINT, onintr);
#else
signal(SIGINT, inopen ? vintr : onintr);
#endif
alarm(0); /* in case we were called from map */
draino();
if (!inopen) {
pstop();
setlastchar('\n');
#ifdef CBREAK
}
#else
} else
vraw();
#endif
error("\nInterrupt" + inopen);
}
/*
* If we are interruptible, enable interrupts again.
* In some critical sections we turn interrupts off,
* but not very often.
*/
setrupt()
{
if (ruptible) {
#ifndef CBREAK
signal(SIGINT, onintr);
#else
signal(SIGINT, inopen ? vintr : onintr);
#endif
#ifdef SIGTSTP
if (dosusp)
signal(SIGTSTP, onsusp);
#endif
}
}
preserve()
{
#ifdef VMUNIX
tflush();
#endif
synctmp();
pid = vfork();
if (pid < 0)
return (0);
if (pid == 0) {
close(0);
dup(tfile);
execl(_PATH_EXPRESERVE, "expreserve", (char *) 0);
ex_exit(1);
}
waitfor();
if (rpid == pid && status == 0)
return (1);
return (0);
}
#ifndef V6
ex_exit(i)
int i;
{
# ifdef TRACE
if (trace)
fclose(trace);
# endif
_exit(i);
}
#endif
#ifdef SIGTSTP
/*
* We have just gotten a susp. Suspend and prepare to resume.
*/
onsusp()
{
ttymode f;
struct winsize win;
f = setty(normf);
vnfl();
putpad(TE);
flush();
(void) sigsetmask(0);
signal(SIGTSTP, SIG_DFL);
kill(0, SIGTSTP);
/* the pc stops here */
signal(SIGTSTP, onsusp);
vcontin(0);
ignore(setty(f));
if (!inopen)
error((char *) 0);
else {
#ifdef TIOCGWINSZ
if (ioctl(0, TIOCGWINSZ, &win) >= 0)
if (win.ws_row != winsz.ws_row ||
win.ws_col != winsz.ws_col)
winch();
#endif
if (vcnt < 0) {
vcnt = -vcnt;
if (state == VISUAL)
vclear();
else if (state == CRTOPEN)
vcnt = 0;
}
vdirty(0, LINES);
vrepaint(cursor);
}
}
#endif