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