"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libnetbsd/glob.c" (5 Jul 2020, 27575 Bytes) of package /linux/privat/tnftp-20200705.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. For more information about "glob.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /*  $NetBSD: glob.c,v 1.13 2020/07/05 10:03:09 lukem Exp $  */
    2 /*  from: NetBSD: glob.c,v 1.34 2013/02/21 18:17:43 christos Exp    */
    3 
    4 /*
    5  * Copyright (c) 1989, 1993
    6  *  The Regents of the University of California.  All rights reserved.
    7  *
    8  * This code is derived from software contributed to Berkeley by
    9  * Guido van Rossum.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 #if 0
   37 
   38 #include <sys/cdefs.h>
   39 #if defined(LIBC_SCCS) && !defined(lint)
   40 #if 0
   41 static char sccsid[] = "@(#)glob.c  8.3 (Berkeley) 10/13/93";
   42 #else
   43 __RCSID(" NetBSD: glob.c,v 1.38 2017/05/08 14:42:16 christos Exp ");
   44 #endif
   45 #endif /* LIBC_SCCS and not lint */
   46 
   47 #endif
   48 
   49 /*
   50  * glob(3) -- a superset of the one defined in POSIX 1003.2.
   51  *
   52  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
   53  *
   54  * Optional extra services, controlled by flags not defined by POSIX:
   55  *
   56  * GLOB_MAGCHAR:
   57  *  Set in gl_flags if pattern contained a globbing character.
   58  * GLOB_NOMAGIC:
   59  *  Same as GLOB_NOCHECK, but it will only append pattern if it did
   60  *  not contain any magic characters.  [Used in csh style globbing]
   61  * GLOB_ALTDIRFUNC:
   62  *  Use alternately specified directory access functions.
   63  * GLOB_TILDE:
   64  *  expand ~user/foo to the /home/dir/of/user/foo
   65  * GLOB_BRACE:
   66  *  expand {1,2}{a,b} to 1a 1b 2a 2b 
   67  * GLOB_PERIOD:
   68  *  allow metacharacters to match leading dots in filenames.
   69  * GLOB_NO_DOTDIRS:
   70  *  . and .. are hidden from wildcards, even if GLOB_PERIOD is set.
   71  * gl_matchc:
   72  *  Number of matches in the current invocation of glob.
   73  */
   74 
   75 #include "tnftp.h"
   76 
   77 #define NO_GETPW_R
   78 
   79 #undef  TILDE           /* XXX: AIX 4.1.5 has this in <sys/ioctl.h> */
   80 
   81 #ifndef __UNCONST
   82 #define __UNCONST(a)    ((void *)(unsigned long)(const void *)(a))
   83 #endif
   84 
   85 #if 0
   86 
   87 #include "namespace.h"
   88 #include <sys/param.h>
   89 #include <sys/stat.h>
   90 
   91 #include <assert.h>
   92 #include <ctype.h>
   93 #include <dirent.h>
   94 #include <errno.h>
   95 #include <glob.h>
   96 #include <pwd.h>
   97 #include <stdio.h>
   98 #include <stddef.h>
   99 #include <stdlib.h>
  100 #include <string.h>
  101 #include <unistd.h>
  102 
  103 #ifdef HAVE_NBTOOL_CONFIG_H
  104 #define NO_GETPW_R
  105 #endif
  106 
  107 #endif
  108 
  109 #define GLOB_LIMIT_STRING   524288  /* number of readdirs */
  110 #define GLOB_LIMIT_STAT     128 /* number of stat system calls */
  111 #define GLOB_LIMIT_READDIR  65536   /* total buffer size of path strings */
  112 #define GLOB_LIMIT_PATH     1024    /* number of path elements */
  113 #define GLOB_LIMIT_BRACE    128 /* Number of brace calls */
  114 
  115 struct glob_limit {
  116     size_t l_string;
  117     size_t l_stat;  
  118     size_t l_readdir;   
  119     size_t l_brace;
  120 };
  121 
  122 /*
  123  * XXX: For NetBSD 1.4.x compatibility. (kill me l8r)
  124  */
  125 #ifndef _DIAGASSERT
  126 #define _DIAGASSERT(a)
  127 #endif
  128 
  129 #define DOLLAR      '$'
  130 #define DOT     '.'
  131 #define EOS     '\0'
  132 #define LBRACKET    '['
  133 #define NOT     '!'
  134 #define QUESTION    '?'
  135 #define QUOTE       '\\'
  136 #define RANGE       '-'
  137 #define RBRACKET    ']'
  138 #define SEP     '/'
  139 #define STAR        '*'
  140 #define TILDE       '~'
  141 #define UNDERSCORE  '_'
  142 #define LBRACE      '{'
  143 #define RBRACE      '}'
  144 #define SLASH       '/'
  145 #define COMMA       ','
  146 
  147 #ifndef USE_8BIT_CHARS
  148 
  149 #define M_QUOTE     0x8000
  150 #define M_PROTECT   0x4000
  151 #define M_MASK      0xffff
  152 #define M_ASCII     0x00ff
  153 
  154 typedef unsigned short Char;
  155 
  156 #else
  157 
  158 #define M_QUOTE     (Char)0x80
  159 #define M_PROTECT   (Char)0x40
  160 #define M_MASK      (Char)0xff
  161 #define M_ASCII     (Char)0x7f
  162 
  163 typedef char Char;
  164 
  165 #endif
  166 
  167 
  168 #define CHAR(c)     ((Char)((c)&M_ASCII))
  169 #define META(c)     ((Char)((c)|M_QUOTE))
  170 #define M_ALL       META('*')
  171 #define M_END       META(']')
  172 #define M_NOT       META('!')
  173 #define M_ONE       META('?')
  174 #define M_RNG       META('-')
  175 #define M_SET       META('[')
  176 #define ismeta(c)   (((c)&M_QUOTE) != 0)
  177 
  178 
  179 static int   compare(const void *, const void *);
  180 static int   g_Ctoc(const Char *, char *, size_t);
  181 static int   g_lstat(Char *, __gl_stat_t  *, glob_t *);
  182 static DIR  *g_opendir(Char *, glob_t *);
  183 static Char *g_strchr(const Char *, int);
  184 static int   g_stat(Char *, __gl_stat_t *, glob_t *);
  185 static int   glob0(const Char *, glob_t *, struct glob_limit *);
  186 static int   glob1(Char *, glob_t *, struct glob_limit *);
  187 static int   glob2(Char *, Char *, Char *, const Char *, glob_t *,
  188     struct glob_limit *);
  189 static int   glob3(Char *, Char *, Char *, const Char *, const Char *,
  190     const Char *, glob_t *, struct glob_limit *);
  191 static int   globextend(const Char *, glob_t *, struct glob_limit *);
  192 static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
  193 static int   globexp1(const Char *, glob_t *, struct glob_limit *);
  194 static int   globexp2(const Char *, const Char *, glob_t *, int *,
  195     struct glob_limit *);
  196 static int   match(const Char *, const Char *, const Char *);
  197 #ifdef DEBUG
  198 static void  qprintf(const char *, Char *);
  199 #endif
  200 
  201 int
  202 glob(const char * __restrict pattern, int flags, int (*errfunc)(const char *,
  203     int), glob_t * __restrict pglob)
  204 {
  205     const unsigned char *patnext;
  206     int c;
  207     Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
  208     struct glob_limit limit = { 0, 0, 0, 0 };
  209 
  210     _DIAGASSERT(pattern != NULL);
  211 
  212     patnext = (const unsigned char *) pattern;
  213     if (!(flags & GLOB_APPEND)) {
  214         pglob->gl_pathc = 0;
  215         pglob->gl_pathv = NULL;
  216         if (!(flags & GLOB_DOOFFS))
  217             pglob->gl_offs = 0;
  218     }
  219     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  220     pglob->gl_errfunc = errfunc;
  221     pglob->gl_matchc = 0;
  222 
  223     bufnext = patbuf;
  224     bufend = bufnext + MAXPATHLEN;
  225     if (flags & GLOB_NOESCAPE) {
  226         while (bufnext < bufend && (c = *patnext++) != EOS) 
  227             *bufnext++ = c;
  228     } else {
  229         /* Protect the quoted characters. */
  230         while (bufnext < bufend && (c = *patnext++) != EOS) 
  231             if (c == QUOTE) {
  232                 if ((c = *patnext++) == EOS) {
  233                     c = QUOTE;
  234                     --patnext;
  235                 }
  236                 *bufnext++ = c | M_PROTECT;
  237             }
  238             else
  239                 *bufnext++ = c;
  240     }
  241     *bufnext = EOS;
  242 
  243     if (flags & GLOB_BRACE)
  244         return globexp1(patbuf, pglob, &limit);
  245     else
  246         return glob0(patbuf, pglob, &limit);
  247 }
  248 
  249 /*
  250  * Expand recursively a glob {} pattern. When there is no more expansion
  251  * invoke the standard globbing routine to glob the rest of the magic
  252  * characters
  253  */
  254 static int
  255 globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
  256 {
  257     const Char* ptr = pattern;
  258     int rv;
  259 
  260     _DIAGASSERT(pattern != NULL);
  261     _DIAGASSERT(pglob != NULL);
  262 
  263     if ((pglob->gl_flags & GLOB_LIMIT) &&
  264         limit->l_brace++ >= GLOB_LIMIT_BRACE) {
  265         errno = 0;
  266         return GLOB_NOSPACE;
  267     }
  268 
  269     /* Protect a single {}, for find(1), like csh */
  270     if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
  271         return glob0(pattern, pglob, limit);
  272 
  273     while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
  274         if (!globexp2(ptr, pattern, pglob, &rv, limit))
  275             return rv;
  276 
  277     return glob0(pattern, pglob, limit);
  278 }
  279 
  280 
  281 /*
  282  * Recursive brace globbing helper. Tries to expand a single brace.
  283  * If it succeeds then it invokes globexp1 with the new pattern.
  284  * If it fails then it tries to glob the rest of the pattern and returns.
  285  */
  286 static int
  287 globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
  288     struct glob_limit *limit)
  289 {
  290     int     i;
  291     Char   *lm, *ls;
  292     const Char *pe, *pm, *pl;
  293     Char    patbuf[MAXPATHLEN + 1];
  294 
  295     _DIAGASSERT(ptr != NULL);
  296     _DIAGASSERT(pattern != NULL);
  297     _DIAGASSERT(pglob != NULL);
  298     _DIAGASSERT(rv != NULL);
  299 
  300     /* copy part up to the brace */
  301     for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
  302         continue;
  303     ls = lm;
  304 
  305     /* Find the balanced brace */
  306     for (i = 0, pe = ++ptr; *pe; pe++)
  307         if (*pe == LBRACKET) {
  308             /* Ignore everything between [] */
  309             for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
  310                 continue;
  311             if (*pe == EOS) {
  312                 /* 
  313                  * We could not find a matching RBRACKET.
  314                  * Ignore and just look for RBRACE
  315                  */
  316                 pe = pm;
  317             }
  318         }
  319         else if (*pe == LBRACE)
  320             i++;
  321         else if (*pe == RBRACE) {
  322             if (i == 0)
  323                 break;
  324             i--;
  325         }
  326 
  327     /* Non matching braces; just glob the pattern */
  328     if (i != 0 || *pe == EOS) {
  329         /*
  330          * we use `pattern', not `patbuf' here so that that
  331          * unbalanced braces are passed to the match
  332          */
  333         *rv = glob0(pattern, pglob, limit);
  334         return 0;
  335     }
  336 
  337     for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
  338         switch (*pm) {
  339         case LBRACKET:
  340             /* Ignore everything between [] */
  341             for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
  342                 continue;
  343             if (*pm == EOS) {
  344                 /* 
  345                  * We could not find a matching RBRACKET.
  346                  * Ignore and just look for RBRACE
  347                  */
  348                 pm = pl;
  349             }
  350             break;
  351 
  352         case LBRACE:
  353             i++;
  354             break;
  355 
  356         case RBRACE:
  357             if (i) {
  358                 i--;
  359                 break;
  360             }
  361             /* FALLTHROUGH */
  362         case COMMA:
  363             if (i && *pm == COMMA)
  364                 break;
  365             else {
  366                 /* Append the current string */
  367                 for (lm = ls; (pl < pm); *lm++ = *pl++)
  368                     continue;
  369                 /* 
  370                  * Append the rest of the pattern after the
  371                  * closing brace
  372                  */
  373                 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
  374                     continue;
  375 
  376                 /* Expand the current pattern */
  377 #ifdef DEBUG
  378                 qprintf("globexp2", patbuf);
  379 #endif
  380                 *rv = globexp1(patbuf, pglob, limit);
  381 
  382                 /* move after the comma, to the next string */
  383                 pl = pm + 1;
  384             }
  385             break;
  386 
  387         default:
  388             break;
  389         }
  390     }
  391     *rv = 0;
  392     return 0;
  393 }
  394 
  395 
  396 
  397 /*
  398  * expand tilde from the passwd file.
  399  */
  400 static const Char *
  401 globtilde(const Char *pattern, Char *patbuf, size_t patsize, glob_t *pglob)
  402 {
  403     struct passwd *pwd;
  404     const char *h;
  405     const Char *p;
  406     Char *b;
  407     char *d;
  408     Char *pend = &patbuf[patsize / sizeof(Char)];
  409 #ifndef NO_GETPW_R
  410     struct passwd pwres;
  411     char pwbuf[1024];
  412 #endif
  413 
  414     pend--;
  415 
  416     _DIAGASSERT(pattern != NULL);
  417     _DIAGASSERT(patbuf != NULL);
  418     _DIAGASSERT(pglob != NULL);
  419 
  420     if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
  421         return pattern;
  422 
  423     /* Copy up to the end of the string or / */
  424     for (p = pattern + 1, d = (char *)(void *)patbuf; 
  425          d < (char *)(void *)pend && *p && *p != SLASH; 
  426          *d++ = *p++)
  427         continue;
  428 
  429     if (d == (char *)(void *)pend)
  430         return NULL;
  431 
  432     *d = EOS;
  433     d = (char *)(void *)patbuf;
  434 
  435     if (*d == EOS) {
  436         /* 
  437          * handle a plain ~ or ~/ by expanding $HOME 
  438          * first and then trying the password file
  439          */
  440         if ((h = getenv("HOME")) == NULL) {
  441 #ifdef NO_GETPW_R
  442             if ((pwd = getpwuid(getuid())) == NULL)
  443 #else
  444             if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf),
  445                 &pwd) != 0 || pwd == NULL)
  446 #endif
  447                 return pattern;
  448             else
  449                 h = pwd->pw_dir;
  450         }
  451     }
  452     else {
  453         /*
  454          * Expand a ~user
  455          */
  456 #ifdef NO_GETPW_R
  457         if ((pwd = getpwnam(d)) == NULL)
  458 #else
  459         if (getpwnam_r(d, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
  460             pwd == NULL)
  461 #endif
  462             return pattern;
  463         else
  464             h = pwd->pw_dir;
  465     }
  466 
  467     /* Copy the home directory */
  468     for (b = patbuf; b < pend && *h; *b++ = *h++)
  469         continue;
  470 
  471     if (b == pend)
  472         return NULL;
  473     
  474     /* Append the rest of the pattern */
  475     while (b < pend && (*b++ = *p++) != EOS)
  476         continue;
  477 
  478     if (b == pend)
  479         return NULL;
  480 
  481     return patbuf;
  482 }
  483     
  484 
  485 /*
  486  * The main glob() routine: compiles the pattern (optionally processing
  487  * quotes), calls glob1() to do the real pattern matching, and finally
  488  * sorts the list (unless unsorted operation is requested).  Returns 0
  489  * if things went well, nonzero if errors occurred.  It is not an error
  490  * to find no matches.
  491  */
  492 static int
  493 glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
  494 {
  495     const Char *qpatnext;
  496     int c, error;
  497     __gl_size_t oldpathc;
  498     Char *bufnext, patbuf[MAXPATHLEN+1];
  499 
  500     _DIAGASSERT(pattern != NULL);
  501     _DIAGASSERT(pglob != NULL);
  502 
  503     if ((qpatnext = globtilde(pattern, patbuf, sizeof(patbuf),
  504         pglob)) == NULL)
  505         return GLOB_ABEND;
  506     oldpathc = pglob->gl_pathc;
  507     bufnext = patbuf;
  508 
  509     /* We don't need to check for buffer overflow any more. */
  510     while ((c = *qpatnext++) != EOS) {
  511         switch (c) {
  512         case LBRACKET:
  513             c = *qpatnext;
  514             if (c == NOT)
  515                 ++qpatnext;
  516             if (*qpatnext == EOS ||
  517                 g_strchr(qpatnext+1, RBRACKET) == NULL) {
  518                 *bufnext++ = LBRACKET;
  519                 if (c == NOT)
  520                     --qpatnext;
  521                 break;
  522             }
  523             *bufnext++ = M_SET;
  524             if (c == NOT)
  525                 *bufnext++ = M_NOT;
  526             c = *qpatnext++;
  527             do {
  528                 *bufnext++ = CHAR(c);
  529                 if (*qpatnext == RANGE &&
  530                     (c = qpatnext[1]) != RBRACKET) {
  531                     *bufnext++ = M_RNG;
  532                     *bufnext++ = CHAR(c);
  533                     qpatnext += 2;
  534                 }
  535             } while ((c = *qpatnext++) != RBRACKET);
  536             pglob->gl_flags |= GLOB_MAGCHAR;
  537             *bufnext++ = M_END;
  538             break;
  539         case QUESTION:
  540             pglob->gl_flags |= GLOB_MAGCHAR;
  541             *bufnext++ = M_ONE;
  542             break;
  543         case STAR:
  544             pglob->gl_flags |= GLOB_MAGCHAR;
  545             /* collapse adjacent stars to one [or three if globstar]
  546              * to avoid exponential behavior
  547              */
  548             if (bufnext == patbuf || bufnext[-1] != M_ALL ||
  549                 ((pglob->gl_flags & GLOB_STAR) != 0 && 
  550                 (bufnext - 1 == patbuf || bufnext[-2] != M_ALL ||
  551                 bufnext - 2 == patbuf || bufnext[-3] != M_ALL)))
  552                 *bufnext++ = M_ALL;
  553             break;
  554         default:
  555             *bufnext++ = CHAR(c);
  556             break;
  557         }
  558     }
  559     *bufnext = EOS;
  560 #ifdef DEBUG
  561     qprintf("glob0", patbuf);
  562 #endif
  563 
  564     if ((error = glob1(patbuf, pglob, limit)) != 0)
  565         return error;
  566 
  567     if (pglob->gl_pathc == oldpathc) {  
  568         /*
  569          * If there was no match we are going to append the pattern 
  570          * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was
  571          * specified and the pattern did not contain any magic
  572          * characters GLOB_NOMAGIC is there just for compatibility
  573          * with csh.
  574          */
  575         if ((pglob->gl_flags & GLOB_NOCHECK) ||
  576             ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR))
  577              == GLOB_NOMAGIC)) {
  578             return globextend(pattern, pglob, limit);
  579         } else {
  580             return GLOB_NOMATCH;
  581         }
  582     } else if (!(pglob->gl_flags & GLOB_NOSORT)) {
  583         qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
  584             (size_t)pglob->gl_pathc - oldpathc, sizeof(char *),
  585             compare);
  586     }
  587 
  588     return 0;
  589 }
  590 
  591 static int
  592 compare(const void *p, const void *q)
  593 {
  594 
  595     _DIAGASSERT(p != NULL);
  596     _DIAGASSERT(q != NULL);
  597 
  598     return strcoll(*(const char * const *)p, *(const char * const *)q);
  599 }
  600 
  601 static int
  602 glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit)
  603 {
  604     Char pathbuf[MAXPATHLEN+1];
  605 
  606     _DIAGASSERT(pattern != NULL);
  607     _DIAGASSERT(pglob != NULL);
  608 
  609     /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
  610     if (*pattern == EOS)
  611         return 0;
  612     /*
  613      * we save one character so that we can use ptr >= limit,
  614      * in the general case when we are appending non nul chars only.
  615      */
  616     return glob2(pathbuf, pathbuf,
  617         pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1, pattern,
  618         pglob, limit);
  619 }
  620 
  621 /*
  622  * The functions glob2 and glob3 are mutually recursive; there is one level
  623  * of recursion for each segment in the pattern that contains one or more
  624  * meta characters.
  625  */
  626 static int
  627 glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
  628     glob_t *pglob, struct glob_limit *limit)
  629 {
  630     __gl_stat_t sb;
  631     const Char *p;
  632     Char *q;
  633     int anymeta;
  634 
  635     _DIAGASSERT(pathbuf != NULL);
  636     _DIAGASSERT(pathend != NULL);
  637     _DIAGASSERT(pattern != NULL);
  638     _DIAGASSERT(pglob != NULL);
  639 
  640 #ifdef DEBUG
  641     qprintf("glob2", pathbuf);
  642 #endif
  643     /*
  644      * Loop over pattern segments until end of pattern or until
  645      * segment with meta character found.
  646      */
  647     for (anymeta = 0;;) {
  648         if (*pattern == EOS) {      /* End of pattern? */
  649             *pathend = EOS;
  650             if (g_lstat(pathbuf, &sb, pglob))
  651                 return 0;
  652         
  653             if ((pglob->gl_flags & GLOB_LIMIT) &&
  654                 limit->l_stat++ >= GLOB_LIMIT_STAT) {
  655                 errno = 0;
  656                 *pathend++ = SEP;
  657                 *pathend = EOS;
  658                 return GLOB_NOSPACE;
  659             }
  660             if (((pglob->gl_flags & GLOB_MARK) &&
  661                 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
  662                 (S_ISLNK(sb.st_mode) &&
  663                 (g_stat(pathbuf, &sb, pglob) == 0) &&
  664                 S_ISDIR(sb.st_mode)))) {
  665                 if (pathend >= pathlim)
  666                     return GLOB_ABORTED;
  667                 *pathend++ = SEP;
  668                 *pathend = EOS;
  669             }
  670             ++pglob->gl_matchc;
  671             return globextend(pathbuf, pglob, limit);
  672         }
  673 
  674         /* Find end of next segment, copy tentatively to pathend. */
  675         q = pathend;
  676         p = pattern;
  677         while (*p != EOS && *p != SEP) {
  678             if (ismeta(*p))
  679                 anymeta = 1;
  680             if (q >= pathlim)
  681                 return GLOB_ABORTED;
  682             *q++ = *p++;
  683         }
  684 
  685                 if (!anymeta) {
  686             pathend = q;
  687             pattern = p;
  688             while (*pattern == SEP) {
  689                 if (pathend >= pathlim)
  690                     return GLOB_ABORTED;
  691                 *pathend++ = *pattern++;
  692             }
  693         } else          /* Need expansion, recurse. */
  694             return glob3(pathbuf, pathend, pathlim, pattern, p,
  695                 pattern, pglob, limit);
  696     }
  697     /* NOTREACHED */
  698 }
  699 
  700 static int
  701 glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern,
  702     const Char *restpattern, const Char *pglobstar, glob_t *pglob,
  703     struct glob_limit *limit)
  704 {
  705     struct dirent *dp;
  706     DIR *dirp;
  707     __gl_stat_t sbuf;
  708     int error;
  709     char buf[MAXPATHLEN];
  710     int globstar = 0;
  711     int chase_symlinks = 0;
  712     const Char *termstar = NULL;
  713 
  714     /*
  715      * The readdirfunc declaration can't be prototyped, because it is
  716      * assigned, below, to two functions which are prototyped in glob.h
  717      * and dirent.h as taking pointers to differently typed opaque
  718      * structures.
  719      */
  720     struct dirent *(*readdirfunc)(void *);
  721 
  722     _DIAGASSERT(pathbuf != NULL);
  723     _DIAGASSERT(pathend != NULL);
  724     _DIAGASSERT(pattern != NULL);
  725     _DIAGASSERT(restpattern != NULL);
  726     _DIAGASSERT(pglob != NULL);
  727 
  728     *pathend = EOS;
  729     errno = 0;
  730         
  731     while (pglobstar < restpattern) {
  732         if ((pglobstar[0] & M_MASK) == M_ALL &&
  733             (pglobstar[1] & M_MASK) == M_ALL) {
  734             globstar = 1;
  735             chase_symlinks = (pglobstar[2] & M_MASK) == M_ALL;
  736             termstar = pglobstar + (2 + chase_symlinks);
  737             break;
  738         }
  739         pglobstar++;
  740     } 
  741 
  742     if (globstar) {
  743         error = pglobstar == pattern && termstar == restpattern ?
  744             *restpattern == EOS ?
  745             glob2(pathbuf, pathend, pathlim, restpattern - 1, pglob,
  746             limit) :
  747             glob2(pathbuf, pathend, pathlim, restpattern + 1, pglob,
  748             limit) :
  749             glob3(pathbuf, pathend, pathlim, pattern, restpattern,
  750             termstar, pglob, limit);
  751         if (error)
  752             return error;
  753         *pathend = EOS;
  754     }
  755 
  756     if (*pathbuf && (g_lstat(pathbuf, &sbuf, pglob) ||
  757         !S_ISDIR(sbuf.st_mode)
  758 #ifdef S_IFLINK
  759          && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode))
  760 #endif
  761         ))
  762         return 0;
  763 
  764     if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
  765         if (pglob->gl_errfunc) {
  766             if (g_Ctoc(pathbuf, buf, sizeof(buf)))
  767                 return GLOB_ABORTED;
  768             if (pglob->gl_errfunc(buf, errno) ||
  769                 pglob->gl_flags & GLOB_ERR)
  770                 return GLOB_ABORTED;
  771         }
  772         /*
  773          * Posix/XOpen: glob should return when it encounters a
  774          * directory that it cannot open or read
  775          * XXX: Should we ignore ENOTDIR and ENOENT though?
  776          * I think that Posix had in mind EPERM...
  777          */
  778         if (pglob->gl_flags & GLOB_ERR)
  779             return GLOB_ABORTED;
  780 
  781         return 0;
  782     }
  783 
  784     error = 0;
  785 
  786     /* Search directory for matching names. */
  787     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  788         readdirfunc = pglob->gl_readdir;
  789     else
  790         readdirfunc = (struct dirent *(*)(void *)) readdir;
  791     while ((dp = (*readdirfunc)(dirp)) != NULL) {
  792         unsigned char *sc;
  793         Char *dc;
  794 
  795         if ((pglob->gl_flags & GLOB_LIMIT) &&
  796             limit->l_readdir++ >= GLOB_LIMIT_READDIR) {
  797             errno = 0;
  798             *pathend++ = SEP;
  799             *pathend = EOS;
  800             error = GLOB_NOSPACE;
  801             break;
  802         }
  803 
  804         /*
  805          * Initial DOT must be matched literally, unless we have
  806          * GLOB_PERIOD set.
  807          */
  808         if ((pglob->gl_flags & GLOB_PERIOD) == 0)
  809             if (dp->d_name[0] == DOT && *pattern != DOT)
  810                 continue;
  811         /*
  812          * If GLOB_NO_DOTDIRS is set, . and .. vanish.
  813          */
  814         if ((pglob->gl_flags & GLOB_NO_DOTDIRS) &&
  815             (dp->d_name[0] == DOT) &&
  816             ((dp->d_name[1] == EOS) ||
  817              ((dp->d_name[1] == DOT) && (dp->d_name[2] == EOS))))
  818             continue;
  819         /*
  820          * The resulting string contains EOS, so we can
  821          * use the pathlim character, if it is the nul
  822          */
  823         for (sc = (unsigned char *) dp->d_name, dc = pathend; 
  824              dc <= pathlim && (*dc++ = *sc++) != EOS;)
  825             continue;
  826 
  827         /*
  828          * Have we filled the buffer without seeing EOS?
  829          */
  830         if (dc > pathlim && *pathlim != EOS) {
  831             /*
  832              * Abort when requested by caller, otherwise
  833              * reset pathend back to last SEP and continue
  834              * with next dir entry.
  835              */
  836             if (pglob->gl_flags & GLOB_ERR) {
  837                 error = GLOB_ABORTED;
  838                 break;
  839             }
  840             else {
  841                 *pathend = EOS;
  842                 continue;
  843             }
  844         }
  845 
  846         if (globstar) {
  847 #ifdef S_IFLNK
  848             if (!chase_symlinks &&
  849                 (g_lstat(pathbuf, &sbuf, pglob) ||
  850                 S_ISLNK(sbuf.st_mode)))
  851                 continue;
  852 #endif
  853 
  854             if (!match(pathend, pattern, termstar))
  855                 continue;
  856         
  857             if (--dc < pathlim - 2)
  858                 *dc++ = SEP;
  859             *dc = EOS;
  860             error = glob2(pathbuf, dc, pathlim, pglobstar,
  861                 pglob, limit);
  862             if (error)
  863                 break;
  864             *pathend = EOS;
  865         } else {
  866             if (!match(pathend, pattern, restpattern)) {
  867                 *pathend = EOS;
  868                 continue;
  869             }
  870             error = glob2(pathbuf, --dc, pathlim, restpattern,
  871                 pglob, limit);
  872             if (error)
  873                 break;
  874         }
  875     }
  876     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  877         (*pglob->gl_closedir)(dirp);
  878     else
  879         closedir(dirp);
  880 
  881     /*
  882      * Again Posix X/Open issue with regards to error handling.
  883      */
  884     if ((error || errno) && (pglob->gl_flags & GLOB_ERR))
  885         return GLOB_ABORTED;
  886 
  887     return error;
  888 }
  889 
  890 
  891 /*
  892  * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
  893  * add the new item, and update gl_pathc.
  894  *
  895  * This assumes the BSD realloc, which only copies the block when its size
  896  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  897  * behavior.
  898  *
  899  * Return 0 if new item added, error code if memory couldn't be allocated.
  900  *
  901  * Invariant of the glob_t structure:
  902  *  Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  903  *  gl_pathv points to (gl_offs + gl_pathc + 1) items.
  904  */
  905 static int
  906 globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
  907 {
  908     char **pathv;
  909     size_t i, newsize, len;
  910     char *copy;
  911     const Char *p;
  912 
  913     _DIAGASSERT(path != NULL);
  914     _DIAGASSERT(pglob != NULL);
  915 
  916     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  917     if ((pglob->gl_flags & GLOB_LIMIT) &&
  918         newsize > GLOB_LIMIT_PATH * sizeof(*pathv))
  919         goto nospace;
  920     pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) :
  921         malloc(newsize);
  922     if (pathv == NULL)
  923         return GLOB_NOSPACE;
  924 
  925     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  926         /* first time around -- clear initial gl_offs items */
  927         pathv += pglob->gl_offs;
  928         for (i = pglob->gl_offs + 1; --i > 0; )
  929             *--pathv = NULL;
  930     }
  931     pglob->gl_pathv = pathv;
  932 
  933     for (p = path; *p++;)
  934         continue;
  935     len = (size_t)(p - path);
  936     limit->l_string += len;
  937     if ((copy = malloc(len)) != NULL) {
  938         if (g_Ctoc(path, copy, len)) {
  939             free(copy);
  940             return GLOB_ABORTED;
  941         }
  942         pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  943     }
  944     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  945 
  946     if ((pglob->gl_flags & GLOB_LIMIT) &&
  947         (newsize + limit->l_string) >= GLOB_LIMIT_STRING)
  948         goto nospace;
  949 
  950     return copy == NULL ? GLOB_NOSPACE : 0;
  951 nospace:
  952     errno = 0;
  953     return GLOB_NOSPACE;
  954 }
  955 
  956 
  957 /*
  958  * pattern matching function for filenames.
  959  */
  960 static int
  961 match(const Char *name, const Char *pat, const Char *patend)
  962 {
  963     int ok, negate_range;
  964     Char c, k;
  965     const Char *patNext, *nameNext, *nameStart, *nameEnd;
  966 
  967     _DIAGASSERT(name != NULL);
  968     _DIAGASSERT(pat != NULL);
  969     _DIAGASSERT(patend != NULL);
  970     patNext = pat;
  971     nameStart = nameNext = name;
  972     nameEnd = NULL;
  973 
  974     while (pat < patend || *name) {
  975         c = *pat;
  976         if (*name == EOS)
  977             nameEnd = name;
  978         switch (c & M_MASK) {
  979         case M_ALL:
  980             while ((pat[1] & M_MASK) == M_ALL) pat++;
  981             patNext = pat;
  982             nameNext = name + 1;
  983             pat++;
  984             continue;
  985         case M_ONE:
  986             if (*name == EOS)
  987                 break;
  988             pat++;
  989             name++;
  990             continue;
  991         case M_SET:
  992             ok = 0;
  993             if ((k = *name) == EOS)
  994                 break;
  995             pat++;
  996             name++;
  997             if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
  998                 ++pat;
  999             while (((c = *pat++) & M_MASK) != M_END)
 1000                 if ((*pat & M_MASK) == M_RNG) {
 1001                     if (c <= k && k <= pat[1])
 1002                         ok = 1;
 1003                     pat += 2;
 1004                 } else if (c == k)
 1005                     ok = 1;
 1006             if (ok == negate_range)
 1007                 break;
 1008             continue;
 1009         default:
 1010             if (*name != c)
 1011                 break;
 1012             pat++;
 1013             name++;
 1014             continue;
 1015         }
 1016         if (nameNext != nameStart
 1017             && (nameEnd == NULL || nameNext <= nameEnd)) {
 1018             pat = patNext;
 1019             name = nameNext;
 1020             continue;
 1021         }
 1022         return 0;
 1023     }
 1024     return 1;
 1025 }
 1026 
 1027 /* Free allocated data belonging to a glob_t structure. */
 1028 void
 1029 globfree(glob_t *pglob)
 1030 {
 1031     size_t i;
 1032     char **pp;
 1033 
 1034     _DIAGASSERT(pglob != NULL);
 1035 
 1036     if (pglob->gl_pathv != NULL) {
 1037         pp = pglob->gl_pathv + pglob->gl_offs;
 1038         for (i = pglob->gl_pathc; i--; ++pp)
 1039             if (*pp)
 1040                 free(*pp);
 1041         free(pglob->gl_pathv);
 1042         pglob->gl_pathv = NULL;
 1043         pglob->gl_pathc = 0;
 1044     }
 1045 }
 1046 
 1047 #ifndef __LIBC12_SOURCE__
 1048 int
 1049 glob_pattern_p(const char *pattern, int quote)
 1050 {
 1051     int range = 0;
 1052 
 1053     for (; *pattern; pattern++)
 1054         switch (*pattern) {
 1055         case QUESTION:
 1056         case STAR:
 1057             return 1;
 1058 
 1059         case QUOTE:
 1060             if (quote && pattern[1] != EOS)
 1061                   ++pattern;
 1062             break;
 1063 
 1064         case LBRACKET:
 1065             range = 1;
 1066             break;
 1067 
 1068         case RBRACKET:
 1069             if (range)
 1070                   return 1;
 1071             break;
 1072         default:
 1073             break;
 1074         }
 1075 
 1076       return 0;
 1077 }
 1078 #endif
 1079 
 1080 static DIR *
 1081 g_opendir(Char *str, glob_t *pglob)
 1082 {
 1083     char buf[MAXPATHLEN];
 1084 
 1085     _DIAGASSERT(str != NULL);
 1086     _DIAGASSERT(pglob != NULL);
 1087 
 1088     if (!*str)
 1089         (void)strlcpy(buf, ".", sizeof(buf));
 1090     else {
 1091         if (g_Ctoc(str, buf, sizeof(buf)))
 1092             return NULL;
 1093     }
 1094 
 1095     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 1096         return (*pglob->gl_opendir)(buf);
 1097 
 1098     return opendir(buf);
 1099 }
 1100 
 1101 static int
 1102 g_lstat(Char *fn, __gl_stat_t *sb, glob_t *pglob)
 1103 {
 1104     char buf[MAXPATHLEN];
 1105 
 1106     _DIAGASSERT(fn != NULL);
 1107     _DIAGASSERT(sb != NULL);
 1108     _DIAGASSERT(pglob != NULL);
 1109 
 1110     if (g_Ctoc(fn, buf, sizeof(buf)))
 1111         return -1;
 1112     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 1113         return (*pglob->gl_lstat)(buf, sb);
 1114     return lstat(buf, sb);
 1115 }
 1116 
 1117 static int
 1118 g_stat(Char *fn, __gl_stat_t *sb, glob_t *pglob)
 1119 {
 1120     char buf[MAXPATHLEN];
 1121 
 1122     _DIAGASSERT(fn != NULL);
 1123     _DIAGASSERT(sb != NULL);
 1124     _DIAGASSERT(pglob != NULL);
 1125 
 1126     if (g_Ctoc(fn, buf, sizeof(buf)))
 1127         return -1;
 1128     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
 1129         return (*pglob->gl_stat)(buf, sb);
 1130     return stat(buf, sb);
 1131 }
 1132 
 1133 static Char *
 1134 g_strchr(const Char *str, int ch)
 1135 {
 1136 
 1137     _DIAGASSERT(str != NULL);
 1138 
 1139     do {
 1140         if (*str == ch)
 1141             return __UNCONST(str);
 1142     } while (*str++);
 1143     return NULL;
 1144 }
 1145 
 1146 static int
 1147 g_Ctoc(const Char *str, char *buf, size_t len)
 1148 {
 1149     char *dc;
 1150 
 1151     _DIAGASSERT(str != NULL);
 1152     _DIAGASSERT(buf != NULL);
 1153 
 1154     if (len == 0)
 1155         return 1;
 1156 
 1157     for (dc = buf; len && (*dc++ = *str++) != EOS; len--)
 1158         continue;
 1159 
 1160     return len == 0;
 1161 }
 1162 
 1163 #ifdef DEBUG
 1164 static void 
 1165 qprintf(const char *str, Char *s)
 1166 {
 1167     Char *p;
 1168 
 1169     _DIAGASSERT(str != NULL);
 1170     _DIAGASSERT(s != NULL);
 1171 
 1172     (void)printf("%s:\n", str);
 1173     for (p = s; *p; p++)
 1174         (void)printf("%c", CHAR(*p));
 1175     (void)printf("\n");
 1176     for (p = s; *p; p++)
 1177         (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
 1178     (void)printf("\n");
 1179     for (p = s; *p; p++)
 1180         (void)printf("%c", ismeta(*p) ? '_' : ' ');
 1181     (void)printf("\n");
 1182 }
 1183 #endif