1 /* $Header: /src/pub/tcsh/sh.glob.c,v 3.47 2000/11/11 23:03:37 christos Exp $ */
3 * sh.glob.c: Regular expression expansion
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 RCSID("$Id: sh.glob.c,v 3.47 2000/11/11 23:03:37 christos Exp $")
46 static int pargsiz, gargsiz;
51 #define G_NONE 0 /* No globbing needed */
52 #define G_GLOB 1 /* string contains *?[] characters */
53 #define G_CSH 2 /* string contains ~`{ characters */
55 #define GLOBSPACE 100 /* Alloc increment */
56 #define LONGBSIZE 10240 /* Backquote expansion buffer size */
71 * globbing is now done in two stages. In the first pass we expand
72 * csh globbing idioms ~`{ and then we proceed doing the normal
73 * globbing if needed ?*[
75 * Csh type globbing is handled in globexpand() and the rest is
76 * handled in glob() which is part of the 4.4BSD libc.
79 static Char *globtilde __P((Char **, Char *));
80 static Char *handleone __P((Char *, Char **, int));
81 static Char **libglob __P((Char **));
82 static Char **globexpand __P((Char **));
83 static int globbrace __P((Char *, Char *, Char ***));
84 static void expbrace __P((Char ***, Char ***, int));
85 static int pmatch __P((Char *, Char *, Char **));
86 static void pword __P((int));
87 static void psave __P((int));
88 static void backeval __P((Char *, bool));
94 Char gbuf[BUFSIZE], *gstart, *b, *u, *e;
102 for (b = gstart, e = &gbuf[BUFSIZE - 1];
103 *s && *s != '/' && *s != ':' && b < e;
107 if (gethdir(gstart)) {
108 if (adrof(STRnonomatch))
112 stderror(ERR_UNKUSER, short2str(gstart));
114 stderror(ERR_NOHOME);
116 b = &gstart[Strlen(gstart)];
118 slash = gstart[0] == '/' && gstart[1] == '\0';
126 if (slash && gstart[1] == '/')
129 return (Strsave(gstart));
140 * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
141 * in stack. PWP: let =foobar pass through (for X windows)
143 if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
148 else if (Isdigit(old[1])) {
151 for (b = &old[2]; Isdigit(*b); b++)
152 dig = dig * 10 + (*b - '0');
153 if (*b != '\0' && *b != '/')
154 /* =<number>foobar */
161 if (!getstakd(new, dig))
164 /* Copy the rest of the string */
165 for (d = &new[Strlen(new)];
166 d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';)
178 Char *pm, *pe, *lm, *pl;
181 int size = GLOBSPACE;
183 nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
187 /* copy part up to the brace */
188 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
191 /* check for balanced braces */
192 for (i = 0, pe = ++p; *pe; pe++)
194 if (Ismbyte1(*pe) && *(pe + 1) != EOS)
197 #endif /* DSPMBYTE */
199 /* Ignore everything between [] */
200 for (++pe; *pe != RBRK && *pe != EOS; pe++)
202 if (Ismbyte1(*pe) && *(pe + 1) != EOS)
205 #endif /* DSPMBYTE */
212 else if (*pe == LBRC)
214 else if (*pe == RBRC) {
220 if (i != 0 || *pe == '\0') {
225 for (i = 0, pl = pm = p; pm <= pe; pm++)
227 if (Ismbyte1(*pm) && pm + 1 <= pe)
230 #endif /* DSPMBYTE */
233 for (++pm; *pm != RBRK && *pm != EOS; pm++)
235 if (Ismbyte1(*pm) && *(pm + 1) != EOS)
238 #endif /* DSPMBYTE */
262 (void) Strcpy(lm, pl);
263 (void) Strcat(gbuf, pe + 1);
265 *vl++ = Strsave(gbuf);
268 if (vl == &nv[size]) {
270 nv = (Char **) xrealloc((ptr_t) nv,
271 (size_t) (size * sizeof(Char *)));
272 vl = &nv[size - GLOBSPACE];
286 expbrace(nvp, elp, size)
290 Char **vl, **el, **nv, *s;
296 for (el = vl; *el; el++)
299 for (s = *vl; s; s = *++vl) {
303 /* leave {} untouched for find */
304 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
306 if ((b = Strchr(s, '{')) != NULL) {
310 #if defined (DSPMBYTE)
311 if (b != s && Ismbyte2(*b) && Ismbyte1(*(b-1))) {
312 /* The "{" is the 2nd byte of a MB character */
315 #endif /* DSPMBYTE */
316 if ((len = globbrace(s, b, &bl)) < 0) {
318 stderror(ERR_MISSING, -len);
326 if (&el[len] >= &nv[size]) {
328 l = (int) (&el[len] - &nv[size]);
329 size += GLOBSPACE > l ? GLOBSPACE : l;
332 nv = (Char **) xrealloc((ptr_t) nv,
333 (size_t) (size * sizeof(Char *)));
346 for (bp = el; bp != vp; bp--)
356 for (bp = bl + 1; *bp; *vp++ = *bp++)
372 Char **nv, **vl, **el;
373 int size = GLOBSPACE;
376 nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
380 * Step 1: expand backquotes.
382 while ((s = *v++) != '\0') {
383 if (Strchr(s, '`')) {
386 (void) dobackp(s, 0);
387 for (i = 0; i < pargc; i++) {
389 if (vl == &nv[size]) {
391 nv = (Char **) xrealloc((ptr_t) nv,
392 (size_t) (size * sizeof(Char *)));
393 vl = &nv[size - GLOBSPACE];
396 xfree((ptr_t) pargv);
401 if (vl == &nv[size]) {
403 nv = (Char **) xrealloc((ptr_t) nv,
404 (size_t) (size * sizeof(Char *)));
405 vl = &nv[size - GLOBSPACE];
415 * Step 2: expand braces
418 expbrace(&nv, &el, size);
425 for (s = *vl; s; s = *++vl)
427 Char gp[BUFSIZE], *ns;
429 *vl = globtilde(nv, s);
432 if ((ns = globequal(gp, s)) == NULL) {
433 if (!adrof(STRnonomatch)) {
440 /* Expansion succeeded */
451 * Step 4: expand .. if the variable symlinks==expand is set
453 if ( symlinks == SYM_EXPAND )
454 for (s = *vl; s; s = *++vl) {
455 char *path = short2str(s);
456 if (strstr(path, "..") != NULL && access(path, F_OK) == 0) {
457 *vl = dnormalize(s, 1);
467 handleone(str, vl, action)
478 setname(short2str(str));
480 stderror(ERR_NAME | ERR_AMBIG);
484 for (t = vlp; (p = *t++) != '\0'; chars++)
487 str = (Char *)xmalloc((size_t)(chars * sizeof(Char)));
488 for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) {
490 *strp++ = *p++ & TRIM;
497 str = Strsave(strip(*vlp));
510 int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
513 int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
523 gflgs |= GLOB_NOCHECK;
526 ptr = short2qstr(*vl);
527 switch (glob(ptr, gflgs, 0, &globv)) {
531 stderror(ERR_NAME | ERR_GLOB);
540 if (globv.gl_flags & GLOB_MAGCHAR) {
541 match |= (globv.gl_matchc != 0);
544 gflgs |= GLOB_APPEND;
547 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
548 NULL : blk2short(globv.gl_pathv);
559 Char *v[2], **vl, **vo;
562 noglob = adrof(STRnoglob) != 0;
569 return (strip(Strsave(str)));
573 * Expand back-quote, tilde and brace
576 if (noglob || (gflg & G_GLOB) == 0) {
579 return (Strsave(STRNULL));
582 return (handleone(str, vo, action));
590 else if (noglob || (gflg & G_GLOB) == 0)
591 return (strip(Strsave(str)));
596 if ((gflg & G_CSH) && vl != vo)
599 setname(short2str(str));
600 stderror(ERR_NAME | ERR_NOMATCH);
604 return (Strsave(STRNULL));
607 return (handleone(str, vl, action));
624 gargc = blklen(gargv);
628 noglob = adrof(STRnoglob) != 0;
632 * Expand back-quote, tilde and brace
634 vl = vo = globexpand(v);
636 vl = vo = saveblk(v);
638 if (!noglob && (gflg & G_GLOB)) {
646 gargc = vl ? blklen(vl) : 0;
654 gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz));
662 void (*f) __P((int));
666 while ((p = *t++) != '\0')
677 while ((p = *t++) != '\0')
686 register Char *p, *c;
688 while ((p = *t++) != '\0') {
689 if (*p == '~' || *p == '=')
691 else if (*p == '{' &&
692 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
695 * The following line used to be *(c = p++), but hp broke their
696 * optimizer in 9.01, so we break the assignment into two pieces
697 * The careful reader here will note that *most* compiler workarounds
698 * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence?
700 while ( *(c = p) != '\0') {
706 * We do want to expand echo `echo '*'`, so we don't\
707 * use this piece of code anymore.
709 while (*p && *p != '`')
711 if (*p) /* Quoted chars */
716 if (*p) /* The matching ` */
726 else if (symlinks == SYM_EXPAND &&
727 *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') )
734 * Command substitute cp. If literal, then this is a substitution from a
735 * << redirection, and so we should not crunch blanks and tabs, separating
736 * words only at newlines.
743 register Char *lp, *rp;
744 Char *ep, word[LONGBSIZE];
753 pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz));
755 pargcp = pargs = word;
757 pnleft = LONGBSIZE - 4;
759 #if defined(DSPMBYTE)
760 for (lp = cp;; lp++) {
762 (lp-1 < cp || !Ismbyte2(*lp) || !Ismbyte1(*(lp-1)))) {
766 for (lp = cp; *lp != '`'; lp++) {
767 #endif /* DSPMBYTE */
776 for (rp = lp; *rp && *rp != '`'; rp++)
783 oops: stderror(ERR_UNMATCHED, '`');
786 backeval(ep, literal);
793 backeval(cp, literal)
797 register int icnt, c;
799 struct command faket;
802 Char *fakecom[2], ibuf[BUFSIZE];
807 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
808 faket.t_dtyp = NODE_COMMAND;
809 faket.t_dflg = F_BACKQ;
813 faket.t_dcom = fakecom;
814 fakecom[0] = STRfakecom1;
818 * We do the psave job to temporarily change the current job so that the
819 * following fork is considered a separate job. This is so that when
820 * backquotes are used in a builtin function that calls glob the "current
821 * job" is not corrupted. We only need one level of pushed jobs as long as
822 * we are sure to fork here.
827 * It would be nicer if we could integrate this redirection more with the
828 * routines in sh.sem.c by doing a fake execute on a builtin function that
832 if (pfork(&faket, -1) == 0) {
835 (void) close(pvec[0]);
836 (void) dmove(pvec[1], 1);
837 (void) dmove(SHDIAG, 2);
840 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
841 * posted to comp.bugs.4bsd 12 Sep. 1989.
843 if (pargv) /* mg, 21.dec.88 */
844 blkfree(pargv), pargv = 0, pargsiz = 0;
851 * In the child ``forget'' everything about current aliases or
862 t = syntax(paraml.next, ¶ml, 0);
866 t->t_dflg |= F_NOFORK;
868 (void) sigignore(SIGTSTP);
871 (void) sigignore(SIGTTIN);
874 (void) sigignore(SIGTTOU);
876 execute(t, -1, NULL, NULL);
880 (void) close(pvec[1]);
892 icnt = read(pvec[0], tibuf, BUFSIZE);
893 while (icnt == -1 && errno == EINTR);
898 for (i = 0; i < icnt; i++)
899 ip[i] = (unsigned char) tibuf[i];
910 #endif /* WINNT_NATIVE */
913 * Continue around the loop one more time, so that we can eat
914 * the last newline without terminating this word.
919 if (!quoted && (c == ' ' || c == '\t'))
925 * Unless at end-of-file, we will form a new word here if there were
926 * characters in the word, or in any case when we take text literally.
927 * If we didn't make empty words here when literal was set then we
928 * would lose blank lines.
930 if (c != -1 && (cnt || literal))
934 (void) close(pvec[0]);
944 stderror(ERR_WTOOLONG);
945 *pargcp++ = (Char) c;
953 if (pargc == pargsiz - 1) {
954 pargsiz += GLOBSPACE;
955 pargv = (Char **) xrealloc((ptr_t) pargv,
956 (size_t) (pargsiz * sizeof(Char *)));
958 pargv[pargc++] = Strsave(pargs);
965 Gmatch(string, pattern)
966 Char *string, *pattern;
968 return Gnmatch(string, pattern, NULL);
972 Gnmatch(string, pattern, endstr)
973 Char *string, *pattern, **endstr;
975 Char **blk, **p, *tstring = string;
976 int gpol = 1, gres = 0;
978 if (*pattern == '^') {
983 blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *)));
984 blk[0] = Strsave(pattern);
987 expbrace(&blk, NULL, GLOBSPACE);
990 /* Exact matches only */
991 for (p = blk; *p; p++)
992 gres |= pmatch(string, *p, &tstring) == 2 ? 1 : 0;
994 /* partial matches */
995 int minc = 0x7fffffff;
996 for (p = blk; *p; p++)
997 if (pmatch(string, *p, &tstring) != 0) {
998 int t = (int) (tstring - string);
1000 if (minc == -1 || minc > t)
1003 *endstr = string + minc;
1007 return(gres == gpol);
1011 * Return 2 on exact match,
1012 * Return 1 on substring match.
1013 * Return 0 on no match.
1014 * *estr will point to the end of the longest exact or substring match.
1017 pmatch(string, pattern, estr)
1018 register Char *string, *pattern, **estr;
1020 register Char stringc, patternc;
1021 int match, negate_range;
1022 Char rangec, *oestr, *pestr;
1025 stringc = *string & TRIM;
1027 * apollo compiler bug: switch (patternc = *pattern++) dies
1029 patternc = *pattern++;
1033 return (stringc == 0 ? 2 : 1);
1041 while (*string) string++;
1049 switch(pmatch(string, pattern, estr)) {
1058 abort(); /* Cannot happen */
1075 if ((negate_range = (*pattern == '^')) != 0)
1077 while ((rangec = *pattern++) != '\0') {
1082 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') {
1083 match = (globcharcoll(stringc, *pattern & TRIM) <= 0 &&
1084 globcharcoll(*(pattern-2) & TRIM, stringc) <= 0);
1088 match = (stringc == (rangec & TRIM));
1091 stderror(ERR_NAME | ERR_MISSING, ']');
1092 if (match == negate_range)
1097 if ((patternc & TRIM) != stringc)
1109 register Char *p, *q;
1116 n = (int) ((p - s1) + (q - s2) - 1);
1117 if (++gargc >= gargsiz) {
1118 gargsiz += GLOBSPACE;
1119 gargv = (Char **) xrealloc((ptr_t) gargv,
1120 (size_t) (gargsiz * sizeof(Char *)));
1123 p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char)));
1124 for (q = s1; (*p++ = *q++) != '\0';)
1126 for (p--, q = s2; (*p++ = *q++) != '\0';)
1133 register Char **a, **b;
1135 if (!a) /* check for NULL */
1140 if (!*a) /* check for NULL */
1141 return (*b ? 1 : 0);
1145 return (int) collate(*a, *b);