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