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