xref: /original-bsd/bin/csh/glob.c (revision 6c57d260)
1 static	char *sccsid = "@(#)glob.c 4.2 03/11/81";
2 #include "sh.h"
3 
4 /*
5  * C Shell
6  */
7 
8 int	globcnt;
9 
10 char	*globchars =	"`{[*?";
11 
12 char	*gpath, *gpathp, *lastgpathp;
13 int	globbed;
14 bool	noglob;
15 bool	nonomatch;
16 char	*entp;
17 char	**sortbas;
18 
19 char **
20 glob(v)
21 	register char **v;
22 {
23 	char agpath[BUFSIZ];
24 	char *agargv[GAVSIZ];
25 
26 	gpath = agpath; gpathp = gpath; *gpathp = 0;
27 	lastgpathp = &gpath[sizeof agpath - 2];
28 	ginit(agargv); globcnt = 0;
29 #ifdef GDEBUG
30 	printf("glob entered: "); blkpr(v); printf("\n");
31 #endif
32 	noglob = adrof("noglob") != 0;
33 	nonomatch = adrof("nonomatch") != 0;
34 	globcnt = noglob | nonomatch;
35 	while (*v)
36 		collect(*v++);
37 #ifdef GDEBUG
38 	printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n");
39 #endif
40 	if (globcnt == 0 && (gflag&1)) {
41 		blkfree(gargv), gargv = 0;
42 		return (0);
43 	} else
44 		return (gargv = copyblk(gargv));
45 }
46 
47 ginit(agargv)
48 	char **agargv;
49 {
50 
51 	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
52 	gnleft = NCARGS - 4;
53 }
54 
55 collect(as)
56 	register char *as;
57 {
58 	register int i;
59 
60 	if (any('`', as)) {
61 #ifdef GDEBUG
62 		printf("doing backp of %s\n", as);
63 #endif
64 		dobackp(as, 0);
65 #ifdef GDEBUG
66 		printf("backp done, acollect'ing\n");
67 #endif
68 		for (i = 0; i < pargc; i++)
69 			if (noglob)
70 				Gcat(pargv[i], "");
71 			else
72 				acollect(pargv[i]);
73 		if (pargv)
74 			blkfree(pargv), pargv = 0;
75 #ifdef GDEBUG
76 		printf("acollect done\n");
77 #endif
78 	} else if (noglob || eq(as, "{") || eq(as, "{}")) {
79 		Gcat(as, "");
80 		sort();
81 	} else
82 		acollect(as);
83 }
84 
85 acollect(as)
86 	register char *as;
87 {
88 	register int ogargc = gargc;
89 
90 	gpathp = gpath; *gpathp = 0; globbed = 0;
91 	expand(as);
92 	if (gargc == ogargc) {
93 		if (nonomatch) {
94 			Gcat(as, "");
95 			sort();
96 		}
97 	} else
98 		sort();
99 }
100 
101 sort()
102 {
103 	register char **p1, **p2, *c;
104 	char **Gvp = &gargv[gargc];
105 
106 	p1 = sortbas;
107 	while (p1 < Gvp-1) {
108 		p2 = p1;
109 		while (++p2 < Gvp)
110 			if (strcmp(*p1, *p2) > 0)
111 				c = *p1, *p1 = *p2, *p2 = c;
112 		p1++;
113 	}
114 	sortbas = Gvp;
115 }
116 
117 expand(as)
118 	char *as;
119 {
120 	register char *cs;
121 	register char *sgpathp, *oldcs;
122 	struct stat stb;
123 
124 	sgpathp = gpathp;
125 	cs = as;
126 	if (*cs == '~' && gpathp == gpath) {
127 		addpath('~');
128 		for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
129 			addpath(*cs++);
130 		if (!*cs || *cs == '/') {
131 			if (gpathp != gpath + 1) {
132 				*gpathp = 0;
133 				if (gethdir(gpath + 1))
134 					error("Unknown user: %s", gpath + 1);
135 				strcpy(gpath, gpath + 1);
136 			} else
137 				strcpy(gpath, value("home"));
138 			gpathp = strend(gpath);
139 		}
140 	}
141 	while (!any(*cs, globchars)) {
142 		if (*cs == 0) {
143 			if (!globbed)
144 				Gcat(gpath, "");
145 			else if (stat(gpath, &stb) >= 0) {
146 				Gcat(gpath, "");
147 				globcnt++;
148 			}
149 			goto endit;
150 		}
151 		addpath(*cs++);
152 	}
153 	oldcs = cs;
154 	while (cs > as && *cs != '/')
155 		cs--, gpathp--;
156 	if (*cs == '/')
157 		cs++, gpathp++;
158 	*gpathp = 0;
159 	if (*oldcs == '{') {
160 		execbrc(cs, NOSTR);
161 		return;
162 	}
163 	matchdir(cs);
164 endit:
165 	gpathp = sgpathp;
166 	*gpathp = 0;
167 }
168 
169 matchdir(pattern)
170 	char *pattern;
171 {
172 	struct stat stb;
173 	struct direct dirbuf[BUFSIZ / sizeof (struct direct)];
174 	char d_name[DIRSIZ+1];
175 	register int dirf, cnt;
176 
177 	dirf = open(gpath, 0);
178 	if (dirf < 0) {
179 		if (globbed)
180 			return;
181 		goto patherr;
182 	}
183 	if (fstat(dirf, &stb) < 0)
184 		goto patherr;
185 	if (!isdir(stb)) {
186 		errno = ENOTDIR;
187 		goto patherr;
188 	}
189 	while ((cnt = read(dirf, (char *) dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0]) {
190 		register struct direct *ep = dirbuf;
191 
192 		for (cnt /= sizeof (struct direct); cnt > 0; cnt--, ep++) {
193 			if (ep->d_ino == 0)
194 				continue;
195 			copdent(d_name, ep->d_name);
196 			if (match(d_name, pattern)) {
197 				Gcat(gpath, d_name);
198 				globcnt++;
199 			}
200 		}
201 	}
202 	close(dirf);
203 	return;
204 
205 patherr:
206 	Perror(gpath);
207 }
208 
209 copdent(to, from)
210 	register char *to, *from;
211 {
212 	register int cnt = DIRSIZ;
213 
214 	do
215 		*to++ = *from++;
216 	while (--cnt);
217 	*to = 0;
218 }
219 
220 execbrc(p, s)
221 	char *p, *s;
222 {
223 	char restbuf[BUFSIZ + 2];
224 	register char *pe, *pm, *pl;
225 	int brclev = 0;
226 	char *lm, savec, *sgpathp;
227 
228 	for (lm = restbuf; *p != '{'; *lm++ = *p++)
229 		continue;
230 	for (pe = ++p; *pe; pe++)
231 	switch (*pe) {
232 
233 	case '{':
234 		brclev++;
235 		continue;
236 
237 	case '}':
238 		if (brclev == 0)
239 			goto pend;
240 		brclev--;
241 		continue;
242 
243 	case '[':
244 		for (pe++; *pe && *pe != ']'; pe++)
245 			continue;
246 		if (!*pe)
247 			error("Missing ]");
248 		continue;
249 	}
250 pend:
251 	if (brclev || !*pe)
252 		error("Missing }");
253 	for (pl = pm = p; pm <= pe; pm++)
254 	switch (*pm & (QUOTE|TRIM)) {
255 
256 	case '{':
257 		brclev++;
258 		continue;
259 
260 	case '}':
261 		if (brclev) {
262 			brclev--;
263 			continue;
264 		}
265 		goto doit;
266 
267 	case ','|QUOTE:
268 	case ',':
269 		if (brclev)
270 			continue;
271 doit:
272 		savec = *pm;
273 		*pm = 0;
274 		strcpy(lm, pl);
275 		strcat(restbuf, pe + 1);
276 		*pm = savec;
277 		if (s == 0) {
278 			sgpathp = gpathp;
279 			expand(restbuf);
280 			gpathp = sgpathp;
281 			*gpathp = 0;
282 		} else if (amatch(s, restbuf))
283 			return (1);
284 		sort();
285 		pl = pm + 1;
286 		continue;
287 
288 	case '[':
289 		for (pm++; *pm && *pm != ']'; pm++)
290 			continue;
291 		if (!*pm)
292 			error("Missing ]");
293 		continue;
294 	}
295 	return (0);
296 }
297 
298 match(s, p)
299 	char *s, *p;
300 {
301 	register int c;
302 	register char *sentp;
303 	char sglobbed = globbed;
304 
305 	if (*s == '.' && *p != '.')
306 		return (0);
307 	sentp = entp;
308 	entp = s;
309 	c = amatch(s, p);
310 	entp = sentp;
311 	globbed = sglobbed;
312 	return (c);
313 }
314 
315 amatch(s, p)
316 	register char *s, *p;
317 {
318 	register int scc;
319 	int ok, lc;
320 	char *sgpathp;
321 	struct stat stb;
322 	int c, cc;
323 
324 	globbed = 1;
325 	for (;;) {
326 		scc = *s++ & TRIM;
327 		switch (c = *p++) {
328 
329 		case '{':
330 			return (execbrc(p - 1, s - 1));
331 
332 		case '[':
333 			ok = 0;
334 			lc = 077777;
335 			while (cc = *p++) {
336 				if (cc == ']') {
337 					if (ok)
338 						break;
339 					return (0);
340 				}
341 				if (cc == '-') {
342 					if (lc <= scc && scc <= *p++)
343 						ok++;
344 				} else
345 					if (scc == (lc = cc))
346 						ok++;
347 			}
348 			if (cc == 0)
349 				error("Missing ]");
350 			continue;
351 
352 		case '*':
353 			if (!*p)
354 				return (1);
355 			if (*p == '/') {
356 				p++;
357 				goto slash;
358 			}
359 			for (s--; *s; s++)
360 				if (amatch(s, p))
361 					return (1);
362 			return (0);
363 
364 		case 0:
365 			return (scc == 0);
366 
367 		default:
368 			if (c != scc)
369 				return (0);
370 			continue;
371 
372 		case '?':
373 			if (scc == 0)
374 				return (0);
375 			continue;
376 
377 		case '/':
378 			if (scc)
379 				return (0);
380 slash:
381 			s = entp;
382 			sgpathp = gpathp;
383 			while (*s)
384 				addpath(*s++);
385 			addpath('/');
386 			if (stat(gpath, &stb) == 0 && isdir(stb))
387 				if (*p == 0) {
388 					Gcat(gpath, "");
389 					globcnt++;
390 				} else
391 					expand(p);
392 			gpathp = sgpathp;
393 			*gpathp = 0;
394 			return (0);
395 		}
396 	}
397 }
398 
399 Gmatch(s, p)
400 	register char *s, *p;
401 {
402 	register int scc;
403 	int ok, lc;
404 	int c, cc;
405 
406 	for (;;) {
407 		scc = *s++ & TRIM;
408 		switch (c = *p++) {
409 
410 		case '[':
411 			ok = 0;
412 			lc = 077777;
413 			while (cc = *p++) {
414 				if (cc == ']') {
415 					if (ok)
416 						break;
417 					return (0);
418 				}
419 				if (cc == '-') {
420 					if (lc <= scc && scc <= *p++)
421 						ok++;
422 				} else
423 					if (scc == (lc = cc))
424 						ok++;
425 			}
426 			if (cc == 0)
427 				bferr("Missing ]");
428 			continue;
429 
430 		case '*':
431 			if (!*p)
432 				return (1);
433 			for (s--; *s; s++)
434 				if (Gmatch(s, p))
435 					return (1);
436 			return (0);
437 
438 		case 0:
439 			return (scc == 0);
440 
441 		default:
442 			if ((c & TRIM) != scc)
443 				return (0);
444 			continue;
445 
446 		case '?':
447 			if (scc == 0)
448 				return (0);
449 			continue;
450 
451 		}
452 	}
453 }
454 
455 Gcat(s1, s2)
456 	register char *s1, *s2;
457 {
458 
459 	gnleft -= strlen(s1) + strlen(s2) + 1;
460 	if (gnleft <= 0 || ++gargc >= GAVSIZ)
461 		error("Arguments too long");
462 	gargv[gargc] = 0;
463 	gargv[gargc - 1] = strspl(s1, s2);
464 }
465 
466 addpath(c)
467 	char c;
468 {
469 
470 	if (gpathp >= lastgpathp)
471 		error("Pathname too long");
472 	*gpathp++ = c;
473 	*gpathp = 0;
474 }
475 
476 rscan(t, f)
477 	register char **t;
478 	int (*f)();
479 {
480 	register char *p, c;
481 
482 	while (p = *t++) {
483 		if (f == tglob)
484 			if (*p == '~')
485 				gflag |= 2;
486 			else if (eq(p, "{") || eq(p, "{}"))
487 				continue;
488 		while (c = *p++)
489 			(*f)(c);
490 	}
491 }
492 
493 scan(t, f)
494 	register char **t;
495 	int (*f)();
496 {
497 	register char *p, c;
498 
499 	while (p = *t++)
500 		while (c = *p)
501 			*p++ = (*f)(c);
502 }
503 
504 tglob(c)
505 	register char c;
506 {
507 
508 	if (any(c, globchars))
509 		gflag |= c == '{' ? 2 : 1;
510 	return (c);
511 }
512 
513 trim(c)
514 	char c;
515 {
516 
517 	return (c & TRIM);
518 }
519 
520 tback(c)
521 	char c;
522 {
523 
524 	if (c == '`')
525 		gflag = 1;
526 }
527 
528 char *
529 globone(str)
530 	register char *str;
531 {
532 	char *gv[2];
533 	register char **gvp;
534 	register char *cp;
535 
536 	gv[0] = str;
537 	gv[1] = 0;
538 	gflag = 0;
539 	rscan(gv, tglob);
540 	if (gflag) {
541 		gvp = glob(gv);
542 		if (gvp == 0) {
543 			setname(str);
544 			bferr("No match");
545 		}
546 		cp = *gvp++;
547 		if (cp == 0)
548 			cp = "";
549 		else if (*gvp) {
550 			setname(str);
551 			bferr("Ambiguous");
552 		} else
553 			cp = strip(cp);
554 /*
555 		if (cp == 0 || *gvp) {
556 			setname(str);
557 			bferr(cp ? "Ambiguous" : "No output");
558 		}
559 */
560 		xfree((char *)gargv); gargv = 0;
561 	} else {
562 		scan(gv, trim);
563 		cp = savestr(gv[0]);
564 	}
565 	return (cp);
566 }
567 
568 /*
569  * Command substitute cp.  If literal, then this is
570  * a substitution from a << redirection, and so we should
571  * not crunch blanks and tabs, separating words only at newlines.
572  */
573 char **
574 dobackp(cp, literal)
575 	char *cp;
576 	bool literal;
577 {
578 	register char *lp, *rp;
579 	char *ep;
580 	char word[BUFSIZ];
581 	char *apargv[GAVSIZ + 2];
582 
583 	if (pargv) {
584 		abort();
585 		blkfree(pargv);
586 	}
587 	pargv = apargv;
588 	pargv[0] = NOSTR;
589 	pargcp = pargs = word;
590 	pargc = 0;
591 	pnleft = BUFSIZ - 4;
592 	for (;;) {
593 		for (lp = cp; *lp != '`'; lp++) {
594 			if (*lp == 0) {
595 				if (pargcp != pargs)
596 					pword();
597 #ifdef GDEBUG
598 				printf("leaving dobackp\n");
599 #endif
600 				return (pargv = copyblk(pargv));
601 			}
602 			psave(*lp);
603 		}
604 		lp++;
605 		for (rp = lp; *rp && *rp != '`'; rp++)
606 			if (*rp == '\\') {
607 				rp++;
608 				if (!*rp)
609 					goto oops;
610 			}
611 		if (!*rp)
612 oops:
613 			error("Unmatched `");
614 		ep = savestr(lp);
615 		ep[rp - lp] = 0;
616 		backeval(ep, literal);
617 #ifdef GDEBUG
618 		printf("back from backeval\n");
619 #endif
620 		cp = rp + 1;
621 	}
622 }
623 
624 backeval(cp, literal)
625 	char *cp;
626 	bool literal;
627 {
628 	int pvec[2];
629 	int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
630 	char ibuf[BUFSIZ];
631 	register int icnt = 0, c;
632 	register char *ip;
633 	bool hadnl = 0;
634 	char *fakecom[2];
635 	struct command faket;
636 
637 	faket.t_dtyp = TCOM;
638 	faket.t_dflg = 0;
639 	faket.t_dlef = 0;
640 	faket.t_drit = 0;
641 	faket.t_dspr = 0;
642 	faket.t_dcom = fakecom;
643 	fakecom[0] = "` ... `";
644 	fakecom[1] = 0;
645 	/*
646 	 * We do the psave job to temporarily change the current job
647 	 * so that the following fork is considered a separate job.
648 	 * This is so that when backquotes are used in a
649 	 * builtin function that calls glob the "current job" is not corrupted.
650 	 * We only need one level of pushed jobs as long as we are sure to
651 	 * fork here.
652 	 */
653 	psavejob();
654 	/*
655 	 * It would be nicer if we could integrate this redirection more
656 	 * with the routines in sh.sem.c by doing a fake execute on a builtin
657 	 * function that was piped out.
658 	 */
659 	mypipe(pvec);
660 	if (pfork(&faket, -1) == 0) {
661 		struct wordent paraml;
662 		struct command *t;
663 
664 		close(pvec[0]);
665 		dmove(pvec[1], 1);
666 		dmove(SHDIAG, 2);
667 		initdesc();
668 		arginp = cp;
669 		while (*cp)
670 			*cp++ &= TRIM;
671 		lex(&paraml);
672 		if (err)
673 			error(err);
674 		alias(&paraml);
675 		t = syntax(paraml.next, &paraml, 0);
676 		if (err)
677 			error(err);
678 		if (t)
679 			t->t_dflg |= FPAR;
680 		execute(t, -1);
681 		exitstat();
682 	}
683 	xfree(cp);
684 	close(pvec[1]);
685 	do {
686 		int cnt = 0;
687 		for (;;) {
688 			if (icnt == 0) {
689 				ip = ibuf;
690 				icnt = read(pvec[0], ip, BUFSIZ);
691 				if (icnt <= 0) {
692 					c = -1;
693 					break;
694 				}
695 			}
696 			if (hadnl)
697 				break;
698 			--icnt;
699 			c = (*ip++ & TRIM);
700 			if (c == 0)
701 				break;
702 			if (c == '\n') {
703 				/*
704 				 * Continue around the loop one
705 				 * more time, so that we can eat
706 				 * the last newline without terminating
707 				 * this word.
708 				 */
709 				hadnl = 1;
710 				continue;
711 			}
712 			if (!quoted && (c == ' ' || c == '\t'))
713 				break;
714 			cnt++;
715 			psave(c | quoted);
716 		}
717 		/*
718 		 * Unless at end-of-file, we will form a new word
719 		 * here if there were characters in the word, or in
720 		 * any case when we take text literally.  If
721 		 * we didn't make empty words here when literal was
722 		 * set then we would lose blank lines.
723 		 */
724 		if (c != -1 && (cnt || literal))
725 			pword();
726 		hadnl = 0;
727 	} while (c >= 0);
728 #ifdef GDEBUG
729 	printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
730 	printf("also c = %c <%o>\n", c, c);
731 #endif
732 	close(pvec[0]);
733 	pwait();
734 	prestjob();
735 }
736 
737 psave(c)
738 	char c;
739 {
740 
741 	if (--pnleft <= 0)
742 		error("Word too long");
743 	*pargcp++ = c;
744 }
745 
746 pword()
747 {
748 
749 	psave(0);
750 	if (pargc == GAVSIZ)
751 		error("Too many words from ``");
752 	pargv[pargc++] = savestr(pargs);
753 	pargv[pargc] = NOSTR;
754 #ifdef GDEBUG
755 	printf("got word %s\n", pargv[pargc-1]);
756 #endif
757 	pargcp = pargs;
758 	pnleft = BUFSIZ - 4;
759 }
760