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