~showard314/ubuntu/karmic/r-base/remove_start_comments

« back to all changes in this revision

Viewing changes to src/gnuwin32/dos_glob.c

  • Committer: Bazaar Package Importer
  • Author(s): Dirk Eddelbuettel
  • Date: 2009-01-19 12:40:24 UTC
  • mfrom: (5.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20090119124024-abxsf4e0y7713w9m
Tags: 2.8.1-2
debian/control: Add another Build-Depends: exclusion for the 
'kfreebsd-i386 kfreebsd-amd64 hurd-i386' architecture to openjdk-6-jdk.
Thanks to Petr Salinger for the heads-up.               (Closes: 512324)

Show diffs side-by-side

added added

removed removed

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