home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl560.zip / ext / File / Glob / bsd_glob.c next >
C/C++ Source or Header  |  2000-03-02  |  23KB  |  946 lines

  1. /*
  2.  * Copyright (c) 1989, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Guido van Rossum.
  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.  
  33. #if defined(LIBC_SCCS) && !defined(lint)
  34. static char sccsid[] = "@(#)glob.c    8.3 (Berkeley) 10/13/93";
  35. #endif /* LIBC_SCCS and not lint */
  36.  
  37. /*
  38.  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  39.  *
  40.  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  41.  *
  42.  * Optional extra services, controlled by flags not defined by POSIX:
  43.  *
  44.  * GLOB_QUOTE:
  45.  *    Escaping convention: \ inhibits any special meaning the following
  46.  *    character might have (except \ at end of string is retained).
  47.  * GLOB_MAGCHAR:
  48.  *    Set in gl_flags if pattern contained a globbing character.
  49.  * GLOB_NOMAGIC:
  50.  *    Same as GLOB_NOCHECK, but it will only append pattern if it did
  51.  *    not contain any magic characters.  [Used in csh style globbing]
  52.  * GLOB_ALTDIRFUNC:
  53.  *    Use alternately specified directory access functions.
  54.  * GLOB_TILDE:
  55.  *    expand ~user/foo to the /home/dir/of/user/foo
  56.  * GLOB_BRACE:
  57.  *    expand {1,2}{a,b} to 1a 1b 2a 2b
  58.  * gl_matchc:
  59.  *    Number of matches in the current invocation of glob.
  60.  */
  61.  
  62. #include <EXTERN.h>
  63. #include <perl.h>
  64. #include <XSUB.h>
  65.  
  66. #include "bsd_glob.h"
  67. #ifdef I_PWD
  68. #    include <pwd.h>
  69. #else
  70. #ifdef HAS_PASSWD
  71.     struct passwd *getpwnam(char *);
  72.     struct passwd *getpwuid(Uid_t);
  73. #endif
  74. #endif
  75.  
  76. #ifndef MAXPATHLEN
  77. #  ifdef PATH_MAX
  78. #    define    MAXPATHLEN    PATH_MAX
  79. #  else
  80. #    define    MAXPATHLEN    1024
  81. #  endif
  82. #endif
  83.  
  84. #define    BG_DOLLAR    '$'
  85. #define    BG_DOT        '.'
  86. #define    BG_EOS        '\0'
  87. #define    BG_LBRACKET    '['
  88. #define    BG_NOT        '!'
  89. #define    BG_QUESTION    '?'
  90. #define    BG_QUOTE    '\\'
  91. #define    BG_RANGE    '-'
  92. #define    BG_RBRACKET    ']'
  93. #define    BG_SEP        '/'
  94. #ifdef DOSISH
  95. #define BG_SEP2        '\\'
  96. #endif
  97. #define    BG_STAR        '*'
  98. #define    BG_TILDE    '~'
  99. #define    BG_UNDERSCORE    '_'
  100. #define    BG_LBRACE    '{'
  101. #define    BG_RBRACE    '}'
  102. #define    BG_SLASH    '/'
  103. #define    BG_COMMA    ','
  104.  
  105. #ifndef GLOB_DEBUG
  106.  
  107. #define    M_QUOTE        0x8000
  108. #define    M_PROTECT    0x4000
  109. #define    M_MASK        0xffff
  110. #define    M_ASCII        0x00ff
  111.  
  112. typedef U16 Char;
  113.  
  114. #else
  115.  
  116. #define    M_QUOTE        0x80
  117. #define    M_PROTECT    0x40
  118. #define    M_MASK        0xff
  119. #define    M_ASCII        0x7f
  120.  
  121. typedef U8 Char;
  122.  
  123. #endif /* !GLOB_DEBUG */
  124.  
  125.  
  126. #define    CHAR(c)        ((Char)((c)&M_ASCII))
  127. #define    META(c)        ((Char)((c)|M_QUOTE))
  128. #define    M_ALL        META('*')
  129. #define    M_END        META(']')
  130. #define    M_NOT        META('!')
  131. #define    M_ONE        META('?')
  132. #define    M_RNG        META('-')
  133. #define    M_SET        META('[')
  134. #define    ismeta(c)    (((c)&M_QUOTE) != 0)
  135.  
  136.  
  137. static int     compare(const void *, const void *);
  138. static int     ci_compare(const void *, const void *);
  139. static void     g_Ctoc(const Char *, char *);
  140. static int     g_lstat(Char *, Stat_t *, glob_t *);
  141. static DIR    *g_opendir(Char *, glob_t *);
  142. static Char    *g_strchr(Char *, int);
  143. #ifdef notdef
  144. static Char    *g_strcat(Char *, const Char *);
  145. #endif
  146. static int     g_stat(Char *, Stat_t *, glob_t *);
  147. static int     glob0(const Char *, glob_t *);
  148. static int     glob1(Char *, glob_t *);
  149. static int     glob2(Char *, Char *, Char *, glob_t *);
  150. static int     glob3(Char *, Char *, Char *, Char *, glob_t *);
  151. static int     globextend(const Char *, glob_t *);
  152. static const Char *     globtilde(const Char *, Char *, glob_t *);
  153. static int     globexp1(const Char *, glob_t *);
  154. static int     globexp2(const Char *, const Char *, glob_t *, int *);
  155. static int     match(Char *, Char *, Char *, int);
  156. #ifdef GLOB_DEBUG
  157. static void     qprintf(const char *, Char *);
  158. #endif /* GLOB_DEBUG */
  159.  
  160. #ifdef PERL_IMPLICIT_CONTEXT
  161. static Direntry_t *    my_readdir(DIR*);
  162.  
  163. static Direntry_t *
  164. my_readdir(DIR *d)
  165. {
  166.     return PerlDir_read(d);
  167. }
  168. #else
  169. #define    my_readdir    readdir
  170. #endif
  171.  
  172. int
  173. bsd_glob(const char *pattern, int flags,
  174.      int (*errfunc)(const char *, int), glob_t *pglob)
  175. {
  176.     const U8 *patnext;
  177.     int c;
  178.     Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
  179.  
  180.     patnext = (U8 *) pattern;
  181.     if (!(flags & GLOB_APPEND)) {
  182.         pglob->gl_pathc = 0;
  183.         pglob->gl_pathv = NULL;
  184.         if (!(flags & GLOB_DOOFFS))
  185.             pglob->gl_offs = 0;
  186.     }
  187.     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  188.     pglob->gl_errfunc = errfunc;
  189.     pglob->gl_matchc = 0;
  190.  
  191.     bufnext = patbuf;
  192.     bufend = bufnext + MAXPATHLEN;
  193. #ifdef DOSISH
  194.     /* Nasty hack to treat patterns like "C:*" correctly. In this
  195.      * case, the * should match any file in the current directory
  196.      * on the C: drive. However, the glob code does not treat the
  197.      * colon specially, so it looks for files beginning "C:" in
  198.      * the current directory. To fix this, change the pattern to
  199.      * add an explicit "./" at the start (just after the drive
  200.      * letter and colon - ie change to "C:./*").
  201.      */
  202.     if (isalpha(pattern[0]) && pattern[1] == ':' &&
  203.         pattern[2] != BG_SEP && pattern[2] != BG_SEP2 &&
  204.         bufend - bufnext > 4) {
  205.         *bufnext++ = pattern[0];
  206.         *bufnext++ = ':';
  207.         *bufnext++ = '.';
  208.         *bufnext++ = BG_SEP;
  209.         patnext += 2;
  210.     }
  211. #endif
  212.     if (flags & GLOB_QUOTE) {
  213.         /* Protect the quoted characters. */
  214.         while (bufnext < bufend && (c = *patnext++) != BG_EOS)
  215.             if (c == BG_QUOTE) {
  216. #ifdef DOSISH
  217.                     /* To avoid backslashitis on Win32,
  218.                      * we only treat \ as a quoting character
  219.                      * if it precedes one of the
  220.                      * metacharacters []-{}~\
  221.                      */
  222.                 if ((c = *patnext++) != '[' && c != ']' &&
  223.                     c != '-' && c != '{' && c != '}' &&
  224.                     c != '~' && c != '\\') {
  225. #else
  226.                 if ((c = *patnext++) == BG_EOS) {
  227. #endif
  228.                     c = BG_QUOTE;
  229.                     --patnext;
  230.                 }
  231.                 *bufnext++ = c | M_PROTECT;
  232.             }
  233.             else
  234.                 *bufnext++ = c;
  235.     }
  236.     else
  237.         while (bufnext < bufend && (c = *patnext++) != BG_EOS)
  238.             *bufnext++ = c;
  239.     *bufnext = BG_EOS;
  240.  
  241.     if (flags & GLOB_BRACE)
  242.         return globexp1(patbuf, pglob);
  243.     else
  244.         return glob0(patbuf, pglob);
  245. }
  246.  
  247. /*
  248.  * Expand recursively a glob {} pattern. When there is no more expansion
  249.  * invoke the standard globbing routine to glob the rest of the magic
  250.  * characters
  251.  */
  252. static int globexp1(const Char *pattern, glob_t *pglob)
  253. {
  254.     const Char* ptr = pattern;
  255.     int rv;
  256.  
  257.     /* Protect a single {}, for find(1), like csh */
  258.     if (pattern[0] == BG_LBRACE && pattern[1] == BG_RBRACE && pattern[2] == BG_EOS)
  259.         return glob0(pattern, pglob);
  260.  
  261.     while ((ptr = (const Char *) g_strchr((Char *) ptr, BG_LBRACE)) != NULL)
  262.         if (!globexp2(ptr, pattern, pglob, &rv))
  263.             return rv;
  264.  
  265.     return glob0(pattern, pglob);
  266. }
  267.  
  268.  
  269. /*
  270.  * Recursive brace globbing helper. Tries to expand a single brace.
  271.  * If it succeeds then it invokes globexp1 with the new pattern.
  272.  * If it fails then it tries to glob the rest of the pattern and returns.
  273.  */
  274. static int globexp2(const Char *ptr, const Char *pattern,
  275.             glob_t *pglob, int *rv)
  276. {
  277.     int     i;
  278.     Char   *lm, *ls;
  279.     const Char *pe, *pm, *pl;
  280.     Char    patbuf[MAXPATHLEN + 1];
  281.  
  282.     /* copy part up to the brace */
  283.     for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
  284.         continue;
  285.     ls = lm;
  286.  
  287.     /* Find the balanced brace */
  288.     for (i = 0, pe = ++ptr; *pe; pe++)
  289.         if (*pe == BG_LBRACKET) {
  290.             /* Ignore everything between [] */
  291.             for (pm = pe++; *pe != BG_RBRACKET && *pe != BG_EOS; pe++)
  292.                 continue;
  293.             if (*pe == BG_EOS) {
  294.                 /*
  295.                  * We could not find a matching BG_RBRACKET.
  296.                  * Ignore and just look for BG_RBRACE
  297.                  */
  298.                 pe = pm;
  299.             }
  300.         }
  301.         else if (*pe == BG_LBRACE)
  302.             i++;
  303.         else if (*pe == BG_RBRACE) {
  304.             if (i == 0)
  305.                 break;
  306.             i--;
  307.         }
  308.  
  309.     /* Non matching braces; just glob the pattern */
  310.     if (i != 0 || *pe == BG_EOS) {
  311.         *rv = glob0(patbuf, pglob);
  312.         return 0;
  313.     }
  314.  
  315.     for (i = 0, pl = pm = ptr; pm <= pe; pm++)
  316.         switch (*pm) {
  317.         case BG_LBRACKET:
  318.             /* Ignore everything between [] */
  319.             for (pl = pm++; *pm != BG_RBRACKET && *pm != BG_EOS; pm++)
  320.                 continue;
  321.             if (*pm == BG_EOS) {
  322.                 /*
  323.                  * We could not find a matching BG_RBRACKET.
  324.                  * Ignore and just look for BG_RBRACE
  325.                  */
  326.                 pm = pl;
  327.             }
  328.             break;
  329.  
  330.         case BG_LBRACE:
  331.             i++;
  332.             break;
  333.  
  334.         case BG_RBRACE:
  335.             if (i) {
  336.                 i--;
  337.                 break;
  338.             }
  339.             /* FALLTHROUGH */
  340.         case BG_COMMA:
  341.             if (i && *pm == BG_COMMA)
  342.                 break;
  343.             else {
  344.                 /* Append the current string */
  345.                 for (lm = ls; (pl < pm); *lm++ = *pl++)
  346.                     continue;
  347.                 /*
  348.                  * Append the rest of the pattern after the
  349.                  * closing brace
  350.                  */
  351.                 for (pl = pe + 1; (*lm++ = *pl++) != BG_EOS;)
  352.                     continue;
  353.  
  354.                 /* Expand the current pattern */
  355. #ifdef GLOB_DEBUG
  356.                 qprintf("globexp2:", patbuf);
  357. #endif /* GLOB_DEBUG */
  358.                 *rv = globexp1(patbuf, pglob);
  359.  
  360.                 /* move after the comma, to the next string */
  361.                 pl = pm + 1;
  362.             }
  363.             break;
  364.  
  365.         default:
  366.             break;
  367.         }
  368.     *rv = 0;
  369.     return 0;
  370. }
  371.  
  372.  
  373.  
  374. /*
  375.  * expand tilde from the passwd file.
  376.  */
  377. static const Char *
  378. globtilde(const Char *pattern, Char *patbuf, glob_t *pglob)
  379. {
  380.     struct passwd *pwd;
  381.     char *h;
  382.     const Char *p;
  383.     Char *b;
  384.  
  385.     if (*pattern != BG_TILDE || !(pglob->gl_flags & GLOB_TILDE))
  386.         return pattern;
  387.  
  388.     /* Copy up to the end of the string or / */
  389.     for (p = pattern + 1, h = (char *) patbuf; *p && *p != BG_SLASH;
  390.          *h++ = *p++)
  391.         continue;
  392.  
  393.     *h = BG_EOS;
  394.  
  395.     if (((char *) patbuf)[0] == BG_EOS) {
  396.         /*
  397.          * handle a plain ~ or ~/ by expanding $HOME
  398.          * first and then trying the password file
  399.          */
  400.         if ((h = getenv("HOME")) == NULL) {
  401. #ifdef HAS_PASSWD
  402.             if ((pwd = getpwuid(getuid())) == NULL)
  403.                 return pattern;
  404.             else
  405.                 h = pwd->pw_dir;
  406. #else
  407.                         return pattern;
  408. #endif
  409.         }
  410.     }
  411.     else {
  412.         /*
  413.          * Expand a ~user
  414.          */
  415. #ifdef HAS_PASSWD
  416.         if ((pwd = getpwnam((char*) patbuf)) == NULL)
  417.             return pattern;
  418.         else
  419.             h = pwd->pw_dir;
  420. #else
  421.                 return pattern;
  422. #endif
  423.     }
  424.  
  425.     /* Copy the home directory */
  426.     for (b = patbuf; *h; *b++ = *h++)
  427.         continue;
  428.  
  429.     /* Append the rest of the pattern */
  430.     while ((*b++ = *p++) != BG_EOS)
  431.         continue;
  432.  
  433.     return patbuf;
  434. }
  435.  
  436.  
  437. /*
  438.  * The main glob() routine: compiles the pattern (optionally processing
  439.  * quotes), calls glob1() to do the real pattern matching, and finally
  440.  * sorts the list (unless unsorted operation is requested).  Returns 0
  441.  * if things went well, nonzero if errors occurred.  It is not an error
  442.  * to find no matches.
  443.  */
  444. static int
  445. glob0(const Char *pattern, glob_t *pglob)
  446. {
  447.     const Char *qpat, *qpatnext;
  448.     int c, err, oldflags, oldpathc;
  449.     Char *bufnext, patbuf[MAXPATHLEN+1];
  450.  
  451.     qpat = globtilde(pattern, patbuf, pglob);
  452.     qpatnext = qpat;
  453.     oldflags = pglob->gl_flags;
  454.     oldpathc = pglob->gl_pathc;
  455.     bufnext = patbuf;
  456.  
  457.     /* We don't need to check for buffer overflow any more. */
  458.     while ((c = *qpatnext++) != BG_EOS) {
  459.         switch (c) {
  460.         case BG_LBRACKET:
  461.             c = *qpatnext;
  462.             if (c == BG_NOT)
  463.                 ++qpatnext;
  464.             if (*qpatnext == BG_EOS ||
  465.                 g_strchr((Char *) qpatnext+1, BG_RBRACKET) == NULL) {
  466.                 *bufnext++ = BG_LBRACKET;
  467.                 if (c == BG_NOT)
  468.                     --qpatnext;
  469.                 break;
  470.             }
  471.             *bufnext++ = M_SET;
  472.             if (c == BG_NOT)
  473.                 *bufnext++ = M_NOT;
  474.             c = *qpatnext++;
  475.             do {
  476.                 *bufnext++ = CHAR(c);
  477.                 if (*qpatnext == BG_RANGE &&
  478.                     (c = qpatnext[1]) != BG_RBRACKET) {
  479.                     *bufnext++ = M_RNG;
  480.                     *bufnext++ = CHAR(c);
  481.                     qpatnext += 2;
  482.                 }
  483.             } while ((c = *qpatnext++) != BG_RBRACKET);
  484.             pglob->gl_flags |= GLOB_MAGCHAR;
  485.             *bufnext++ = M_END;
  486.             break;
  487.         case BG_QUESTION:
  488.             pglob->gl_flags |= GLOB_MAGCHAR;
  489.             *bufnext++ = M_ONE;
  490.             break;
  491.         case BG_STAR:
  492.             pglob->gl_flags |= GLOB_MAGCHAR;
  493.             /* collapse adjacent stars to one,
  494.              * to avoid exponential behavior
  495.              */
  496.             if (bufnext == patbuf || bufnext[-1] != M_ALL)
  497.                 *bufnext++ = M_ALL;
  498.             break;
  499.         default:
  500.             *bufnext++ = CHAR(c);
  501.             break;
  502.         }
  503.     }
  504.     *bufnext = BG_EOS;
  505. #ifdef GLOB_DEBUG
  506.     qprintf("glob0:", patbuf);
  507. #endif /* GLOB_DEBUG */
  508.  
  509.     if ((err = glob1(patbuf, pglob)) != 0) {
  510.         pglob->gl_flags = oldflags;
  511.         return(err);
  512.     }
  513.  
  514.     /*
  515.      * If there was no match we are going to append the pattern
  516.      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
  517.      * and the pattern did not contain any magic characters
  518.      * GLOB_NOMAGIC is there just for compatibility with csh.
  519.      */
  520.     if (pglob->gl_pathc == oldpathc &&
  521.         ((pglob->gl_flags & GLOB_NOCHECK) ||
  522.           ((pglob->gl_flags & GLOB_NOMAGIC) &&
  523.            !(pglob->gl_flags & GLOB_MAGCHAR))))
  524.     {
  525. #ifdef GLOB_DEBUG
  526.         printf("calling globextend from glob0\n");
  527. #endif /* GLOB_DEBUG */
  528.         pglob->gl_flags = oldflags;
  529.         return(globextend(qpat, pglob));
  530.         }
  531.     else if (!(pglob->gl_flags & GLOB_NOSORT))
  532.         qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
  533.             pglob->gl_pathc - oldpathc, sizeof(char *), 
  534.             (pglob->gl_flags & GLOB_NOCASE) ? ci_compare : compare);
  535.     pglob->gl_flags = oldflags;
  536.     return(0);
  537. }
  538.  
  539. static int
  540. ci_compare(const void *p, const void *q)
  541. {
  542.     const char *pp = *(const char **)p;
  543.     const char *qq = *(const char **)q;
  544.     while (*pp && *qq) {
  545.     if (tolower(*pp) != tolower(*qq))
  546.         break;
  547.     ++pp;
  548.     ++qq;
  549.     }
  550.     return (tolower(*pp) - tolower(*qq));
  551. }
  552.  
  553. static int
  554. compare(const void *p, const void *q)
  555. {
  556.     return(strcmp(*(char **)p, *(char **)q));
  557. }
  558.  
  559. static int
  560. glob1(Char *pattern, glob_t *pglob)
  561. {
  562.     Char pathbuf[MAXPATHLEN+1];
  563.  
  564.     /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
  565.     if (*pattern == BG_EOS)
  566.         return(0);
  567.     return(glob2(pathbuf, pathbuf, pattern, pglob));
  568. }
  569.  
  570. /*
  571.  * The functions glob2 and glob3 are mutually recursive; there is one level
  572.  * of recursion for each segment in the pattern that contains one or more
  573.  * meta characters.
  574.  */
  575. static int
  576. glob2(Char *pathbuf, Char *pathend, Char *pattern, glob_t *pglob)
  577. {
  578.     Stat_t sb;
  579.     Char *p, *q;
  580.     int anymeta;
  581.  
  582.     /*
  583.      * Loop over pattern segments until end of pattern or until
  584.      * segment with meta character found.
  585.      */
  586.     for (anymeta = 0;;) {
  587.         if (*pattern == BG_EOS) {        /* End of pattern? */
  588.             *pathend = BG_EOS;
  589.  
  590.             if (g_lstat(pathbuf, &sb, pglob))
  591.                 return(0);
  592.  
  593.             if (((pglob->gl_flags & GLOB_MARK) &&
  594.                 pathend[-1] != BG_SEP
  595. #ifdef DOSISH
  596.                 && pathend[-1] != BG_SEP2
  597. #endif
  598.                 ) && (S_ISDIR(sb.st_mode)
  599.                 || (S_ISLNK(sb.st_mode) &&
  600.                 (g_stat(pathbuf, &sb, pglob) == 0) &&
  601.                 S_ISDIR(sb.st_mode)))) {
  602.                 *pathend++ = BG_SEP;
  603.                 *pathend = BG_EOS;
  604.             }
  605.             ++pglob->gl_matchc;
  606. #ifdef GLOB_DEBUG
  607.                         printf("calling globextend from glob2\n");
  608. #endif /* GLOB_DEBUG */
  609.             return(globextend(pathbuf, pglob));
  610.         }
  611.  
  612.         /* Find end of next segment, copy tentatively to pathend. */
  613.         q = pathend;
  614.         p = pattern;
  615.         while (*p != BG_EOS && *p != BG_SEP
  616. #ifdef DOSISH
  617.                && *p != BG_SEP2
  618. #endif
  619.                ) {
  620.             if (ismeta(*p))
  621.                 anymeta = 1;
  622.             *q++ = *p++;
  623.         }
  624.  
  625.         if (!anymeta) {        /* No expansion, do next segment. */
  626.             pathend = q;
  627.             pattern = p;
  628.             while (*pattern == BG_SEP
  629. #ifdef DOSISH
  630.                    || *pattern == BG_SEP2
  631. #endif
  632.                    )
  633.                 *pathend++ = *pattern++;
  634.         } else            /* Need expansion, recurse. */
  635.             return(glob3(pathbuf, pathend, pattern, p, pglob));
  636.     }
  637.     /* NOTREACHED */
  638. }
  639.  
  640. static int
  641. glob3(Char *pathbuf, Char *pathend, Char *pattern,
  642.       Char *restpattern, glob_t *pglob)
  643. {
  644.     register Direntry_t *dp;
  645.     DIR *dirp;
  646.     int err;
  647.     int nocase;
  648.     char buf[MAXPATHLEN];
  649.  
  650.     /*
  651.      * The readdirfunc declaration can't be prototyped, because it is
  652.      * assigned, below, to two functions which are prototyped in glob.h
  653.      * and dirent.h as taking pointers to differently typed opaque
  654.      * structures.
  655.      */
  656.     Direntry_t *(*readdirfunc)();
  657.  
  658.     *pathend = BG_EOS;
  659.     errno = 0;
  660.  
  661. #ifdef VMS
  662.         {
  663.             Char *q = pathend;
  664.             if (q - pathbuf > 5) {
  665.                 q -= 5;
  666.                 if (q[0] == '.' && tolower(q[1]) == 'd' && tolower(q[2]) == 'i'
  667.             && tolower(q[3]) == 'r' && q[4] == '/')
  668.         {
  669.                     q[0] = '/';
  670.                     q[1] = BG_EOS;
  671.                     pathend = q+1;
  672.                 }
  673.             }
  674.         }
  675. #endif
  676.     if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
  677.         /* TODO: don't call for ENOENT or ENOTDIR? */
  678.         if (pglob->gl_errfunc) {
  679.             g_Ctoc(pathbuf, buf);
  680.             if (pglob->gl_errfunc(buf, errno) ||
  681.                 (pglob->gl_flags & GLOB_ERR))
  682.                 return (GLOB_ABEND);
  683.         }
  684.         return(0);
  685.     }
  686.  
  687.     err = 0;
  688.     nocase = ((pglob->gl_flags & GLOB_NOCASE) != 0);
  689.  
  690.     /* Search directory for matching names. */
  691.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  692.         readdirfunc = pglob->gl_readdir;
  693.     else
  694.         readdirfunc = my_readdir;
  695.     while ((dp = (*readdirfunc)(dirp))) {
  696.         register U8 *sc;
  697.         register Char *dc;
  698.  
  699.         /* Initial BG_DOT must be matched literally. */
  700.         if (dp->d_name[0] == BG_DOT && *pattern != BG_DOT)
  701.             continue;
  702.         for (sc = (U8 *) dp->d_name, dc = pathend;
  703.              (*dc++ = *sc++) != BG_EOS;)
  704.             continue;
  705.         if (!match(pathend, pattern, restpattern, nocase)) {
  706.             *pathend = BG_EOS;
  707.             continue;
  708.         }
  709.         err = glob2(pathbuf, --dc, restpattern, pglob);
  710.         if (err)
  711.             break;
  712.     }
  713.  
  714.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  715.         (*pglob->gl_closedir)(dirp);
  716.     else
  717.         PerlDir_close(dirp);
  718.     return(err);
  719. }
  720.  
  721.  
  722. /*
  723.  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
  724.  * add the new item, and update gl_pathc.
  725.  *
  726.  * This assumes the BSD realloc, which only copies the block when its size
  727.  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  728.  * behavior.
  729.  *
  730.  * Return 0 if new item added, error code if memory couldn't be allocated.
  731.  *
  732.  * Invariant of the glob_t structure:
  733.  *    Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  734.  *    gl_pathv points to (gl_offs + gl_pathc + 1) items.
  735.  */
  736. static int
  737. globextend(const Char *path, glob_t *pglob)
  738. {
  739.     register char **pathv;
  740.     register int i;
  741.     char *copy;
  742.     const Char *p;
  743.  
  744. #ifdef GLOB_DEBUG
  745.     printf("Adding ");
  746.         for (p = path; *p; p++)
  747.                 (void)printf("%c", CHAR(*p));
  748.         printf("\n");
  749. #endif /* GLOB_DEBUG */
  750.  
  751.     if (pglob->gl_pathv)
  752.         pathv = Renew(pglob->gl_pathv,
  753.                   (2 + pglob->gl_pathc + pglob->gl_offs),char*);
  754.     else
  755.         New(0,pathv,(2 + pglob->gl_pathc + pglob->gl_offs),char*);
  756.     if (pathv == NULL)
  757.         return(GLOB_NOSPACE);
  758.  
  759.     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  760.         /* first time around -- clear initial gl_offs items */
  761.         pathv += pglob->gl_offs;
  762.         for (i = pglob->gl_offs; --i >= 0; )
  763.             *--pathv = NULL;
  764.     }
  765.     pglob->gl_pathv = pathv;
  766.  
  767.     for (p = path; *p++;)
  768.         continue;
  769.     New(0, copy, p-path, char);
  770.     if (copy != NULL) {
  771.         g_Ctoc(path, copy);
  772.         pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  773.     }
  774.     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  775.     return(copy == NULL ? GLOB_NOSPACE : 0);
  776. }
  777.  
  778.  
  779. /*
  780.  * pattern matching function for filenames.  Each occurrence of the *
  781.  * pattern causes a recursion level.
  782.  */
  783. static int
  784. match(register Char *name, register Char *pat, register Char *patend, int nocase)
  785. {
  786.     int ok, negate_range;
  787.     Char c, k;
  788.  
  789.     while (pat < patend) {
  790.         c = *pat++;
  791.         switch (c & M_MASK) {
  792.         case M_ALL:
  793.             if (pat == patend)
  794.                 return(1);
  795.             do
  796.                 if (match(name, pat, patend, nocase))
  797.                     return(1);
  798.             while (*name++ != BG_EOS);
  799.             return(0);
  800.         case M_ONE:
  801.             if (*name++ == BG_EOS)
  802.                 return(0);
  803.             break;
  804.         case M_SET:
  805.             ok = 0;
  806.             if ((k = *name++) == BG_EOS)
  807.                 return(0);
  808.             if ((negate_range = ((*pat & M_MASK) == M_NOT)) != BG_EOS)
  809.                 ++pat;
  810.             while (((c = *pat++) & M_MASK) != M_END)
  811.                 if ((*pat & M_MASK) == M_RNG) {
  812.                     if (nocase) {
  813.                         if (tolower(c) <= tolower(k) && tolower(k) <= tolower(pat[1]))
  814.                             ok = 1;
  815.                     } else {
  816.                         if (c <= k && k <= pat[1])
  817.                             ok = 1;
  818.                     }
  819.                     pat += 2;
  820.                 } else if (nocase ? (tolower(c) == tolower(k)) : (c == k))
  821.                     ok = 1;
  822.             if (ok == negate_range)
  823.                 return(0);
  824.             break;
  825.         default:
  826.             k = *name++;
  827.             if (nocase ? (tolower(k) != tolower(c)) : (k != c))
  828.                 return(0);
  829.             break;
  830.         }
  831.     }
  832.     return(*name == BG_EOS);
  833. }
  834.  
  835. /* Free allocated data belonging to a glob_t structure. */
  836. void
  837. bsd_globfree(glob_t *pglob)
  838. {
  839.     register int i;
  840.     register char **pp;
  841.  
  842.     if (pglob->gl_pathv != NULL) {
  843.         pp = pglob->gl_pathv + pglob->gl_offs;
  844.         for (i = pglob->gl_pathc; i--; ++pp)
  845.             if (*pp)
  846.                 Safefree(*pp);
  847.         Safefree(pglob->gl_pathv);
  848.     }
  849. }
  850.  
  851. static DIR *
  852. g_opendir(register Char *str, glob_t *pglob)
  853. {
  854.     char buf[MAXPATHLEN];
  855.  
  856.     if (!*str)
  857.         strcpy(buf, ".");
  858.     else
  859.         g_Ctoc(str, buf);
  860.  
  861.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  862.         return((*pglob->gl_opendir)(buf));
  863.     else
  864.         return(PerlDir_open(buf));
  865. }
  866.  
  867. static int
  868. g_lstat(register Char *fn, Stat_t *sb, glob_t *pglob)
  869. {
  870.     char buf[MAXPATHLEN];
  871.  
  872.     g_Ctoc(fn, buf);
  873.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  874.         return((*pglob->gl_lstat)(buf, sb));
  875. #ifdef HAS_LSTAT
  876.     return(PerlLIO_lstat(buf, sb));
  877. #else
  878.     return(PerlLIO_stat(buf, sb));
  879. #endif /* HAS_LSTAT */
  880. }
  881.  
  882. static int
  883. g_stat(register Char *fn, Stat_t *sb, glob_t *pglob)
  884. {
  885.     char buf[MAXPATHLEN];
  886.  
  887.     g_Ctoc(fn, buf);
  888.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  889.         return((*pglob->gl_stat)(buf, sb));
  890.     return(PerlLIO_stat(buf, sb));
  891. }
  892.  
  893. static Char *
  894. g_strchr(Char *str, int ch)
  895. {
  896.     do {
  897.         if (*str == ch)
  898.             return (str);
  899.     } while (*str++);
  900.     return (NULL);
  901. }
  902.  
  903. #ifdef notdef
  904. static Char *
  905. g_strcat(Char *dst, const Char *src)
  906. {
  907.     Char *sdst = dst;
  908.  
  909.     while (*dst++)
  910.         continue;
  911.     --dst;
  912.     while((*dst++ = *src++) != BG_EOS)
  913.         continue;
  914.  
  915.     return (sdst);
  916. }
  917. #endif
  918.  
  919. static void
  920. g_Ctoc(register const Char *str, char *buf)
  921. {
  922.     register char *dc;
  923.  
  924.     for (dc = buf; (*dc++ = *str++) != BG_EOS;)
  925.         continue;
  926. }
  927.  
  928. #ifdef GLOB_DEBUG
  929. static void
  930. qprintf(const char *str, register Char *s)
  931. {
  932.     register Char *p;
  933.  
  934.     (void)printf("%s:\n", str);
  935.     for (p = s; *p; p++)
  936.         (void)printf("%c", CHAR(*p));
  937.     (void)printf("\n");
  938.     for (p = s; *p; p++)
  939.         (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
  940.     (void)printf("\n");
  941.     for (p = s; *p; p++)
  942.         (void)printf("%c", ismeta(*p) ? '_' : ' ');
  943.     (void)printf("\n");
  944. }
  945. #endif /* GLOB_DEBUG */
  946.