1221828Sgrehan#define Extern extern
2221828Sgrehan#include <sys/types.h>
3221828Sgrehan#include <signal.h>
4221828Sgrehan#define _NSIG NSIG
5221828Sgrehan#include <errno.h>
6221828Sgrehan#include <setjmp.h>
7221828Sgrehan#include "sh.h"
8221828Sgrehan/* -------- sh.c -------- */
9221828Sgrehan/*
10221828Sgrehan * shell
11221828Sgrehan */
12221828Sgrehan
13221828Sgrehan/* #include "sh.h" */
14221828Sgrehan
15221828Sgrehanint	intr;
16221828Sgrehanint	inparse;
17221828Sgrehanchar	flags['z'-'a'+1];
18221828Sgrehanchar	*flag = flags-'a';
19221828Sgrehanchar	*elinep = line+sizeof(line)-5;
20221828Sgrehanchar	*null	= "";
21221828Sgrehanint	heedint =1;
22221828Sgrehanstruct	env	e ={line, iostack, iostack-1,
23221828Sgrehan		    (xint *)NULL, FDBASE, (struct env *)NULL};
24221828Sgrehan
25221828Sgrehanextern	char	**environ;	/* environment pointer */
26221828Sgrehan
27221828Sgrehan/*
28221828Sgrehan * default shell, search rules
29221828Sgrehan */
30221828Sgrehanchar	shellname[] = "/bin/sh";
31221828Sgrehanchar	search[] = ":/bin:/usr/bin";
32221828Sgrehan
33221828Sgrehan_PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
34221828Sgrehan
35221828Sgrehan_PROTOTYPE(int main, (int argc, char **argv ));
36221828Sgrehan_PROTOTYPE(int newfile, (char *s ));
37221828Sgrehan_PROTOTYPE(static char *findeq, (char *cp ));
38221828Sgrehan_PROTOTYPE(static char *cclass, (char *p, int sub ));
39221828Sgrehan_PROTOTYPE(void initarea, (void));
40221828Sgrehan
41221828Sgrehanint main(argc, argv)
42221828Sgrehanint argc;
43221828Sgrehanregister char **argv;
44221828Sgrehan{
45221828Sgrehan	register int f;
46221828Sgrehan	register char *s;
47221828Sgrehan	int cflag;
48221828Sgrehan	char *name, **ap;
49221828Sgrehan	int (*iof)();
50221828Sgrehan
51221828Sgrehan	initarea();
52221828Sgrehan	if ((ap = environ) != NULL) {
53221828Sgrehan		while (*ap)
54221828Sgrehan			assign(*ap++, !COPYV);
55221828Sgrehan		for (ap = environ; *ap;)
56221828Sgrehan			export(lookup(*ap++));
57221828Sgrehan	}
58221828Sgrehan	closeall();
59221828Sgrehan	areanum = 1;
60221828Sgrehan
61221828Sgrehan	shell = lookup("SHELL");
62221828Sgrehan	if (shell->value == null)
63221828Sgrehan		setval(shell, shellname);
64221828Sgrehan	export(shell);
65221828Sgrehan
66221828Sgrehan	homedir = lookup("HOME");
67221828Sgrehan	if (homedir->value == null)
68221828Sgrehan		setval(homedir, "/");
69221828Sgrehan	export(homedir);
70221828Sgrehan
71221828Sgrehan	setval(lookup("$"), itoa(getpid(), 5));
72221828Sgrehan
73221828Sgrehan	path = lookup("PATH");
74221828Sgrehan	if (path->value == null)
75221828Sgrehan		setval(path, search);
76221828Sgrehan	export(path);
77221828Sgrehan
78221828Sgrehan	ifs = lookup("IFS");
79221828Sgrehan	if (ifs->value == null)
80221828Sgrehan		setval(ifs, " \t\n");
81221828Sgrehan
82221828Sgrehan	prompt = lookup("PS1");
83221828Sgrehan	if (prompt->value == null)
84221828Sgrehan#ifndef UNIXSHELL
85221828Sgrehan		setval(prompt, "$ ");
86221828Sgrehan#else
87221828Sgrehan		setval(prompt, "% ");
88221828Sgrehan#endif
89221828Sgrehan
90221828Sgrehan	if (geteuid() == 0) {
91221828Sgrehan		setval(prompt, "# ");
92221828Sgrehan		prompt->status &= ~EXPORT;
93221828Sgrehan	}
94221828Sgrehan	cprompt = lookup("PS2");
95221828Sgrehan	if (cprompt->value == null)
96221828Sgrehan		setval(cprompt, "> ");
97221828Sgrehan
98221828Sgrehan	iof = filechar;
99221828Sgrehan	cflag = 0;
100221828Sgrehan	name = *argv++;
101221828Sgrehan	if (--argc >= 1) {
102221828Sgrehan		if(argv[0][0] == '-' && argv[0][1] != '\0') {
103221828Sgrehan			for (s = argv[0]+1; *s; s++)
104221828Sgrehan				switch (*s) {
105221828Sgrehan				case 'c':
106221828Sgrehan					prompt->status &= ~EXPORT;
107221828Sgrehan					cprompt->status &= ~EXPORT;
108221828Sgrehan					setval(prompt, "");
109221828Sgrehan					setval(cprompt, "");
110221828Sgrehan					cflag = 1;
111221828Sgrehan					if (--argc > 0)
112221828Sgrehan						PUSHIO(aword, *++argv, iof = nlchar);
113221828Sgrehan					break;
114221828Sgrehan
115221828Sgrehan				case 'q':
116221828Sgrehan					qflag = SIG_DFL;
117221828Sgrehan					break;
118221828Sgrehan
119221828Sgrehan				case 's':
120221828Sgrehan					/* standard input */
121221828Sgrehan					break;
122221828Sgrehan
123221828Sgrehan				case 't':
124221828Sgrehan					prompt->status &= ~EXPORT;
125221828Sgrehan					setval(prompt, "");
126221828Sgrehan					iof = linechar;
127221828Sgrehan					break;
128221828Sgrehan
129221828Sgrehan				case 'i':
130221828Sgrehan					talking++;
131221828Sgrehan				default:
132221828Sgrehan					if (*s>='a' && *s<='z')
133221828Sgrehan						flag[*s]++;
134221828Sgrehan				}
135221828Sgrehan		} else {
136221828Sgrehan			argv--;
137221828Sgrehan			argc++;
138221828Sgrehan		}
139221828Sgrehan		if (iof == filechar && --argc > 0) {
140221828Sgrehan			setval(prompt, "");
141221828Sgrehan			setval(cprompt, "");
142221828Sgrehan			prompt->status &= ~EXPORT;
143221828Sgrehan			cprompt->status &= ~EXPORT;
144221828Sgrehan			if (newfile(name = *++argv))
145221828Sgrehan				exit(1);
146221828Sgrehan		}
147221828Sgrehan	}
148221828Sgrehan	setdash();
149221828Sgrehan	if (e.iop < iostack) {
150221828Sgrehan		PUSHIO(afile, 0, iof);
151221828Sgrehan		if (isatty(0) && isatty(1) && !cflag)
152221828Sgrehan			talking++;
153221828Sgrehan	}
154221828Sgrehan	signal(SIGQUIT, qflag);
155221828Sgrehan	if (name && name[0] == '-') {
156221828Sgrehan		talking++;
157221828Sgrehan		if ((f = open(".profile", 0)) >= 0)
158221828Sgrehan			next(remap(f));
159221828Sgrehan		if ((f = open("/etc/profile", 0)) >= 0)
160221828Sgrehan			next(remap(f));
161221828Sgrehan	}
162221828Sgrehan	if (talking)
163221828Sgrehan		signal(SIGTERM, sig);
164221828Sgrehan	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
165221828Sgrehan		signal(SIGINT, onintr);
166221828Sgrehan	dolv = argv;
167221828Sgrehan	dolc = argc;
168221828Sgrehan	dolv[0] = name;
169221828Sgrehan	if (dolc > 1)
170221828Sgrehan		for (ap = ++argv; --argc > 0;)
171221828Sgrehan			if (assign(*ap = *argv++, !COPYV))
172221828Sgrehan				dolc--;	/* keyword */
173221828Sgrehan			else
174221828Sgrehan				ap++;
175221828Sgrehan	setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
176221828Sgrehan
177221828Sgrehan	for (;;) {
178221828Sgrehan		if (talking && e.iop <= iostack)
179221828Sgrehan			prs(prompt->value);
180221828Sgrehan		onecommand();
181221828Sgrehan	}
182221828Sgrehan}
183221828Sgrehan
184221828Sgrehanvoid
185221828Sgrehansetdash()
186221828Sgrehan{
187221828Sgrehan	register char *cp, c;
188221828Sgrehan	char m['z'-'a'+1];
189221828Sgrehan
190221828Sgrehan	cp = m;
191221828Sgrehan	for (c='a'; c<='z'; c++)
192221828Sgrehan		if (flag[c])
193221828Sgrehan			*cp++ = c;
194221828Sgrehan	*cp = 0;
195221828Sgrehan	setval(lookup("-"), m);
196221828Sgrehan}
197221828Sgrehan
198221828Sgrehanint
199221828Sgrehannewfile(s)
200221828Sgrehanregister char *s;
201221828Sgrehan{
202221828Sgrehan	register f;
203221828Sgrehan
204221828Sgrehan	if (strcmp(s, "-") != 0) {
205221828Sgrehan		f = open(s, 0);
206221828Sgrehan		if (f < 0) {
207221828Sgrehan			prs(s);
208221828Sgrehan			err(": cannot open");
209221828Sgrehan			return(1);
210221828Sgrehan		}
211221828Sgrehan	} else
212221828Sgrehan		f = 0;
213221828Sgrehan	next(remap(f));
214221828Sgrehan	return(0);
215221828Sgrehan}
216221828Sgrehan
217221828Sgrehanvoid
218221828Sgrehanonecommand()
219221828Sgrehan{
220221828Sgrehan	register i;
221221828Sgrehan	jmp_buf m1;
222221828Sgrehan
223221828Sgrehan	while (e.oenv)
224221828Sgrehan		quitenv();
225221828Sgrehan	areanum = 1;
226221828Sgrehan	freehere(areanum);
227221828Sgrehan	freearea(areanum);
228221828Sgrehan	garbage();
229221828Sgrehan	wdlist = 0;
230221828Sgrehan	iolist = 0;
231221828Sgrehan	e.errpt = 0;
232221828Sgrehan	e.linep = line;
233221828Sgrehan	yynerrs = 0;
234221828Sgrehan	multiline = 0;
235221828Sgrehan	inparse = 1;
236221828Sgrehan	intr = 0;
237221828Sgrehan	execflg = 0;
238221828Sgrehan	setjmp(failpt = m1);	/* Bruce Evans' fix */
239221828Sgrehan	if (setjmp(failpt = m1) || yyparse() || intr) {
240221828Sgrehan		while (e.oenv)
241221828Sgrehan			quitenv();
242221828Sgrehan		scraphere();
243221828Sgrehan		if (!talking && intr)
244221828Sgrehan			leave();
245221828Sgrehan		inparse = 0;
246221828Sgrehan		intr = 0;
247221828Sgrehan		return;
248221828Sgrehan	}
249221828Sgrehan	inparse = 0;
250221828Sgrehan	brklist = 0;
251221828Sgrehan	intr = 0;
252221828Sgrehan	execflg = 0;
253221828Sgrehan	if (!flag['n'])
254221828Sgrehan		execute(outtree, NOPIPE, NOPIPE, 0);
255221828Sgrehan	if (!talking && intr) {
256221828Sgrehan		execflg = 0;
257221828Sgrehan		leave();
258221828Sgrehan	}
259221828Sgrehan	if ((i = trapset) != 0) {
260221828Sgrehan		trapset = 0;
261221828Sgrehan		runtrap(i);
262221828Sgrehan	}
263221828Sgrehan}
264221828Sgrehan
265221828Sgrehanvoid
266221828Sgrehanfail()
267221828Sgrehan{
268221828Sgrehan	longjmp(failpt, 1);
269221828Sgrehan	/* NOTREACHED */
270221828Sgrehan}
271221828Sgrehan
272221828Sgrehanvoid
273221828Sgrehanleave()
274221828Sgrehan{
275221828Sgrehan	if (execflg)
276221828Sgrehan		fail();
277221828Sgrehan	scraphere();
278221828Sgrehan	freehere(1);
279221828Sgrehan	runtrap(0);
280221828Sgrehan	exit(exstat);
281221828Sgrehan	/* NOTREACHED */
282221828Sgrehan}
283221828Sgrehan
284221828Sgrehanvoid
285221828Sgrehanwarn(s)
286221828Sgrehanregister char *s;
287221828Sgrehan{
288221828Sgrehan	if(*s) {
289221828Sgrehan		prs(s);
290221828Sgrehan		exstat = -1;
291221828Sgrehan	}
292221828Sgrehan	prs("\n");
293221828Sgrehan	if (flag['e'])
294221828Sgrehan		leave();
295221828Sgrehan}
296221828Sgrehan
297221828Sgrehanvoid
298221828Sgrehanerr(s)
299221828Sgrehanchar *s;
300221828Sgrehan{
301221828Sgrehan	warn(s);
302221828Sgrehan	if (flag['n'])
303221828Sgrehan		return;
304221828Sgrehan	if (!talking)
305221828Sgrehan		leave();
306221828Sgrehan	if (e.errpt)
307221828Sgrehan		longjmp(e.errpt, 1);
308221828Sgrehan	closeall();
309221828Sgrehan	e.iop = e.iobase = iostack;
310221828Sgrehan}
311221828Sgrehan
312221828Sgrehanint
313221828Sgrehannewenv(f)
314221828Sgrehanint f;
315221828Sgrehan{
316221828Sgrehan	register struct env *ep;
317239026Sneel
318239026Sneel	if (f) {
319239026Sneel		quitenv();
320239026Sneel		return(1);
321239026Sneel	}
322239026Sneel	ep = (struct env *) space(sizeof(*ep));
323239026Sneel	if (ep == NULL) {
324239026Sneel		while (e.oenv)
325239026Sneel			quitenv();
326239026Sneel		fail();
327221828Sgrehan	}
328221828Sgrehan	*ep = e;
329221828Sgrehan	e.oenv = ep;
330221828Sgrehan	e.errpt = errpt;
331221828Sgrehan	return(0);
332221828Sgrehan}
333221828Sgrehan
334221828Sgrehanvoid
335221828Sgrehanquitenv()
336221828Sgrehan{
337221828Sgrehan	register struct env *ep;
338221828Sgrehan	register fd;
339221828Sgrehan
340221828Sgrehan	if ((ep = e.oenv) != NULL) {
341221828Sgrehan		fd = e.iofd;
342221828Sgrehan		e = *ep;
343221828Sgrehan		/* should close `'d files */
344221828Sgrehan		DELETE(ep);
345221828Sgrehan		while (--fd >= e.iofd)
346221828Sgrehan			close(fd);
347221828Sgrehan	}
348221828Sgrehan}
349221828Sgrehan
350221828Sgrehan/*
351221828Sgrehan * Is any character from s1 in s2?
352221828Sgrehan */
353221828Sgrehanint
354221828Sgrehananys(s1, s2)
355221828Sgrehanregister char *s1, *s2;
356221828Sgrehan{
357221828Sgrehan	while (*s1)
358221828Sgrehan		if (any(*s1++, s2))
359221828Sgrehan			return(1);
360221828Sgrehan	return(0);
361221828Sgrehan}
362221828Sgrehan
363221828Sgrehan/*
364221828Sgrehan * Is character c in s?
365221828Sgrehan */
366221828Sgrehanint
367221828Sgrehanany(c, s)
368221828Sgrehanregister int c;
369221828Sgrehanregister char *s;
370221828Sgrehan{
371221828Sgrehan	while (*s)
372221828Sgrehan		if (*s++ == c)
373221828Sgrehan			return(1);
374221828Sgrehan	return(0);
375221828Sgrehan}
376221828Sgrehan
377221828Sgrehanchar *
378221828Sgrehanputn(n)
379221828Sgrehanregister int n;
380221828Sgrehan{
381221828Sgrehan	return(itoa(n, -1));
382221828Sgrehan}
383221828Sgrehan
384221828Sgrehanchar *
385221828Sgrehanitoa(u, n)
386221828Sgrehanregister unsigned u;
387221828Sgrehanint n;
388221828Sgrehan{
389221828Sgrehan	register char *cp;
390221828Sgrehan	static char s[20];
391221828Sgrehan	int m;
392221828Sgrehan
393221828Sgrehan	m = 0;
394221828Sgrehan	if (n < 0 && (int) u < 0) {
395221828Sgrehan		m++;
396221828Sgrehan		u = -u;
397221828Sgrehan	}
398221828Sgrehan	cp = s+sizeof(s);
399221828Sgrehan	*--cp = 0;
400221828Sgrehan	do {
401221828Sgrehan		*--cp = u%10 + '0';
402221828Sgrehan		u /= 10;
403221828Sgrehan	} while (--n > 0 || u);
404221828Sgrehan	if (m)
405221828Sgrehan		*--cp = '-';
406221828Sgrehan	return(cp);
407221828Sgrehan}
408221828Sgrehan
409221828Sgrehanvoid
410221828Sgrehannext(f)
411221828Sgrehanint f;
412221828Sgrehan{
413221828Sgrehan	PUSHIO(afile, f, filechar);
414221828Sgrehan}
415221828Sgrehan
416221828Sgrehanvoid
417221828Sgrehanonintr(s)
418221828Sgrehanint s;				/* ANSI C requires a parameter */
419221828Sgrehan{
420221828Sgrehan	signal(SIGINT, onintr);
421221828Sgrehan	intr = 1;
422221828Sgrehan	if (talking) {
423221828Sgrehan		if (inparse) {
424221828Sgrehan			prs("\n");
425221828Sgrehan			fail();
426221828Sgrehan		}
427221828Sgrehan	}
428221828Sgrehan	else if (heedint) {
429221828Sgrehan		execflg = 0;
430221828Sgrehan		leave();
431221828Sgrehan	}
432221828Sgrehan}
433221828Sgrehan
434221828Sgrehanint
435221828Sgrehanletter(c)
436221828Sgrehanregister c;
437221828Sgrehan{
438221828Sgrehan	return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
439221828Sgrehan}
440221828Sgrehan
441221828Sgrehanint
442221828Sgrehandigit(c)
443221828Sgrehanregister c;
444221828Sgrehan{
445221828Sgrehan	return(c >= '0' && c <= '9');
446221828Sgrehan}
447221828Sgrehan
448221828Sgrehanint
449221828Sgrehanletnum(c)
450221828Sgrehanregister c;
451221828Sgrehan{
452221828Sgrehan	return(letter(c) || digit(c));
453221828Sgrehan}
454221828Sgrehan
455221828Sgrehanchar *
456221828Sgrehanspace(n)
457221828Sgrehanint n;
458221828Sgrehan{
459221828Sgrehan	register char *cp;
460221828Sgrehan
461221828Sgrehan	if ((cp = getcell(n)) == 0)
462221828Sgrehan		err("out of string space");
463234761Sgrehan	return(cp);
464234761Sgrehan}
465234761Sgrehan
466234761Sgrehanchar *
467234761Sgrehanstrsave(s, a)
468234761Sgrehanregister char *s;
469234761Sgrehanint a;
470234761Sgrehan{
471234761Sgrehan	register char *cp, *xp;
472234761Sgrehan
473234761Sgrehan	if ((cp = space(strlen(s)+1)) != NULL) {
474234761Sgrehan		setarea((char *)cp, a);
475234761Sgrehan		for (xp = cp; (*xp++ = *s++) != '\0';)
476234761Sgrehan			;
477234761Sgrehan		return(cp);
478234761Sgrehan	}
479234761Sgrehan	return("");
480234761Sgrehan}
481234761Sgrehan
482221828Sgrehanvoid
483221828Sgrehanxfree(s)
484221828Sgrehanregister char *s;
485221828Sgrehan{
486221828Sgrehan	DELETE(s);
487221828Sgrehan}
488221828Sgrehan
489221828Sgrehan/*
490221828Sgrehan * trap handling
491221828Sgrehan */
492221828Sgrehanvoid
493221828Sgrehansig(i)
494221828Sgrehanregister int i;
495221828Sgrehan{
496221828Sgrehan	trapset = i;
497221828Sgrehan	signal(i, sig);
498221828Sgrehan}
499221828Sgrehan
500221828Sgrehanvoid runtrap(i)
501221828Sgrehanint i;
502221828Sgrehan{
503221828Sgrehan	char *trapstr;
504221828Sgrehan
505221828Sgrehan	if ((trapstr = trap[i]) == NULL)
506221828Sgrehan		return;
507221828Sgrehan	if (i == 0)
508221828Sgrehan		trap[i] = 0;
509221828Sgrehan	RUN(aword, trapstr, nlchar);
510221828Sgrehan}
511221828Sgrehan
512221828Sgrehan/* -------- var.c -------- */
513221828Sgrehan/* #include "sh.h" */
514221828Sgrehan
515221828Sgrehan/*
516221828Sgrehan * Find the given name in the dictionary
517221828Sgrehan * and return its value.  If the name was
518221828Sgrehan * not previously there, enter it now and
519221828Sgrehan * return a null value.
520221828Sgrehan */
521221828Sgrehanstruct var *
522221828Sgrehanlookup(n)
523221828Sgrehanregister char *n;
524221828Sgrehan{
525221828Sgrehan	register struct var *vp;
526221828Sgrehan	register char *cp;
527221828Sgrehan	register int c;
528221828Sgrehan	static struct var dummy;
529221828Sgrehan
530221828Sgrehan	if (digit(*n)) {
531221828Sgrehan		dummy.name = n;
532221828Sgrehan		for (c = 0; digit(*n) && c < 1000; n++)
533221828Sgrehan			c = c*10 + *n-'0';
534221828Sgrehan		dummy.status = RONLY;
535221828Sgrehan		dummy.value = c <= dolc? dolv[c]: null;
536221828Sgrehan		return(&dummy);
537221828Sgrehan	}
538221828Sgrehan	for (vp = vlist; vp; vp = vp->next)
539221828Sgrehan		if (eqname(vp->name, n))
540221828Sgrehan			return(vp);
541221828Sgrehan	cp = findeq(n);
542221828Sgrehan	vp = (struct var *)space(sizeof(*vp));
543221828Sgrehan	if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
544221828Sgrehan		dummy.name = dummy.value = "";
545239025Sneel		return(&dummy);
546221828Sgrehan	}
547221828Sgrehan	for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
548221828Sgrehan		;
549221828Sgrehan	if (*cp == 0)
550221828Sgrehan		*cp = '=';
551221828Sgrehan	*++cp = 0;
552221828Sgrehan	setarea((char *)vp, 0);
553221828Sgrehan	setarea((char *)vp->name, 0);
554221828Sgrehan	vp->value = null;
555221828Sgrehan	vp->next = vlist;
556221828Sgrehan	vp->status = GETCELL;
557221828Sgrehan	vlist = vp;
558221828Sgrehan	return(vp);
559221828Sgrehan}
560221828Sgrehan
561221828Sgrehan/*
562221828Sgrehan * give variable at `vp' the value `val'.
563221828Sgrehan */
564221828Sgrehanvoid
565221828Sgrehansetval(vp, val)
566221828Sgrehanstruct var *vp;
567221828Sgrehanchar *val;
568221828Sgrehan{
569221828Sgrehan	nameval(vp, val, (char *)NULL);
570221828Sgrehan}
571221828Sgrehan
572221828Sgrehan/*
573221828Sgrehan * if name is not NULL, it must be
574221828Sgrehan * a prefix of the space `val',
575221828Sgrehan * and end with `='.
576221828Sgrehan * this is all so that exporting
577221828Sgrehan * values is reasonably painless.
578221828Sgrehan */
579221828Sgrehanvoid
580221828Sgrehannameval(vp, val, name)
581221828Sgrehanregister struct var *vp;
582221828Sgrehanchar *val, *name;
583221828Sgrehan{
584221828Sgrehan	register char *cp, *xp;
585221828Sgrehan	char *nv;
586221828Sgrehan	int fl;
587221828Sgrehan
588221828Sgrehan	if (vp->status & RONLY) {
589221828Sgrehan		for (xp = vp->name; *xp && *xp != '=';)
590221828Sgrehan			putc(*xp++);
591221828Sgrehan		err(" is read-only");
592221828Sgrehan		return;
593221828Sgrehan	}
594221828Sgrehan	fl = 0;
595221828Sgrehan	if (name == NULL) {
596221828Sgrehan		xp = space(strlen(vp->name)+strlen(val)+2);
597221828Sgrehan		if (xp == 0)
598221828Sgrehan			return;
599221828Sgrehan		/* make string:  name=value */
600221828Sgrehan		setarea((char *)xp, 0);
601221828Sgrehan		name = xp;
602221828Sgrehan		for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
603221828Sgrehan			;
604221828Sgrehan		if (*xp++ == 0)
605221828Sgrehan			xp[-1] = '=';
606221828Sgrehan		nv = xp;
607221828Sgrehan		for (cp = val; (*xp++ = *cp++) != '\0';)
608221828Sgrehan			;
609221828Sgrehan		val = nv;
610221828Sgrehan		fl = GETCELL;
611221828Sgrehan	}
612221828Sgrehan	if (vp->status & GETCELL)
613221828Sgrehan		xfree(vp->name);	/* form new string `name=value' */
614221828Sgrehan	vp->name = name;
615221828Sgrehan	vp->value = val;
616221828Sgrehan	vp->status |= fl;
617221828Sgrehan}
618221828Sgrehan
619221828Sgrehanvoid
620221828Sgrehanexport(vp)
621221828Sgrehanstruct var *vp;
622221828Sgrehan{
623221828Sgrehan	vp->status |= EXPORT;
624221828Sgrehan}
625221828Sgrehan
626221828Sgrehanvoid
627221828Sgrehanronly(vp)
628221828Sgrehanstruct var *vp;
629221828Sgrehan{
630221828Sgrehan	if (letter(vp->name[0]))	/* not an internal symbol ($# etc) */
631221828Sgrehan		vp->status |= RONLY;
632221828Sgrehan}
633221828Sgrehan
634221828Sgrehanint
635221828Sgrehanisassign(s)
636221828Sgrehanregister char *s;
637221828Sgrehan{
638221828Sgrehan	if (!letter((int)*s))
639221828Sgrehan		return(0);
640221828Sgrehan	for (; *s != '='; s++)
641221828Sgrehan		if (*s == 0 || !letnum(*s))
642221828Sgrehan			return(0);
643221828Sgrehan	return(1);
644221828Sgrehan}
645221828Sgrehan
646221828Sgrehanint
647221828Sgrehanassign(s, cf)
648221828Sgrehanregister char *s;
649221828Sgrehanint cf;
650221828Sgrehan{
651221828Sgrehan	register char *cp;
652221828Sgrehan	struct var *vp;
653221828Sgrehan
654221828Sgrehan	if (!letter(*s))
655221828Sgrehan		return(0);
656221828Sgrehan	for (cp = s; *cp != '='; cp++)
657221828Sgrehan		if (*cp == 0 || !letnum(*cp))
658221828Sgrehan			return(0);
659221828Sgrehan	vp = lookup(s);
660221828Sgrehan	nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
661221828Sgrehan	if (cf != COPYV)
662221828Sgrehan		vp->status &= ~GETCELL;
663221828Sgrehan	return(1);
664221828Sgrehan}
665221828Sgrehan
666221828Sgrehanint
667221828Sgrehancheckname(cp)
668221828Sgrehanregister char *cp;
669221828Sgrehan{
670221828Sgrehan	if (!letter(*cp++))
671		return(0);
672	while (*cp)
673		if (!letnum(*cp++))
674			return(0);
675	return(1);
676}
677
678void
679putvlist(f, out)
680register int f, out;
681{
682	register struct var *vp;
683
684	for (vp = vlist; vp; vp = vp->next)
685		if (vp->status & f && letter(*vp->name)) {
686			if (vp->status & EXPORT)
687				write(out, "export ", 7);
688			if (vp->status & RONLY)
689				write(out, "readonly ", 9);
690			write(out, vp->name, (int)(findeq(vp->name) - vp->name));
691			write(out, "\n", 1);
692		}
693}
694
695int
696eqname(n1, n2)
697register char *n1, *n2;
698{
699	for (; *n1 != '=' && *n1 != 0; n1++)
700		if (*n2++ != *n1)
701			return(0);
702	return(*n2 == 0 || *n2 == '=');
703}
704
705static char *
706findeq(cp)
707register char *cp;
708{
709	while (*cp != '\0' && *cp != '=')
710		cp++;
711	return(cp);
712}
713
714/* -------- gmatch.c -------- */
715/*
716 * int gmatch(string, pattern)
717 * char *string, *pattern;
718 *
719 * Match a pattern as in sh(1).
720 */
721
722#define	CMASK	0377
723#define	QUOTE	0200
724#define	QMASK	(CMASK&~QUOTE)
725#define	NOT	'!'	/* might use ^ */
726
727int
728gmatch(s, p)
729register char *s, *p;
730{
731	register int sc, pc;
732
733	if (s == NULL || p == NULL)
734		return(0);
735	while ((pc = *p++ & CMASK) != '\0') {
736		sc = *s++ & QMASK;
737		switch (pc) {
738		case '[':
739			if ((p = cclass(p, sc)) == NULL)
740				return(0);
741			break;
742
743		case '?':
744			if (sc == 0)
745				return(0);
746			break;
747
748		case '*':
749			s--;
750			do {
751				if (*p == '\0' || gmatch(s, p))
752					return(1);
753			} while (*s++ != '\0');
754			return(0);
755
756		default:
757			if (sc != (pc&~QUOTE))
758				return(0);
759		}
760	}
761	return(*s == 0);
762}
763
764static char *
765cclass(p, sub)
766register char *p;
767register int sub;
768{
769	register int c, d, not, found;
770
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