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