home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / gcc / ixemulsrc.lha / ixemul / general / glob.c < prev    next >
C/C++ Source or Header  |  1996-12-11  |  20KB  |  862 lines

  1. /*    $NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $    */
  2.  
  3. /*
  4.  * Copyright (c) 1989, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Guido van Rossum.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  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. static char rcsid[] = "$NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $";
  44. #endif
  45. #endif /* LIBC_SCCS and not lint */
  46.  
  47. /*
  48.  * glob(3) -- a superset of the one defined in POSIX 1003.2.
  49.  *
  50.  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  51.  *
  52.  * Optional extra services, controlled by flags not defined by POSIX:
  53.  *
  54.  * GLOB_QUOTE:
  55.  *    Escaping convention: \ inhibits any special meaning the following
  56.  *    character might have (except \ at end of string is retained).
  57.  * GLOB_MAGCHAR:
  58.  *    Set in gl_flags if pattern contained a globbing character.
  59.  * GLOB_NOMAGIC:
  60.  *    Same as GLOB_NOCHECK, but it will only append pattern if it did
  61.  *    not contain any magic characters.  [Used in csh style globbing]
  62.  * GLOB_ALTDIRFUNC:
  63.  *    Use alternately specified directory access functions.
  64.  * GLOB_TILDE:
  65.  *    expand ~user/foo to the /home/dir/of/user/foo
  66.  * GLOB_BRACE:
  67.  *    expand {1,2}{a,b} to 1a 1b 2a 2b 
  68.  * gl_matchc:
  69.  *    Number of matches in the current invocation of glob.
  70.  */
  71.  
  72. #define _KERNEL
  73. #include "ixemul.h"
  74. #include "kprintf.h"
  75.  
  76. #include <sys/param.h>
  77. #include <sys/stat.h>
  78.  
  79. #include <ctype.h>
  80. #include <dirent.h>
  81. #include <errno.h>
  82. #include <glob.h>
  83. #include <pwd.h>
  84. #include <stdio.h>
  85. #include <stdlib.h>
  86. #include <string.h>
  87. #include <unistd.h>
  88.  
  89. #undef NOT    /* in <intuition/intuition.h> on AmigaOS */
  90.  
  91. #define    DOLLAR        '$'
  92. #define    DOT        '.'
  93. #define    EOS        '\0'
  94. #define    LBRACKET    '['
  95. #define    NOT        '!'
  96. #define    QUESTION    '?'
  97. #define    QUOTE        '\\'
  98. #define    RANGE        '-'
  99. #define    RBRACKET    ']'
  100. #define    SEP        '/'
  101. #define    STAR        '*'
  102. #define    TILDE        '~'
  103. #define    UNDERSCORE    '_'
  104. #define    LBRACE        '{'
  105. #define    RBRACE        '}'
  106. #define    SLASH        '/'
  107. #define    COMMA        ','
  108. #define HASH            '#'
  109.  
  110. #define    M_QUOTE        0x8000
  111. #define    M_PROTECT    0x4000
  112. #define    M_MASK        0xffff
  113. #define    M_ASCII        0x00ff
  114.  
  115. typedef u_short Char;
  116.  
  117. #define    CHAR(c)        ((Char)((c)&M_ASCII))
  118. #define    META(c)        ((Char)((c)|M_QUOTE))
  119. #define    M_ALL        META('*')
  120. #define    M_END        META(']')
  121. #define    M_NOT        META('!')
  122. #define    M_ONE        META('?')
  123. #define    M_RNG        META('-')
  124. #define    M_SET        META('[')
  125. #define    ismeta(c)    (((c)&M_QUOTE) != 0)
  126.  
  127.  
  128. static int     compare __P((const void *, const void *));
  129. static int     icompare __P((const void *, const void *));
  130. static void     g_Ctoc __P((const Char *, char *));
  131. static int     g_lstat __P((Char *, struct stat *, glob_t *));
  132. static DIR    *g_opendir __P((Char *, glob_t *));
  133. static Char    *g_strchr __P((Char *, int));
  134. #ifdef notdef
  135. static Char    *g_strcat __P((Char *, const Char *));
  136. #endif
  137. static int     g_stat __P((Char *, struct stat *, glob_t *));
  138. static int     glob0 __P((const Char *, glob_t *));
  139. static int     glob1 __P((Char *, glob_t *));
  140. static int     glob2 __P((Char *, Char *, Char *, glob_t *));
  141. static int     glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
  142. static int     globextend __P((const Char *, glob_t *));
  143. static const Char *     globtilde __P((const Char *, Char *, glob_t *));
  144. static int     globexp1 __P((const Char *, glob_t *));
  145. static int     globexp2 __P((const Char *, const Char *, glob_t *, int *));
  146. static int     match __P((Char *, Char *, Char *, int));
  147.  
  148. DIR *opendir __P((const char *));
  149. struct dirent *readdir __P((DIR *));
  150. int closedir __P((DIR *));
  151.  
  152. int
  153. glob(pattern, flags, errfunc, pglob)
  154.     const char *pattern;
  155.     int flags, (*errfunc) __P((const char *, int));
  156.     glob_t *pglob;
  157. {
  158.     const u_char *patnext;
  159.     char *glob_pattern = (char *)pattern;
  160.     int c;
  161.     Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
  162.  
  163.         if (index(pattern, ':'))
  164.           {
  165.             char *colon;
  166.  
  167.             glob_pattern = alloca(strlen(pattern) + 2);
  168.             strcpy(glob_pattern + 1, pattern);
  169.             *glob_pattern = '/';
  170.             colon = index(glob_pattern, ':');
  171.             *colon = '/';
  172.           }
  173.     patnext = (u_char *) glob_pattern;
  174.     if (!(flags & GLOB_APPEND)) {
  175.         pglob->gl_pathc = 0;
  176.         pglob->gl_pathv = NULL;
  177.         if (!(flags & GLOB_DOOFFS))
  178.             pglob->gl_offs = 0;
  179.     }
  180.     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  181.     pglob->gl_errfunc = errfunc;
  182.     pglob->gl_matchc = 0;
  183.  
  184.     bufnext = patbuf;
  185.     bufend = bufnext + MAXPATHLEN;
  186.     if (flags & GLOB_QUOTE) {
  187.         /* Protect the quoted characters. */
  188.         while (bufnext < bufend && (c = *patnext++) != EOS) 
  189.             if (c == QUOTE) {
  190.                 if ((c = *patnext++) == EOS) {
  191.                     c = QUOTE;
  192.                     --patnext;
  193.                 }
  194.                 *bufnext++ = c | M_PROTECT;
  195.             }
  196.             else
  197.                 *bufnext++ = c;
  198.     }
  199.     else 
  200.         while (bufnext < bufend && (c = *patnext++) != EOS) 
  201.             *bufnext++ = c;
  202.     *bufnext = EOS;
  203.  
  204.     if (flags & GLOB_BRACE)
  205.         return globexp1(patbuf, pglob);
  206.     else
  207.         return glob0(patbuf, pglob);
  208. }
  209.  
  210. /*
  211.  * Expand recursively a glob {} pattern. When there is no more expansion
  212.  * invoke the standard globbing routine to glob the rest of the magic
  213.  * characters
  214.  */
  215. static int globexp1(pattern, pglob)
  216.     const Char *pattern;
  217.     glob_t *pglob;
  218. {
  219.     const Char* ptr = pattern;
  220.     int rv;
  221.  
  222.     /* Protect a single {}, for find(1), like csh */
  223.     if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
  224.         return glob0(pattern, pglob);
  225.  
  226.     while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
  227.         if (!globexp2(ptr, pattern, pglob, &rv))
  228.             return rv;
  229.  
  230.     return glob0(pattern, pglob);
  231. }
  232.  
  233.  
  234. /*
  235.  * Recursive brace globbing helper. Tries to expand a single brace.
  236.  * If it succeeds then it invokes globexp1 with the new pattern.
  237.  * If it fails then it tries to glob the rest of the pattern and returns.
  238.  */
  239. static int globexp2(ptr, pattern, pglob, rv)
  240.     const Char *ptr, *pattern;
  241.     glob_t *pglob;
  242.     int *rv;
  243. {
  244.     int     i;
  245.     Char   *lm, *ls;
  246.     const Char *pe, *pm, *pl;
  247.     Char    patbuf[MAXPATHLEN + 1];
  248.  
  249.     /* copy part up to the brace */
  250.     for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
  251.         continue;
  252.     ls = lm;
  253.  
  254.     /* Find the balanced brace */
  255.     for (i = 0, pe = ++ptr; *pe; pe++)
  256.         if (*pe == LBRACKET) {
  257.             /* Ignore everything between [] */
  258.             for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
  259.                 continue;
  260.             if (*pe == EOS) {
  261.                 /* 
  262.                  * We could not find a matching RBRACKET.
  263.                  * Ignore and just look for RBRACE
  264.                  */
  265.                 pe = pm;
  266.             }
  267.         }
  268.         else if (*pe == LBRACE)
  269.             i++;
  270.         else if (*pe == RBRACE) {
  271.             if (i == 0)
  272.                 break;
  273.             i--;
  274.         }
  275.  
  276.     /* Non matching braces; just glob the pattern */
  277.     if (i != 0 || *pe == EOS) {
  278.         *rv = glob0(patbuf, pglob);
  279.         return 0;
  280.     }
  281.  
  282.     for (i = 0, pl = pm = ptr; pm <= pe; pm++)
  283.         switch (*pm) {
  284.         case LBRACKET:
  285.             /* Ignore everything between [] */
  286.             for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
  287.                 continue;
  288.             if (*pm == EOS) {
  289.                 /* 
  290.                  * We could not find a matching RBRACKET.
  291.                  * Ignore and just look for RBRACE
  292.                  */
  293.                 pm = pl;
  294.             }
  295.             break;
  296.  
  297.         case LBRACE:
  298.             i++;
  299.             break;
  300.  
  301.         case RBRACE:
  302.             if (i) {
  303.                 i--;
  304.                 break;
  305.             }
  306.             /* FALLTHROUGH */
  307.         case COMMA:
  308.             if (i && *pm == COMMA)
  309.                 break;
  310.             else {
  311.                 /* Append the current string */
  312.                 for (lm = ls; (pl < pm); *lm++ = *pl++)
  313.                     continue;
  314.                 /* 
  315.                  * Append the rest of the pattern after the
  316.                  * closing brace
  317.                  */
  318.                 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
  319.                     continue;
  320.  
  321.                 /* Expand the current pattern */
  322.                 *rv = globexp1(patbuf, pglob);
  323.  
  324.                 /* move after the comma, to the next string */
  325.                 pl = pm + 1;
  326.             }
  327.             break;
  328.  
  329.         default:
  330.             break;
  331.         }
  332.     *rv = 0;
  333.     return 0;
  334. }
  335.  
  336.  
  337.  
  338. /*
  339.  * expand tilde from the passwd file.
  340.  */
  341. static const Char *
  342. globtilde(pattern, patbuf, pglob)
  343.     const Char *pattern;
  344.     Char *patbuf;
  345.     glob_t *pglob;
  346. {
  347.     struct passwd *pwd;
  348.     char *h;
  349.     const Char *p;
  350.     Char *b;
  351.  
  352.     if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
  353.         return pattern;
  354.  
  355.     /* Copy up to the end of the string or / */
  356.     for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH; 
  357.          *h++ = *p++)
  358.         continue;
  359.  
  360.     *h = EOS;
  361.  
  362.     if (((char *) patbuf)[0] == EOS) {
  363.         /* 
  364.          * handle a plain ~ or ~/ by expanding $HOME 
  365.          * first and then trying the password file
  366.          */
  367.         if ((h = getenv("HOME")) == NULL) {
  368.             if ((pwd = getpwuid(getuid())) == NULL)
  369.                 return pattern;
  370.             else
  371.                 h = pwd->pw_dir;
  372.         }
  373.     }
  374.     else {
  375.         /*
  376.          * Expand a ~user
  377.          */
  378.         if ((pwd = getpwnam((char*) patbuf)) == NULL)
  379.             return pattern;
  380.         else
  381.             h = pwd->pw_dir;
  382.     }
  383.  
  384.     /* Copy the home directory */
  385.     for (b = patbuf; *h; *b++ = *h++)
  386.         continue;
  387.     
  388.     /* Append the rest of the pattern */
  389.     while ((*b++ = *p++) != EOS)
  390.         continue;
  391.  
  392.     return patbuf;
  393. }
  394.     
  395.  
  396. /*
  397.  * The main glob() routine: compiles the pattern (optionally processing
  398.  * quotes), calls glob1() to do the real pattern matching, and finally
  399.  * sorts the list (unless unsorted operation is requested).  Returns 0
  400.  * if things went well, nonzero if errors occurred.  It is not an error
  401.  * to find no matches.
  402.  */
  403. static int
  404. glob0(pattern, pglob)
  405.     const Char *pattern;
  406.     glob_t *pglob;
  407. {
  408.     const Char *qpatnext;
  409.     int c, err, oldpathc;
  410.     Char *bufnext, patbuf[MAXPATHLEN+1];
  411.  
  412.     qpatnext = globtilde(pattern, patbuf, pglob);
  413.     oldpathc = pglob->gl_pathc;
  414.     bufnext = patbuf;
  415.  
  416.     /* We don't need to check for buffer overflow any more. */
  417.     while ((c = *qpatnext++) != EOS) {
  418.         switch (c) {
  419.         case LBRACKET:
  420.             c = *qpatnext;
  421.             if (c == NOT)
  422.                 ++qpatnext;
  423.             if (*qpatnext == EOS ||
  424.                 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
  425.                 *bufnext++ = LBRACKET;
  426.                 if (c == NOT)
  427.                     --qpatnext;
  428.                 break;
  429.             }
  430.             *bufnext++ = M_SET;
  431.             if (c == NOT)
  432.                 *bufnext++ = M_NOT;
  433.             c = *qpatnext++;
  434.             do {
  435.                 *bufnext++ = CHAR(c);
  436.                 if (*qpatnext == RANGE &&
  437.                     (c = qpatnext[1]) != RBRACKET) {
  438.                     *bufnext++ = M_RNG;
  439.                     *bufnext++ = CHAR(c);
  440.                     qpatnext += 2;
  441.                 }
  442.             } while ((c = *qpatnext++) != RBRACKET);
  443.             pglob->gl_flags |= GLOB_MAGCHAR;
  444.             *bufnext++ = M_END;
  445.             break;
  446.         case QUESTION:
  447.             pglob->gl_flags |= GLOB_MAGCHAR;
  448.             *bufnext++ = M_ONE;
  449.             break;
  450.         case STAR:
  451.             pglob->gl_flags |= GLOB_MAGCHAR;
  452.             /* collapse adjacent stars to one, 
  453.              * to avoid exponential behavior
  454.              */
  455.             if (bufnext == patbuf || bufnext[-1] != M_ALL)
  456.                 *bufnext++ = M_ALL;
  457.             break;
  458.         case HASH:
  459.             if ((pglob->gl_flags & GLOB_AMIGA) && *qpatnext == QUESTION)
  460.             {
  461.               qpatnext++;
  462.               pglob->gl_flags |= GLOB_MAGCHAR;
  463.               if (bufnext == patbuf || bufnext[-1] != M_ALL)
  464.                 *bufnext++ = M_ALL;
  465.               break;
  466.             }
  467.             /* fall through */
  468.         default:
  469.             *bufnext++ = CHAR(c);
  470.             break;
  471.         }
  472.     }
  473.     *bufnext = EOS;
  474.  
  475.     if ((err = glob1(patbuf, pglob)) != 0)
  476.         return(err);
  477.  
  478.     /*
  479.      * If there was no match we are going to append the pattern 
  480.      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
  481.      * and the pattern did not contain any magic characters
  482.      * GLOB_NOMAGIC is there just for compatibility with csh.
  483.      */
  484.     if (pglob->gl_pathc == oldpathc && 
  485.         ((pglob->gl_flags & GLOB_NOCHECK) || 
  486.           ((pglob->gl_flags & GLOB_NOMAGIC) &&
  487.            !(pglob->gl_flags & GLOB_MAGCHAR))))
  488.         return(globextend(pattern, pglob));
  489.     else if (!(pglob->gl_flags & GLOB_NOSORT)) 
  490.         qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
  491.             pglob->gl_pathc - oldpathc, sizeof(char *), 
  492.                     (pglob->gl_flags & GLOB_NOCASE) ? icompare : compare);
  493.     return(0);
  494. }
  495.  
  496. static int
  497. compare(p, q)
  498.     const void *p, *q;
  499. {
  500.     return(strcmp(*(char **)p, *(char **)q));
  501. }
  502.  
  503. static int
  504. icompare(p, q)
  505.     const void *p, *q;
  506. {
  507.     return(strcasecmp(*(char **)p, *(char **)q));
  508. }
  509.  
  510. static int
  511. glob1(pattern, pglob)
  512.     Char *pattern;
  513.     glob_t *pglob;
  514. {
  515.     Char pathbuf[MAXPATHLEN+1];
  516.  
  517.     /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
  518.     if (*pattern == EOS)
  519.         return(0);
  520.     return(glob2(pathbuf, pathbuf, pattern, pglob));
  521. }
  522.  
  523. /*
  524.  * The functions glob2 and glob3 are mutually recursive; there is one level
  525.  * of recursion for each segment in the pattern that contains one or more
  526.  * meta characters.
  527.  */
  528. static int
  529. glob2(pathbuf, pathend, pattern, pglob)
  530.     Char *pathbuf, *pathend, *pattern;
  531.     glob_t *pglob;
  532. {
  533.     struct stat sb;
  534.     Char *p, *q;
  535.     int anymeta;
  536.  
  537.     /*
  538.      * Loop over pattern segments until end of pattern or until
  539.      * segment with meta character found.
  540.      */
  541.     for (anymeta = 0;;) {
  542.         if (*pattern == EOS) {        /* End of pattern? */
  543.             *pathend = EOS;
  544.             if (g_lstat(pathbuf, &sb, pglob))
  545.                 return(0);
  546.         
  547.             if (((pglob->gl_flags & GLOB_MARK) &&
  548.                 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
  549.                 || (S_ISLNK(sb.st_mode) &&
  550.                 (g_stat(pathbuf, &sb, pglob) == 0) &&
  551.                 S_ISDIR(sb.st_mode)))) {
  552.                 *pathend++ = SEP;
  553.                 *pathend = EOS;
  554.             }
  555.             ++pglob->gl_matchc;
  556.             return(globextend(pathbuf, pglob));
  557.         }
  558.  
  559.         /* Find end of next segment, copy tentatively to pathend. */
  560.         q = pathend;
  561.         p = pattern;
  562.         while (*p != EOS && *p != SEP) {
  563.             if (ismeta(*p))
  564.                 anymeta = 1;
  565.             *q++ = *p++;
  566.         }
  567.  
  568.         if (!anymeta) {        /* No expansion, do next segment. */
  569.             pathend = q;
  570.             pattern = p;
  571.             while (*pattern == SEP)
  572.                 *pathend++ = *pattern++;
  573.         } else            /* Need expansion, recurse. */
  574.             return(glob3(pathbuf, pathend, pattern, p, pglob));
  575.     }
  576.     /* NOTREACHED */
  577. }
  578.  
  579. static int
  580. glob3(pathbuf, pathend, pattern, restpattern, pglob)
  581.     Char *pathbuf, *pathend, *pattern, *restpattern;
  582.     glob_t *pglob;
  583. {
  584.     register struct dirent *dp;
  585.     DIR *dirp;
  586.     int err;
  587.     char buf[MAXPATHLEN];
  588.  
  589.     /*
  590.      * The readdirfunc declaration can't be prototyped, because it is
  591.      * assigned, below, to two functions which are prototyped in glob.h
  592.      * and dirent.h as taking pointers to differently typed opaque
  593.      * structures.
  594.      */
  595.     struct dirent *(*readdirfunc)();
  596.  
  597.     *pathend = EOS;
  598.     errno = 0;
  599.         
  600.     if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
  601.         /* TODO: don't call for ENOENT or ENOTDIR? */
  602.         if (pglob->gl_errfunc) {
  603.             g_Ctoc(pathbuf, buf);
  604.             if (pglob->gl_errfunc(buf, errno) ||
  605.                 pglob->gl_flags & GLOB_ERR)
  606.                 return (GLOB_ABEND);
  607.         }
  608.         return(0);
  609.     }
  610.  
  611.     err = 0;
  612.  
  613.     /* Search directory for matching names. */
  614.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  615.         readdirfunc = pglob->gl_readdir;
  616.     else
  617.         readdirfunc = readdir;
  618.     while ((dp = (*readdirfunc)(dirp))) {
  619.         register u_char *sc;
  620.         register Char *dc;
  621.  
  622.         /* Initial DOT must be matched literally. */
  623.         if (dp->d_name[0] == DOT && *pattern != DOT)
  624.             continue;
  625.         for (sc = (u_char *) dp->d_name, dc = pathend; 
  626.              (*dc++ = *sc++) != EOS;)
  627.             continue;
  628.         if (!match(pathend, pattern, restpattern, pglob->gl_flags & GLOB_NOCASE)) {
  629.             *pathend = EOS;
  630.             continue;
  631.         }
  632.         err = glob2(pathbuf, --dc, restpattern, pglob);
  633.         if (err)
  634.             break;
  635.     }
  636.  
  637.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  638.         (*pglob->gl_closedir)(dirp);
  639.     else
  640.         closedir(dirp);
  641.     return(err);
  642. }
  643.  
  644.  
  645. /*
  646.  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
  647.  * add the new item, and update gl_pathc.
  648.  *
  649.  * This assumes the BSD realloc, which only copies the block when its size
  650.  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  651.  * behavior.
  652.  *
  653.  * Return 0 if new item added, error code if memory couldn't be allocated.
  654.  *
  655.  * Invariant of the glob_t structure:
  656.  *    Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  657.  *    gl_pathv points to (gl_offs + gl_pathc + 1) items.
  658.  */
  659. static int
  660. globextend(path, pglob)
  661.     const Char *path;
  662.     glob_t *pglob;
  663. {
  664.     register char **pathv;
  665.     register int i;
  666.     u_int newsize;
  667.     char *copy;
  668.     const Char *p;
  669.  
  670.     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  671.     pathv = pglob->gl_pathv ? 
  672.             realloc((char *)pglob->gl_pathv, newsize) :
  673.             malloc(newsize);
  674.     if (pathv == NULL)
  675.         return(GLOB_NOSPACE);
  676.  
  677.     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  678.         /* first time around -- clear initial gl_offs items */
  679.         pathv += pglob->gl_offs;
  680.         for (i = pglob->gl_offs; --i >= 0; )
  681.             *--pathv = NULL;
  682.     }
  683.     pglob->gl_pathv = pathv;
  684.  
  685.     for (p = path; *p++;)
  686.         continue;
  687.     if ((copy = malloc(p - path)) != NULL) {
  688.         g_Ctoc(path, copy);
  689.         pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  690.     }
  691.     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  692.     return(copy == NULL ? GLOB_NOSPACE : 0);
  693. }
  694.  
  695.  
  696. /*
  697.  * pattern matching function for filenames.  Each occurrence of the *
  698.  * pattern causes a recursion level.
  699.  */
  700. static int
  701. match(name, pat, patend, nocase)
  702.     register Char *name, *pat, *patend;
  703.         int nocase;
  704. {
  705.     int ok, negate_range;
  706.     Char c, k;
  707.  
  708.     while (pat < patend) {
  709.         c = *pat++;
  710.         switch (c & M_MASK) {
  711.         case M_ALL:
  712.             if (pat == patend)
  713.                 return(1);
  714.             do 
  715.                 if (match(name, pat, patend, nocase))
  716.                     return(1);
  717.             while (*name++ != EOS);
  718.             return(0);
  719.         case M_ONE:
  720.             if (*name++ == EOS)
  721.                 return(0);
  722.             break;
  723.         case M_SET:
  724.             ok = 0;
  725.             if ((k = *name++) == EOS)
  726.                 return(0);
  727.             if (nocase)
  728.               k = tolower(k);
  729.             if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
  730.                 ++pat;
  731.             while (((c = *pat++) & M_MASK) != M_END) {
  732.                     if (nocase)
  733.                             c = tolower(c);
  734.                 if ((*pat & M_MASK) == M_RNG) {
  735.                     if (c <= k && k <= (nocase ? tolower(pat[1]) : pat[1]))
  736.                         ok = 1;
  737.                     pat += 2;
  738.                 } else if (c == k)
  739.                     ok = 1;
  740.             }
  741.             if (ok == negate_range)
  742.                 return(0);
  743.             break;
  744.         default:
  745.                 if (nocase)
  746.                 {
  747.                   k = *name++;
  748.                   if (tolower(k) != tolower(c))
  749.                     return 0;
  750.                 }
  751.             else if (*name++ != c)
  752.                 return(0);
  753.             break;
  754.         }
  755.     }
  756.     return(*name == EOS);
  757. }
  758.  
  759. /* Free allocated data belonging to a glob_t structure. */
  760. void
  761. globfree(pglob)
  762.     glob_t *pglob;
  763. {
  764.     register int i;
  765.     register char **pp;
  766.  
  767.     if (pglob->gl_pathv != NULL) {
  768.         pp = pglob->gl_pathv + pglob->gl_offs;
  769.         for (i = pglob->gl_pathc; i--; ++pp)
  770.             if (*pp)
  771.                 free(*pp);
  772.         free(pglob->gl_pathv);
  773.     }
  774. }
  775.  
  776. static DIR *
  777. g_opendir(str, pglob)
  778.     register Char *str;
  779.     glob_t *pglob;
  780. {
  781.     char buf[MAXPATHLEN];
  782.  
  783.     if (!*str)
  784.         strcpy(buf, ".");
  785.     else
  786.         g_Ctoc(str, buf);
  787.  
  788.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  789.         return((*pglob->gl_opendir)(buf));
  790.  
  791.     return(opendir(buf));
  792. }
  793.  
  794. static int
  795. g_lstat(fn, sb, pglob)
  796.     register Char *fn;
  797.     struct stat *sb;
  798.     glob_t *pglob;
  799. {
  800.     char buf[MAXPATHLEN];
  801.  
  802.     g_Ctoc(fn, buf);
  803.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  804.         return((*pglob->gl_lstat)(buf, sb));
  805.     return(lstat(buf, sb));
  806. }
  807.  
  808. static int
  809. g_stat(fn, sb, pglob)
  810.     register Char *fn;
  811.     struct stat *sb;
  812.     glob_t *pglob;
  813. {
  814.     char buf[MAXPATHLEN];
  815.  
  816.     g_Ctoc(fn, buf);
  817.     if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  818.         return((*pglob->gl_stat)(buf, sb));
  819.     return(stat(buf, sb));
  820. }
  821.  
  822. static Char *
  823. g_strchr(str, ch)
  824.     Char *str;
  825.     int ch;
  826. {
  827.     do {
  828.         if (*str == ch)
  829.             return (str);
  830.     } while (*str++);
  831.     return (NULL);
  832. }
  833.  
  834. #ifdef notdef
  835. static Char *
  836. g_strcat(dst, src)
  837.     Char *dst;
  838.     const Char* src;
  839. {
  840.     Char *sdst = dst;
  841.  
  842.     while (*dst++)
  843.         continue;
  844.     --dst;
  845.     while((*dst++ = *src++) != EOS)
  846.         continue;
  847.  
  848.     return (sdst);
  849. }
  850. #endif
  851.  
  852. static void
  853. g_Ctoc(str, buf)
  854.     register const Char *str;
  855.     char *buf;
  856. {
  857.     register char *dc;
  858.  
  859.     for (dc = buf; (*dc++ = *str++) != EOS;)
  860.         continue;
  861. }
  862.