139213Sgibbs#define Extern extern
239213Sgibbs#include <sys/types.h>
339213Sgibbs#include <signal.h>
439213Sgibbs#define _NSIG NSIG
539213Sgibbs#include <errno.h>
639213Sgibbs#include <setjmp.h>
739213Sgibbs#include "sh.h"
839213Sgibbs/* -------- sh.c -------- */
939213Sgibbs/*
1039213Sgibbs * shell
1139213Sgibbs */
1239213Sgibbs
1339213Sgibbs/* #include "sh.h" */
1439213Sgibbs
1539213Sgibbsint	intr;
1639213Sgibbsint	inparse;
1739213Sgibbschar	flags['z'-'a'+1];
1839213Sgibbschar	*flag = flags-'a';
1939213Sgibbschar	*elinep = line+sizeof(line)-5;
2039213Sgibbschar	*null	= "";
2139213Sgibbsint	heedint =1;
2239213Sgibbsstruct	env	e ={line, iostack, iostack-1,
2339213Sgibbs		    (xint *)NULL, FDBASE, (struct env *)NULL};
2439213Sgibbs
2539213Sgibbsextern	char	**environ;	/* environment pointer */
2639213Sgibbs
2739213Sgibbs/*
2850477Speter * default shell, search rules
2939213Sgibbs */
3039213Sgibbschar	shellname[] = "/bin/sh";
3139213Sgibbschar	search[] = ":/bin:/usr/bin";
3239213Sgibbs
3339213Sgibbs_PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
3439213Sgibbs
3539213Sgibbs_PROTOTYPE(int main, (int argc, char **argv ));
3660041Sphk_PROTOTYPE(int newfile, (char *s ));
3739213Sgibbs_PROTOTYPE(static char *findeq, (char *cp ));
3839213Sgibbs_PROTOTYPE(static char *cclass, (char *p, int sub ));
3939213Sgibbs_PROTOTYPE(void initarea, (void));
4050073Sken
4139213Sgibbsint main(argc, argv)
4239213Sgibbsint argc;
4339213Sgibbsregister char **argv;
4439213Sgibbs{
4539213Sgibbs	register int f;
4639213Sgibbs	register char *s;
4739213Sgibbs	int cflag;
4839213Sgibbs	char *name, **ap;
4939213Sgibbs	int (*iof)();
5039213Sgibbs
5139213Sgibbs	initarea();
5239213Sgibbs	if ((ap = environ) != NULL) {
5350073Sken		while (*ap)
5450073Sken			assign(*ap++, !COPYV);
5539213Sgibbs		for (ap = environ; *ap;)
5639213Sgibbs			export(lookup(*ap++));
5739213Sgibbs	}
5839213Sgibbs	closeall();
5939213Sgibbs	areanum = 1;
6039213Sgibbs
6139213Sgibbs	shell = lookup("SHELL");
6239213Sgibbs	if (shell->value == null)
6339213Sgibbs		setval(shell, shellname);
6439213Sgibbs	export(shell);
6539213Sgibbs
6639213Sgibbs	homedir = lookup("HOME");
6739213Sgibbs	if (homedir->value == null)
6839213Sgibbs		setval(homedir, "/");
6939213Sgibbs	export(homedir);
7039213Sgibbs
7139213Sgibbs	setval(lookup("$"), itoa(getpid(), 5));
7239213Sgibbs
7339213Sgibbs	path = lookup("PATH");
7439213Sgibbs	if (path->value == null)
7539213Sgibbs		setval(path, search);
7639213Sgibbs	export(path);
7739213Sgibbs
7839213Sgibbs	ifs = lookup("IFS");
7959249Sphk	if (ifs->value == null)
8039213Sgibbs		setval(ifs, " \t\n");
8160938Sjake
8239213Sgibbs	prompt = lookup("PS1");
8339213Sgibbs	if (prompt->value == null)
8439213Sgibbs#ifndef UNIXSHELL
8550073Sken		setval(prompt, "$ ");
8653257Sken#else
8739213Sgibbs		setval(prompt, "% ");
8839213Sgibbs#endif
8939213Sgibbs
9039213Sgibbs	if (geteuid() == 0) {
9139213Sgibbs		setval(prompt, "# ");
9239213Sgibbs		prompt->status &= ~EXPORT;
9339213Sgibbs	}
9439213Sgibbs	cprompt = lookup("PS2");
9539213Sgibbs	if (cprompt->value == null)
9640603Sken		setval(cprompt, "> ");
9739213Sgibbs
9839213Sgibbs	iof = filechar;
9939213Sgibbs	cflag = 0;
10039213Sgibbs	name = *argv++;
10150073Sken	if (--argc >= 1) {
10239213Sgibbs		if(argv[0][0] == '-' && argv[0][1] != '\0') {
10339213Sgibbs			for (s = argv[0]+1; *s; s++)
10439213Sgibbs				switch (*s) {
10539213Sgibbs				case 'c':
10639213Sgibbs					prompt->status &= ~EXPORT;
10739213Sgibbs					cprompt->status &= ~EXPORT;
10839213Sgibbs					setval(prompt, "");
10939213Sgibbs					setval(cprompt, "");
11039213Sgibbs					cflag = 1;
11139213Sgibbs					if (--argc > 0)
11239213Sgibbs						PUSHIO(aword, *++argv, iof = nlchar);
11339213Sgibbs					break;
11439213Sgibbs
11539213Sgibbs				case 'q':
11639213Sgibbs					qflag = SIG_DFL;
11739213Sgibbs					break;
11839213Sgibbs
11939213Sgibbs				case 's':
12039213Sgibbs					/* standard input */
12147625Sphk					break;
12247625Sphk
12347625Sphk				case 't':
12447625Sphk					prompt->status &= ~EXPORT;
12547625Sphk					setval(prompt, "");
12650073Sken					iof = linechar;
12747625Sphk					break;
12847625Sphk
12947625Sphk				case 'i':
13047625Sphk					talking++;
13147625Sphk				default:
13247625Sphk					if (*s>='a' && *s<='z')
13347625Sphk						flag[*s]++;
13447625Sphk				}
13547625Sphk		} else {
13639213Sgibbs			argv--;
13739213Sgibbs			argc++;
13839213Sgibbs		}
13939213Sgibbs		if (iof == filechar && --argc > 0) {
14050073Sken			setval(prompt, "");
14150073Sken			setval(cprompt, "");
14250073Sken			prompt->status &= ~EXPORT;
14350073Sken			cprompt->status &= ~EXPORT;
14439213Sgibbs			if (newfile(name = *++argv))
14539213Sgibbs				exit(1);
14639213Sgibbs		}
14739213Sgibbs	}
14839213Sgibbs	setdash();
14939213Sgibbs	if (e.iop < iostack) {
15039213Sgibbs		PUSHIO(afile, 0, iof);
15140603Sken		if (isatty(0) && isatty(1) && !cflag)
15239213Sgibbs			talking++;
15339213Sgibbs	}
15439213Sgibbs	signal(SIGQUIT, qflag);
15539213Sgibbs	if (name && name[0] == '-') {
15639213Sgibbs		talking++;
15739213Sgibbs		if ((f = open(".profile", 0)) >= 0)
15839213Sgibbs			next(remap(f));
15939213Sgibbs		if ((f = open("/etc/profile", 0)) >= 0)
16040603Sken			next(remap(f));
16140603Sken	}
16240603Sken	if (talking)
16340603Sken		signal(SIGTERM, sig);
16440603Sken	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
16540603Sken		signal(SIGINT, onintr);
16639213Sgibbs	dolv = argv;
16749982Sbillf	dolc = argc;
16839213Sgibbs	dolv[0] = name;
16941297Sken	if (dolc > 1)
17041297Sken		for (ap = ++argv; --argc > 0;)
17139213Sgibbs			if (assign(*ap = *argv++, !COPYV))
17241297Sken				dolc--;	/* keyword */
17339213Sgibbs			else
17441297Sken				ap++;
17541297Sken	setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
17639213Sgibbs
17739213Sgibbs	for (;;) {
17839213Sgibbs		if (talking && e.iop <= iostack)
17939213Sgibbs			prs(prompt->value);
18039213Sgibbs		onecommand();
18139213Sgibbs	}
18239213Sgibbs}
18339213Sgibbs
18439213Sgibbsvoid
18539213Sgibbssetdash()
18639213Sgibbs{
18739213Sgibbs	register char *cp, c;
18839213Sgibbs	char m['z'-'a'+1];
18939213Sgibbs
19039213Sgibbs	cp = m;
19139213Sgibbs	for (c='a'; c<='z'; c++)
19239213Sgibbs		if (flag[c])
19339213Sgibbs			*cp++ = c;
19439213Sgibbs	*cp = 0;
19539213Sgibbs	setval(lookup("-"), m);
19639213Sgibbs}
19739213Sgibbs
19839213Sgibbsint
19939213Sgibbsnewfile(s)
20039213Sgibbsregister char *s;
20139213Sgibbs{
20239213Sgibbs	register f;
20339213Sgibbs
20439213Sgibbs	if (strcmp(s, "-") != 0) {
20539213Sgibbs		f = open(s, 0);
20639213Sgibbs		if (f < 0) {
20739213Sgibbs			prs(s);
20839213Sgibbs			err(": cannot open");
20939213Sgibbs			return(1);
21039213Sgibbs		}
21139213Sgibbs	} else
21239213Sgibbs		f = 0;
21339213Sgibbs	next(remap(f));
21439213Sgibbs	return(0);
21539213Sgibbs}
21639213Sgibbs
21739213Sgibbsvoid
21859249Sphkonecommand()
21939213Sgibbs{
22039213Sgibbs	register i;
22139213Sgibbs	jmp_buf m1;
22239213Sgibbs
22339213Sgibbs	while (e.oenv)
22439213Sgibbs		quitenv();
22559249Sphk	areanum = 1;
22639213Sgibbs	freehere(areanum);
22739213Sgibbs	freearea(areanum);
22859249Sphk	garbage();
22939213Sgibbs	wdlist = 0;
23039213Sgibbs	iolist = 0;
23139213Sgibbs	e.errpt = 0;
23239213Sgibbs	e.linep = line;
23339213Sgibbs	yynerrs = 0;
23439213Sgibbs	multiline = 0;
23539213Sgibbs	inparse = 1;
23639213Sgibbs	intr = 0;
23739213Sgibbs	execflg = 0;
23839213Sgibbs	setjmp(failpt = m1);	/* Bruce Evans' fix */
23939213Sgibbs	if (setjmp(failpt = m1) || yyparse() || intr) {
24039213Sgibbs		while (e.oenv)
24139213Sgibbs			quitenv();
24239213Sgibbs		scraphere();
24339213Sgibbs		if (!talking && intr)
24439213Sgibbs			leave();
24559249Sphk		inparse = 0;
24639213Sgibbs		intr = 0;
24739213Sgibbs		return;
24839213Sgibbs	}
24939213Sgibbs	inparse = 0;
25039213Sgibbs	brklist = 0;
25139213Sgibbs	intr = 0;
25259249Sphk	execflg = 0;
25339213Sgibbs	if (!flag['n'])
25439213Sgibbs		execute(outtree, NOPIPE, NOPIPE, 0);
25539213Sgibbs	if (!talking && intr) {
25639213Sgibbs		execflg = 0;
25739213Sgibbs		leave();
25839213Sgibbs	}
25939213Sgibbs	if ((i = trapset) != 0) {
26039213Sgibbs		trapset = 0;
26139213Sgibbs		runtrap(i);
26239213Sgibbs	}
26359249Sphk}
26439213Sgibbs
26539213Sgibbsvoid
26639213Sgibbsfail()
26739213Sgibbs{
26859249Sphk	longjmp(failpt, 1);
26939213Sgibbs	/* NOTREACHED */
27039213Sgibbs}
27139213Sgibbs
27239213Sgibbsvoid
27339213Sgibbsleave()
27439213Sgibbs{
27539213Sgibbs	if (execflg)
27639213Sgibbs		fail();
27739213Sgibbs	scraphere();
27839213Sgibbs	freehere(1);
27939213Sgibbs	runtrap(0);
28039213Sgibbs	exit(exstat);
28139213Sgibbs	/* NOTREACHED */
28239213Sgibbs}
28339213Sgibbs
28439213Sgibbsvoid
28539213Sgibbswarn(s)
28639213Sgibbsregister char *s;
28739213Sgibbs{
28839213Sgibbs	if(*s) {
28939213Sgibbs		prs(s);
29039213Sgibbs		exstat = -1;
29139213Sgibbs	}
29239213Sgibbs	prs("\n");
29339213Sgibbs	if (flag['e'])
29439213Sgibbs		leave();
29539213Sgibbs}
29639213Sgibbs
29739213Sgibbsvoid
29839213Sgibbserr(s)
29939213Sgibbschar *s;
30039213Sgibbs{
30139213Sgibbs	warn(s);
30239213Sgibbs	if (flag['n'])
30339213Sgibbs		return;
30439213Sgibbs	if (!talking)
30539213Sgibbs		leave();
30639213Sgibbs	if (e.errpt)
30739213Sgibbs		longjmp(e.errpt, 1);
30839213Sgibbs	closeall();
30939213Sgibbs	e.iop = e.iobase = iostack;
31039213Sgibbs}
31139213Sgibbs
31239213Sgibbsint
31339213Sgibbsnewenv(f)
31439213Sgibbsint f;
31539213Sgibbs{
31639213Sgibbs	register struct env *ep;
31739213Sgibbs
31839213Sgibbs	if (f) {
31939213Sgibbs		quitenv();
32039213Sgibbs		return(1);
32139213Sgibbs	}
32239213Sgibbs	ep = (struct env *) space(sizeof(*ep));
32339213Sgibbs	if (ep == NULL) {
32439213Sgibbs		while (e.oenv)
32539213Sgibbs			quitenv();
32639213Sgibbs		fail();
32739213Sgibbs	}
32839213Sgibbs	*ep = e;
32939213Sgibbs	e.oenv = ep;
33039213Sgibbs	e.errpt = errpt;
33139213Sgibbs	return(0);
33239213Sgibbs}
33339213Sgibbs
33439213Sgibbsvoid
33539213Sgibbsquitenv()
33639213Sgibbs{
33739213Sgibbs	register struct env *ep;
33839213Sgibbs	register fd;
33939213Sgibbs
34039213Sgibbs	if ((ep = e.oenv) != NULL) {
34139213Sgibbs		fd = e.iofd;
34259249Sphk		e = *ep;
34339213Sgibbs		/* should close `'d files */
34450073Sken		DELETE(ep);
34550073Sken		while (--fd >= e.iofd)
34639213Sgibbs			close(fd);
34739213Sgibbs	}
34839213Sgibbs}
34939213Sgibbs
35039213Sgibbs/*
35139213Sgibbs * Is any character from s1 in s2?
35239213Sgibbs */
35356148Smjacobint
35443819Skenanys(s1, s2)
35539213Sgibbsregister char *s1, *s2;
35653257Sken{
35753257Sken	while (*s1)
35853257Sken		if (any(*s1++, s2))
35939213Sgibbs			return(1);
36039213Sgibbs	return(0);
36139213Sgibbs}
36239213Sgibbs
36339213Sgibbs/*
36439213Sgibbs * Is character c in s?
36539213Sgibbs */
36639213Sgibbsint
36739213Sgibbsany(c, s)
36839213Sgibbsregister int c;
36939213Sgibbsregister char *s;
37039213Sgibbs{
37139213Sgibbs	while (*s)
37239213Sgibbs		if (*s++ == c)
37339213Sgibbs			return(1);
37439213Sgibbs	return(0);
37539213Sgibbs}
37639213Sgibbs
37739213Sgibbschar *
37839213Sgibbsputn(n)
37939213Sgibbsregister int n;
38039213Sgibbs{
38140603Sken	return(itoa(n, -1));
38240603Sken}
38340603Sken
38440603Skenchar *
38559249Sphkitoa(u, n)
38640603Skenregister unsigned u;
38740603Skenint n;
38840603Sken{
38940603Sken	register char *cp;
39040603Sken	static char s[20];
39140603Sken	int m;
39240603Sken
39340603Sken	m = 0;
39440603Sken	if (n < 0 && (int) u < 0) {
39540603Sken		m++;
39640603Sken		u = -u;
39740603Sken	}
39840603Sken	cp = s+sizeof(s);
39940603Sken	*--cp = 0;
40040603Sken	do {
40140603Sken		*--cp = u%10 + '0';
40240603Sken		u /= 10;
40340603Sken	} while (--n > 0 || u);
40440603Sken	if (m)
40540603Sken		*--cp = '-';
40640603Sken	return(cp);
40740603Sken}
40840603Sken
40940603Skenvoid
41040603Skennext(f)
41140603Skenint f;
41240603Sken{
41340603Sken	PUSHIO(afile, f, filechar);
41440603Sken}
41559249Sphk
41659249Sphkvoid
41759249Sphkonintr(s)
41859249Sphkint s;				/* ANSI C requires a parameter */
41959249Sphk{
42040603Sken	signal(SIGINT, onintr);
42140603Sken	intr = 1;
42240603Sken	if (talking) {
42340603Sken		if (inparse) {
42440603Sken			prs("\n");
42540603Sken			fail();
42640603Sken		}
42740603Sken	}
42840603Sken	else if (heedint) {
42940603Sken		execflg = 0;
43039213Sgibbs		leave();
43139213Sgibbs	}
43240603Sken}
43340603Sken
43440603Skenint
43540603Skenletter(c)
43640603Skenregister c;
43740603Sken{
43853257Sken	return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
43953257Sken}
44039213Sgibbs
44139213Sgibbsint
44239213Sgibbsdigit(c)
44340603Skenregister c;
44439213Sgibbs{
44539213Sgibbs	return(c >= '0' && c <= '9');
44639213Sgibbs}
44739213Sgibbs
44839213Sgibbsint
44939213Sgibbsletnum(c)
45039213Sgibbsregister c;
45139213Sgibbs{
45239213Sgibbs	return(letter(c) || digit(c));
45339213Sgibbs}
45439213Sgibbs
45539213Sgibbschar *
45639213Sgibbsspace(n)
45739213Sgibbsint n;
45839213Sgibbs{
45939213Sgibbs	register char *cp;
46056148Smjacob
46139213Sgibbs	if ((cp = getcell(n)) == 0)
46239213Sgibbs		err("out of string space");
46339213Sgibbs	return(cp);
46439213Sgibbs}
46539213Sgibbs
46639213Sgibbschar *
46739213Sgibbsstrsave(s, a)
46840603Skenregister char *s;
46940603Skenint a;
47040603Sken{
47140603Sken	register char *cp, *xp;
47239213Sgibbs
47339213Sgibbs	if ((cp = space(strlen(s)+1)) != NULL) {
47439213Sgibbs		setarea((char *)cp, a);
47539213Sgibbs		for (xp = cp; (*xp++ = *s++) != '\0';)
47639213Sgibbs			;
47739213Sgibbs		return(cp);
47839213Sgibbs	}
47939213Sgibbs	return("");
48039213Sgibbs}
48139213Sgibbs
48239213Sgibbsvoid
48339213Sgibbsxfree(s)
48439213Sgibbsregister char *s;
48539213Sgibbs{
48639213Sgibbs	DELETE(s);
48739213Sgibbs}
48839213Sgibbs
48939213Sgibbs/*
49039213Sgibbs * trap handling
49139213Sgibbs */
49239213Sgibbsvoid
49339213Sgibbssig(i)
49439213Sgibbsregister int i;
49539213Sgibbs{
49639213Sgibbs	trapset = i;
49747413Sgibbs	signal(i, sig);
49839213Sgibbs}
49939213Sgibbs
50047413Sgibbsvoid runtrap(i)
50139213Sgibbsint i;
50239213Sgibbs{
50339213Sgibbs	char *trapstr;
50439213Sgibbs
50539213Sgibbs	if ((trapstr = trap[i]) == NULL)
50639213Sgibbs		return;
50739213Sgibbs	if (i == 0)
50839213Sgibbs		trap[i] = 0;
50959249Sphk	RUN(aword, trapstr, nlchar);
51039213Sgibbs}
51139213Sgibbs
51239213Sgibbs/* -------- var.c -------- */
51339213Sgibbs/* #include "sh.h" */
51439213Sgibbs
51539213Sgibbs/*
51639213Sgibbs * Find the given name in the dictionary
51739213Sgibbs * and return its value.  If the name was
51859249Sphk * not previously there, enter it now and
51939213Sgibbs * return a null value.
52039213Sgibbs */
52139213Sgibbsstruct var *
52239213Sgibbslookup(n)
52339213Sgibbsregister char *n;
52439213Sgibbs{
52539213Sgibbs	register struct var *vp;
52639213Sgibbs	register char *cp;
52739213Sgibbs	register int c;
52839213Sgibbs	static struct var dummy;
52939213Sgibbs
53039213Sgibbs	if (digit(*n)) {
53139213Sgibbs		dummy.name = n;
53239213Sgibbs		for (c = 0; digit(*n) && c < 1000; n++)
53339213Sgibbs			c = c*10 + *n-'0';
53459249Sphk		dummy.status = RONLY;
53539213Sgibbs		dummy.value = c <= dolc? dolv[c]: null;
53639213Sgibbs		return(&dummy);
53739213Sgibbs	}
53839213Sgibbs	for (vp = vlist; vp; vp = vp->next)
53939213Sgibbs		if (eqname(vp->name, n))
54039213Sgibbs			return(vp);
54139213Sgibbs	cp = findeq(n);
54259249Sphk	vp = (struct var *)space(sizeof(*vp));
54339213Sgibbs	if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
54459249Sphk		dummy.name = dummy.value = "";
54559249Sphk		return(&dummy);
54639213Sgibbs	}
54750073Sken	for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
54839213Sgibbs		;
54939213Sgibbs	if (*cp == 0)
55039213Sgibbs		*cp = '=';
55139213Sgibbs	*++cp = 0;
55239213Sgibbs	setarea((char *)vp, 0);
55339213Sgibbs	setarea((char *)vp->name, 0);
55439213Sgibbs	vp->value = null;
55539213Sgibbs	vp->next = vlist;
55639213Sgibbs	vp->status = GETCELL;
55739213Sgibbs	vlist = vp;
55839213Sgibbs	return(vp);
55939213Sgibbs}
56039213Sgibbs
56159249Sphk/*
56239213Sgibbs * give variable at `vp' the value `val'.
56339213Sgibbs */
56439213Sgibbsvoid
56539213Sgibbssetval(vp, val)
56639213Sgibbsstruct var *vp;
56739213Sgibbschar *val;
56839213Sgibbs{
56939213Sgibbs	nameval(vp, val, (char *)NULL);
57039213Sgibbs}
57139213Sgibbs
57239213Sgibbs/*
57339213Sgibbs * if name is not NULL, it must be
57439213Sgibbs * a prefix of the space `val',
57539213Sgibbs * and end with `='.
57639213Sgibbs * this is all so that exporting
57739213Sgibbs * values is reasonably painless.
57839213Sgibbs */
57939213Sgibbsvoid
58039213Sgibbsnameval(vp, val, name)
58139213Sgibbsregister struct var *vp;
58239213Sgibbschar *val, *name;
58339213Sgibbs{
58439213Sgibbs	register char *cp, *xp;
58559249Sphk	char *nv;
58639213Sgibbs	int fl;
58739213Sgibbs
58859249Sphk	if (vp->status & RONLY) {
58939213Sgibbs		for (xp = vp->name; *xp && *xp != '=';)
59039213Sgibbs			putc(*xp++);
59139213Sgibbs		err(" is read-only");
59239213Sgibbs		return;
59339213Sgibbs	}
59439213Sgibbs	fl = 0;
59539213Sgibbs	if (name == NULL) {
59639213Sgibbs		xp = space(strlen(vp->name)+strlen(val)+2);
59739213Sgibbs		if (xp == 0)
59839213Sgibbs			return;
59946747Sken		/* make string:  name=value */
60046747Sken		setarea((char *)xp, 0);
60139213Sgibbs		name = xp;
60239213Sgibbs		for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
60339213Sgibbs			;
60439213Sgibbs		if (*xp++ == 0)
60539213Sgibbs			xp[-1] = '=';
60639213Sgibbs		nv = xp;
60739213Sgibbs		for (cp = val; (*xp++ = *cp++) != '\0';)
60839213Sgibbs			;
60959249Sphk		val = nv;
61039213Sgibbs		fl = GETCELL;
61139213Sgibbs	}
61239213Sgibbs	if (vp->status & GETCELL)
61339213Sgibbs		xfree(vp->name);	/* form new string `name=value' */
61439213Sgibbs	vp->name = name;
61539213Sgibbs	vp->value = val;
61639213Sgibbs	vp->status |= fl;
61739213Sgibbs}
61839213Sgibbs
61939213Sgibbsvoid
62039213Sgibbsexport(vp)
62139213Sgibbsstruct var *vp;
62239213Sgibbs{
62339213Sgibbs	vp->status |= EXPORT;
62439213Sgibbs}
62539213Sgibbs
62639213Sgibbsvoid
62739213Sgibbsronly(vp)
62859249Sphkstruct var *vp;
62939213Sgibbs{
63059249Sphk	if (letter(vp->name[0]))	/* not an internal symbol ($# etc) */
63159249Sphk		vp->status |= RONLY;
63259249Sphk}
63359249Sphk
63439213Sgibbsint
63539213Sgibbsisassign(s)
63639213Sgibbsregister char *s;
63759249Sphk{
63859249Sphk	if (!letter((int)*s))
63959249Sphk		return(0);
64039213Sgibbs	for (; *s != '='; s++)
64159249Sphk		if (*s == 0 || !letnum(*s))
64259249Sphk			return(0);
64359249Sphk	return(1);
64439213Sgibbs}
64559249Sphk
64639213Sgibbsint
64739213Sgibbsassign(s, cf)
64839213Sgibbsregister char *s;
64939213Sgibbsint cf;
65039213Sgibbs{
65139213Sgibbs	register char *cp;
65239213Sgibbs	struct var *vp;
65339213Sgibbs
65439213Sgibbs	if (!letter(*s))
65559249Sphk		return(0);
65659249Sphk	for (cp = s; *cp != '='; cp++)
65759249Sphk		if (*cp == 0 || !letnum(*cp))
65839213Sgibbs			return(0);
65939213Sgibbs	vp = lookup(s);
66039213Sgibbs	nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
66139213Sgibbs	if (cf != COPYV)
66239213Sgibbs		vp->status &= ~GETCELL;
66339213Sgibbs	return(1);
66439213Sgibbs}
66539213Sgibbs
66639213Sgibbsint
66739213Sgibbscheckname(cp)
66859249Sphkregister char *cp;
66939213Sgibbs{
67039213Sgibbs	if (!letter(*cp++))
67139213Sgibbs		return(0);
67239213Sgibbs	while (*cp)
67339213Sgibbs		if (!letnum(*cp++))
67439213Sgibbs			return(0);
67539213Sgibbs	return(1);
67639213Sgibbs}
67739213Sgibbs
67839213Sgibbsvoid
67939213Sgibbsputvlist(f, out)
68039213Sgibbsregister int f, out;
68139213Sgibbs{
68239213Sgibbs	register struct var *vp;
68339213Sgibbs
68439213Sgibbs	for (vp = vlist; vp; vp = vp->next)
68539213Sgibbs		if (vp->status & f && letter(*vp->name)) {
68639213Sgibbs			if (vp->status & EXPORT)
68739213Sgibbs				write(out, "export ", 7);
68839213Sgibbs			if (vp->status & RONLY)
68939213Sgibbs				write(out, "readonly ", 9);
69039213Sgibbs			write(out, vp->name, (int)(findeq(vp->name) - vp->name));
69139213Sgibbs			write(out, "\n", 1);
69239213Sgibbs		}
69350073Sken}
69450073Sken
69550073Skenint
69650073Skeneqname(n1, n2)
69750073Skenregister char *n1, *n2;
69850073Sken{
69950073Sken	for (; *n1 != '=' && *n1 != 0; n1++)
70050073Sken		if (*n2++ != *n1)
70150073Sken			return(0);
70250073Sken	return(*n2 == 0 || *n2 == '=');
70350073Sken}
70450073Sken
70550073Skenstatic char *
70650073Skenfindeq(cp)
70750073Skenregister char *cp;
70850073Sken{
70950073Sken	while (*cp != '\0' && *cp != '=')
71050073Sken		cp++;
71150073Sken	return(cp);
71250073Sken}
71350073Sken
71450073Sken/* -------- gmatch.c -------- */
71550073Sken/*
71650073Sken * int gmatch(string, pattern)
71750073Sken * char *string, *pattern;
71850073Sken *
71950073Sken * Match a pattern as in sh(1).
72050073Sken */
72150073Sken
72250073Sken#define	CMASK	0377
72350073Sken#define	QUOTE	0200
72450073Sken#define	QMASK	(CMASK&~QUOTE)
72550073Sken#define	NOT	'!'	/* might use ^ */
72650073Sken
72750073Skenint
72850073Skengmatch(s, p)
72950073Skenregister char *s, *p;
73050073Sken{
73150073Sken	register int sc, pc;
73250073Sken
73350073Sken	if (s == NULL || p == NULL)
73450073Sken		return(0);
73550073Sken	while ((pc = *p++ & CMASK) != '\0') {
73650073Sken		sc = *s++ & QMASK;
73750073Sken		switch (pc) {
73850073Sken		case '[':
73950073Sken			if ((p = cclass(p, sc)) == NULL)
74050073Sken				return(0);
74150073Sken			break;
74250073Sken
74350073Sken		case '?':
74450073Sken			if (sc == 0)
74539213Sgibbs				return(0);
74639213Sgibbs			break;
74739213Sgibbs
74839213Sgibbs		case '*':
74939213Sgibbs			s--;
75039213Sgibbs			do {
75139213Sgibbs				if (*p == '\0' || gmatch(s, p))
75239213Sgibbs					return(1);
75339213Sgibbs			} while (*s++ != '\0');
75439213Sgibbs			return(0);
75539213Sgibbs
75639213Sgibbs		default:
75739213Sgibbs			if (sc != (pc&~QUOTE))
75839213Sgibbs				return(0);
75939213Sgibbs		}
76039213Sgibbs	}
76139213Sgibbs	return(*s == 0);
76239213Sgibbs}
76339213Sgibbs
76439213Sgibbsstatic char *
76539213Sgibbscclass(p, sub)
76639213Sgibbsregister char *p;
76739213Sgibbsregister int sub;
76839213Sgibbs{
76939213Sgibbs	register int c, d, not, found;
77039213Sgibbs
771	if ((not = *p == NOT) != 0)
772		p++;
773	found = not;
774	do {
775		if (*p == '\0')
776			return((char *)NULL);
777		c = *p & CMASK;
778		if (p[1] == '-' && p[2] != ']') {
779			d = p[2] & CMASK;
780			p++;
781		} else
782			d = c;
783		if (c == sub || (c <= sub && sub <= d))
784			found = !not;
785	} while (*++p != ']');
786	return(found? p+1: (char *)NULL);
787}
788
789/* -------- area.c -------- */
790#define	REGSIZE		sizeof(struct region)
791#define GROWBY		256
792#undef	SHRINKBY	64
793#define FREE 32767
794#define BUSY 0
795#define	ALIGN (sizeof(int)-1)
796
797/* #include "area.h" */
798
799struct region {
800	struct	region *next;
801	int	area;
802};
803
804/*
805 * All memory between (char *)areabot and (char *)(areatop+1) is
806 * exclusively administered by the area management routines.
807 * It is assumed that sbrk() and brk() manipulate the high end.
808 */
809static	struct region *areabot;		/* bottom of area */
810static	struct region *areatop;		/* top of area */
811static	struct region *areanxt;		/* starting point of scan */
812
813void
814initarea()
815{
816	while ((int)sbrk(0) & ALIGN)
817		sbrk(1);
818	areabot = (struct region *)sbrk(REGSIZE);
819	areabot->next = areabot;
820	areabot->area = BUSY;
821	areatop = areabot;
822	areanxt = areabot;
823}
824
825char *
826getcell(nbytes)
827unsigned nbytes;
828{
829	register int nregio;
830	register struct region *p, *q;
831	register i;
832
833	if (nbytes == 0)
834		abort();	/* silly and defeats the algorithm */
835	/*
836	 * round upwards and add administration area
837	 */
838	nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
839	for (p = areanxt;;) {
840		if (p->area > areanum) {
841			/*
842			 * merge free cells
843			 */
844			while ((q = p->next)->area > areanum && q != areanxt)
845				p->next = q->next;
846			/*
847			 * exit loop if cell big enough
848			 */
849			if (q >= p + nregio)
850				goto found;
851		}
852		p = p->next;
853		if (p == areanxt)
854			break;
855	}
856	i = nregio >= GROWBY ? nregio : GROWBY;
857	p = (struct region *)sbrk(i * REGSIZE);
858	if (p == (struct region *)-1)
859		return((char *)NULL);
860	p--;
861	if (p != areatop)
862		abort();	/* allocated areas are contiguous */
863	q = p + i;
864	p->next = q;
865	p->area = FREE;
866	q->next = areabot;
867	q->area = BUSY;
868	areatop = q;
869found:
870	/*
871	 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
872	 */
873	areanxt = p + nregio;
874	if (areanxt < q) {
875		/*
876		 * split into requested area and rest
877		 */
878		if (areanxt+1 > q)
879			abort();	/* insufficient space left for admin */
880		areanxt->next = q;
881		areanxt->area = FREE;
882		p->next = areanxt;
883	}
884	p->area = areanum;
885	return((char *)(p+1));
886}
887
888void
889freecell(cp)
890char *cp;
891{
892	register struct region *p;
893
894	if ((p = (struct region *)cp) != NULL) {
895		p--;
896		if (p < areanxt)
897			areanxt = p;
898		p->area = FREE;
899	}
900}
901
902void
903freearea(a)
904register int a;
905{
906	register struct region *p, *top;
907
908	top = areatop;
909	for (p = areabot; p != top; p = p->next)
910		if (p->area >= a)
911			p->area = FREE;
912}
913
914void
915setarea(cp,a)
916char *cp;
917int a;
918{
919	register struct region *p;
920
921	if ((p = (struct region *)cp) != NULL)
922		(p-1)->area = a;
923}
924
925int
926getarea(cp)
927char *cp;
928{
929	return ((struct region*)cp-1)->area;
930}
931
932void
933garbage()
934{
935	register struct region *p, *q, *top;
936
937	top = areatop;
938	for (p = areabot; p != top; p = p->next) {
939		if (p->area > areanum) {
940			while ((q = p->next)->area > areanum)
941				p->next = q->next;
942			areanxt = p;
943		}
944	}
945#ifdef SHRINKBY
946	if (areatop >= q + SHRINKBY && q->area > areanum) {
947		brk((char *)(q+1));
948		q->next = areabot;
949		q->area = BUSY;
950		areatop = q;
951	}
952#endif
953}
954