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