xref: /original-bsd/bin/csh/glob.c (revision e6022291)
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.27 (Berkeley) 08/02/91";
10 #endif /* not lint */
11 
12 #include <sys/param.h>
13 #include <glob.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #if __STDC__
19 # include <stdarg.h>
20 #else
21 # include <varargs.h>
22 #endif
23 
24 #include "csh.h"
25 #include "extern.h"
26 
27 static int noglob;
28 static int pargsiz, gargsiz;
29 
30 /*
31  * Values for gflag
32  */
33 #define	G_NONE	0		/* No globbing needed			*/
34 #define	G_GLOB	1		/* string contains *?[] characters	*/
35 #define	G_CSH	2		/* string contains ~`{ characters	*/
36 
37 #define	GLOBSPACE	100	/* Alloc increment			*/
38 
39 #define LBRC '{'
40 #define RBRC '}'
41 #define LBRK '['
42 #define RBRK ']'
43 #define EOS '\0'
44 
45 Char  **gargv = NULL;
46 long    gargc = 0;
47 Char  **pargv = NULL;
48 long    pargc = 0;
49 
50 /*
51  * globbing is now done in two stages. In the first pass we expand
52  * csh globbing idioms ~`{ and then we proceed doing the normal
53  * globbing if needed ?*[
54  *
55  * Csh type globbing is handled in globexpand() and the rest is
56  * handled in glob() which is part of the 4.4BSD libc.
57  *
58  */
59 static Char	*globtilde __P((Char **, Char *));
60 static Char	**libglob __P((Char **));
61 static Char	**globexpand __P((Char **));
62 static int	globbrace __P((Char *, Char *, Char ***));
63 static void	pword __P((void));
64 static void	psave __P((int));
65 static void	backeval __P((Char *, bool));
66 
67 
68 static Char *
69 globtilde(nv, s)
70     Char  **nv, *s;
71 {
72     Char    gbuf[MAXPATHLEN], *gstart, *b, *u, *e;
73 
74     gstart = gbuf;
75     *gstart++ = *s++;
76     u = s;
77     for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; *s && *s != '/' && b < e;
78 	 *b++ = *s++);
79     *b = EOS;
80     if (gethdir(gstart)) {
81 	blkfree(nv);
82 	if (*gstart)
83 	    stderror(ERR_UNKUSER, short2str(gstart));
84 	else
85 	    stderror(ERR_NOHOME);
86     }
87     b = &gstart[Strlen(gstart)];
88     while (*s)
89 	*b++ = *s++;
90     *b = EOS;
91     --u;
92     xfree((ptr_t) u);
93     return (Strsave(gstart));
94 }
95 
96 static int
97 globbrace(s, p, bl)
98     Char   *s, *p, ***bl;
99 {
100     int     i, len;
101     Char   *pm, *pe, *lm, *pl;
102     Char  **nv, **vl;
103     Char    gbuf[MAXPATHLEN];
104     int     size = GLOBSPACE;
105 
106     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
107     *vl = NULL;
108 
109     len = 0;
110     /* copy part up to the brace */
111     for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
112 	continue;
113 
114     /* check for balanced braces */
115     for (i = 0, pe = ++p; *pe; pe++)
116 	if (*pe == LBRK) {
117 	    /* Ignore everything between [] */
118 	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
119 		continue;
120 	    if (*pe == EOS) {
121 		blkfree(nv);
122 		return (-LBRK);
123 	    }
124 	}
125 	else if (*pe == LBRC)
126 	    i++;
127 	else if (*pe == RBRC) {
128 	    if (i == 0)
129 		break;
130 	    i--;
131 	}
132 
133     if (i != 0 || *pe == '\0') {
134 	blkfree(nv);
135 	return (-RBRC);
136     }
137 
138     for (i = 0, pl = pm = p; pm <= pe; pm++)
139 	switch (*pm) {
140 	case LBRK:
141 	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
142 		continue;
143 	    if (*pm == EOS) {
144 		*vl = NULL;
145 		blkfree(nv);
146 		return (-RBRK);
147 	    }
148 	    break;
149 	case LBRC:
150 	    i++;
151 	    break;
152 	case RBRC:
153 	    if (i) {
154 		i--;
155 		break;
156 	    }
157 	    /* FALLTHROUGH */
158 	case ',':
159 	    if (i && *pm == ',')
160 		break;
161 	    else {
162 		Char    savec = *pm;
163 
164 		*pm = EOS;
165 		(void) Strcpy(lm, pl);
166 		(void) Strcat(gbuf, pe + 1);
167 		*pm = savec;
168 		*vl++ = Strsave(gbuf);
169 		len++;
170 		pl = pm + 1;
171 		if (vl == &nv[size]) {
172 		    size += GLOBSPACE;
173 		    nv = (Char **) xrealloc((ptr_t) nv, (size_t)
174 					    size * sizeof(Char *));
175 		    vl = &nv[size - GLOBSPACE];
176 		}
177 	    }
178 	    break;
179 	}
180     *vl = NULL;
181     *bl = nv;
182     return (len);
183 }
184 
185 static Char **
186 globexpand(v)
187     Char  **v;
188 {
189     Char   *s;
190     Char  **nv, **vl, **el;
191     int     size = GLOBSPACE;
192 
193 
194     nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size);
195     *vl = NULL;
196 
197     /*
198      * Step 1: expand backquotes.
199      */
200     while (s = *v++) {
201 	if (Strchr(s, '`')) {
202 	    int     i;
203 
204 	    (void) dobackp(s, 0);
205 	    for (i = 0; i < pargc; i++) {
206 		*vl++ = pargv[i];
207 		if (vl == &nv[size]) {
208 		    size += GLOBSPACE;
209 		    nv = (Char **) xrealloc((ptr_t) nv,
210 					    (size_t) size * sizeof(Char *));
211 		    vl = &nv[size - GLOBSPACE];
212 		}
213 	    }
214 	    xfree((ptr_t) pargv);
215 	    pargv = NULL;
216 	}
217 	else {
218 	    *vl++ = Strsave(s);
219 	    if (vl == &nv[size]) {
220 		size += GLOBSPACE;
221 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
222 					size * sizeof(Char *));
223 		vl = &nv[size - GLOBSPACE];
224 	    }
225 	}
226     }
227     *vl = NULL;
228 
229     if (noglob)
230 	return (nv);
231 
232     /*
233      * Step 2: expand braces
234      */
235     el = vl;
236     vl = nv;
237     for (s = *vl; s; s = *++vl) {
238 	Char   *b;
239 	Char  **vp, **bp;
240 
241 	if ((b = Strchr(s, LBRC)) != NULL && b[1] != '\0' && b[1] != RBRC) {
242 	    Char  **bl;
243 	    int     len;
244 
245 	    if ((len = globbrace(s, b, &bl)) < 0) {
246 		blkfree(nv);
247 		stderror(ERR_MISSING, -len);
248 	    }
249 	    xfree((ptr_t) s);
250 	    if (len == 1) {
251 		*vl-- = *bl;
252 		xfree((ptr_t) bl);
253 		continue;
254 	    }
255 	    len = blklen(bl);
256 	    if (&el[len] >= &nv[size]) {
257 		int     l, e;
258 
259 		l = &el[len] - &nv[size];
260 		size += GLOBSPACE > l ? GLOBSPACE : l;
261 		l = vl - nv;
262 		e = el - nv;
263 		nv = (Char **) xrealloc((ptr_t) nv, (size_t)
264 					size * sizeof(Char *));
265 		vl = nv + l;
266 		el = nv + e;
267 	    }
268 	    vp = vl--;
269 	    *vp = *bl;
270 	    len--;
271 	    for (bp = el; bp != vp; bp--)
272 		bp[len] = *bp;
273 	    el += len;
274 	    vp++;
275 	    for (bp = bl + 1; *bp; *vp++ = *bp++)
276 		continue;
277 	    xfree((ptr_t) bl);
278 	}
279 
280     }
281 
282     /*
283      * Step 3: expand ~
284      */
285     vl = nv;
286     for (s = *vl; s; s = *++vl)
287 	if (*s == '~')
288 	    *vl = globtilde(nv, s);
289     vl = nv;
290     return (vl);
291 }
292 
293 static Char *
294 handleone(str, vl, action)
295     Char   *str, **vl;
296     int     action;
297 {
298 
299     Char   *cp, **vlp = vl;
300 
301     switch (action) {
302     case G_ERROR:
303 	setname(short2str(str));
304 	blkfree(vl);
305 	stderror(ERR_NAME | ERR_AMBIG);
306 	break;
307     case G_APPEND:
308 	trim(vlp);
309 	str = Strsave(*vlp++);
310 	do {
311 	    cp = Strspl(str, STRspace);
312 	    xfree((ptr_t) str);
313 	    str = Strspl(cp, *vlp);
314 	    xfree((ptr_t) cp);
315 	}
316 	while (*++vlp);
317 	blkfree(vl);
318 	break;
319     case G_IGNORE:
320 	str = Strsave(strip(*vlp));
321 	blkfree(vl);
322 	break;
323     }
324     return (str);
325 }
326 
327 static Char **
328 libglob(vl)
329     Char  **vl;
330 {
331     int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC;
332     glob_t  globv;
333     char   *ptr;
334     int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
335 
336     if (!vl || !vl[0])
337 	return (vl);
338 
339     globv.gl_offs = 0;
340     globv.gl_pathv = 0;
341     globv.gl_pathc = 0;
342 
343     if (nonomatch)
344 	gflgs |= GLOB_NOCHECK;
345 
346     do {
347 	ptr = short2qstr(*vl);
348 	switch (glob(ptr, gflgs, 0, &globv)) {
349 	case GLOB_ABEND:
350 	    setname(ptr);
351 	    stderror(ERR_NAME | ERR_GLOB);
352 	    /* NOTREACHED */
353 	case GLOB_NOSPACE:
354 	    stderror(ERR_NOMEM);
355 	    /* NOTREACHED */
356 	default:
357 	    break;
358 	}
359 	if (globv.gl_flags & GLOB_MAGCHAR) {
360 	    match |= (globv.gl_matchc != 0);
361 	    magic = 1;
362 	}
363 	gflgs |= GLOB_APPEND;
364     }
365     while (*++vl);
366     vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
367 	NULL : blk2short(globv.gl_pathv);
368     globfree(&globv);
369     return (vl);
370 }
371 
372 Char   *
373 globone(str, action)
374     Char   *str;
375     int     action;
376 {
377     Char   *v[2], **vl, **vo;
378     int    gflg;
379 
380     noglob = adrof(STRnoglob) != 0;
381     gflag = 0;
382     v[0] = str;
383     v[1] = 0;
384     tglob(v);
385     gflg = gflag;
386     if (gflg == G_NONE)
387 	return (strip(Strsave(str)));
388 
389     if (gflg & G_CSH) {
390 	/*
391 	 * Expand back-quote, tilde and brace
392 	 */
393 	vo = globexpand(v);
394 	if (noglob || (gflg & G_GLOB) == 0) {
395 	    if (vo[0] == NULL) {
396 		xfree((ptr_t) vo);
397 		return (Strsave(STRNULL));
398 	    }
399 	    if (vo[1] != NULL)
400 		return (handleone(str, vo, action));
401 	    else {
402 		str = strip(vo[0]);
403 		xfree((ptr_t) vo);
404 		return (str);
405 	    }
406 	}
407     }
408     else if (noglob || (gflg & G_GLOB) == 0)
409 	return (strip(Strsave(str)));
410     else
411 	vo = v;
412 
413     vl = libglob(vo);
414     if ((gflg & G_CSH) && vl != vo)
415 	blkfree(vo);
416     if (vl == NULL) {
417 	setname(short2str(str));
418 	stderror(ERR_NAME | ERR_NOMATCH);
419     }
420     if (vl[0] == NULL) {
421 	xfree((ptr_t) vl);
422 	return (Strsave(STRNULL));
423     }
424     if (vl[1] != NULL)
425 	return (handleone(str, vl, action));
426     else {
427 	str = strip(*vl);
428 	xfree((ptr_t) vl);
429 	return (str);
430     }
431 }
432 
433 Char  **
434 globall(v)
435     Char  **v;
436 {
437     Char  **vl, **vo;
438     int   gflg = gflag;
439 
440     if (!v || !v[0]) {
441 	gargv = saveblk(v);
442 	gargc = blklen(gargv);
443 	return (gargv);
444     }
445 
446     noglob = adrof(STRnoglob) != 0;
447 
448     if (gflg & G_CSH)
449 	/*
450 	 * Expand back-quote, tilde and brace
451 	 */
452 	vl = vo = globexpand(v);
453     else
454 	vl = vo = saveblk(v);
455 
456     if (!noglob && (gflg & G_GLOB)) {
457 	vl = libglob(vo);
458 	if ((gflg & G_CSH) && vl != vo)
459 	    blkfree(vo);
460     }
461 
462     gargc = vl ? blklen(vl) : 0;
463     return (gargv = vl);
464 }
465 
466 void
467 ginit()
468 {
469     gargsiz = GLOBSPACE;
470     gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz);
471     gargv[0] = 0;
472     gargc = 0;
473 }
474 
475 void
476 rscan(t, f)
477     register Char **t;
478     void    (*f) ();
479 {
480     register Char *p;
481 
482     while (p = *t++)
483 	while (*p)
484 	    (*f) (*p++);
485 }
486 
487 void
488 trim(t)
489     register Char **t;
490 {
491     register Char *p;
492 
493     while (p = *t++)
494 	while (*p)
495 	    *p++ &= TRIM;
496 }
497 
498 void
499 tglob(t)
500     register Char **t;
501 {
502     register Char *p, c;
503 
504     while (p = *t++) {
505 	if (*p == '~' || *p == '=')
506 	    gflag |= G_CSH;
507 	else if (*p == '{' &&
508 		 (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
509 	    continue;
510 	while (c = *p++)
511 	    if (isglob(c))
512 		gflag |= (c == '{' || c == '`') ? G_CSH : G_GLOB;
513     }
514 }
515 
516 /*
517  * Command substitute cp.  If literal, then this is a substitution from a
518  * << redirection, and so we should not crunch blanks and tabs, separating
519  * words only at newlines.
520  */
521 Char  **
522 dobackp(cp, literal)
523     Char   *cp;
524     bool    literal;
525 {
526     register Char *lp, *rp;
527     Char   *ep, word[MAXPATHLEN];
528 
529     if (pargv) {
530 	abort();
531 	blkfree(pargv);
532     }
533     pargsiz = GLOBSPACE;
534     pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz);
535     pargv[0] = NULL;
536     pargcp = pargs = word;
537     pargc = 0;
538     pnleft = MAXPATHLEN - 4;
539     for (;;) {
540 	for (lp = cp; *lp != '`'; lp++) {
541 	    if (*lp == 0) {
542 		if (pargcp != pargs)
543 		    pword();
544 		return (pargv);
545 	    }
546 	    psave(*lp);
547 	}
548 	lp++;
549 	for (rp = lp; *rp && *rp != '`'; rp++)
550 	    if (*rp == '\\') {
551 		rp++;
552 		if (!*rp)
553 		    goto oops;
554 	    }
555 	if (!*rp)
556     oops:  stderror(ERR_UNMATCHED, '`');
557 	ep = Strsave(lp);
558 	ep[rp - lp] = 0;
559 	backeval(ep, literal);
560 	cp = rp + 1;
561     }
562 }
563 
564 static void
565 backeval(cp, literal)
566     Char   *cp;
567     bool    literal;
568 {
569     register int icnt, c;
570     register Char *ip;
571     struct command faket;
572     bool    hadnl;
573     int     pvec[2], quoted;
574     Char   *fakecom[2], ibuf[BUFSIZ];
575     char    tibuf[BUFSIZ];
576 
577     hadnl = 0;
578     icnt = 0;
579     quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
580     faket.t_dtyp = NODE_COMMAND;
581     faket.t_dflg = 0;
582     faket.t_dlef = 0;
583     faket.t_drit = 0;
584     faket.t_dspr = 0;
585     faket.t_dcom = fakecom;
586     fakecom[0] = STRfakecom1;
587     fakecom[1] = 0;
588 
589     /*
590      * We do the psave job to temporarily change the current job so that the
591      * following fork is considered a separate job.  This is so that when
592      * backquotes are used in a builtin function that calls glob the "current
593      * job" is not corrupted.  We only need one level of pushed jobs as long as
594      * we are sure to fork here.
595      */
596     psavejob();
597 
598     /*
599      * It would be nicer if we could integrate this redirection more with the
600      * routines in sh.sem.c by doing a fake execute on a builtin function that
601      * was piped out.
602      */
603     mypipe(pvec);
604     if (pfork(&faket, -1) == 0) {
605 	struct wordent paraml;
606 	struct command *t;
607 
608 	(void) close(pvec[0]);
609 	(void) dmove(pvec[1], 1);
610 	(void) dmove(SHERR, 2);
611 	initdesc();
612 	/*
613 	 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
614 	 * posted to comp.bugs.4bsd 12 Sep. 1989.
615 	 */
616 	if (pargv)		/* mg, 21.dec.88 */
617 	    blkfree(pargv), pargv = 0, pargsiz = 0;
618 	/* mg, 21.dec.88 */
619 	arginp = cp;
620 	while (*cp)
621 	    *cp++ &= TRIM;
622 	(void) lex(&paraml);
623 	if (seterr)
624 	    stderror(ERR_OLD);
625 	alias(&paraml);
626 	t = syntax(paraml.next, &paraml, 0);
627 	if (seterr)
628 	    stderror(ERR_OLD);
629 	if (t)
630 	    t->t_dflg |= F_NOFORK;
631 	(void) signal(SIGTSTP, SIG_IGN);
632 	(void) signal(SIGTTIN, SIG_IGN);
633 	(void) signal(SIGTTOU, SIG_IGN);
634 	execute(t, -1, NULL, NULL);
635 	exitstat();
636     }
637     xfree((ptr_t) cp);
638     (void) close(pvec[1]);
639     c = 0;
640     ip = NULL;
641     do {
642 	int     cnt = 0;
643 
644 	for (;;) {
645 	    if (icnt == 0) {
646 		int     i;
647 
648 		ip = ibuf;
649 		do
650 		    icnt = read(pvec[0], tibuf, BUFSIZ);
651 		while (icnt == -1 && errno == EINTR);
652 		if (icnt <= 0) {
653 		    c = -1;
654 		    break;
655 		}
656 		for (i = 0; i < icnt; i++)
657 		    ip[i] = (unsigned char) tibuf[i];
658 	    }
659 	    if (hadnl)
660 		break;
661 	    --icnt;
662 	    c = (*ip++ & TRIM);
663 	    if (c == 0)
664 		break;
665 	    if (c == '\n') {
666 		/*
667 		 * Continue around the loop one more time, so that we can eat
668 		 * the last newline without terminating this word.
669 		 */
670 		hadnl = 1;
671 		continue;
672 	    }
673 	    if (!quoted && (c == ' ' || c == '\t'))
674 		break;
675 	    cnt++;
676 	    psave(c | quoted);
677 	}
678 	/*
679 	 * Unless at end-of-file, we will form a new word here if there were
680 	 * characters in the word, or in any case when we take text literally.
681 	 * If we didn't make empty words here when literal was set then we
682 	 * would lose blank lines.
683 	 */
684 	if (c != -1 && (cnt || literal))
685 	    pword();
686 	hadnl = 0;
687     } while (c >= 0);
688     (void) close(pvec[0]);
689     pwait();
690     prestjob();
691 }
692 
693 static void
694 psave(c)
695     int    c;
696 {
697     if (--pnleft <= 0)
698 	stderror(ERR_WTOOLONG);
699     *pargcp++ = c;
700 }
701 
702 static void
703 pword()
704 {
705     psave(0);
706     if (pargc == pargsiz - 1) {
707 	pargsiz += GLOBSPACE;
708 	pargv = (Char **) xrealloc((ptr_t) pargv,
709 				   (size_t) pargsiz * sizeof(Char *));
710     }
711     pargv[pargc++] = Strsave(pargs);
712     pargv[pargc] = NULL;
713     pargcp = pargs;
714     pnleft = MAXPATHLEN - 4;
715 }
716 
717 int
718 Gmatch(string, pattern)
719     register Char *string, *pattern;
720 {
721     register Char stringc, patternc;
722     int     match;
723     Char    rangec;
724 
725     for (;; ++string) {
726 	stringc = *string & TRIM;
727 	patternc = *pattern++;
728 	switch (patternc) {
729 	case 0:
730 	    return (stringc == 0);
731 	case '?':
732 	    if (stringc == 0)
733 		return (0);
734 	    break;
735 	case '*':
736 	    if (!*pattern)
737 		return (1);
738 	    while (*string)
739 		if (Gmatch(string++, pattern))
740 		    return (1);
741 	    return (0);
742 	case '[':
743 	    match = 0;
744 	    while (rangec = *pattern++) {
745 		if (rangec == ']')
746 		    if (match)
747 			break;
748 		    else
749 			return (0);
750 		if (match)
751 		    continue;
752 		if (rangec == '-' && *(pattern - 2) != '[' && *pattern != ']') {
753 		    match = (stringc <= (*pattern & TRIM) &&
754 			     (*(pattern - 2) & TRIM) <= stringc);
755 		    pattern++;
756 		}
757 		else
758 		    match = (stringc == rangec);
759 	    }
760 	    if (rangec == 0)
761 		stderror(ERR_NAME | ERR_MISSING, ']');
762 	    break;
763 	default:
764 	    if ((patternc & TRIM) != stringc)
765 		return (0);
766 	    break;
767 
768 	}
769     }
770 }
771 
772 void
773 Gcat(s1, s2)
774     Char   *s1, *s2;
775 {
776     register Char *p, *q;
777     int     n;
778 
779     for (p = s1; *p++;);
780     for (q = s2; *q++;);
781     n = (p - s1) + (q - s2) - 1;
782     if (++gargc >= gargsiz) {
783 	gargsiz += GLOBSPACE;
784 	gargv = (Char **) xrealloc((ptr_t) gargv,
785 				   (size_t) gargsiz * sizeof(Char *));
786     }
787     gargv[gargc] = 0;
788     p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char));
789     for (q = s1; *p++ = *q++;);
790     for (p--, q = s2; *p++ = *q++;);
791 }
792 
793 #ifdef FILEC
794 int
795 sortscmp(a, b)
796     register Char **a, **b;
797 {
798 #if defined(NLS) && !defined(NOSTRCOLL)
799     char    buf[2048];
800 
801 #endif
802 
803     if (!a)			/* check for NULL */
804 	return (b ? 1 : 0);
805     if (!b)
806 	return (-1);
807 
808     if (!*a)			/* check for NULL */
809 	return (*b ? 1 : 0);
810     if (!*b)
811 	return (-1);
812 
813 #if defined(NLS) && !defined(NOSTRCOLL)
814     (void) strcpy(buf, short2str(*a));
815     return ((int) strcoll(buf, short2str(*b)));
816 #else
817     return ((int) Strcmp(*a, *b));
818 #endif
819 }
820 #endif /* FILEC */
821