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