1#define Extern extern
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <dirent.h>
5#include <limits.h>
6#include <signal.h>
7#define _NSIG NSIG
8#include <errno.h>
9#include <setjmp.h>
10#include "sh.h"
11
12/* -------- eval.c -------- */
13/* #include "sh.h" */
14/* #include "word.h" */
15
16/*
17 * ${}
18 * `command`
19 * blank interpretation
20 * quoting
21 * glob
22 */
23
24_PROTOTYPE(static int expand, (char *cp, struct wdblock **wbp, int f ));
25_PROTOTYPE(static char *blank, (int f ));
26_PROTOTYPE(static int dollar, (int quoted ));
27_PROTOTYPE(static int grave, (int quoted ));
28_PROTOTYPE(void globname, (char *we, char *pp ));
29_PROTOTYPE(static char *generate, (char *start1, char *end1, char *middle, char *end ));
30_PROTOTYPE(static int anyspcl, (struct wdblock *wb ));
31_PROTOTYPE(static int xstrcmp, (char *p1, char *p2 ));
32_PROTOTYPE(void glob0, (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *)));
33_PROTOTYPE(void glob1, (char *base, char *lim ));
34_PROTOTYPE(void glob2, (char *i, char *j ));
35_PROTOTYPE(void glob3, (char *i, char *j, char *k ));
36_PROTOTYPE(char *memcopy, (char *ato, char *from, int nb ));
37
38char **
39eval(ap, f)
40register char **ap;
41int f;
42{
43	struct wdblock *wb;
44	char **wp;
45	char **wf;
46	jmp_buf ev;
47
48	wp = NULL;
49	wb = NULL;
50	wf = NULL;
51	if (newenv(setjmp(errpt = ev)) == 0) {
52		while (*ap && isassign(*ap))
53			expand(*ap++, &wb, f & ~DOGLOB);
54		if (flag['k']) {
55			for (wf = ap; *wf; wf++) {
56				if (isassign(*wf))
57					expand(*wf, &wb, f & ~DOGLOB);
58			}
59		}
60		for (wb = addword((char *)0, wb); *ap; ap++) {
61			if (!flag['k'] || !isassign(*ap))
62				expand(*ap, &wb, f & ~DOKEY);
63		}
64		wb = addword((char *)0, wb);
65		wp = getwords(wb);
66		quitenv();
67	} else
68		gflg = 1;
69	return(gflg? (char **)NULL: wp);
70}
71
72/*
73 * Make the exported environment from the exported
74 * names in the dictionary. Keyword assignments
75 * will already have been done.
76 */
77char **
78makenv()
79
80{
81	register struct wdblock *wb;
82	register struct var *vp;
83
84	wb = NULL;
85	for (vp = vlist; vp; vp = vp->next)
86		if (vp->status & EXPORT)
87			wb = addword(vp->name, wb);
88	wb = addword((char *)0, wb);
89	return(getwords(wb));
90}
91
92char *
93evalstr(cp, f)
94register char *cp;
95int f;
96{
97	struct wdblock *wb;
98
99	wb = NULL;
100	if (expand(cp, &wb, f)) {
101		if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
102			cp = "";
103		DELETE(wb);
104	} else
105		cp = NULL;
106	return(cp);
107}
108
109static int
110expand(cp, wbp, f)
111register char *cp;
112register struct wdblock **wbp;
113int f;
114{
115	jmp_buf ev;
116
117	gflg = 0;
118	if (cp == NULL)
119		return(0);
120	if (!anys("$`'\"", cp) &&
121	    !anys(ifs->value, cp) &&
122	    ((f&DOGLOB)==0 || !anys("[*?", cp))) {
123		cp = strsave(cp, areanum);
124		if (f & DOTRIM)
125			unquote(cp);
126		*wbp = addword(cp, *wbp);
127		return(1);
128	}
129	if (newenv(setjmp(errpt = ev)) == 0) {
130		PUSHIO(aword, cp, strchar);
131		e.iobase = e.iop;
132		while ((cp = blank(f)) && gflg == 0) {
133			e.linep = cp;
134			cp = strsave(cp, areanum);
135			if ((f&DOGLOB) == 0) {
136				if (f & DOTRIM)
137					unquote(cp);
138				*wbp = addword(cp, *wbp);
139			} else
140				*wbp = glob(cp, *wbp);
141		}
142		quitenv();
143	} else
144		gflg = 1;
145	return(gflg == 0);
146}
147
148/*
149 * Blank interpretation and quoting
150 */
151static char *
152blank(f)
153int f;
154{
155	register c, c1;
156	register char *sp;
157	int scanequals, foundequals;
158
159	sp = e.linep;
160	scanequals = f & DOKEY;
161	foundequals = 0;
162
163loop:
164	switch (c = subgetc('"', foundequals)) {
165	case 0:
166		if (sp == e.linep)
167			return(0);
168		*e.linep++ = 0;
169		return(sp);
170
171	default:
172		if (f & DOBLANK && any(c, ifs->value))
173			goto loop;
174		break;
175
176	case '"':
177	case '\'':
178		scanequals = 0;
179		if (INSUB())
180			break;
181		for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
182			if (c == 0)
183				break;
184			if (c == '\'' || !any(c, "$`\""))
185				c |= QUOTE;
186			*e.linep++ = c;
187		}
188		c = 0;
189	}
190	unget(c);
191	if (!letter(c))
192		scanequals = 0;
193	for (;;) {
194		c = subgetc('"', foundequals);
195		if (c == 0 ||
196		    f & (DOBLANK && any(c, ifs->value)) ||
197		    (!INSUB() && any(c, "\"'"))) {
198		        scanequals = 0;
199			unget(c);
200			if (any(c, "\"'"))
201				goto loop;
202			break;
203		}
204		if (scanequals)
205			if (c == '=') {
206				foundequals = 1;
207				scanequals  = 0;
208			}
209			else if (!letnum(c))
210				scanequals = 0;
211		*e.linep++ = c;
212	}
213	*e.linep++ = 0;
214	return(sp);
215}
216
217/*
218 * Get characters, substituting for ` and $
219 */
220int
221subgetc(ec, quoted)
222register char ec;
223int quoted;
224{
225	register char c;
226
227again:
228	c = getc(ec);
229	if (!INSUB() && ec != '\'') {
230		if (c == '`') {
231			if (grave(quoted) == 0)
232				return(0);
233			e.iop->task = XGRAVE;
234			goto again;
235		}
236		if (c == '$' && (c = dollar(quoted)) == 0) {
237			e.iop->task = XDOLL;
238			goto again;
239		}
240	}
241	return(c);
242}
243
244/*
245 * Prepare to generate the string returned by ${} substitution.
246 */
247static int
248dollar(quoted)
249int quoted;
250{
251	int otask;
252	struct io *oiop;
253	char *dolp;
254	register char *s, c, *cp;
255	struct var *vp;
256
257	c = readc();
258	s = e.linep;
259	if (c != '{') {
260		*e.linep++ = c;
261		if (letter(c)) {
262			while ((c = readc())!=0 && letnum(c))
263				if (e.linep < elinep)
264					*e.linep++ = c;
265			unget(c);
266		}
267		c = 0;
268	} else {
269		oiop = e.iop;
270		otask = e.iop->task;
271		e.iop->task = XOTHER;
272		while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
273			if (e.linep < elinep)
274				*e.linep++ = c;
275		if (oiop == e.iop)
276			e.iop->task = otask;
277		if (c != '}') {
278			err("unclosed ${");
279			gflg++;
280			return(c);
281		}
282	}
283	if (e.linep >= elinep) {
284		err("string in ${} too long");
285		gflg++;
286		e.linep -= 10;
287	}
288	*e.linep = 0;
289	if (*s)
290		for (cp = s+1; *cp; cp++)
291			if (any(*cp, "=-+?")) {
292				c = *cp;
293				*cp++ = 0;
294				break;
295			}
296	if (s[1] == 0 && (*s == '*' || *s == '@')) {
297		if (dolc > 1) {
298			/* currently this does not distinguish $* and $@ */
299			/* should check dollar */
300			e.linep = s;
301			PUSHIO(awordlist, dolv+1, dolchar);
302			return(0);
303		} else {	/* trap the nasty ${=} */
304			s[0] = '1';
305			s[1] = 0;
306		}
307	}
308	vp = lookup(s);
309	if ((dolp = vp->value) == null) {
310		switch (c) {
311		case '=':
312			if (digit(*s)) {
313				err("cannot use ${...=...} with $n");
314				gflg++;
315				break;
316			}
317			setval(vp, cp);
318			dolp = vp->value;
319			break;
320
321		case '-':
322			dolp = strsave(cp, areanum);
323			break;
324
325		case '?':
326			if (*cp == 0) {
327				prs("missing value for ");
328				err(s);
329			} else
330				err(cp);
331			gflg++;
332			break;
333		}
334	} else if (c == '+')
335		dolp = strsave(cp, areanum);
336	if (flag['u'] && dolp == null) {
337		prs("unset variable: ");
338		err(s);
339		gflg++;
340	}
341	e.linep = s;
342	PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
343	return(0);
344}
345
346/*
347 * Run the command in `...` and read its output.
348 */
349static int
350grave(quoted)
351int quoted;
352{
353	register char *cp;
354	register int i;
355	int pf[2];
356
357	for (cp = e.iop->argp->aword; *cp != '`'; cp++)
358		if (*cp == 0) {
359			err("no closing `");
360			return(0);
361		}
362	if (openpipe(pf) < 0)
363		return(0);
364	if ((i = fork()) == -1) {
365		closepipe(pf);
366		err("try again");
367		return(0);
368	}
369	if (i != 0) {
370		e.iop->argp->aword = ++cp;
371		close(pf[1]);
372		PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
373		return(1);
374	}
375	*cp = 0;
376	/* allow trapped signals */
377	for (i=0; i<=_NSIG; i++)
378		if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
379			signal(i, SIG_DFL);
380	dup2(pf[1], 1);
381	closepipe(pf);
382	flag['e'] = 0;
383	flag['v'] = 0;
384	flag['n'] = 0;
385	cp = strsave(e.iop->argp->aword, 0);
386	areanum = 1;
387	freehere(areanum);
388	freearea(areanum);	/* free old space */
389	e.oenv = NULL;
390	e.iop = (e.iobase = iostack) - 1;
391	unquote(cp);
392	talking = 0;
393	PUSHIO(aword, cp, nlchar);
394	onecommand();
395	exit(1);
396}
397
398char *
399unquote(as)
400register char *as;
401{
402	register char *s;
403
404	if ((s = as) != NULL)
405		while (*s)
406			*s++ &= ~QUOTE;
407	return(as);
408}
409
410/* -------- glob.c -------- */
411/* #include "sh.h" */
412
413/*
414 * glob
415 */
416
417#define	scopy(x) strsave((x), areanum)
418#define	BLKSIZ	512
419#define	NDENT	((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
420
421static	struct wdblock	*cl, *nl;
422static	char	spcl[] = "[?*";
423
424struct wdblock *
425glob(cp, wb)
426char *cp;
427struct wdblock *wb;
428{
429	register i;
430	register char *pp;
431
432	if (cp == 0)
433		return(wb);
434	i = 0;
435	for (pp = cp; *pp; pp++)
436		if (any(*pp, spcl))
437			i++;
438		else if (!any(*pp & ~QUOTE, spcl))
439			*pp &= ~QUOTE;
440	if (i != 0) {
441		for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
442			nl = newword(cl->w_nword*2);
443			for(i=0; i<cl->w_nword; i++) { /* for each argument */
444				for (pp = cl->w_words[i]; *pp; pp++)
445					if (any(*pp, spcl)) {
446						globname(cl->w_words[i], pp);
447						break;
448					}
449				if (*pp == '\0')
450					nl = addword(scopy(cl->w_words[i]), nl);
451			}
452			for(i=0; i<cl->w_nword; i++)
453				DELETE(cl->w_words[i]);
454			DELETE(cl);
455		}
456		for(i=0; i<cl->w_nword; i++)
457			unquote(cl->w_words[i]);
458		glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
459		if (cl->w_nword) {
460			for (i=0; i<cl->w_nword; i++)
461				wb = addword(cl->w_words[i], wb);
462			DELETE(cl);
463			return(wb);
464		}
465	}
466	wb = addword(unquote(cp), wb);
467	return(wb);
468}
469
470void
471globname(we, pp)
472char *we;
473register char *pp;
474{
475	register char *np, *cp;
476	char *name, *gp, *dp;
477	int dn, j, n, k;
478	DIR *dirp;
479	struct dirent *de;
480	char dname[NAME_MAX+1];
481	struct stat dbuf;
482
483	for (np = we; np != pp; pp--)
484		if (pp[-1] == '/')
485			break;
486	for (dp = cp = space((int)(pp-np)+3); np < pp;)
487		*cp++ = *np++;
488	*cp++ = '.';
489	*cp = '\0';
490	for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
491		*cp++ = *np++;
492	*cp = '\0';
493	dirp = opendir(dp);
494	if (dirp == 0) {
495		DELETE(dp);
496		DELETE(gp);
497		return;
498	}
499	dname[NAME_MAX] = '\0';
500	while ((de=readdir(dirp))!=NULL) {
501		/* XXX Hmmm... What this could be? (abial) */
502		/*
503		if (ent[j].d_ino == 0)
504			continue;
505		*/
506		strncpy(dname, de->d_name, NAME_MAX);
507			if (dname[0] == '.')
508				if (*gp != '.')
509					continue;
510			for(k=0; k<NAME_MAX; k++)
511				if (any(dname[k], spcl))
512					dname[k] |= QUOTE;
513			if (gmatch(dname, gp)) {
514				name = generate(we, pp, dname, np);
515				if (*np && !anys(np, spcl)) {
516					if (stat(name,&dbuf)) {
517						DELETE(name);
518						continue;
519					}
520				}
521				nl = addword(name, nl);
522			}
523	}
524	closedir(dirp);
525	DELETE(dp);
526	DELETE(gp);
527}
528
529/*
530 * generate a pathname as below.
531 * start..end1 / middle end
532 * the slashes come for free
533 */
534static char *
535generate(start1, end1, middle, end)
536char *start1;
537register char *end1;
538char *middle, *end;
539{
540	char *p;
541	register char *op, *xp;
542
543	p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
544	for (xp = start1; xp != end1;)
545		*op++ = *xp++;
546	for (xp = middle; (*op++ = *xp++) != '\0';)
547		;
548	op--;
549	for (xp = end; (*op++ = *xp++) != '\0';)
550		;
551	return(p);
552}
553
554static int
555anyspcl(wb)
556register struct wdblock *wb;
557{
558	register i;
559	register char **wd;
560
561	wd = wb->w_words;
562	for (i=0; i<wb->w_nword; i++)
563		if (anys(spcl, *wd++))
564			return(1);
565	return(0);
566}
567
568static int
569xstrcmp(p1, p2)
570char *p1, *p2;
571{
572	return(strcmp(*(char **)p1, *(char **)p2));
573}
574
575/* -------- word.c -------- */
576/* #include "sh.h" */
577/* #include "word.h" */
578
579#define	NSTART	16	/* default number of words to allow for initially */
580
581struct wdblock *
582newword(nw)
583register int nw;
584{
585	register struct wdblock *wb;
586
587	wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
588	wb->w_bsize = nw;
589	wb->w_nword = 0;
590	return(wb);
591}
592
593struct wdblock *
594addword(wd, wb)
595char *wd;
596register struct wdblock *wb;
597{
598	register struct wdblock *wb2;
599	register nw;
600
601	if (wb == NULL)
602		wb = newword(NSTART);
603	if ((nw = wb->w_nword) >= wb->w_bsize) {
604		wb2 = newword(nw * 2);
605		memcopy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
606		wb2->w_nword = nw;
607		DELETE(wb);
608		wb = wb2;
609	}
610	wb->w_words[wb->w_nword++] = wd;
611	return(wb);
612}
613
614char **
615getwords(wb)
616register struct wdblock *wb;
617{
618	register char **wd;
619	register nb;
620
621	if (wb == NULL)
622		return((char **)NULL);
623	if (wb->w_nword == 0) {
624		DELETE(wb);
625		return((char **)NULL);
626	}
627	wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
628	memcopy((char *)wd, (char *)wb->w_words, nb);
629	DELETE(wb);	/* perhaps should done by caller */
630	return(wd);
631}
632
633_PROTOTYPE(int (*func), (char *, char *));
634int	globv;
635
636void
637glob0(a0, a1, a2, a3)
638char *a0;
639unsigned a1;
640int a2;
641_PROTOTYPE(int (*a3), (char *, char *));
642{
643	func = a3;
644	globv = a2;
645	glob1(a0, a0 + a1 * a2);
646}
647
648void
649glob1(base, lim)
650char *base, *lim;
651{
652	register char *i, *j;
653	int v2;
654	char *lptr, *hptr;
655	int c;
656	unsigned n;
657
658
659	v2 = globv;
660
661top:
662	if ((n=(int)(lim-base)) <= v2)
663		return;
664	n = v2 * (n / (2*v2));
665	hptr = lptr = base+n;
666	i = base;
667	j = lim-v2;
668	for(;;) {
669		if (i < lptr) {
670			if ((c = (*func)(i, lptr)) == 0) {
671				glob2(i, lptr -= v2);
672				continue;
673			}
674			if (c < 0) {
675				i += v2;
676				continue;
677			}
678		}
679
680begin:
681		if (j > hptr) {
682			if ((c = (*func)(hptr, j)) == 0) {
683				glob2(hptr += v2, j);
684				goto begin;
685			}
686			if (c > 0) {
687				if (i == lptr) {
688					glob3(i, hptr += v2, j);
689					i = lptr += v2;
690					goto begin;
691				}
692				glob2(i, j);
693				j -= v2;
694				i += v2;
695				continue;
696			}
697			j -= v2;
698			goto begin;
699		}
700
701
702		if (i == lptr) {
703			if (lptr-base >= lim-hptr) {
704				glob1(hptr+v2, lim);
705				lim = lptr;
706			} else {
707				glob1(base, lptr);
708				base = hptr+v2;
709			}
710			goto top;
711		}
712
713
714		glob3(j, lptr -= v2, i);
715		j = hptr -= v2;
716	}
717}
718
719void
720glob2(i, j)
721char *i, *j;
722{
723	register char *index1, *index2, c;
724	int m;
725
726	m = globv;
727	index1 = i;
728	index2 = j;
729	do {
730		c = *index1;
731		*index1++ = *index2;
732		*index2++ = c;
733	} while(--m);
734}
735
736void
737glob3(i, j, k)
738char *i, *j, *k;
739{
740	register char *index1, *index2, *index3;
741	int c;
742	int m;
743
744	m = globv;
745	index1 = i;
746	index2 = j;
747	index3 = k;
748	do {
749		c = *index1;
750		*index1++ = *index3;
751		*index3++ = *index2;
752		*index2++ = c;
753	} while(--m);
754}
755
756char *
757memcopy(ato, from, nb)
758register char *ato, *from;
759register int nb;
760{
761	register char *to;
762
763	to = ato;
764	while (--nb >= 0)
765		*to++ = *from++;
766	return(ato);
767}
768