Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / appl / ftp / common / 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  * 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 #ifdef HAVE_CONFIG_H
63 #include <config.h>
64 #endif
65
66 #ifdef HAVE_SYS_PARAM_H
67 #include <sys/param.h>
68 #endif
69 #ifdef HAVE_SYS_TYPES_H
70 #include <sys/types.h>
71 #endif
72 #ifdef HAVE_SYS_STAT_H
73 #include <sys/stat.h>
74 #endif
75
76 #include <ctype.h>
77 #ifdef HAVE_DIRENT_H
78 #include <dirent.h>
79 #endif
80 #include <errno.h>
81 #ifdef HAVE_PWD_H
82 #include <pwd.h>
83 #endif
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #ifdef HAVE_UNISTD_H
88 #include <unistd.h>
89 #endif
90
91 #include "glob.h"
92 #include "roken.h"
93
94 #define CHAR_DOLLAR             '$'
95 #define CHAR_DOT                '.'
96 #define CHAR_EOS                '\0'
97 #define CHAR_LBRACKET           '['
98 #define CHAR_NOT                '!'
99 #define CHAR_QUESTION           '?'
100 #define CHAR_QUOTE              '\\'
101 #define CHAR_RANGE              '-'
102 #define CHAR_RBRACKET           ']'
103 #define CHAR_SEP                '/'
104 #define CHAR_STAR               '*'
105 #define CHAR_TILDE              '~'
106 #define CHAR_UNDERSCORE         '_'
107 #define CHAR_LBRACE             '{'
108 #define CHAR_RBRACE             '}'
109 #define CHAR_SLASH              '/'
110 #define CHAR_COMMA              ','
111
112 #ifndef 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 u_short 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 char Char;
129
130 #endif
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 *, struct stat *, 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 *, struct stat *, 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 DEBUG
163 static void      qprintf (const char *, Char *);
164 #endif
165
166 int
167 glob(const char *pattern, 
168      int flags, 
169      int (*errfunc)(const char *, int), 
170      glob_t *pglob)
171 {
172         const u_char *patnext;
173         int c;
174         Char *bufnext, *bufend, patbuf[MaxPathLen+1];
175
176         patnext = (u_char *) pattern;
177         if (!(flags & GLOB_APPEND)) {
178                 pglob->gl_pathc = 0;
179                 pglob->gl_pathv = NULL;
180                 if (!(flags & GLOB_DOOFFS))
181                         pglob->gl_offs = 0;
182         }
183         pglob->gl_flags = flags & ~GLOB_MAGCHAR;
184         pglob->gl_errfunc = errfunc;
185         pglob->gl_matchc = 0;
186
187         bufnext = patbuf;
188         bufend = bufnext + MaxPathLen;
189         if (flags & GLOB_QUOTE) {
190                 /* Protect the quoted characters. */
191                 while (bufnext < bufend && (c = *patnext++) != CHAR_EOS) 
192                         if (c == CHAR_QUOTE) {
193                                 if ((c = *patnext++) == CHAR_EOS) {
194                                         c = CHAR_QUOTE;
195                                         --patnext;
196                                 }
197                                 *bufnext++ = c | M_PROTECT;
198                         }
199                         else
200                                 *bufnext++ = c;
201         }
202         else 
203             while (bufnext < bufend && (c = *patnext++) != CHAR_EOS) 
204                     *bufnext++ = c;
205         *bufnext = CHAR_EOS;
206
207         if (flags & GLOB_BRACE)
208             return globexp1(patbuf, pglob);
209         else
210             return glob0(patbuf, pglob);
211 }
212
213 /*
214  * Expand recursively a glob {} pattern. When there is no more expansion
215  * invoke the standard globbing routine to glob the rest of the magic
216  * characters
217  */
218 static int globexp1(const Char *pattern, glob_t *pglob)
219 {
220         const Char* ptr = pattern;
221         int rv;
222
223         /* Protect a single {}, for find(1), like csh */
224         if (pattern[0] == CHAR_LBRACE && pattern[1] == CHAR_RBRACE && pattern[2] == CHAR_EOS)
225                 return glob0(pattern, pglob);
226
227         while ((ptr = (const Char *) g_strchr((Char *) ptr, CHAR_LBRACE)) != NULL)
228                 if (!globexp2(ptr, pattern, pglob, &rv))
229                         return rv;
230
231         return glob0(pattern, pglob);
232 }
233
234
235 /*
236  * Recursive brace globbing helper. Tries to expand a single brace.
237  * If it succeeds then it invokes globexp1 with the new pattern.
238  * If it fails then it tries to glob the rest of the pattern and returns.
239  */
240 static int globexp2(const Char *ptr, const Char *pattern, 
241                     glob_t *pglob, int *rv)
242 {
243         int     i;
244         Char   *lm, *ls;
245         const Char *pe, *pm, *pl;
246         Char    patbuf[MaxPathLen + 1];
247
248         /* copy part up to the brace */
249         for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
250                 continue;
251         ls = lm;
252
253         /* Find the balanced brace */
254         for (i = 0, pe = ++ptr; *pe; pe++)
255                 if (*pe == CHAR_LBRACKET) {
256                         /* Ignore everything between [] */
257                         for (pm = pe++; *pe != CHAR_RBRACKET && *pe != CHAR_EOS; pe++)
258                                 continue;
259                         if (*pe == CHAR_EOS) {
260                                 /* 
261                                  * We could not find a matching CHAR_RBRACKET.
262                                  * Ignore and just look for CHAR_RBRACE
263                                  */
264                                 pe = pm;
265                         }
266                 }
267                 else if (*pe == CHAR_LBRACE)
268                         i++;
269                 else if (*pe == CHAR_RBRACE) {
270                         if (i == 0)
271                                 break;
272                         i--;
273                 }
274
275         /* Non matching braces; just glob the pattern */
276         if (i != 0 || *pe == CHAR_EOS) {
277                 *rv = glob0(patbuf, pglob);
278                 return 0;
279         }
280
281         for (i = 0, pl = pm = ptr; pm <= pe; pm++)
282                 switch (*pm) {
283                 case CHAR_LBRACKET:
284                         /* Ignore everything between [] */
285                         for (pl = pm++; *pm != CHAR_RBRACKET && *pm != CHAR_EOS; pm++)
286                                 continue;
287                         if (*pm == CHAR_EOS) {
288                                 /* 
289                                  * We could not find a matching CHAR_RBRACKET.
290                                  * Ignore and just look for CHAR_RBRACE
291                                  */
292                                 pm = pl;
293                         }
294                         break;
295
296                 case CHAR_LBRACE:
297                         i++;
298                         break;
299
300                 case CHAR_RBRACE:
301                         if (i) {
302                             i--;
303                             break;
304                         }
305                         /* FALLTHROUGH */
306                 case CHAR_COMMA:
307                         if (i && *pm == CHAR_COMMA)
308                                 break;
309                         else {
310                                 /* Append the current string */
311                                 for (lm = ls; (pl < pm); *lm++ = *pl++)
312                                         continue;
313                                 /* 
314                                  * Append the rest of the pattern after the
315                                  * closing brace
316                                  */
317                                 for (pl = pe + 1; (*lm++ = *pl++) != CHAR_EOS;)
318                                         continue;
319
320                                 /* Expand the current pattern */
321 #ifdef DEBUG
322                                 qprintf("globexp2:", patbuf);
323 #endif
324                                 *rv = globexp1(patbuf, pglob);
325
326                                 /* move after the comma, to the next string */
327                                 pl = pm + 1;
328                         }
329                         break;
330
331                 default:
332                         break;
333                 }
334         *rv = 0;
335         return 0;
336 }
337
338
339
340 /*
341  * expand tilde from the passwd file.
342  */
343 static const Char *
344 globtilde(const Char *pattern, Char *patbuf, glob_t *pglob)
345 {
346         struct passwd *pwd;
347         char *h;
348         const Char *p;
349         Char *b;
350
351         if (*pattern != CHAR_TILDE || !(pglob->gl_flags & GLOB_TILDE))
352                 return pattern;
353
354         /* Copy up to the end of the string or / */
355         for (p = pattern + 1, h = (char *) patbuf; *p && *p != CHAR_SLASH; 
356              *h++ = *p++)
357                 continue;
358
359         *h = CHAR_EOS;
360
361         if (((char *) patbuf)[0] == CHAR_EOS) {
362                 /* 
363                  * handle a plain ~ or ~/ by expanding $HOME 
364                  * first and then trying the password file
365                  */
366                 if ((h = getenv("HOME")) == NULL) {
367                         if ((pwd = k_getpwuid(getuid())) == NULL)
368                                 return pattern;
369                         else
370                                 h = pwd->pw_dir;
371                 }
372         }
373         else {
374                 /*
375                  * Expand a ~user
376                  */
377                 if ((pwd = k_getpwnam((char*) patbuf)) == NULL)
378                         return pattern;
379                 else
380                         h = pwd->pw_dir;
381         }
382
383         /* Copy the home directory */
384         for (b = patbuf; *h; *b++ = *h++)
385                 continue;
386         
387         /* Append the rest of the pattern */
388         while ((*b++ = *p++) != CHAR_EOS)
389                 continue;
390
391         return patbuf;
392 }
393         
394
395 /*
396  * The main glob() routine: compiles the pattern (optionally processing
397  * quotes), calls glob1() to do the real pattern matching, and finally
398  * sorts the list (unless unsorted operation is requested).  Returns 0
399  * if things went well, nonzero if errors occurred.  It is not an error
400  * to find no matches.
401  */
402 static int
403 glob0(const Char *pattern, glob_t *pglob)
404 {
405         const Char *qpatnext;
406         int c, err, oldpathc;
407         Char *bufnext, patbuf[MaxPathLen+1];
408
409         qpatnext = globtilde(pattern, patbuf, pglob);
410         oldpathc = pglob->gl_pathc;
411         bufnext = patbuf;
412
413         /* We don't need to check for buffer overflow any more. */
414         while ((c = *qpatnext++) != CHAR_EOS) {
415                 switch (c) {
416                 case CHAR_LBRACKET:
417                         c = *qpatnext;
418                         if (c == CHAR_NOT)
419                                 ++qpatnext;
420                         if (*qpatnext == CHAR_EOS ||
421                             g_strchr((Char *) qpatnext+1, CHAR_RBRACKET) == NULL) {
422                                 *bufnext++ = CHAR_LBRACKET;
423                                 if (c == CHAR_NOT)
424                                         --qpatnext;
425                                 break;
426                         }
427                         *bufnext++ = M_SET;
428                         if (c == CHAR_NOT)
429                                 *bufnext++ = M_NOT;
430                         c = *qpatnext++;
431                         do {
432                                 *bufnext++ = CHAR(c);
433                                 if (*qpatnext == CHAR_RANGE &&
434                                     (c = qpatnext[1]) != CHAR_RBRACKET) {
435                                         *bufnext++ = M_RNG;
436                                         *bufnext++ = CHAR(c);
437                                         qpatnext += 2;
438                                 }
439                         } while ((c = *qpatnext++) != CHAR_RBRACKET);
440                         pglob->gl_flags |= GLOB_MAGCHAR;
441                         *bufnext++ = M_END;
442                         break;
443                 case CHAR_QUESTION:
444                         pglob->gl_flags |= GLOB_MAGCHAR;
445                         *bufnext++ = M_ONE;
446                         break;
447                 case CHAR_STAR:
448                         pglob->gl_flags |= GLOB_MAGCHAR;
449                         /* collapse adjacent stars to one, 
450                          * to avoid exponential behavior
451                          */
452                         if (bufnext == patbuf || bufnext[-1] != M_ALL)
453                             *bufnext++ = M_ALL;
454                         break;
455                 default:
456                         *bufnext++ = CHAR(c);
457                         break;
458                 }
459         }
460         *bufnext = CHAR_EOS;
461 #ifdef DEBUG
462         qprintf("glob0:", patbuf);
463 #endif
464
465         if ((err = glob1(patbuf, pglob)) != 0)
466                 return(err);
467
468         /*
469          * If there was no match we are going to append the pattern 
470          * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
471          * and the pattern did not contain any magic characters
472          * GLOB_NOMAGIC is there just for compatibility with csh.
473          */
474         if (pglob->gl_pathc == oldpathc && 
475             ((pglob->gl_flags & GLOB_NOCHECK) || 
476               ((pglob->gl_flags & GLOB_NOMAGIC) &&
477                !(pglob->gl_flags & GLOB_MAGCHAR))))
478                 return(globextend(pattern, pglob));
479         else if (!(pglob->gl_flags & GLOB_NOSORT)) 
480                 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
481                     pglob->gl_pathc - oldpathc, sizeof(char *), compare);
482         return(0);
483 }
484
485 static int
486 compare(const void *p, const void *q)
487 {
488         return(strcmp(*(char **)p, *(char **)q));
489 }
490
491 static int
492 glob1(Char *pattern, glob_t *pglob)
493 {
494         Char pathbuf[MaxPathLen+1];
495
496         /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
497         if (*pattern == CHAR_EOS)
498                 return(0);
499         return(glob2(pathbuf, pathbuf, pattern, pglob));
500 }
501
502 /*
503  * The functions glob2 and glob3 are mutually recursive; there is one level
504  * of recursion for each segment in the pattern that contains one or more
505  * meta characters.
506  */
507
508 #ifndef S_ISLNK
509 #if defined(S_IFLNK) && defined(S_IFMT)
510 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
511 #else
512 #define S_ISLNK(mode) 0
513 #endif
514 #endif
515
516 static int
517 glob2(Char *pathbuf, Char *pathend, Char *pattern, glob_t *pglob)
518 {
519         struct stat sb;
520         Char *p, *q;
521         int anymeta;
522
523         /*
524          * Loop over pattern segments until end of pattern or until
525          * segment with meta character found.
526          */
527         for (anymeta = 0;;) {
528                 if (*pattern == CHAR_EOS) {             /* End of pattern? */
529                         *pathend = CHAR_EOS;
530                         if (g_lstat(pathbuf, &sb, pglob))
531                                 return(0);
532                 
533                         if (((pglob->gl_flags & GLOB_MARK) &&
534                             pathend[-1] != CHAR_SEP) && (S_ISDIR(sb.st_mode)
535                             || (S_ISLNK(sb.st_mode) &&
536                             (g_stat(pathbuf, &sb, pglob) == 0) &&
537                             S_ISDIR(sb.st_mode)))) {
538                                 *pathend++ = CHAR_SEP;
539                                 *pathend = CHAR_EOS;
540                         }
541                         ++pglob->gl_matchc;
542                         return(globextend(pathbuf, pglob));
543                 }
544
545                 /* Find end of next segment, copy tentatively to pathend. */
546                 q = pathend;
547                 p = pattern;
548                 while (*p != CHAR_EOS && *p != CHAR_SEP) {
549                         if (ismeta(*p))
550                                 anymeta = 1;
551                         *q++ = *p++;
552                 }
553
554                 if (!anymeta) {         /* No expansion, do next segment. */
555                         pathend = q;
556                         pattern = p;
557                         while (*pattern == CHAR_SEP)
558                                 *pathend++ = *pattern++;
559                 } else                  /* Need expansion, recurse. */
560                         return(glob3(pathbuf, pathend, pattern, p, pglob));
561         }
562         /* CHAR_NOTREACHED */
563 }
564
565 static int
566 glob3(Char *pathbuf, Char *pathend, Char *pattern, Char *restpattern, 
567       glob_t *pglob)
568 {
569         struct dirent *dp;
570         DIR *dirp;
571         int err;
572         char buf[MaxPathLen];
573
574         /*
575          * The readdirfunc declaration can't be prototyped, because it is
576          * assigned, below, to two functions which are prototyped in glob.h
577          * and dirent.h as taking pointers to differently typed opaque
578          * structures.
579          */
580         struct dirent *(*readdirfunc)(void *);
581
582         *pathend = CHAR_EOS;
583         errno = 0;
584             
585         if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
586                 /* TODO: don't call for ENOENT or ENOTDIR? */
587                 if (pglob->gl_errfunc) {
588                         g_Ctoc(pathbuf, buf);
589                         if (pglob->gl_errfunc(buf, errno) ||
590                             pglob->gl_flags & GLOB_ERR)
591                                 return (GLOB_ABEND);
592                 }
593                 return(0);
594         }
595
596         err = 0;
597
598         /* Search directory for matching names. */
599         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
600                 readdirfunc = pglob->gl_readdir;
601         else
602                 readdirfunc = (struct dirent *(*)(void *))readdir;
603         while ((dp = (*readdirfunc)(dirp))) {
604                 u_char *sc;
605                 Char *dc;
606
607                 /* Initial CHAR_DOT must be matched literally. */
608                 if (dp->d_name[0] == CHAR_DOT && *pattern != CHAR_DOT)
609                         continue;
610                 for (sc = (u_char *) dp->d_name, dc = pathend; 
611                      (*dc++ = *sc++) != CHAR_EOS;)
612                         continue;
613                 if (!match(pathend, pattern, restpattern)) {
614                         *pathend = CHAR_EOS;
615                         continue;
616                 }
617                 err = glob2(pathbuf, --dc, restpattern, pglob);
618                 if (err)
619                         break;
620         }
621
622         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
623                 (*pglob->gl_closedir)(dirp);
624         else
625                 closedir(dirp);
626         return(err);
627 }
628
629
630 /*
631  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
632  * add the new item, and update gl_pathc.
633  *
634  * This assumes the BSD realloc, which only copies the block when its size
635  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
636  * behavior.
637  *
638  * Return 0 if new item added, error code if memory couldn't be allocated.
639  *
640  * Invariant of the glob_t structure:
641  *      Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
642  *      gl_pathv points to (gl_offs + gl_pathc + 1) items.
643  */
644 static int
645 globextend(const Char *path, glob_t *pglob)
646 {
647         char **pathv;
648         int i;
649         u_int newsize;
650         char *copy;
651         const Char *p;
652
653         newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
654         pathv = pglob->gl_pathv ? 
655                     realloc(pglob->gl_pathv, newsize) :
656                     malloc(newsize);
657         if (pathv == NULL)
658                 return(GLOB_NOSPACE);
659
660         if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
661                 /* first time around -- clear initial gl_offs items */
662                 pathv += pglob->gl_offs;
663                 for (i = pglob->gl_offs; --i >= 0; )
664                         *--pathv = NULL;
665         }
666         pglob->gl_pathv = pathv;
667
668         for (p = path; *p++;)
669                 continue;
670         if ((copy = malloc(p - path)) != NULL) {
671                 g_Ctoc(path, copy);
672                 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
673         }
674         pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
675         return(copy == NULL ? GLOB_NOSPACE : 0);
676 }
677
678
679 /*
680  * pattern matching function for filenames.  Each occurrence of the *
681  * pattern causes a recursion level.
682  */
683 static int
684 match(Char *name, Char *pat, Char *patend)
685 {
686         int ok, negate_range;
687         Char c, k;
688
689         while (pat < patend) {
690                 c = *pat++;
691                 switch (c & M_MASK) {
692                 case M_ALL:
693                         if (pat == patend)
694                                 return(1);
695                         do 
696                             if (match(name, pat, patend))
697                                     return(1);
698                         while (*name++ != CHAR_EOS);
699                         return(0);
700                 case M_ONE:
701                         if (*name++ == CHAR_EOS)
702                                 return(0);
703                         break;
704                 case M_SET:
705                         ok = 0;
706                         if ((k = *name++) == CHAR_EOS)
707                                 return(0);
708                         if ((negate_range = ((*pat & M_MASK) == M_NOT)) != CHAR_EOS)
709                                 ++pat;
710                         while (((c = *pat++) & M_MASK) != M_END)
711                                 if ((*pat & M_MASK) == M_RNG) {
712                                         if (c <= k && k <= pat[1])
713                                                 ok = 1;
714                                         pat += 2;
715                                 } else if (c == k)
716                                         ok = 1;
717                         if (ok == negate_range)
718                                 return(0);
719                         break;
720                 default:
721                         if (*name++ != c)
722                                 return(0);
723                         break;
724                 }
725         }
726         return(*name == CHAR_EOS);
727 }
728
729 /* Free allocated data belonging to a glob_t structure. */
730 void
731 globfree(glob_t *pglob)
732 {
733         int i;
734         char **pp;
735
736         if (pglob->gl_pathv != NULL) {
737                 pp = pglob->gl_pathv + pglob->gl_offs;
738                 for (i = pglob->gl_pathc; i--; ++pp)
739                         if (*pp)
740                                 free(*pp);
741                 free(pglob->gl_pathv);
742         }
743 }
744
745 static DIR *
746 g_opendir(Char *str, glob_t *pglob)
747 {
748         char buf[MaxPathLen];
749
750         if (!*str)
751                 strcpy(buf, ".");
752         else
753                 g_Ctoc(str, buf);
754
755         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
756                 return((*pglob->gl_opendir)(buf));
757
758         return(opendir(buf));
759 }
760
761 static int
762 g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
763 {
764         char buf[MaxPathLen];
765
766         g_Ctoc(fn, buf);
767         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
768                 return((*pglob->gl_lstat)(buf, sb));
769         return(lstat(buf, sb));
770 }
771
772 static int
773 g_stat(Char *fn, struct stat *sb, glob_t *pglob)
774 {
775         char buf[MaxPathLen];
776
777         g_Ctoc(fn, buf);
778         if (pglob->gl_flags & GLOB_ALTDIRFUNC)
779                 return((*pglob->gl_stat)(buf, sb));
780         return(stat(buf, sb));
781 }
782
783 static Char *
784 g_strchr(Char *str, int ch)
785 {
786         do {
787                 if (*str == ch)
788                         return (str);
789         } while (*str++);
790         return (NULL);
791 }
792
793 #ifdef notdef
794 static Char *
795 g_strcat(Char *dst, const Char *src)
796 {
797         Char *sdst = dst;
798
799         while (*dst++)
800                 continue;
801         --dst;
802         while((*dst++ = *src++) != CHAR_EOS)
803             continue;
804
805         return (sdst);
806 }
807 #endif
808
809 static void
810 g_Ctoc(const Char *str, char *buf)
811 {
812         char *dc;
813
814         for (dc = buf; (*dc++ = *str++) != CHAR_EOS;)
815                 continue;
816 }
817
818 #ifdef DEBUG
819 static void 
820 qprintf(const Char *str, Char *s)
821 {
822         Char *p;
823
824         printf("%s:\n", str);
825         for (p = s; *p; p++)
826                 printf("%c", CHAR(*p));
827         printf("\n");
828         for (p = s; *p; p++)
829                 printf("%c", *p & M_PROTECT ? '"' : ' ');
830         printf("\n");
831         for (p = s; *p; p++)
832                 printf("%c", ismeta(*p) ? '_' : ' ');
833         printf("\n");
834 }
835 #endif