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