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