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