OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [misc/] [glob/] [glob.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
2
 
3
This library is free software; you can redistribute it and/or
4
modify it under the terms of the GNU Library General Public License as
5
published by the Free Software Foundation; either version 2 of the
6
License, or (at your option) any later version.
7
 
8
This library is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
Library General Public License for more details.
12
 
13
You should have received a copy of the GNU Library General Public
14
License along with this library; see the file COPYING.LIB.  If
15
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
16
Cambridge, MA 02139, USA.  */
17
 
18
#include <features.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#include <errno.h>
22
#include <sys/types.h>
23
#include <sys/stat.h>
24
#include <unistd.h>
25
#include <dirent.h>
26
#include <malloc.h>
27
#include <fnmatch.h>
28
#define _GNU_SOURCE
29
#include <glob.h>
30
 
31
extern __ptr_t (*__glob_opendir_hook) __P ((const char *directory));
32
extern void (*__glob_closedir_hook) __P ((__ptr_t stream));
33
extern const char *(*__glob_readdir_hook) __P ((__ptr_t stream));
34
 
35
 
36
static int glob_in_dir __P ((const char *pattern, const char *directory,
37
                             int flags,
38
                             int (*errfunc) __P ((const char *, int)),
39
                             glob_t *pglob));
40
static int prefix_array __P ((const char *prefix, char **array, size_t n,
41
                              int add_slash));
42
static int collated_compare __P ((const __ptr_t, const __ptr_t));
43
 
44
#ifdef __GLOB64
45
extern int glob_pattern_p(const char *pattern, int quote);
46
#else
47
/* Return nonzero if PATTERN contains any metacharacters.
48
   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
49
int glob_pattern_p(const char *pattern, int quote)
50
{
51
    const char *p;
52
    int open = 0;
53
 
54
    for (p = pattern; *p != '\0'; ++p)
55
        switch (*p)
56
        {
57
            case '?':
58
            case '*':
59
                return 1;
60
 
61
            case '\\':
62
                if (quote)
63
                    ++p;
64
                break;
65
 
66
            case '[':
67
                open = 1;
68
                break;
69
 
70
            case ']':
71
                if (open)
72
                    return 1;
73
                break;
74
        }
75
 
76
    return 0;
77
}
78
#endif
79
 
80
 
81
/* Do glob searching for PATTERN, placing results in PGLOB.
82
   The bits defined above may be set in FLAGS.
83
   If a directory cannot be opened or read and ERRFUNC is not nil,
84
   it is called with the pathname that caused the error, and the
85
   `errno' value from the failing call; if it returns non-zero
86
   `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
87
   If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
88
   Otherwise, `glob' returns zero.  */
89
int
90
glob (pattern, flags, errfunc, pglob)
91
     const char *pattern;
92
     int flags;
93
     int (*errfunc) __P ((const char *, int));
94
     glob_t *pglob;
95
{
96
  const char *filename;
97
  char *dirname;
98
  size_t dirlen;
99
  int status;
100
  int oldcount;
101
 
102
  if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
103
    {
104
      errno = EINVAL;
105
      return -1;
106
    }
107
 
108
  /* Find the filename.  */
109
  filename = strrchr (pattern, '/');
110
  if (filename == NULL)
111
    {
112
      filename = pattern;
113
      dirname = (char *) ".";
114
      dirlen = 0;
115
    }
116
  else if (filename == pattern)
117
    {
118
      /* "/pattern".  */
119
      dirname = (char *) "/";
120
      dirlen = 1;
121
      ++filename;
122
    }
123
  else
124
    {
125
      dirlen = filename - pattern;
126
      dirname = (char *) alloca (dirlen + 1);
127
      memcpy (dirname, pattern, dirlen);
128
      dirname[dirlen] = '\0';
129
      ++filename;
130
    }
131
 
132
  if (filename[0] == '\0' && dirlen > 1)
133
    /* "pattern/".  Expand "pattern", appending slashes.  */
134
    {
135
      int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
136
      if (val == 0)
137
        pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK);
138
      return val;
139
    }
140
 
141
  if (!(flags & GLOB_APPEND))
142
    {
143
      pglob->gl_pathc = 0;
144
      pglob->gl_pathv = NULL;
145
    }
146
 
147
  oldcount = pglob->gl_pathc;
148
 
149
  if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
150
    {
151
      /* The directory name contains metacharacters, so we
152
         have to glob for the directory, and then glob for
153
         the pattern in each directory found.  */
154
      glob_t dirs;
155
      register int i;
156
 
157
      status = glob (dirname,
158
                     ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) |
159
                      GLOB_NOSORT),
160
                     errfunc, &dirs);
161
      if (status != 0)
162
        return status;
163
 
164
      /* We have successfully globbed the preceding directory name.
165
         For each name we found, call glob_in_dir on it and FILENAME,
166
         appending the results to PGLOB.  */
167
      for (i = 0; i < dirs.gl_pathc; ++i)
168
        {
169
          int oldcount;
170
 
171
#ifdef  SHELL
172
          {
173
            /* Make globbing interruptible in the bash shell. */
174
            extern int interrupt_state;
175
 
176
            if (interrupt_state)
177
              {
178
                globfree (&dirs);
179
                globfree (&files);
180
                return GLOB_ABEND;
181
              }
182
          }
183
#endif /* SHELL.  */
184
 
185
          oldcount = pglob->gl_pathc;
186
          status = glob_in_dir (filename, dirs.gl_pathv[i],
187
                                (flags | GLOB_APPEND) & ~GLOB_NOCHECK,
188
                                errfunc, pglob);
189
          if (status == GLOB_NOMATCH)
190
            /* No matches in this directory.  Try the next.  */
191
            continue;
192
 
193
          if (status != 0)
194
            {
195
              globfree (&dirs);
196
              globfree (pglob);
197
              return status;
198
            }
199
 
200
          /* Stick the directory on the front of each name.  */
201
          if (prefix_array (dirs.gl_pathv[i],
202
                            &pglob->gl_pathv[oldcount],
203
                            pglob->gl_pathc - oldcount,
204
                            flags & GLOB_MARK))
205
            {
206
              globfree (&dirs);
207
              globfree (pglob);
208
              return GLOB_NOSPACE;
209
            }
210
        }
211
 
212
      flags |= GLOB_MAGCHAR;
213
 
214
      if (pglob->gl_pathc == oldcount)
215
      {
216
        /* No matches.  */
217
        if (flags & GLOB_NOCHECK)
218
        {
219
            size_t len = strlen (pattern) + 1;
220
            char *patcopy = (char *) malloc (len);
221
            if (patcopy == NULL)
222
              return GLOB_NOSPACE;
223
            memcpy (patcopy, pattern, len);
224
 
225
            pglob->gl_pathv
226
              = (char **) realloc (pglob->gl_pathv,
227
                                   (pglob->gl_pathc +
228
                                    ((flags & GLOB_DOOFFS) ?
229
                                     pglob->gl_offs : 0) +
230
                                    1 + 1) *
231
                                   sizeof (char *));
232
            if (pglob->gl_pathv == NULL)
233
              {
234
                free (patcopy);
235
                return GLOB_NOSPACE;
236
              }
237
 
238
            if (flags & GLOB_DOOFFS)
239
              while (pglob->gl_pathc < pglob->gl_offs)
240
                pglob->gl_pathv[pglob->gl_pathc++] = NULL;
241
 
242
            pglob->gl_pathv[pglob->gl_pathc++] = patcopy;
243
            pglob->gl_pathv[pglob->gl_pathc] = NULL;
244
            pglob->gl_flags = flags;
245
        }
246
        else
247
        {
248
          return GLOB_NOMATCH;
249
        }
250
      }
251
    }
252
  else
253
    {
254
      status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
255
      if (status != 0)
256
        return status;
257
 
258
      if (dirlen > 0)
259
        {
260
          /* Stick the directory on the front of each name.  */
261
          if (prefix_array (dirname,
262
                            &pglob->gl_pathv[oldcount],
263
                            pglob->gl_pathc - oldcount,
264
                            flags & GLOB_MARK))
265
            {
266
              globfree (pglob);
267
              return GLOB_NOSPACE;
268
            }
269
        }
270
    }
271
 
272
  if (flags & GLOB_MARK)
273
    {
274
      /* Append slashes to directory names.  glob_in_dir has already
275
         allocated the extra character for us.  */
276
      int i;
277
      struct stat st;
278
      for (i = oldcount; i < pglob->gl_pathc; ++i)
279
        if (lstat (pglob->gl_pathv[i], &st) == 0 &&
280
            S_ISDIR (st.st_mode))
281
          strcat (pglob->gl_pathv[i], "/");
282
    }
283
 
284
  if (!(flags & GLOB_NOSORT))
285
    /* Sort the vector.  */
286
    qsort ((__ptr_t) &pglob->gl_pathv[oldcount],
287
           pglob->gl_pathc - oldcount,
288
           sizeof (char *), (__compar_fn_t)collated_compare);
289
 
290
  return 0;
291
}
292
 
293
 
294
/* Free storage allocated in PGLOB by a previous `glob' call.  */
295
void
296
globfree (pglob)
297
     register glob_t *pglob;
298
{
299
  if (pglob->gl_pathv != NULL)
300
    {
301
      register int i = pglob->gl_flags & GLOB_DOOFFS? pglob->gl_offs : 0;
302
      for (; i < pglob->gl_pathc; ++i)
303
        if (pglob->gl_pathv[i] != NULL)
304
          free ((__ptr_t) pglob->gl_pathv[i]);
305
      free ((__ptr_t) pglob->gl_pathv);
306
    }
307
}
308
 
309
 
310
/* Do a collated comparison of A and B.  */
311
static int
312
collated_compare (a, b)
313
     const __ptr_t a;
314
     const __ptr_t b;
315
{
316
  const char *const s1 = *(const char *const *) a;
317
  const char *const s2 = *(const char *const *) b;
318
 
319
  if (s1 == s2)
320
    return 0;
321
  if (s1 == NULL)
322
    return 1;
323
  if (s2 == NULL)
324
    return -1;
325
  return strcoll (s1, s2);
326
}
327
 
328
 
329
/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
330
   elements in place.  Return nonzero if out of memory, zero if successful.
331
   A slash is inserted between DIRNAME and each elt of ARRAY,
332
   unless DIRNAME is just "/".  Each old element of ARRAY is freed.
333
   If ADD_SLASH is non-zero, allocate one character more than
334
   necessary, so that a slash can be appended later.  */
335
static int
336
prefix_array (dirname, array, n, add_slash)
337
     const char *dirname;
338
     char **array;
339
     size_t n;
340
     int add_slash;
341
{
342
  register size_t i;
343
  size_t dirlen = strlen (dirname);
344
 
345
  if (dirlen == 1 && dirname[0] == '/')
346
    /* DIRNAME is just "/", so normal prepending would get us "//foo".
347
       We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
348
    dirlen = 0;
349
 
350
  for (i = 0; i < n; ++i)
351
    {
352
      size_t eltlen = strlen (array[i]) + 1;
353
      char *new = (char *) malloc (dirlen + 1 + eltlen + (add_slash ? 1 : 0));
354
      if (new == NULL)
355
        {
356
          while (i > 0)
357
            free ((__ptr_t) array[--i]);
358
          return 1;
359
        }
360
 
361
      memcpy (new, dirname, dirlen);
362
      new[dirlen] = '/';
363
      memcpy (&new[dirlen + 1], array[i], eltlen);
364
      free ((__ptr_t) array[i]);
365
      array[i] = new;
366
    }
367
 
368
  return 0;
369
}
370
 
371
 
372
/* Like `glob', but PATTERN is a final pathname component,
373
   and matches are searched for in DIRECTORY.
374
   The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
375
   The GLOB_APPEND flag is assumed to be set (always appends).  */
376
static int
377
glob_in_dir (pattern, directory, flags, errfunc, pglob)
378
     const char *pattern;
379
     const char *directory;
380
     int flags;
381
     int (*errfunc) __P ((const char *, int));
382
     glob_t *pglob;
383
{
384
  __ptr_t stream;
385
 
386
  struct globlink
387
    {
388
      struct globlink *next;
389
      char *name;
390
    };
391
  struct globlink *names = NULL;
392
  size_t nfound = 0;
393
  int meta;
394
 
395
  stream = (__glob_opendir_hook ? (*__glob_opendir_hook) (directory)
396
           : (__ptr_t) opendir (directory));
397
  if (stream == NULL)
398
    {
399
      if ((errfunc != NULL && (*errfunc) (directory, errno)) ||
400
          (flags & GLOB_ERR))
401
        return GLOB_ABORTED;
402
    }
403
 
404
  meta = glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
405
 
406
  if (meta)
407
    flags |= GLOB_MAGCHAR;
408
 
409
  while (1)
410
    {
411
      const char *name;
412
      size_t len;
413
 
414
      if (__glob_readdir_hook)
415
        {
416
          name = (*__glob_readdir_hook) (stream);
417
          if (name == NULL)
418
            break;
419
          len = 0;
420
        }
421
      else
422
        {
423
          struct dirent *d = readdir ((DIR *) stream);
424
          if (d == NULL)
425
            break;
426
          if (! (d->d_ino != 0))
427
            continue;
428
          name = d->d_name;
429
#ifdef  HAVE_D_NAMLEN
430
          len = d->d_namlen;
431
#else
432
          len = 0;
433
#endif
434
        }
435
 
436
      if ((!meta && strcmp (pattern, name) == 0)
437
          || fnmatch (pattern, name,
438
                      (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |
439
                      ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)) == 0)
440
        {
441
          struct globlink *new
442
            = (struct globlink *) alloca (sizeof (struct globlink));
443
          if (len == 0)
444
            len = strlen (name);
445
          new->name
446
            = (char *) malloc (len + ((flags & GLOB_MARK) ? 1 : 0) + 1);
447
          if (new->name == NULL)
448
            goto memory_error;
449
          memcpy ((__ptr_t) new->name, name, len);
450
          new->name[len] = '\0';
451
          new->next = names;
452
          names = new;
453
          ++nfound;
454
          if (!meta)
455
            break;
456
        }
457
    }
458
 
459
  if (nfound == 0 && (flags & GLOB_NOCHECK))
460
    {
461
      size_t len = strlen (pattern);
462
      nfound = 1;
463
      names = (struct globlink *) alloca (sizeof (struct globlink));
464
      names->next = NULL;
465
      names->name = (char *) malloc (len + (flags & GLOB_MARK ? 1 : 0) + 1);
466
      if (names->name == NULL)
467
        goto memory_error;
468
      memcpy (names->name, pattern, len);
469
      names->name[len] = '\0';
470
    }
471
 
472
  pglob->gl_pathv
473
    = (char **) realloc (pglob->gl_pathv,
474
                         (pglob->gl_pathc +
475
                          ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) +
476
                          nfound + 1) *
477
                         sizeof (char *));
478
  if (pglob->gl_pathv == NULL)
479
    goto memory_error;
480
 
481
  if (flags & GLOB_DOOFFS)
482
    while (pglob->gl_pathc < pglob->gl_offs)
483
      pglob->gl_pathv[pglob->gl_pathc++] = NULL;
484
 
485
  for (; names != NULL; names = names->next)
486
    pglob->gl_pathv[pglob->gl_pathc++] = names->name;
487
  pglob->gl_pathv[pglob->gl_pathc] = NULL;
488
 
489
  pglob->gl_flags = flags;
490
 
491
  {
492
    int save = errno;
493
    if (__glob_closedir_hook)
494
      (*__glob_closedir_hook) (stream);
495
    else
496
      (void) closedir ((DIR *) stream);
497
    errno = save;
498
  }
499
  return nfound == 0 ? GLOB_NOMATCH : 0;
500
 
501
 memory_error:
502
  {
503
    int save = errno;
504
    if (__glob_closedir_hook)
505
      (*__glob_closedir_hook) (stream);
506
    else
507
      (void) closedir ((DIR *) stream);
508
    errno = save;
509
  }
510
  while (names != NULL)
511
    {
512
      if (names->name != NULL)
513
        free ((__ptr_t) names->name);
514
      names = names->next;
515
    }
516
  return GLOB_NOSPACE;
517
}
518
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.