"Fossies" - the Fresh Open Source Software Archive

Member "tcsh-6.22.03/sh.glob.c" (18 Nov 2020, 21539 Bytes) of package /linux/misc/tcsh-6.22.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "sh.glob.c": 6.22.02_vs_6.22.03.

    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 }