]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcsh/sh.glob.c
unbound: Vendor import 1.18.0
[FreeBSD/FreeBSD.git] / contrib / tcsh / sh.glob.c
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 *
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 *
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
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
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 **
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 *
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 **
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   *
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  **
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 **
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
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
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
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  **
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
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
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
887 Gmatch(const Char *string, const Char *pattern)
888 {
889     return Gnmatch(string, pattern, NULL);
890 }
891
892 int
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
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 }