953 lines
14 KiB
C
953 lines
14 KiB
C
|
#define Extern extern
|
||
|
#include <sys/types.h>
|
||
|
#include <signal.h>
|
||
|
#include <errno.h>
|
||
|
#include <setjmp.h>
|
||
|
#include "sh.h"
|
||
|
/* -------- sh.c -------- */
|
||
|
/*
|
||
|
* shell
|
||
|
*/
|
||
|
|
||
|
/* #include "sh.h" */
|
||
|
|
||
|
int intr;
|
||
|
int inparse;
|
||
|
char flags['z'-'a'+1];
|
||
|
char *flag = flags-'a';
|
||
|
char *elinep = line+sizeof(line)-5;
|
||
|
char *null = "";
|
||
|
int heedint =1;
|
||
|
struct env e ={line, iostack, iostack-1,
|
||
|
(xint *)NULL, FDBASE, (struct env *)NULL};
|
||
|
|
||
|
extern char **environ; /* environment pointer */
|
||
|
|
||
|
/*
|
||
|
* default shell, search rules
|
||
|
*/
|
||
|
char shellname[] = "/bin/sh";
|
||
|
char search[] = ":/bin:/usr/bin";
|
||
|
|
||
|
_PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
|
||
|
|
||
|
_PROTOTYPE(int main, (int argc, char **argv ));
|
||
|
_PROTOTYPE(int newfile, (char *s ));
|
||
|
_PROTOTYPE(static char *findeq, (char *cp ));
|
||
|
_PROTOTYPE(static char *cclass, (char *p, int sub ));
|
||
|
_PROTOTYPE(void initarea, (void));
|
||
|
|
||
|
int main(argc, argv)
|
||
|
int argc;
|
||
|
register char **argv;
|
||
|
{
|
||
|
register int f;
|
||
|
register char *s;
|
||
|
int cflag;
|
||
|
char *name, **ap;
|
||
|
int (*iof)();
|
||
|
|
||
|
initarea();
|
||
|
if ((ap = environ) != NULL) {
|
||
|
while (*ap)
|
||
|
assign(*ap++, !COPYV);
|
||
|
for (ap = environ; *ap;)
|
||
|
export(lookup(*ap++));
|
||
|
}
|
||
|
closeall();
|
||
|
areanum = 1;
|
||
|
|
||
|
shell = lookup("SHELL");
|
||
|
if (shell->value == null)
|
||
|
setval(shell, shellname);
|
||
|
export(shell);
|
||
|
|
||
|
homedir = lookup("HOME");
|
||
|
if (homedir->value == null)
|
||
|
setval(homedir, "/");
|
||
|
export(homedir);
|
||
|
|
||
|
setval(lookup("$"), itoa(getpid(), 5));
|
||
|
|
||
|
path = lookup("PATH");
|
||
|
if (path->value == null)
|
||
|
setval(path, search);
|
||
|
export(path);
|
||
|
|
||
|
ifs = lookup("IFS");
|
||
|
if (ifs->value == null)
|
||
|
setval(ifs, " \t\n");
|
||
|
|
||
|
prompt = lookup("PS1");
|
||
|
if (prompt->value == null)
|
||
|
#ifndef UNIXSHELL
|
||
|
setval(prompt, "$ ");
|
||
|
#else
|
||
|
setval(prompt, "% ");
|
||
|
#endif
|
||
|
|
||
|
if (geteuid() == 0) {
|
||
|
setval(prompt, "# ");
|
||
|
prompt->status &= ~EXPORT;
|
||
|
}
|
||
|
cprompt = lookup("PS2");
|
||
|
if (cprompt->value == null)
|
||
|
setval(cprompt, "> ");
|
||
|
|
||
|
iof = filechar;
|
||
|
cflag = 0;
|
||
|
name = *argv++;
|
||
|
if (--argc >= 1) {
|
||
|
if(argv[0][0] == '-' && argv[0][1] != '\0') {
|
||
|
for (s = argv[0]+1; *s; s++)
|
||
|
switch (*s) {
|
||
|
case 'c':
|
||
|
prompt->status &= ~EXPORT;
|
||
|
cprompt->status &= ~EXPORT;
|
||
|
setval(prompt, "");
|
||
|
setval(cprompt, "");
|
||
|
cflag = 1;
|
||
|
if (--argc > 0)
|
||
|
PUSHIO(aword, *++argv, iof = nlchar);
|
||
|
break;
|
||
|
|
||
|
case 'q':
|
||
|
qflag = SIG_DFL;
|
||
|
break;
|
||
|
|
||
|
case 's':
|
||
|
/* standard input */
|
||
|
break;
|
||
|
|
||
|
case 't':
|
||
|
prompt->status &= ~EXPORT;
|
||
|
setval(prompt, "");
|
||
|
iof = linechar;
|
||
|
break;
|
||
|
|
||
|
case 'i':
|
||
|
talking++;
|
||
|
default:
|
||
|
if (*s>='a' && *s<='z')
|
||
|
flag[*s]++;
|
||
|
}
|
||
|
} else {
|
||
|
argv--;
|
||
|
argc++;
|
||
|
}
|
||
|
if (iof == filechar && --argc > 0) {
|
||
|
setval(prompt, "");
|
||
|
setval(cprompt, "");
|
||
|
prompt->status &= ~EXPORT;
|
||
|
cprompt->status &= ~EXPORT;
|
||
|
if (newfile(name = *++argv))
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
setdash();
|
||
|
if (e.iop < iostack) {
|
||
|
PUSHIO(afile, 0, iof);
|
||
|
if (isatty(0) && isatty(1) && !cflag)
|
||
|
talking++;
|
||
|
}
|
||
|
signal(SIGQUIT, qflag);
|
||
|
if (name && name[0] == '-') {
|
||
|
talking++;
|
||
|
if ((f = open(".profile", 0)) >= 0)
|
||
|
next(remap(f));
|
||
|
if ((f = open("/etc/profile", 0)) >= 0)
|
||
|
next(remap(f));
|
||
|
}
|
||
|
if (talking)
|
||
|
signal(SIGTERM, sig);
|
||
|
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||
|
signal(SIGINT, onintr);
|
||
|
dolv = argv;
|
||
|
dolc = argc;
|
||
|
dolv[0] = name;
|
||
|
if (dolc > 1)
|
||
|
for (ap = ++argv; --argc > 0;)
|
||
|
if (assign(*ap = *argv++, !COPYV))
|
||
|
dolc--; /* keyword */
|
||
|
else
|
||
|
ap++;
|
||
|
setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
|
||
|
|
||
|
for (;;) {
|
||
|
if (talking && e.iop <= iostack)
|
||
|
prs(prompt->value);
|
||
|
onecommand();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
setdash()
|
||
|
{
|
||
|
register char *cp, c;
|
||
|
char m['z'-'a'+1];
|
||
|
|
||
|
cp = m;
|
||
|
for (c='a'; c<='z'; c++)
|
||
|
if (flag[c])
|
||
|
*cp++ = c;
|
||
|
*cp = 0;
|
||
|
setval(lookup("-"), m);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
newfile(s)
|
||
|
register char *s;
|
||
|
{
|
||
|
register f;
|
||
|
|
||
|
if (strcmp(s, "-") != 0) {
|
||
|
f = open(s, 0);
|
||
|
if (f < 0) {
|
||
|
prs(s);
|
||
|
err(": cannot open");
|
||
|
return(1);
|
||
|
}
|
||
|
} else
|
||
|
f = 0;
|
||
|
next(remap(f));
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
onecommand()
|
||
|
{
|
||
|
register i;
|
||
|
jmp_buf m1;
|
||
|
|
||
|
while (e.oenv)
|
||
|
quitenv();
|
||
|
areanum = 1;
|
||
|
freehere(areanum);
|
||
|
freearea(areanum);
|
||
|
garbage();
|
||
|
wdlist = 0;
|
||
|
iolist = 0;
|
||
|
e.errpt = 0;
|
||
|
e.linep = line;
|
||
|
yynerrs = 0;
|
||
|
multiline = 0;
|
||
|
inparse = 1;
|
||
|
intr = 0;
|
||
|
execflg = 0;
|
||
|
setjmp(failpt = m1); /* Bruce Evans' fix */
|
||
|
if (setjmp(failpt = m1) || yyparse() || intr) {
|
||
|
while (e.oenv)
|
||
|
quitenv();
|
||
|
scraphere();
|
||
|
if (!talking && intr)
|
||
|
leave();
|
||
|
inparse = 0;
|
||
|
intr = 0;
|
||
|
return;
|
||
|
}
|
||
|
inparse = 0;
|
||
|
brklist = 0;
|
||
|
intr = 0;
|
||
|
execflg = 0;
|
||
|
if (!flag['n'])
|
||
|
execute(outtree, NOPIPE, NOPIPE, 0);
|
||
|
if (!talking && intr) {
|
||
|
execflg = 0;
|
||
|
leave();
|
||
|
}
|
||
|
if ((i = trapset) != 0) {
|
||
|
trapset = 0;
|
||
|
runtrap(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
fail()
|
||
|
{
|
||
|
longjmp(failpt, 1);
|
||
|
/* NOTREACHED */
|
||
|
}
|
||
|
|
||
|
void
|
||
|
leave()
|
||
|
{
|
||
|
if (execflg)
|
||
|
fail();
|
||
|
scraphere();
|
||
|
freehere(1);
|
||
|
runtrap(0);
|
||
|
exit(exstat);
|
||
|
/* NOTREACHED */
|
||
|
}
|
||
|
|
||
|
void
|
||
|
warn(s)
|
||
|
register char *s;
|
||
|
{
|
||
|
if(*s) {
|
||
|
prs(s);
|
||
|
exstat = -1;
|
||
|
}
|
||
|
prs("\n");
|
||
|
if (flag['e'])
|
||
|
leave();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
err(s)
|
||
|
char *s;
|
||
|
{
|
||
|
warn(s);
|
||
|
if (flag['n'])
|
||
|
return;
|
||
|
if (!talking)
|
||
|
leave();
|
||
|
if (e.errpt)
|
||
|
longjmp(e.errpt, 1);
|
||
|
closeall();
|
||
|
e.iop = e.iobase = iostack;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
newenv(f)
|
||
|
int f;
|
||
|
{
|
||
|
register struct env *ep;
|
||
|
|
||
|
if (f) {
|
||
|
quitenv();
|
||
|
return(1);
|
||
|
}
|
||
|
ep = (struct env *) space(sizeof(*ep));
|
||
|
if (ep == NULL) {
|
||
|
while (e.oenv)
|
||
|
quitenv();
|
||
|
fail();
|
||
|
}
|
||
|
*ep = e;
|
||
|
e.oenv = ep;
|
||
|
e.errpt = errpt;
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
quitenv()
|
||
|
{
|
||
|
register struct env *ep;
|
||
|
register fd;
|
||
|
|
||
|
if ((ep = e.oenv) != NULL) {
|
||
|
fd = e.iofd;
|
||
|
e = *ep;
|
||
|
/* should close `'d files */
|
||
|
DELETE(ep);
|
||
|
while (--fd >= e.iofd)
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Is any character from s1 in s2?
|
||
|
*/
|
||
|
int
|
||
|
anys(s1, s2)
|
||
|
register char *s1, *s2;
|
||
|
{
|
||
|
while (*s1)
|
||
|
if (any(*s1++, s2))
|
||
|
return(1);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Is character c in s?
|
||
|
*/
|
||
|
int
|
||
|
any(c, s)
|
||
|
register int c;
|
||
|
register char *s;
|
||
|
{
|
||
|
while (*s)
|
||
|
if (*s++ == c)
|
||
|
return(1);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
putn(n)
|
||
|
register int n;
|
||
|
{
|
||
|
return(itoa(n, -1));
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
itoa(u, n)
|
||
|
register unsigned u;
|
||
|
int n;
|
||
|
{
|
||
|
register char *cp;
|
||
|
static char s[20];
|
||
|
int m;
|
||
|
|
||
|
m = 0;
|
||
|
if (n < 0 && (int) u < 0) {
|
||
|
m++;
|
||
|
u = -u;
|
||
|
}
|
||
|
cp = s+sizeof(s);
|
||
|
*--cp = 0;
|
||
|
do {
|
||
|
*--cp = u%10 + '0';
|
||
|
u /= 10;
|
||
|
} while (--n > 0 || u);
|
||
|
if (m)
|
||
|
*--cp = '-';
|
||
|
return(cp);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
next(f)
|
||
|
int f;
|
||
|
{
|
||
|
PUSHIO(afile, f, filechar);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
onintr(s)
|
||
|
int s; /* ANSI C requires a parameter */
|
||
|
{
|
||
|
signal(SIGINT, onintr);
|
||
|
intr = 1;
|
||
|
if (talking) {
|
||
|
if (inparse) {
|
||
|
prs("\n");
|
||
|
fail();
|
||
|
}
|
||
|
}
|
||
|
else if (heedint) {
|
||
|
execflg = 0;
|
||
|
leave();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
letter(c)
|
||
|
register c;
|
||
|
{
|
||
|
return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
|
||
|
}
|
||
|
|
||
|
int
|
||
|
digit(c)
|
||
|
register c;
|
||
|
{
|
||
|
return(c >= '0' && c <= '9');
|
||
|
}
|
||
|
|
||
|
int
|
||
|
letnum(c)
|
||
|
register c;
|
||
|
{
|
||
|
return(letter(c) || digit(c));
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
space(n)
|
||
|
int n;
|
||
|
{
|
||
|
register char *cp;
|
||
|
|
||
|
if ((cp = getcell(n)) == 0)
|
||
|
err("out of string space");
|
||
|
return(cp);
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
strsave(s, a)
|
||
|
register char *s;
|
||
|
int a;
|
||
|
{
|
||
|
register char *cp, *xp;
|
||
|
|
||
|
if ((cp = space(strlen(s)+1)) != NULL) {
|
||
|
setarea((char *)cp, a);
|
||
|
for (xp = cp; (*xp++ = *s++) != '\0';)
|
||
|
;
|
||
|
return(cp);
|
||
|
}
|
||
|
return("");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
xfree(s)
|
||
|
register char *s;
|
||
|
{
|
||
|
DELETE(s);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* trap handling
|
||
|
*/
|
||
|
void
|
||
|
sig(i)
|
||
|
register int i;
|
||
|
{
|
||
|
trapset = i;
|
||
|
signal(i, sig);
|
||
|
}
|
||
|
|
||
|
void runtrap(i)
|
||
|
int i;
|
||
|
{
|
||
|
char *trapstr;
|
||
|
|
||
|
if ((trapstr = trap[i]) == NULL)
|
||
|
return;
|
||
|
if (i == 0)
|
||
|
trap[i] = 0;
|
||
|
RUN(aword, trapstr, nlchar);
|
||
|
}
|
||
|
|
||
|
/* -------- var.c -------- */
|
||
|
/* #include "sh.h" */
|
||
|
|
||
|
/*
|
||
|
* Find the given name in the dictionary
|
||
|
* and return its value. If the name was
|
||
|
* not previously there, enter it now and
|
||
|
* return a null value.
|
||
|
*/
|
||
|
struct var *
|
||
|
lookup(n)
|
||
|
register char *n;
|
||
|
{
|
||
|
register struct var *vp;
|
||
|
register char *cp;
|
||
|
register int c;
|
||
|
static struct var dummy;
|
||
|
|
||
|
if (digit(*n)) {
|
||
|
dummy.name = n;
|
||
|
for (c = 0; digit(*n) && c < 1000; n++)
|
||
|
c = c*10 + *n-'0';
|
||
|
dummy.status = RONLY;
|
||
|
dummy.value = c <= dolc? dolv[c]: null;
|
||
|
return(&dummy);
|
||
|
}
|
||
|
for (vp = vlist; vp; vp = vp->next)
|
||
|
if (eqname(vp->name, n))
|
||
|
return(vp);
|
||
|
cp = findeq(n);
|
||
|
vp = (struct var *)space(sizeof(*vp));
|
||
|
if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
|
||
|
dummy.name = dummy.value = "";
|
||
|
return(&dummy);
|
||
|
}
|
||
|
for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
|
||
|
;
|
||
|
if (*cp == 0)
|
||
|
*cp = '=';
|
||
|
*++cp = 0;
|
||
|
setarea((char *)vp, 0);
|
||
|
setarea((char *)vp->name, 0);
|
||
|
vp->value = null;
|
||
|
vp->next = vlist;
|
||
|
vp->status = GETCELL;
|
||
|
vlist = vp;
|
||
|
return(vp);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* give variable at `vp' the value `val'.
|
||
|
*/
|
||
|
void
|
||
|
setval(vp, val)
|
||
|
struct var *vp;
|
||
|
char *val;
|
||
|
{
|
||
|
nameval(vp, val, (char *)NULL);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* if name is not NULL, it must be
|
||
|
* a prefix of the space `val',
|
||
|
* and end with `='.
|
||
|
* this is all so that exporting
|
||
|
* values is reasonably painless.
|
||
|
*/
|
||
|
void
|
||
|
nameval(vp, val, name)
|
||
|
register struct var *vp;
|
||
|
char *val, *name;
|
||
|
{
|
||
|
register char *cp, *xp;
|
||
|
char *nv;
|
||
|
int fl;
|
||
|
|
||
|
if (vp->status & RONLY) {
|
||
|
for (xp = vp->name; *xp && *xp != '=';)
|
||
|
putc(*xp++);
|
||
|
err(" is read-only");
|
||
|
return;
|
||
|
}
|
||
|
fl = 0;
|
||
|
if (name == NULL) {
|
||
|
xp = space(strlen(vp->name)+strlen(val)+2);
|
||
|
if (xp == 0)
|
||
|
return;
|
||
|
/* make string: name=value */
|
||
|
setarea((char *)xp, 0);
|
||
|
name = xp;
|
||
|
for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
|
||
|
;
|
||
|
if (*xp++ == 0)
|
||
|
xp[-1] = '=';
|
||
|
nv = xp;
|
||
|
for (cp = val; (*xp++ = *cp++) != '\0';)
|
||
|
;
|
||
|
val = nv;
|
||
|
fl = GETCELL;
|
||
|
}
|
||
|
if (vp->status & GETCELL)
|
||
|
xfree(vp->name); /* form new string `name=value' */
|
||
|
vp->name = name;
|
||
|
vp->value = val;
|
||
|
vp->status |= fl;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
export(vp)
|
||
|
struct var *vp;
|
||
|
{
|
||
|
vp->status |= EXPORT;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ronly(vp)
|
||
|
struct var *vp;
|
||
|
{
|
||
|
if (letter(vp->name[0])) /* not an internal symbol ($# etc) */
|
||
|
vp->status |= RONLY;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
isassign(s)
|
||
|
register char *s;
|
||
|
{
|
||
|
if (!letter((int)*s))
|
||
|
return(0);
|
||
|
for (; *s != '='; s++)
|
||
|
if (*s == 0 || !letnum(*s))
|
||
|
return(0);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
assign(s, cf)
|
||
|
register char *s;
|
||
|
int cf;
|
||
|
{
|
||
|
register char *cp;
|
||
|
struct var *vp;
|
||
|
|
||
|
if (!letter(*s))
|
||
|
return(0);
|
||
|
for (cp = s; *cp != '='; cp++)
|
||
|
if (*cp == 0 || !letnum(*cp))
|
||
|
return(0);
|
||
|
vp = lookup(s);
|
||
|
nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
|
||
|
if (cf != COPYV)
|
||
|
vp->status &= ~GETCELL;
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
checkname(cp)
|
||
|
register char *cp;
|
||
|
{
|
||
|
if (!letter(*cp++))
|
||
|
return(0);
|
||
|
while (*cp)
|
||
|
if (!letnum(*cp++))
|
||
|
return(0);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
putvlist(f, out)
|
||
|
register int f, out;
|
||
|
{
|
||
|
register struct var *vp;
|
||
|
|
||
|
for (vp = vlist; vp; vp = vp->next)
|
||
|
if (vp->status & f && letter(*vp->name)) {
|
||
|
if (vp->status & EXPORT)
|
||
|
write(out, "export ", 7);
|
||
|
if (vp->status & RONLY)
|
||
|
write(out, "readonly ", 9);
|
||
|
write(out, vp->name, (int)(findeq(vp->name) - vp->name));
|
||
|
write(out, "\n", 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
eqname(n1, n2)
|
||
|
register char *n1, *n2;
|
||
|
{
|
||
|
for (; *n1 != '=' && *n1 != 0; n1++)
|
||
|
if (*n2++ != *n1)
|
||
|
return(0);
|
||
|
return(*n2 == 0 || *n2 == '=');
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
findeq(cp)
|
||
|
register char *cp;
|
||
|
{
|
||
|
while (*cp != '\0' && *cp != '=')
|
||
|
cp++;
|
||
|
return(cp);
|
||
|
}
|
||
|
|
||
|
/* -------- gmatch.c -------- */
|
||
|
/*
|
||
|
* int gmatch(string, pattern)
|
||
|
* char *string, *pattern;
|
||
|
*
|
||
|
* Match a pattern as in sh(1).
|
||
|
*/
|
||
|
|
||
|
#define CMASK 0377
|
||
|
#define QUOTE 0200
|
||
|
#define QMASK (CMASK&~QUOTE)
|
||
|
#define NOT '!' /* might use ^ */
|
||
|
|
||
|
int
|
||
|
gmatch(s, p)
|
||
|
register char *s, *p;
|
||
|
{
|
||
|
register int sc, pc;
|
||
|
|
||
|
if (s == NULL || p == NULL)
|
||
|
return(0);
|
||
|
while ((pc = *p++ & CMASK) != '\0') {
|
||
|
sc = *s++ & QMASK;
|
||
|
switch (pc) {
|
||
|
case '[':
|
||
|
if ((p = cclass(p, sc)) == NULL)
|
||
|
return(0);
|
||
|
break;
|
||
|
|
||
|
case '?':
|
||
|
if (sc == 0)
|
||
|
return(0);
|
||
|
break;
|
||
|
|
||
|
case '*':
|
||
|
s--;
|
||
|
do {
|
||
|
if (*p == '\0' || gmatch(s, p))
|
||
|
return(1);
|
||
|
} while (*s++ != '\0');
|
||
|
return(0);
|
||
|
|
||
|
default:
|
||
|
if (sc != (pc&~QUOTE))
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
return(*s == 0);
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
cclass(p, sub)
|
||
|
register char *p;
|
||
|
register int sub;
|
||
|
{
|
||
|
register int c, d, not, found;
|
||
|
|
||
|
if ((not = *p == NOT) != 0)
|
||
|
p++;
|
||
|
found = not;
|
||
|
do {
|
||
|
if (*p == '\0')
|
||
|
return((char *)NULL);
|
||
|
c = *p & CMASK;
|
||
|
if (p[1] == '-' && p[2] != ']') {
|
||
|
d = p[2] & CMASK;
|
||
|
p++;
|
||
|
} else
|
||
|
d = c;
|
||
|
if (c == sub || (c <= sub && sub <= d))
|
||
|
found = !not;
|
||
|
} while (*++p != ']');
|
||
|
return(found? p+1: (char *)NULL);
|
||
|
}
|
||
|
|
||
|
/* -------- area.c -------- */
|
||
|
#define REGSIZE sizeof(struct region)
|
||
|
#define GROWBY 256
|
||
|
#undef SHRINKBY 64
|
||
|
#define FREE 32767
|
||
|
#define BUSY 0
|
||
|
#define ALIGN (sizeof(int)-1)
|
||
|
|
||
|
/* #include "area.h" */
|
||
|
|
||
|
struct region {
|
||
|
struct region *next;
|
||
|
int area;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* All memory between (char *)areabot and (char *)(areatop+1) is
|
||
|
* exclusively administered by the area management routines.
|
||
|
* It is assumed that sbrk() and brk() manipulate the high end.
|
||
|
*/
|
||
|
static struct region *areabot; /* bottom of area */
|
||
|
static struct region *areatop; /* top of area */
|
||
|
static struct region *areanxt; /* starting point of scan */
|
||
|
|
||
|
void
|
||
|
initarea()
|
||
|
{
|
||
|
while ((int)sbrk(0) & ALIGN)
|
||
|
sbrk(1);
|
||
|
areabot = (struct region *)sbrk(REGSIZE);
|
||
|
areabot->next = areabot;
|
||
|
areabot->area = BUSY;
|
||
|
areatop = areabot;
|
||
|
areanxt = areabot;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
getcell(nbytes)
|
||
|
unsigned nbytes;
|
||
|
{
|
||
|
register int nregio;
|
||
|
register struct region *p, *q;
|
||
|
register i;
|
||
|
|
||
|
if (nbytes == 0)
|
||
|
abort(); /* silly and defeats the algorithm */
|
||
|
/*
|
||
|
* round upwards and add administration area
|
||
|
*/
|
||
|
nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
|
||
|
for (p = areanxt;;) {
|
||
|
if (p->area > areanum) {
|
||
|
/*
|
||
|
* merge free cells
|
||
|
*/
|
||
|
while ((q = p->next)->area > areanum && q != areanxt)
|
||
|
p->next = q->next;
|
||
|
/*
|
||
|
* exit loop if cell big enough
|
||
|
*/
|
||
|
if (q >= p + nregio)
|
||
|
goto found;
|
||
|
}
|
||
|
p = p->next;
|
||
|
if (p == areanxt)
|
||
|
break;
|
||
|
}
|
||
|
i = nregio >= GROWBY ? nregio : GROWBY;
|
||
|
p = (struct region *)sbrk(i * REGSIZE);
|
||
|
if (p == (struct region *)-1)
|
||
|
return((char *)NULL);
|
||
|
p--;
|
||
|
if (p != areatop)
|
||
|
abort(); /* allocated areas are contiguous */
|
||
|
q = p + i;
|
||
|
p->next = q;
|
||
|
p->area = FREE;
|
||
|
q->next = areabot;
|
||
|
q->area = BUSY;
|
||
|
areatop = q;
|
||
|
found:
|
||
|
/*
|
||
|
* we found a FREE area big enough, pointed to by 'p', and up to 'q'
|
||
|
*/
|
||
|
areanxt = p + nregio;
|
||
|
if (areanxt < q) {
|
||
|
/*
|
||
|
* split into requested area and rest
|
||
|
*/
|
||
|
if (areanxt+1 > q)
|
||
|
abort(); /* insufficient space left for admin */
|
||
|
areanxt->next = q;
|
||
|
areanxt->area = FREE;
|
||
|
p->next = areanxt;
|
||
|
}
|
||
|
p->area = areanum;
|
||
|
return((char *)(p+1));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
freecell(cp)
|
||
|
char *cp;
|
||
|
{
|
||
|
register struct region *p;
|
||
|
|
||
|
if ((p = (struct region *)cp) != NULL) {
|
||
|
p--;
|
||
|
if (p < areanxt)
|
||
|
areanxt = p;
|
||
|
p->area = FREE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
freearea(a)
|
||
|
register int a;
|
||
|
{
|
||
|
register struct region *p, *top;
|
||
|
|
||
|
top = areatop;
|
||
|
for (p = areabot; p != top; p = p->next)
|
||
|
if (p->area >= a)
|
||
|
p->area = FREE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
setarea(cp,a)
|
||
|
char *cp;
|
||
|
int a;
|
||
|
{
|
||
|
register struct region *p;
|
||
|
|
||
|
if ((p = (struct region *)cp) != NULL)
|
||
|
(p-1)->area = a;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
getarea(cp)
|
||
|
char *cp;
|
||
|
{
|
||
|
return ((struct region*)cp-1)->area;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
garbage()
|
||
|
{
|
||
|
register struct region *p, *q, *top;
|
||
|
|
||
|
top = areatop;
|
||
|
for (p = areabot; p != top; p = p->next) {
|
||
|
if (p->area > areanum) {
|
||
|
while ((q = p->next)->area > areanum)
|
||
|
p->next = q->next;
|
||
|
areanxt = p;
|
||
|
}
|
||
|
}
|
||
|
#ifdef SHRINKBY
|
||
|
if (areatop >= q + SHRINKBY && q->area > areanum) {
|
||
|
brk((char *)(q+1));
|
||
|
q->next = areabot;
|
||
|
q->area = BUSY;
|
||
|
areatop = q;
|
||
|
}
|
||
|
#endif
|
||
|
}
|