xref: /dragonfly/contrib/tcsh-6/sh.glob.c (revision 84d884bf08edef6c02f15218458cd5df8010b654)
1 /*
2  * sh.glob.c: Regular expression expansion
3  */
4 /*-
5  * Copyright (c) 1980, 1991 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 #include "sh.h"
33 #include "tc.h"
34 #include "tw.h"
35 
36 #include "glob.h"
37 
38 /*
39  * Values for gflag
40  */
41 #define   G_NONE    0                   /* No globbing needed                             */
42 #define   G_GLOB    1                   /* string contains *?[] characters      */
43 #define   G_CSH     2                   /* string contains ~`{ characters       */
44 
45 #define   GLOBSPACE 100       /* Alloc increment                      */
46 
47 
48 #define LBRC '{'
49 #define RBRC '}'
50 #define LBRK '['
51 #define RBRK ']'
52 #define EOS '\0'
53 
54 /*
55  * globbing is now done in two stages. In the first pass we expand
56  * csh globbing idioms ~`{ and then we proceed doing the normal
57  * globbing if needed ?*[
58  *
59  * Csh type globbing is handled in globexpand() and the rest is
60  * handled in glob() which is part of the 4.4BSD libc.
61  *
62  */
63 static    Char       *globtilde         (Char *);
64 static    Char     *handleone (Char *, Char **, int);
65 static    Char      **libglob (Char **);
66 static    Char      **globexpand        (Char **, int);
67 static    int         globbrace         (const Char *, Char ***);
68 static  void          expbrace          (Char ***, Char ***, int);
69 static    void        pword             (struct blk_buf *, struct Strbuf *);
70 static    void        backeval          (struct blk_buf *, struct Strbuf *, Char *,
71                                          int);
72 static Char *
globtilde(Char * s)73 globtilde(Char *s)
74 {
75     Char *name, *u, *home, *res;
76 
77     u = s;
78 
79     if (s[1] == '~')
80           return Strsave(s);
81 
82     for (s++; *s && *s != '/' && *s != ':'; s++)
83           continue;
84 
85     name = Strnsave(u + 1, s - (u + 1));
86     cleanup_push(name, xfree);
87     home = gethdir(name);
88     if (home == NULL) {
89           if (adrof(STRnonomatch)) {
90               cleanup_until(name);
91               return u;
92           }
93           if (*name)
94               stderror(ERR_UNKUSER, short2str(name));
95           else
96               stderror(ERR_NOHOME);
97     }
98     cleanup_until(name);
99     if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
100           res = Strsave(s);
101     else
102           res = Strspl(home, s);
103     xfree(home);
104     xfree(u);
105     return res;
106 }
107 
108 /* Returns a newly allocated string, old or NULL */
109 Char *
globequal(Char * old)110 globequal(Char *old)
111 {
112     int     dig;
113     const Char *dir;
114     Char    *b;
115 
116     /*
117      * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
118      * in stack. PWP: let =foobar pass through (for X windows)
119      */
120     if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
121           /* =- */
122           const Char *olddir = varval (STRowd);
123 
124           if (olddir && *olddir &&
125               !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
126               return Strspl(olddir, &old[2]);
127           dig = -1;
128           b = &old[2];
129     }
130     else if (Isdigit(old[1])) {
131           /* =<number> */
132           dig = old[1] - '0';
133           for (b = &old[2]; Isdigit(*b); b++)
134               dig = dig * 10 + (*b - '0');
135           if (*b != '\0' && *b != '/')
136               /* =<number>foobar */
137               return old;
138     }
139     else
140           /* =foobar */
141           return old;
142 
143     dir = getstakd(dig);
144     if (dir == NULL)
145           return NULL;
146     return Strspl(dir, b);
147 }
148 
149 static int
globbrace(const Char * s,Char *** bl)150 globbrace(const Char *s, Char ***bl)
151 {
152     struct Strbuf gbuf = Strbuf_INIT;
153     struct blk_buf bb = BLK_BUF_INIT;
154     int     i;
155     const Char *p, *pm, *pe, *pl;
156     size_t prefix_len;
157 
158     /* copy part up to the brace */
159     for (p = s; *p != LBRC; p++)
160           ;
161     prefix_len = p - s;
162 
163     /* check for balanced braces */
164     for (i = 0, pe = ++p; *pe; pe++)
165           if (*pe == LBRK) {
166               /* Ignore everything between [] */
167               for (++pe; *pe != RBRK && *pe != EOS; pe++)
168                     continue;
169               if (*pe == EOS)
170                     return (-RBRK);
171           }
172           else if (*pe == LBRC)
173               i++;
174           else if (*pe == RBRC) {
175               if (i == 0)
176                     break;
177               i--;
178           }
179 
180     if (i != 0 || *pe == '\0')
181           return (-RBRC);
182 
183     Strbuf_appendn(&gbuf, s, prefix_len);
184 
185     for (i = 0, pl = pm = p; pm <= pe; pm++)
186           switch (*pm) {
187           case LBRK:
188               for (++pm; *pm != RBRK && *pm != EOS; pm++)
189                     continue;
190               if (*pm == EOS) {
191                     bb_cleanup(&bb);
192                     xfree(gbuf.s);
193                     return (-RBRK);
194               }
195               break;
196           case LBRC:
197               i++;
198               break;
199           case RBRC:
200               if (i) {
201                     i--;
202                     break;
203               }
204               /* FALLTHROUGH */
205           case ',':
206               if (i && *pm == ',')
207                     break;
208               else {
209                     gbuf.len = prefix_len;
210                     Strbuf_appendn(&gbuf, pl, pm - pl);
211                     Strbuf_append(&gbuf, pe + 1);
212                     Strbuf_terminate(&gbuf);
213                     bb_append(&bb, Strsave(gbuf.s));
214                     pl = pm + 1;
215               }
216               break;
217           default:
218               break;
219           }
220     *bl = bb_finish(&bb);
221     xfree(gbuf.s);
222     return bb.len;
223 }
224 
225 
226 static void
expbrace(Char *** nvp,Char *** elp,int size)227 expbrace(Char ***nvp, Char ***elp, int size)
228 {
229     Char **vl, **el, **nv, *s;
230 
231     vl = nv = *nvp;
232     if (elp != NULL)
233           el = *elp;
234     else
235           el = vl + blklen(vl);
236 
237     for (s = *vl; s; s = *++vl) {
238           Char  **vp, **bp;
239 
240           /* leave {} untouched for find */
241           if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
242               continue;
243           if (Strchr(s, '{') != NULL) {
244               Char  **bl = NULL;
245               int     len;
246 
247               if ((len = globbrace(s, &bl)) < 0)
248                     stderror(ERR_MISSING, -len);
249               xfree(s);
250               if (len == 1) {
251                     *vl-- = *bl;
252                     xfree(bl);
253                     continue;
254               }
255               if (&el[len] >= &nv[size]) {
256                     size_t l, e;
257                     l = &el[len] - &nv[size];
258                     size += GLOBSPACE > l ? GLOBSPACE : l;
259                     l = vl - nv;
260                     e = el - nv;
261                     nv = xrealloc(nv, size * sizeof(Char *));
262                     *nvp = nv; /* To keep cleanups working */
263                     vl = nv + l;
264                     el = nv + e;
265               }
266               /* nv vl   el     bl
267                * |  |    |      |
268                * -.--..--           x--
269                *   |            len
270                *   vp
271                */
272               vp = vl--;
273               *vp = *bl;
274               len--;
275               for (bp = el; bp != vp; bp--)
276                     bp[len] = *bp;
277               el += len;
278               /* nv vl    el bl
279                * |  |     |  |
280                * -.-x  ---    --
281                *   |len
282                *   vp
283                */
284               vp++;
285               for (bp = bl + 1; *bp; *vp++ = *bp++)
286                     continue;
287               xfree(bl);
288           }
289 
290     }
291     if (elp != NULL)
292           *elp = el;
293 }
294 
295 static Char **
globexpand(Char ** v,int noglob)296 globexpand(Char **v, int noglob)
297 {
298     Char   *s;
299     Char  ***fnv, **vl, **el;
300     int     size = GLOBSPACE;
301 
302 
303     fnv = xmalloc(sizeof(Char ***));
304     *fnv = vl = xmalloc(sizeof(Char *) * size);
305     *vl = NULL;
306     cleanup_push(fnv, blk_indirect_cleanup);
307 
308     /*
309      * Step 1: expand backquotes.
310      */
311     while ((s = *v++) != NULL) {
312           if (Strchr(s, '`')) {
313               int     i;
314               Char **expanded;
315 
316               expanded = dobackp(s, 0);
317               for (i = 0; expanded[i] != NULL; i++) {
318                     *vl++ = expanded[i];
319                     if (vl == &(*fnv)[size]) {
320                         size += GLOBSPACE;
321                         *fnv = xrealloc(*fnv, size * sizeof(Char *));
322                         vl = &(*fnv)[size - GLOBSPACE];
323                     }
324               }
325               xfree(expanded);
326           }
327           else {
328               *vl++ = Strsave(s);
329               if (vl == &(*fnv)[size]) {
330                     size += GLOBSPACE;
331                     *fnv = xrealloc(*fnv, size * sizeof(Char *));
332                     vl = &(*fnv)[size - GLOBSPACE];
333               }
334           }
335           *vl = NULL;
336     }
337 
338     if (noglob)
339           goto done;
340 
341     /*
342      * Step 2: expand braces
343      */
344     el = vl;
345     expbrace(fnv, &el, size);
346 
347 
348     /*
349      * Step 3: expand ~ =
350      */
351     vl = *fnv;
352     for (s = *vl; s; s = *++vl)
353           switch (*s) {
354               Char *ns;
355           case '~':
356               *vl = globtilde(s);
357               break;
358           case '=':
359               if ((ns = globequal(s)) == NULL) {
360                     if (!adrof(STRnonomatch))
361                         stderror(ERR_DEEP); /* Error */
362               }
363               if (ns && ns != s) {
364                     /* Expansion succeeded */
365                     xfree(s);
366                     *vl = ns;
367               }
368               break;
369           default:
370               break;
371           }
372     vl = *fnv;
373 
374     /*
375      * Step 4: expand .. if the variable symlinks==expand is set
376      */
377     if (symlinks == SYM_EXPAND) {
378           for (s = *vl; s; s = *++vl) {
379               *vl = dnormalize(s, 1);
380               xfree(s);
381           }
382     }
383 
384  done:
385     cleanup_ignore(fnv);
386     cleanup_until(fnv);
387     vl = *fnv;
388     xfree(fnv);
389     return vl;
390 }
391 
392 static Char *
handleone(Char * str,Char ** vl,int action)393 handleone(Char *str, Char **vl, int action)
394 {
395     size_t chars;
396     Char **t, *p, *strp;
397 
398     switch (action) {
399     case G_ERROR:
400           setname(short2str(str));
401           blkfree(vl);
402           stderror(ERR_NAME | ERR_AMBIG);
403           break;
404     case G_APPEND:
405           chars = 0;
406           for (t = vl; (p = *t++) != NULL; chars++)
407               chars += Strlen(p);
408           str = xmalloc(chars * sizeof(Char));
409           for (t = vl, strp = str; (p = *t++) != NULL; chars++) {
410               while (*p)
411                      *strp++ = *p++ & TRIM;
412               *strp++ = ' ';
413           }
414           *--strp = '\0';
415           blkfree(vl);
416           break;
417     case G_IGNORE:
418           str = Strsave(strip(*vl));
419           blkfree(vl);
420           break;
421     default:
422           break;
423     }
424     return (str);
425 }
426 
427 static Char **
libglob(Char ** vl)428 libglob(Char **vl)
429 {
430     int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
431     glob_t  globv;
432     char   *ptr;
433     int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
434 
435     if (adrof(STRglobdot))
436        gflgs |= GLOB_DOT;
437 
438     if (adrof(STRglobstar))
439        gflgs |= GLOB_STAR;
440 
441     if (!vl || !vl[0])
442           return(vl);
443 
444     globv.gl_offs = 0;
445     globv.gl_pathv = 0;
446     globv.gl_pathc = 0;
447 
448     if (nonomatch)
449           gflgs |= GLOB_NOCHECK;
450 
451     do {
452           ptr = short2qstr(*vl);
453           switch (glob(ptr, gflgs, 0, &globv)) {
454           case GLOB_ABEND:
455               globfree(&globv);
456               setname(ptr);
457               stderror(ERR_NAME | ERR_GLOB);
458               /* NOTREACHED */
459           case GLOB_NOSPACE:
460               globfree(&globv);
461               stderror(ERR_NOMEM);
462               /* NOTREACHED */
463           default:
464               break;
465           }
466           if (globv.gl_flags & GLOB_MAGCHAR) {
467               match |= (globv.gl_matchc != 0);
468               magic = 1;
469           }
470           gflgs |= GLOB_APPEND;
471     }
472     while (*++vl);
473     vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
474           NULL : blk2short(globv.gl_pathv);
475     globfree(&globv);
476     return (vl);
477 }
478 
479 Char   *
globone(Char * str,int action)480 globone(Char *str, int action)
481 {
482     Char   *v[2], **vl, **vo;
483     int gflg, noglob;
484 
485     noglob = adrof(STRnoglob) != 0;
486     v[0] = str;
487     v[1] = 0;
488     gflg = tglob(v);
489     if (gflg == G_NONE)
490           return (strip(Strsave(str)));
491 
492     if (gflg & G_CSH) {
493           /*
494            * Expand back-quote, tilde and brace
495            */
496           vo = globexpand(v, noglob);
497           if (noglob || (gflg & G_GLOB) == 0) {
498               vl = vo;
499               goto result;
500           }
501           cleanup_push(vo, blk_cleanup);
502     }
503     else if (noglob || (gflg & G_GLOB) == 0)
504           return (strip(Strsave(str)));
505     else
506           vo = v;
507 
508     vl = libglob(vo);
509     if (gflg & G_CSH) {
510           if (vl != vo)
511               cleanup_until(vo);
512           else
513               cleanup_ignore(vo);
514     }
515     if (vl == NULL) {
516           setname(short2str(str));
517           stderror(ERR_NAME | ERR_NOMATCH);
518     }
519  result:
520     if (vl && vl[0] == NULL) {
521           if (vl != v)
522               xfree(vl);
523           return (Strsave(STRNULL));
524     }
525     if (vl && vl[1])
526           return (handleone(str, vl, action));
527     else {
528           str = strip(*vl);
529           if (vl != v)
530               xfree(vl);
531           return (str);
532     }
533 }
534 
535 Char  **
globall(Char ** v,int gflg)536 globall(Char **v, int gflg)
537 {
538     Char  **vl, **vo;
539     int noglob;
540 
541     if (!v || !v[0])
542           return saveblk(v);
543 
544     noglob = adrof(STRnoglob) != 0;
545 
546     if (gflg & G_CSH)
547           /*
548            * Expand back-quote, tilde and brace
549            */
550           vl = vo = globexpand(v, noglob);
551     else
552           vl = vo = saveblk(v);
553 
554     if (!noglob && (gflg & G_GLOB)) {
555           cleanup_push(vo, blk_cleanup);
556           vl = libglob(vo);
557           if (vl == vo)
558               cleanup_ignore(vo);
559           cleanup_until(vo);
560     }
561     else
562           trim(vl);
563 
564     return vl;
565 }
566 
567 Char **
glob_all_or_error(Char ** v)568 glob_all_or_error(Char **v)
569 {
570     int gflag;
571 
572     gflag = tglob(v);
573     if (gflag) {
574           v = globall(v, gflag);
575           if (v == NULL)
576               stderror(ERR_NAME | ERR_NOMATCH);
577     } else {
578           v = saveblk(v);
579           trim(v);
580     }
581     return v;
582 }
583 
584 void
rscan(Char ** t,void (* f)(Char))585 rscan(Char **t, void (*f) (Char))
586 {
587     Char *p;
588 
589     while ((p = *t++) != NULL)
590           while (*p)
591               (*f) (*p++);
592 }
593 
594 void
trim(Char ** t)595 trim(Char **t)
596 {
597     Char *p;
598 
599     while ((p = *t++) != NULL)
600           while (*p) {
601 #if INVALID_BYTE != 0
602               if ((*p & INVALID_BYTE) != INVALID_BYTE)      /* *p < INVALID_BYTE */
603 #endif
604                     *p &= TRIM;
605               p++;
606           }
607 }
608 
609 int
tglob(Char ** t)610 tglob(Char **t)
611 {
612     int gflag;
613     const Char *p;
614 
615     gflag = 0;
616     while ((p = *t++) != NULL) {
617           if (*p == '~' || *p == '=')
618               gflag |= G_CSH;
619           else if (*p == '{' &&
620                      (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
621               continue;
622           while (*p != '\0') {
623               if (*p == '`') {
624                     gflag |= G_CSH;
625 #ifdef notdef
626                     /*
627                      * We do want to expand echo `echo '*'`, so we don't\
628                      * use this piece of code anymore.
629                      */
630                     p++;
631                     while (*p && *p != '`')
632                         if (*p++ == '\\') {
633                               if (*p)             /* Quoted chars */
634                                   p++;
635                               else
636                                   break;
637                         }
638                     if (!*p)            /* The matching ` */
639                         break;
640 #endif
641               }
642               else if (*p == '{')
643                     gflag |= G_CSH;
644               else if (isglob(*p))
645                     gflag |= G_GLOB;
646               else if (symlinks == SYM_EXPAND &&
647                     p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
648                     gflag |= G_CSH;
649               p++;
650           }
651     }
652     return gflag;
653 }
654 
655 /*
656  * Command substitute cp.  If literal, then this is a substitution from a
657  * << redirection, and so we should not crunch blanks and tabs, separating
658  * words only at newlines.
659  */
660 Char  **
dobackp(Char * cp,int literal)661 dobackp(Char *cp, int literal)
662 {
663     struct Strbuf word = Strbuf_INIT;
664     struct blk_buf bb = BLK_BUF_INIT;
665     Char *lp, *rp, *ep;
666 
667     cleanup_push(&bb, bb_cleanup);
668     cleanup_push(&word, Strbuf_cleanup);
669     for (;;) {
670           for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
671               ;
672           Strbuf_appendn(&word, cp, lp - cp);
673           if (*lp == 0)
674               break;
675           lp++;
676           for (rp = lp; *rp && *rp != '`'; rp++)
677               if (*rp == '\\') {
678                     rp++;
679                     if (!*rp)
680                         goto oops;
681               }
682           if (!*rp) {
683           oops:
684               cleanup_until(&bb);
685               stderror(ERR_UNMATCHED, '`');
686           }
687           ep = Strnsave(lp, rp - lp);
688           cleanup_push(ep, xfree);
689           backeval(&bb, &word, ep, literal);
690           cleanup_until(ep);
691           cp = rp + 1;
692     }
693     if (word.len != 0)
694           pword(&bb, &word);
695     cleanup_ignore(&bb);
696     cleanup_until(&bb);
697     return bb_finish(&bb);
698 }
699 
700 
701 static void
backeval(struct blk_buf * bb,struct Strbuf * word,Char * cp,int literal)702 backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
703 {
704     ssize_t icnt;
705     Char c, *ip;
706     struct command faket;
707     int    hadnl;
708     int     pvec[2], quoted;
709     Char   *fakecom[2], ibuf[BUFSIZE];
710 
711     hadnl = 0;
712     icnt = 0;
713     if (!literal) {
714           for (ip = cp; (*ip & QUOTE) != 0; ip++)
715                     continue;
716           quoted = *ip == '\0';
717     } else
718           quoted = literal;
719     faket.t_dtyp = NODE_COMMAND;
720     faket.t_dflg = F_BACKQ;
721     faket.t_dlef = 0;
722     faket.t_drit = 0;
723     faket.t_dspr = 0;
724     faket.t_dcom = fakecom;
725     fakecom[0] = STRfakecom1;
726     fakecom[1] = 0;
727 
728     /*
729      * We do the psave job to temporarily change the current job so that the
730      * following fork is considered a separate job.  This is so that when
731      * backquotes are used in a builtin function that calls glob the "current
732      * job" is not corrupted.  We only need one level of pushed jobs as long as
733      * we are sure to fork here.
734      */
735     psavejob();
736     cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
737 
738     /*
739      * It would be nicer if we could integrate this redirection more with the
740      * routines in sh.sem.c by doing a fake execute on a builtin function that
741      * was piped out.
742      */
743     mypipe(pvec);
744     cleanup_push(&pvec[0], open_cleanup);
745     cleanup_push(&pvec[1], open_cleanup);
746     if (pfork(&faket, -1) == 0) {
747           jmp_buf_t osetexit;
748           struct command *t;
749           size_t omark;
750 
751           xclose(pvec[0]);
752           (void) dmove(pvec[1], 1);
753           (void) dmove(SHDIAG,  2);
754           initdesc();
755           closem();
756           arginp = cp;
757           for (arginp = cp; *cp; cp++) {
758               *cp &= TRIM;
759               if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
760                     *cp = ' ';
761           }
762 
763         /*
764            * In the child ``forget'' everything about current aliases or
765            * eval vectors.
766            */
767           alvec = NULL;
768           evalvec = NULL;
769           alvecp = NULL;
770           evalp = NULL;
771 
772           omark = cleanup_push_mark();
773           getexit(osetexit);
774           for (;;) {
775               struct wordent paraml1;
776               initlex(&paraml1);
777 
778               (void) setexit();
779               justpr = 0;
780 
781               if (haderr) {
782                     /* unwind */
783                     doneinp = 0;
784                     cleanup_pop_mark(omark);
785                     resexit(osetexit);
786                     reset();
787               }
788               if (seterr) {
789                     xfree(seterr);
790                     seterr = NULL;
791               }
792 
793               freelex(&paraml1);
794               (void) lex(&paraml1);
795               cleanup_push(&paraml1, lex_cleanup);
796               if (seterr)
797                     stderror(ERR_OLD);
798               alias(&paraml1);
799               t = syntax(paraml1.next, &paraml1, 0);
800               cleanup_push(t, syntax_cleanup);
801               /* The F_BACKQ flag must set so the job output is correct if
802                * printexitvalue is set.  If it's not set, the job output
803                * will have "Exit N" appended where N is the exit status. */
804               if (t)
805                         t->t_dflg = F_BACKQ|F_NOFORK;
806               if (seterr)
807                     stderror(ERR_OLD);
808 #ifdef SIGTSTP
809               signal(SIGTSTP, SIG_IGN);
810 #endif
811 #ifdef SIGTTIN
812               signal(SIGTTIN, SIG_IGN);
813 #endif
814 #ifdef SIGTTOU
815               signal(SIGTTOU, SIG_IGN);
816 #endif
817               execute(t, -1, NULL, NULL, TRUE);
818 
819               cleanup_until(&paraml1);
820           }
821     }
822     cleanup_until(&pvec[1]);
823     c = 0;
824     ip = NULL;
825     do {
826           ssize_t     cnt = 0;
827 
828           for (;;) {
829               if (icnt == 0) {
830                     ip = ibuf;
831                     icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
832                     if (icnt <= 0)
833                         goto eof;
834               }
835               if (hadnl)
836                     break;
837               --icnt;
838               c = (*ip++ & TRIM);
839               if (c == 0)
840                     break;
841 #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
842               if (c == '\r')
843                     c = ' ';
844 #endif /* WINNT_NATIVE || __CYGWIN__ */
845               if (c == '\n') {
846                     /*
847                      * Continue around the loop one more time, so that we can eat
848                      * the last newline without terminating this word.
849                      */
850                     hadnl = 1;
851                     continue;
852               }
853               if (!quoted && (c == ' ' || c == '\t'))
854                     break;
855               cnt++;
856               if (c == '\\' || quoted)
857                     c |= QUOTE;
858               Strbuf_append1(word, c);
859           }
860           /*
861            * Unless at end-of-file, we will form a new word here if there were
862            * characters in the word, or in any case when we take text literally.
863            * If we didn't make empty words here when literal was set then we
864            * would lose blank lines.
865            */
866           if (c != 0 && (cnt || literal))
867               pword(bb, word);
868           hadnl = 0;
869     } while (c > 0);
870  eof:
871     cleanup_until(&pvec[0]);
872     pwait();
873     cleanup_until(&faket); /* psavejob_cleanup(); */
874 }
875 
876 static void
pword(struct blk_buf * bb,struct Strbuf * word)877 pword(struct blk_buf *bb, struct Strbuf *word)
878 {
879     Char *s;
880 
881     s = Strbuf_finish(word);
882     bb_append(bb, s);
883     *word = Strbuf_init;
884 }
885 
886 int
Gmatch(const Char * string,const Char * pattern)887 Gmatch(const Char *string, const Char *pattern)
888 {
889     return Gnmatch(string, pattern, NULL);
890 }
891 
892 int
Gnmatch(const Char * string,const Char * pattern,const Char ** endstr)893 Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
894 {
895     Char ***fblk, **p;
896     const Char *tstring = string;
897     int      gpol = 1, gres = 0;
898 
899     if (*pattern == '^') {
900           gpol = 0;
901           pattern++;
902     }
903 
904     fblk = xmalloc(sizeof(Char ***));
905     *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
906     (*fblk)[0] = Strsave(pattern);
907     (*fblk)[1] = NULL;
908 
909     cleanup_push(fblk, blk_indirect_cleanup);
910     expbrace(fblk, NULL, GLOBSPACE);
911 
912     if (endstr == NULL)
913           /* Exact matches only */
914           for (p = *fblk; *p; p++)
915               gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
916     else {
917           const Char *end;
918 
919           /* partial matches */
920         end = Strend(string);
921           for (p = *fblk; *p; p++)
922               if (t_pmatch(string, *p, &tstring, 1) != 0) {
923                     gres |= 1;
924                     if (end > tstring)
925                         end = tstring;
926               }
927           *endstr = end;
928     }
929 
930     cleanup_until(fblk);
931     return(gres == gpol);
932 }
933 
934 /* t_pmatch():
935  *        Return 2 on exact match,
936  *        Return 1 on substring match.
937  *        Return 0 on no match.
938  *        *estr will point to the end of the longest exact or substring match.
939  */
940 int
t_pmatch(const Char * string,const Char * pattern,const Char ** estr,int cs)941 t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
942 {
943     Char stringc, patternc, rangec;
944     int     match, negate_range;
945     const Char *pestr, *nstring;
946 
947     for (nstring = string;; string = nstring) {
948           stringc = *nstring++ & TRIM;
949           patternc = *pattern++ & TRIM;
950           switch (patternc) {
951           case '\0':
952               *estr = string;
953               return (stringc == '\0' ? 2 : 1);
954           case '?':
955               if (stringc == 0)
956                     return (0);
957               break;
958           case '*':
959               if (!*pattern) {
960                     *estr = Strend(string);
961                     return (2);
962               }
963               pestr = NULL;
964 
965               for (;;) {
966                     switch(t_pmatch(string, pattern, estr, cs)) {
967                     case 0:
968                         break;
969                     case 1:
970                         pestr = *estr;/*FIXME: does not guarantee longest match */
971                         break;
972                     case 2:
973                         return 2;
974                     default:
975                         abort();        /* Cannot happen */
976                     }
977                     stringc = *string++ & TRIM;
978                     if (!stringc)
979                         break;
980               }
981 
982               if (pestr) {
983                     *estr = pestr;
984                     return 1;
985               }
986               else
987                     return 0;
988 
989           case '[':
990               match = 0;
991               if ((negate_range = (*pattern == '^')) != 0)
992                     pattern++;
993               while ((rangec = *pattern++ & TRIM) != '\0') {
994                     if (rangec == ']')
995                         break;
996                     if (match)
997                         continue;
998                     if (*pattern == '-' && pattern[1] != ']') {
999                         Char rangec2;
1000                         pattern++;
1001                         rangec2 = *pattern++ & TRIM;
1002                         match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
1003                               globcharcoll(rangec, stringc, 0) <= 0);
1004                     }
1005                     else
1006                         match = (stringc == rangec);
1007               }
1008               if (rangec == '\0')
1009                     stderror(ERR_NAME | ERR_MISSING, ']');
1010               if ((!match) && (stringc == '\0'))
1011                     return (0);
1012               if (match == negate_range)
1013                     return (0);
1014               break;
1015           default:
1016               if (cs ? patternc  != stringc
1017                     : Tolower(patternc) != Tolower(stringc))
1018                     return (0);
1019               break;
1020           }
1021     }
1022 }
1023