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