source: trunk/libs/newlib/src/newlib/libc/posix/glob.c @ 577

Last change on this file since 577 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

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