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