This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
s/use vars/our/g modules that aren't independently maintained on CPAN
[perl5.git] / ext / File / Glob / bsd_glob.c
CommitLineData
72b16652
GS
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.
0e950d83 16 * 3. Neither the name of the University nor the names of its contributors
72b16652
GS
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
72b16652
GS
33#if defined(LIBC_SCCS) && !defined(lint)
34static 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>
4f49e16e
GS
64#include <XSUB.h>
65
72b16652
GS
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
3e5d0dec
GS
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 '/'
220398a0
PM
94#ifdef DOSISH
95#define BG_SEP2 '\\'
96#endif
3e5d0dec
GS
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 ','
72b16652
GS
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
112typedef 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
121typedef 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
137static int compare(const void *, const void *);
220398a0 138static int ci_compare(const void *, const void *);
72b16652
GS
139static void g_Ctoc(const Char *, char *);
140static int g_lstat(Char *, Stat_t *, glob_t *);
141static DIR *g_opendir(Char *, glob_t *);
142static Char *g_strchr(Char *, int);
143#ifdef notdef
144static Char *g_strcat(Char *, const Char *);
145#endif
146static int g_stat(Char *, Stat_t *, glob_t *);
147static int glob0(const Char *, glob_t *);
148static int glob1(Char *, glob_t *);
149static int glob2(Char *, Char *, Char *, glob_t *);
150static int glob3(Char *, Char *, Char *, Char *, glob_t *);
151static int globextend(const Char *, glob_t *);
152static const Char * globtilde(const Char *, Char *, glob_t *);
153static int globexp1(const Char *, glob_t *);
154static int globexp2(const Char *, const Char *, glob_t *, int *);
220398a0 155static int match(Char *, Char *, Char *, int);
72b16652
GS
156#ifdef GLOB_DEBUG
157static void qprintf(const char *, Char *);
158#endif /* GLOB_DEBUG */
159
4f49e16e
GS
160#ifdef PERL_IMPLICIT_CONTEXT
161static Direntry_t * my_readdir(DIR*);
162
163static Direntry_t *
164my_readdir(DIR *d)
165{
166 return PerlDir_read(d);
167}
168#else
169#define my_readdir readdir
170#endif
171
72b16652
GS
172int
173bsd_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;
220398a0
PM
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
72b16652
GS
212 if (flags & GLOB_QUOTE) {
213 /* Protect the quoted characters. */
3e5d0dec
GS
214 while (bufnext < bufend && (c = *patnext++) != BG_EOS)
215 if (c == BG_QUOTE) {
220398a0
PM
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
3e5d0dec 226 if ((c = *patnext++) == BG_EOS) {
220398a0 227#endif
3e5d0dec 228 c = BG_QUOTE;
72b16652
GS
229 --patnext;
230 }
231 *bufnext++ = c | M_PROTECT;
232 }
233 else
234 *bufnext++ = c;
235 }
236 else
3e5d0dec 237 while (bufnext < bufend && (c = *patnext++) != BG_EOS)
72b16652 238 *bufnext++ = c;
3e5d0dec 239 *bufnext = BG_EOS;
72b16652
GS
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 */
252static 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 */
3e5d0dec 258 if (pattern[0] == BG_LBRACE && pattern[1] == BG_RBRACE && pattern[2] == BG_EOS)
72b16652
GS
259 return glob0(pattern, pglob);
260
3e5d0dec 261 while ((ptr = (const Char *) g_strchr((Char *) ptr, BG_LBRACE)) != NULL)
72b16652
GS
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 */
274static 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++)
3e5d0dec 289 if (*pe == BG_LBRACKET) {
72b16652 290 /* Ignore everything between [] */
3e5d0dec 291 for (pm = pe++; *pe != BG_RBRACKET && *pe != BG_EOS; pe++)
72b16652 292 continue;
3e5d0dec 293 if (*pe == BG_EOS) {
72b16652 294 /*
3e5d0dec
GS
295 * We could not find a matching BG_RBRACKET.
296 * Ignore and just look for BG_RBRACE
72b16652
GS
297 */
298 pe = pm;
299 }
300 }
3e5d0dec 301 else if (*pe == BG_LBRACE)
72b16652 302 i++;
3e5d0dec 303 else if (*pe == BG_RBRACE) {
72b16652
GS
304 if (i == 0)
305 break;
306 i--;
307 }
308
309 /* Non matching braces; just glob the pattern */
3e5d0dec 310 if (i != 0 || *pe == BG_EOS) {
72b16652
GS
311 *rv = glob0(patbuf, pglob);
312 return 0;
313 }
314
315 for (i = 0, pl = pm = ptr; pm <= pe; pm++)
316 switch (*pm) {
3e5d0dec 317 case BG_LBRACKET:
72b16652 318 /* Ignore everything between [] */
3e5d0dec 319 for (pl = pm++; *pm != BG_RBRACKET && *pm != BG_EOS; pm++)
72b16652 320 continue;
3e5d0dec 321 if (*pm == BG_EOS) {
72b16652 322 /*
3e5d0dec
GS
323 * We could not find a matching BG_RBRACKET.
324 * Ignore and just look for BG_RBRACE
72b16652
GS
325 */
326 pm = pl;
327 }
328 break;
329
3e5d0dec 330 case BG_LBRACE:
72b16652
GS
331 i++;
332 break;
333
3e5d0dec 334 case BG_RBRACE:
72b16652
GS
335 if (i) {
336 i--;
337 break;
338 }
339 /* FALLTHROUGH */
3e5d0dec
GS
340 case BG_COMMA:
341 if (i && *pm == BG_COMMA)
72b16652
GS
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 */
3e5d0dec 351 for (pl = pe + 1; (*lm++ = *pl++) != BG_EOS;)
72b16652
GS
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 */
377static const Char *
378globtilde(const Char *pattern, Char *patbuf, glob_t *pglob)
379{
380 struct passwd *pwd;
381 char *h;
382 const Char *p;
383 Char *b;
384
3e5d0dec 385 if (*pattern != BG_TILDE || !(pglob->gl_flags & GLOB_TILDE))
72b16652
GS
386 return pattern;
387
388 /* Copy up to the end of the string or / */
3e5d0dec 389 for (p = pattern + 1, h = (char *) patbuf; *p && *p != BG_SLASH;
72b16652
GS
390 *h++ = *p++)
391 continue;
392
3e5d0dec 393 *h = BG_EOS;
72b16652 394
3e5d0dec 395 if (((char *) patbuf)[0] == BG_EOS) {
72b16652
GS
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 */
3e5d0dec 430 while ((*b++ = *p++) != BG_EOS)
72b16652
GS
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 */
444static int
445glob0(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. */
3e5d0dec 458 while ((c = *qpatnext++) != BG_EOS) {
72b16652 459 switch (c) {
3e5d0dec 460 case BG_LBRACKET:
72b16652 461 c = *qpatnext;
3e5d0dec 462 if (c == BG_NOT)
72b16652 463 ++qpatnext;
3e5d0dec
GS
464 if (*qpatnext == BG_EOS ||
465 g_strchr((Char *) qpatnext+1, BG_RBRACKET) == NULL) {
466 *bufnext++ = BG_LBRACKET;
467 if (c == BG_NOT)
72b16652
GS
468 --qpatnext;
469 break;
470 }
471 *bufnext++ = M_SET;
3e5d0dec 472 if (c == BG_NOT)
72b16652
GS
473 *bufnext++ = M_NOT;
474 c = *qpatnext++;
475 do {
476 *bufnext++ = CHAR(c);
3e5d0dec
GS
477 if (*qpatnext == BG_RANGE &&
478 (c = qpatnext[1]) != BG_RBRACKET) {
72b16652
GS
479 *bufnext++ = M_RNG;
480 *bufnext++ = CHAR(c);
481 qpatnext += 2;
482 }
3e5d0dec 483 } while ((c = *qpatnext++) != BG_RBRACKET);
72b16652
GS
484 pglob->gl_flags |= GLOB_MAGCHAR;
485 *bufnext++ = M_END;
486 break;
3e5d0dec 487 case BG_QUESTION:
72b16652
GS
488 pglob->gl_flags |= GLOB_MAGCHAR;
489 *bufnext++ = M_ONE;
490 break;
3e5d0dec 491 case BG_STAR:
72b16652
GS
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 }
3e5d0dec 504 *bufnext = BG_EOS;
72b16652
GS
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,
220398a0
PM
533 pglob->gl_pathc - oldpathc, sizeof(char *),
534 (pglob->gl_flags & GLOB_NOCASE) ? ci_compare : compare);
72b16652
GS
535 pglob->gl_flags = oldflags;
536 return(0);
537}
538
539static int
220398a0
PM
540ci_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
553static int
72b16652
GS
554compare(const void *p, const void *q)
555{
556 return(strcmp(*(char **)p, *(char **)q));
557}
558
559static int
560glob1(Char *pattern, glob_t *pglob)
561{
562 Char pathbuf[MAXPATHLEN+1];
563
564 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
3e5d0dec 565 if (*pattern == BG_EOS)
72b16652
GS
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 */
575static int
576glob2(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;;) {
3e5d0dec
GS
587 if (*pattern == BG_EOS) { /* End of pattern? */
588 *pathend = BG_EOS;
72b16652 589
72b16652
GS
590 if (g_lstat(pathbuf, &sb, pglob))
591 return(0);
72b16652
GS
592
593 if (((pglob->gl_flags & GLOB_MARK) &&
220398a0
PM
594 pathend[-1] != BG_SEP
595#ifdef DOSISH
596 && pathend[-1] != BG_SEP2
597#endif
598 ) && (S_ISDIR(sb.st_mode)
72b16652
GS
599 || (S_ISLNK(sb.st_mode) &&
600 (g_stat(pathbuf, &sb, pglob) == 0) &&
601 S_ISDIR(sb.st_mode)))) {
3e5d0dec
GS
602 *pathend++ = BG_SEP;
603 *pathend = BG_EOS;
72b16652
GS
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;
220398a0
PM
615 while (*p != BG_EOS && *p != BG_SEP
616#ifdef DOSISH
617 && *p != BG_SEP2
618#endif
619 ) {
72b16652
GS
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;
220398a0
PM
628 while (*pattern == BG_SEP
629#ifdef DOSISH
630 || *pattern == BG_SEP2
631#endif
632 )
72b16652
GS
633 *pathend++ = *pattern++;
634 } else /* Need expansion, recurse. */
635 return(glob3(pathbuf, pathend, pattern, p, pglob));
636 }
637 /* NOTREACHED */
638}
639
640static int
641glob3(Char *pathbuf, Char *pathend, Char *pattern,
642 Char *restpattern, glob_t *pglob)
643{
644 register Direntry_t *dp;
645 DIR *dirp;
646 int err;
220398a0 647 int nocase;
72b16652
GS
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
3e5d0dec 658 *pathend = BG_EOS;
72b16652
GS
659 errno = 0;
660
661 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
662 /* TODO: don't call for ENOENT or ENOTDIR? */
663 if (pglob->gl_errfunc) {
664 g_Ctoc(pathbuf, buf);
665 if (pglob->gl_errfunc(buf, errno) ||
666 (pglob->gl_flags & GLOB_ERR))
667 return (GLOB_ABEND);
668 }
669 return(0);
670 }
671
672 err = 0;
220398a0 673 nocase = ((pglob->gl_flags & GLOB_NOCASE) != 0);
72b16652
GS
674
675 /* Search directory for matching names. */
676 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
677 readdirfunc = pglob->gl_readdir;
678 else
4f49e16e 679 readdirfunc = my_readdir;
72b16652
GS
680 while ((dp = (*readdirfunc)(dirp))) {
681 register U8 *sc;
682 register Char *dc;
683
3e5d0dec
GS
684 /* Initial BG_DOT must be matched literally. */
685 if (dp->d_name[0] == BG_DOT && *pattern != BG_DOT)
72b16652
GS
686 continue;
687 for (sc = (U8 *) dp->d_name, dc = pathend;
3e5d0dec 688 (*dc++ = *sc++) != BG_EOS;)
72b16652 689 continue;
220398a0 690 if (!match(pathend, pattern, restpattern, nocase)) {
3e5d0dec 691 *pathend = BG_EOS;
72b16652
GS
692 continue;
693 }
694 err = glob2(pathbuf, --dc, restpattern, pglob);
695 if (err)
696 break;
697 }
698
699 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
700 (*pglob->gl_closedir)(dirp);
701 else
4f49e16e 702 PerlDir_close(dirp);
72b16652
GS
703 return(err);
704}
705
706
707/*
708 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
709 * add the new item, and update gl_pathc.
710 *
711 * This assumes the BSD realloc, which only copies the block when its size
712 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
713 * behavior.
714 *
715 * Return 0 if new item added, error code if memory couldn't be allocated.
716 *
717 * Invariant of the glob_t structure:
718 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
719 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
720 */
721static int
722globextend(const Char *path, glob_t *pglob)
723{
724 register char **pathv;
725 register int i;
72b16652
GS
726 char *copy;
727 const Char *p;
728
729#ifdef GLOB_DEBUG
730 printf("Adding ");
731 for (p = path; *p; p++)
732 (void)printf("%c", CHAR(*p));
733 printf("\n");
3e5d0dec 734#endif /* GLOB_DEBUG */
72b16652 735
4f49e16e
GS
736 if (pglob->gl_pathv)
737 pathv = Renew(pglob->gl_pathv,
738 (2 + pglob->gl_pathc + pglob->gl_offs),char*);
739 else
740 New(0,pathv,(2 + pglob->gl_pathc + pglob->gl_offs),char*);
72b16652
GS
741 if (pathv == NULL)
742 return(GLOB_NOSPACE);
743
744 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
745 /* first time around -- clear initial gl_offs items */
746 pathv += pglob->gl_offs;
747 for (i = pglob->gl_offs; --i >= 0; )
748 *--pathv = NULL;
749 }
750 pglob->gl_pathv = pathv;
751
752 for (p = path; *p++;)
753 continue;
4f49e16e
GS
754 New(0, copy, p-path, char);
755 if (copy != NULL) {
72b16652
GS
756 g_Ctoc(path, copy);
757 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
758 }
759 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
760 return(copy == NULL ? GLOB_NOSPACE : 0);
761}
762
763
764/*
765 * pattern matching function for filenames. Each occurrence of the *
766 * pattern causes a recursion level.
767 */
768static int
220398a0 769match(register Char *name, register Char *pat, register Char *patend, int nocase)
72b16652
GS
770{
771 int ok, negate_range;
772 Char c, k;
773
774 while (pat < patend) {
775 c = *pat++;
776 switch (c & M_MASK) {
777 case M_ALL:
778 if (pat == patend)
779 return(1);
780 do
220398a0 781 if (match(name, pat, patend, nocase))
72b16652 782 return(1);
3e5d0dec 783 while (*name++ != BG_EOS);
72b16652
GS
784 return(0);
785 case M_ONE:
3e5d0dec 786 if (*name++ == BG_EOS)
72b16652
GS
787 return(0);
788 break;
789 case M_SET:
790 ok = 0;
3e5d0dec 791 if ((k = *name++) == BG_EOS)
72b16652 792 return(0);
3e5d0dec 793 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != BG_EOS)
72b16652
GS
794 ++pat;
795 while (((c = *pat++) & M_MASK) != M_END)
796 if ((*pat & M_MASK) == M_RNG) {
220398a0
PM
797 if (nocase) {
798 if (tolower(c) <= tolower(k) && tolower(k) <= tolower(pat[1]))
799 ok = 1;
800 } else {
801 if (c <= k && k <= pat[1])
802 ok = 1;
803 }
72b16652 804 pat += 2;
220398a0 805 } else if (nocase ? (tolower(c) == tolower(k)) : (c == k))
72b16652
GS
806 ok = 1;
807 if (ok == negate_range)
808 return(0);
809 break;
810 default:
220398a0
PM
811 k = *name++;
812 if (nocase ? (tolower(k) != tolower(c)) : (k != c))
72b16652
GS
813 return(0);
814 break;
815 }
816 }
3e5d0dec 817 return(*name == BG_EOS);
72b16652
GS
818}
819
820/* Free allocated data belonging to a glob_t structure. */
821void
822bsd_globfree(glob_t *pglob)
823{
824 register int i;
825 register char **pp;
826
827 if (pglob->gl_pathv != NULL) {
828 pp = pglob->gl_pathv + pglob->gl_offs;
829 for (i = pglob->gl_pathc; i--; ++pp)
830 if (*pp)
4f49e16e
GS
831 Safefree(*pp);
832 Safefree(pglob->gl_pathv);
72b16652
GS
833 }
834}
835
836static DIR *
837g_opendir(register Char *str, glob_t *pglob)
838{
839 char buf[MAXPATHLEN];
840
841 if (!*str)
842 strcpy(buf, ".");
843 else
844 g_Ctoc(str, buf);
845
846 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
847 return((*pglob->gl_opendir)(buf));
4f49e16e
GS
848 else
849 return(PerlDir_open(buf));
72b16652
GS
850}
851
72b16652
GS
852static int
853g_lstat(register Char *fn, Stat_t *sb, glob_t *pglob)
854{
855 char buf[MAXPATHLEN];
856
857 g_Ctoc(fn, buf);
858 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
859 return((*pglob->gl_lstat)(buf, sb));
4f49e16e
GS
860#ifdef HAS_LSTAT
861 return(PerlLIO_lstat(buf, sb));
862#else
863 return(PerlLIO_stat(buf, sb));
72b16652 864#endif /* HAS_LSTAT */
4f49e16e 865}
72b16652
GS
866
867static int
868g_stat(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_stat)(buf, sb));
4f49e16e 875 return(PerlLIO_stat(buf, sb));
72b16652
GS
876}
877
878static Char *
879g_strchr(Char *str, int ch)
880{
881 do {
882 if (*str == ch)
883 return (str);
884 } while (*str++);
885 return (NULL);
886}
887
888#ifdef notdef
889static Char *
890g_strcat(Char *dst, const Char *src)
891{
892 Char *sdst = dst;
893
894 while (*dst++)
895 continue;
896 --dst;
3e5d0dec 897 while((*dst++ = *src++) != BG_EOS)
72b16652
GS
898 continue;
899
900 return (sdst);
901}
902#endif
903
904static void
905g_Ctoc(register const Char *str, char *buf)
906{
907 register char *dc;
908
3e5d0dec 909 for (dc = buf; (*dc++ = *str++) != BG_EOS;)
72b16652
GS
910 continue;
911}
912
913#ifdef GLOB_DEBUG
914static void
915qprintf(const char *str, register Char *s)
916{
917 register Char *p;
918
919 (void)printf("%s:\n", str);
920 for (p = s; *p; p++)
921 (void)printf("%c", CHAR(*p));
922 (void)printf("\n");
923 for (p = s; *p; p++)
924 (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
925 (void)printf("\n");
926 for (p = s; *p; p++)
927 (void)printf("%c", ismeta(*p) ? '_' : ' ');
928 (void)printf("\n");
929}
930#endif /* GLOB_DEBUG */