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