xref: /original-bsd/bin/csh/glob.c (revision ba762ddc)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)glob.c	5.14 (Berkeley) 04/22/91";
10 #endif /* not lint */
11 
12 #include "sh.h"
13 #include "glob.h"
14 
15 static int noglob, nonomatch;
16 
17 static int pargsiz, gargsiz;
18 /*
19  * Values for gflag
20  */
21 #define G_NONE	0	/* No globbing needed			*/
22 #define G_GLOB	1	/* string contains *?[] characters	*/
23 #define G_CSH	2	/* string contains ~`{ characters	*/
24 
25 #define LBRC '{'
26 #define RBRC '}'
27 #define LBRK '['
28 #define RBRK ']'
29 
30 #define EOS '\0'
31 char **gargv = (char **) 0;
32 short gargc = 0;
33 
34 /*
35  * globbing is now done in two stages. In the first pass we expand
36  * csh globbing idioms ~`{ and then we proceed doing the normal
37  * globbing if needed ?*[
38  *
39  * Csh type globbing is handled in globexpand() and the rest is
40  * handled in glob() which is part of the 4.4BSD libc.
41  *
42  */
43 
44 
45 static char *
46 globtilde(nv, s)
47 char **nv, *s;
48 {
49 	char gbuf[MAXPATHLEN], *gstart, *b, *u;
50 
51 	gstart = gbuf;
52 	*gstart++ = *s++;
53 	for (u = s, b = gstart; *s != '\0' && *s != '/'; *b++ = *s++)
54 		 continue;
55 	*b = EOS;
56 	if (*s == EOS || *s == '/') {
57 		if (s == u)
58 			gstart = strcpy(gbuf, value("home"));
59 		else if (gethdir(gstart)) {
60 			blkfree(nv);
61 			error("Unknown user: %s", gstart);
62 		}
63 		b = &gstart[strlen(gstart)];
64 	}
65 	while (*s) *b++ = *s++;
66 	*b = EOS;
67 	return(savestr(gstart));
68 }
69 
70 static int
71 globbrace(s, p, bl)
72 char *s, *p, ***bl;
73 {
74 	int i, len;
75 	char *pm, *pe, *lm, *pl;
76 	char **nv, **vl;
77 	char gbuf[MAXPATHLEN];
78 	int size = GAVSIZ;
79 
80 	nv = vl = (char **) xalloc(sizeof(char *) * size);
81 
82 	len = 0;
83 	/* copy part up to the brace */
84 	for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
85 		continue;
86 
87 	/* check for balanced braces */
88 	for (i = 0, pe = ++p; *pe; pe++)
89 		if (*pe == LBRK) {
90 			/* Ignore everything between [] */
91 			for (++pe; *pe != RBRK && *pe != EOS; pe++)
92 				continue;
93 			if (*pe == EOS) {
94 				blkfree(nv);
95 				return(- LBRK);
96 			}
97 		}
98 		else if (*pe == LBRC)
99 			i++;
100 		else if (*pe == RBRC) {
101 			if (i == 0)
102 				break;
103 			i--;
104 		}
105 
106 	if (i != 0) {
107 		blkfree(nv);
108 		return(- LBRC);
109 	}
110 
111 	for (i = 0, pl = pm = p; pm <= pe; pm++)
112 	switch (*pm) {
113 	case LBRK:
114 		for (++pm; *pm != RBRK && *pm != EOS; pm++)
115 			continue;
116 		if (*pm == EOS) {
117 			blkfree(nv);
118 			return(- RBRK);
119 		}
120 		break;
121 	case LBRC:
122 		i++;
123 		break;
124 	case RBRC:
125 		if (i) {
126 			i--;
127 			break;
128 		}
129 		/*FALLTHROUGH*/
130 	case ',':
131 		if (i && *pm == ',')
132 			break;
133 		else {
134 			char savec = *pm;
135 			*pm = EOS;
136 			(void) strcpy(lm, pl);
137 			(void) strcat(gbuf, pe + 1);
138 			*pm = savec;
139 			*vl++ = savestr(gbuf);
140 			len++;
141 			pl = pm + 1;
142 			if (vl == &nv[size]) {
143 				size += GAVSIZ;
144 				nv = (char **) xrealloc(nv,
145 							size * sizeof(char *));
146 				vl = &nv[size - GAVSIZ];
147 			}
148 		}
149 		break;
150 	}
151 	*vl = (char *) 0;
152 	*bl = nv;
153 	return(len);
154 }
155 
156 static char **
157 globexpand(v)
158 	char **v;
159 {
160 	char *s;
161 	char **nv, **vl, **el;
162 	int size = GAVSIZ;
163 
164 
165 	nv = vl = (char **) xalloc(sizeof(char *) * size);
166 	*vl = (char *) 0;
167 
168 	/*
169 	 * Step 1: expand backquotes.
170 	 */
171 	while (s = *v++) {
172 		if (index(s, '`')) {
173 			int i;
174 
175 			dobackp(s, 0);
176 			for (i = 0; i < pargc; i++) {
177 				*vl++ = pargv[i];
178 				if (vl == &nv[size]) {
179 					size += GAVSIZ;
180 					nv = (char **) xrealloc(nv,
181 							size * sizeof(char *));
182 					vl = &nv[size - GAVSIZ];
183 				}
184 			}
185 			xfree((char *) pargv);
186 			pargv = (char **) 0;
187 		}
188 		else {
189 			*vl++ = savestr(s);
190 			if (vl == &nv[size]) {
191 				size += GAVSIZ;
192 				nv = (char **) xrealloc(nv,
193 							size * sizeof(char *));
194 				vl = &nv[size - GAVSIZ];
195 			}
196 		}
197 	}
198 	*vl = (char *) 0;
199 
200 	if (noglob)
201 		return(nv);
202 
203 	/*
204 	 * Step 2: expand braces
205 	 */
206 	el = vl;
207 	vl = nv;
208 	for (s = *vl; s; s = *++vl) {
209 		char *b;
210 		char **vp, **bp;
211 		if (b = index(s, LBRC)) {
212 			char **bl;
213 			int i, len;
214 			if ((len = globbrace(s, b, &bl)) < 0) {
215 				blkfree(nv);
216 				error("Missing %c", -len);
217 			}
218 			xfree(s);
219 			if (len == 1) {
220 				*vl-- = *bl;
221 				xfree((char *) bl);
222 				continue;
223 			}
224 			len = blklen(bl);
225 			if (&el[len] >= &nv[size]) {
226 				int l, e;
227 				l = &el[len] - &nv[size];
228 				size += GAVSIZ > l ? GAVSIZ : l;
229 				l = vl - nv;
230 				e = el - nv;
231 				nv = (char **) xrealloc(nv,
232 							size * sizeof(char *));
233 				vl = nv + l;
234 				el = nv + e;
235 			}
236 			vp = vl--;
237 			*vp = *bl;
238 			len--;
239 			for (bp = el; bp != vp; bp--)
240 			     bp[len] = *bp;
241 			el += len;
242 			vp++;
243 			for (bp = bl + 1; *bp; *vp++ = *bp++)
244 				continue;
245 			xfree(bl);
246 		}
247 
248 	}
249 	/*
250 	 * Step 3 expand tilde
251 	 */
252 	vl = nv;
253 	for (s = *vl; s; s = *++vl)
254 		if (*s == '~') {
255 			*vl = globtilde(nv, s);
256 			xfree(s);
257 		}
258 	return(nv);
259 }
260 
261 char *
262 globone(str)
263 	char *str;
264 {
265 
266 	char *v[2];
267 	char *nstr;
268 
269 	noglob = adrof("noglob") != 0;
270 	gflag = 0;
271 	v[0] = str;
272 	v[1] = 0;
273 	tglob(v);
274 	if (gflag == G_NONE)
275 		return (strip(savestr(str)));
276 
277 	if (gflag & G_CSH) {
278 		char **vl;
279 
280 		/*
281 		 * Expand back-quote, tilde and brace
282 		 */
283 		vl = globexpand(v);
284 		if (vl[1] != (char *) 0) {
285 			blkfree(vl);
286 			setname(str);
287 			bferr("Ambiguous");
288 			/*NOTREACHED*/
289 		}
290 		nstr = vl[0];
291 		xfree((char *) vl);
292 	}
293 	else
294 		nstr = str;
295 
296 	if (!noglob && (gflag & G_GLOB)) {
297 		glob_t globv;
298 
299 		globv.gl_offs = 0;
300 		globv.gl_pathv = 0;
301 		nonomatch = adrof("nonomatch") != 0;
302 		glob(nstr, nonomatch ? GLOB_NOCHECK : 0, 0, &globv);
303 		if (gflag & G_CSH)
304 			xfree(nstr);
305 		switch (globv.gl_pathc) {
306 		case 0:
307 			setname(str);
308 			globfree(&globv);
309 			bferr("No match");
310 			/*NOTREACHED*/
311 		case 1:
312 			str = strip(savestr(globv.gl_pathv[0]));
313 			globfree(&globv);
314 			return(str);
315 		default:
316 			setname(str);
317 			globfree(&globv);
318 			bferr("Ambiguous");
319 			/*NOTREACHED*/
320 		}
321 	}
322 	return(nstr ? strip(nstr) : (char *) 0);
323 }
324 
325 char **
326 globall(v)
327 	char **v;
328 {
329 	char *c, **vl, **vo;
330 
331 	if (!v || !v[0]) {
332 		gargv = saveblk(v);
333 		gargc = blklen(gargv);
334 		return (gargv);
335 	}
336 
337 	noglob = adrof("noglob") != 0;
338 	nonomatch = adrof("nonomatch") != 0;
339 
340 	if (gflag & G_CSH)
341 		/*
342 		 * Expand back-quote, tilde and brace
343 		 */
344 		vl = vo = globexpand(v);
345 	else
346 		vl = vo = saveblk(v);
347 
348 	if (!noglob && (gflag & G_GLOB)) {
349 		/*
350 		 * Glob the strings in vl using the glob routine
351 		 * from libc
352 		 */
353 		int gappend = 0;
354 		glob_t globv;
355 
356 		globv.gl_offs = 0;
357 		globv.gl_pathv = 0;
358 		gargc = 0;
359 		do {
360 			glob(*vl, gappend | GLOB_NOCHECK, 0, &globv);
361 			if (!nonomatch && (globv.gl_matchc == 0) &&
362 			    (globv.gl_flags & GLOB_MAGCHAR)) {
363 				if (gflag & G_CSH)
364 					blkfree(vo);
365 				globfree(&globv);
366 				gargc = 0;
367 				return(gargv = (char **) 0);
368 			}
369 			gappend = GLOB_APPEND;
370 		}
371 		while (*++vl);
372 
373 		if (gflag & G_CSH)
374 			blkfree(vo);
375 		if (globv.gl_pathc)
376 			vl = saveblk(globv.gl_pathv);
377 		else
378 			vl = 0;
379 		globfree(&globv);
380 	}
381 
382 	gargc = vl ? blklen(vl) : 0;
383 	return(gargv = vl);
384 }
385 
386 ginit()
387 {
388 	gargsiz = GAVSIZ;
389 	gargv = (char **) xalloc(sizeof(char *) * gargsiz);
390 	gargv[0] = 0;
391 	gargc = 0;
392 }
393 
394 rscan(t, f)
395 	register char **t;
396 	int (*f)();
397 {
398 	register char *p;
399 
400 	while (p = *t++)
401 		while (*p)
402 			(*f)(*p++);
403 }
404 
405 trim(t)
406 	register char **t;
407 {
408 	register char *p;
409 
410 	while (p = *t++)
411 		while (*p)
412 			*p++ &= TRIM;
413 }
414 
415 tglob(t)
416 	register char **t;
417 {
418 	register char *p, c;
419 
420 	while (p = *t++) {
421 		if (*p == '~')
422 			gflag |= G_CSH;
423 		else if (*p == '{' &&
424 		    (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
425 			continue;
426 		while (c = *p++)
427 			if (isglob(c))
428 			    gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB;
429 	}
430 }
431 
432 /*
433  * Command substitute cp.  If literal, then this is a substitution from a
434  * << redirection, and so we should not crunch blanks and tabs, separating
435  * words only at newlines.
436  */
437 char **
438 dobackp(cp, literal)
439 	char *cp;
440 	bool literal;
441 {
442 	register char *lp, *rp;
443 	char *ep, word[MAXPATHLEN];
444 
445 	if (pargv) {
446 		abort();
447 		blkfree(pargv);
448 	}
449 	pargsiz = GAVSIZ;
450 	pargv = (char **) xalloc(sizeof(char *) * pargsiz);
451 	pargv[0] = NOSTR;
452 	pargcp = pargs = word;
453 	pargc = 0;
454 	pnleft = MAXPATHLEN - 4;
455 	for (;;) {
456 		for (lp = cp; *lp != '`'; lp++) {
457 			if (*lp == 0) {
458 				if (pargcp != pargs)
459 					pword();
460 				return (pargv);
461 			}
462 			psave(*lp);
463 		}
464 		lp++;
465 		for (rp = lp; *rp && *rp != '`'; rp++)
466 			if (*rp == '\\') {
467 				rp++;
468 				if (!*rp)
469 					goto oops;
470 			}
471 		if (!*rp)
472 oops:			error("Unmatched `");
473 		ep = savestr(lp);
474 		ep[rp - lp] = 0;
475 		backeval(ep, literal);
476 		cp = rp + 1;
477 	}
478 }
479 
480 backeval(cp, literal)
481 	char *cp;
482 	bool literal;
483 {
484 	register int icnt, c;
485 	register char *ip;
486 	struct command faket;
487 	bool hadnl;
488 	int pvec[2], quoted;
489 	char *fakecom[2], ibuf[BUFSIZ];
490 
491 	hadnl = 0;
492 	icnt = 0;
493 	quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
494 	faket.t_dtyp = NODE_COMMAND;
495 	faket.t_dflg = 0;
496 	faket.t_dlef = 0;
497 	faket.t_drit = 0;
498 	faket.t_dspr = 0;
499 	faket.t_dcom = fakecom;
500 	fakecom[0] = "` ... `";
501 	fakecom[1] = 0;
502 
503 	/*
504 	 * We do the psave job to temporarily change the current job so that
505 	 * the following fork is considered a separate job.  This is so that
506 	 * when backquotes are used in a builtin function that calls glob the
507 	 * "current job" is not corrupted.  We only need one level of pushed
508 	 * jobs as long as we are sure to fork here.
509 	 */
510 	psavejob();
511 
512 	/*
513 	 * It would be nicer if we could integrate this redirection more with
514 	 * the routines in sh.sem.c by doing a fake execute on a builtin
515 	 * function that was piped out.
516 	 */
517 	mypipe(pvec);
518 	if (pfork(&faket, -1) == 0) {
519 		struct wordent paraml;
520 		struct command *t;
521 
522 		(void) close(pvec[0]);
523 		(void) dmove(pvec[1], 1);
524 		(void) dmove(SHDIAG, 2);
525 		initdesc();
526 		arginp = cp;
527 		while (*cp)
528 			*cp++ &= TRIM;
529 		(void) lex(&paraml);
530 		if (err)
531 			error(err);
532 		alias(&paraml);
533 		t = syntax(paraml.next, &paraml, 0);
534 		if (err)
535 			error(err);
536 		if (t)
537 			t->t_dflg |= F_NOFORK;
538 		(void) signal(SIGTSTP, SIG_IGN);
539 		(void) signal(SIGTTIN, SIG_IGN);
540 		(void) signal(SIGTTOU, SIG_IGN);
541 		execute(t, -1);
542 		exitstat();
543 	}
544 	xfree(cp);
545 	(void) close(pvec[1]);
546 	do {
547 		int cnt = 0;
548 		for (;;) {
549 			if (icnt == 0) {
550 				ip = ibuf;
551 				icnt = read(pvec[0], ip, BUFSIZ);
552 				if (icnt <= 0) {
553 					c = -1;
554 					break;
555 				}
556 			}
557 			if (hadnl)
558 				break;
559 			--icnt;
560 			c = (*ip++ & TRIM);
561 			if (c == 0)
562 				break;
563 			if (c == '\n') {
564 				/*
565 				 * Continue around the loop one more time, so
566 				 * that we can eat the last newline without
567 				 * terminating this word.
568 				 */
569 				hadnl = 1;
570 				continue;
571 			}
572 			if (!quoted && (c == ' ' || c == '\t'))
573 				break;
574 			cnt++;
575 			psave(c | quoted);
576 		}
577 		/*
578 		 * Unless at end-of-file, we will form a new word here if there
579 		 * were characters in the word, or in any case when we take
580 		 * text literally.  If we didn't make empty words here when
581 		 * literal was set then we would lose blank lines.
582 		 */
583 		if (c != -1 && (cnt || literal))
584 			pword();
585 		hadnl = 0;
586 	} while (c >= 0);
587 	(void) close(pvec[0]);
588 	pwait();
589 	prestjob();
590 }
591 
592 psave(c)
593 	char c;
594 {
595 	if (--pnleft <= 0)
596 		error("Word too long");
597 	*pargcp++ = c;
598 }
599 
600 pword()
601 {
602 	psave(0);
603 	if (pargc == pargsiz - 1) {
604 	    pargsiz += GAVSIZ;
605 	    pargv = (char **) xrealloc(pargv, pargsiz * sizeof(char *));
606 	}
607 	pargv[pargc++] = savestr(pargs);
608 	pargv[pargc] = NOSTR;
609 	pargcp = pargs;
610 	pnleft = MAXPATHLEN - 4;
611 }
612 
613 Gmatch(string, pattern)
614 	register char *string, *pattern;
615 {
616 	register char stringc, patternc;
617 	int match;
618 	char lastchar, rangec;
619 
620 	for (;; ++string) {
621 		stringc = *string & TRIM;
622 		switch (patternc = *pattern++) {
623 		case 0:
624 			return (stringc == 0);
625 		case '?':
626 			if (stringc == 0)
627 				return (0);
628 			break;
629 		case '*':
630 			if (!*pattern)
631 				return (1);
632 			while (*string)
633 				if (Gmatch(string++, pattern))
634 					return (1);
635 			return (0);
636 		case '[':
637 			lastchar = -1;
638 			match = 0;
639 			while (rangec = *pattern++) {
640 				if (rangec == ']')
641 					if (match)
642 						break;
643 					else
644 						return (0);
645 				if (match)
646 					continue;
647 				if (rangec == '-')
648 					match = (stringc <= *pattern++ &&
649 					    *(pattern-2) <= stringc);
650 				else {
651 					lastchar = rangec;
652 					match = (stringc == rangec);
653 				}
654 			}
655 			if (rangec == 0)
656 				bferr("Missing ]");
657 			break;
658 		default:
659 			if ((patternc & TRIM) != stringc)
660 				return (0);
661 			break;
662 
663 		}
664 	}
665 }
666 
667 Gcat(s1, s2)
668 	char *s1, *s2;
669 {
670 	register char *p, *q;
671 	int n;
672 
673 	for (p = s1; *p++;);
674 	for (q = s2; *q++;);
675 	n = (p - s1) + (q - s2) - 1;
676 	if (++gargc >= gargsiz) {
677 		gargsiz += GAVSIZ;
678 		gargv = (char **) xrealloc(gargv, gargsiz * sizeof(char *));
679 	}
680 	gargv[gargc] = 0;
681 	p = gargv[gargc - 1] = xalloc((unsigned)n);
682 	for (q = s1; *p++ = *q++;);
683 	for (p--, q = s2; *p++ = *q++;);
684 }
685 
686 int
687 sortscmp(a1, a2)
688 	char **a1, **a2;
689 {
690 	return(strcmp(*a1, *a2));
691 }
692