]>
Commit | Line | Data |
---|---|---|
02ac66c5 | 1 | /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. |
28f540f4 RM |
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 | /* AIX requires this to be the first thing in the file. */ | |
19 | #if defined (_AIX) && !defined (__GNUC__) | |
20 | #pragma alloca | |
21 | #endif | |
22 | ||
23 | #ifdef HAVE_CONFIG_H | |
24 | #include <config.h> | |
25 | #endif | |
26 | ||
27 | #include <errno.h> | |
28 | #include <sys/types.h> | |
bf3ccd1a | 29 | #include <sys/stat.h> |
28f540f4 RM |
30 | |
31 | ||
32 | /* Comment out all this code if we are using the GNU C Library, and are not | |
33 | actually compiling the library itself. This code is part of the GNU C | |
34 | Library, but also included in many other GNU distributions. Compiling | |
35 | and linking in this code is a waste when using the GNU C library | |
36 | (especially if it is a shared library). Rather than having every GNU | |
37 | program understand `configure --with-gnu-libc' and omit the object files, | |
38 | it is simpler to just do this in the source for each such file. */ | |
39 | ||
787e4db9 RM |
40 | #define GLOB_INTERFACE_VERSION 1 |
41 | #if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 | |
42 | #include <gnu-versions.h> | |
43 | #if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION | |
44 | #define ELIDE_CODE | |
45 | #endif | |
46 | #endif | |
28f540f4 | 47 | |
787e4db9 | 48 | #ifndef ELIDE_CODE |
28f540f4 RM |
49 | |
50 | #ifdef STDC_HEADERS | |
51 | #include <stddef.h> | |
52 | #endif | |
53 | ||
54 | #ifdef HAVE_UNISTD_H | |
55 | #include <unistd.h> | |
56 | #ifndef POSIX | |
57 | #ifdef _POSIX_VERSION | |
58 | #define POSIX | |
59 | #endif | |
60 | #endif | |
61 | #endif | |
62 | ||
787e4db9 RM |
63 | #include <pwd.h> |
64 | ||
28f540f4 RM |
65 | #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) |
66 | extern int errno; | |
67 | #endif | |
68 | ||
69 | #ifndef NULL | |
70 | #define NULL 0 | |
71 | #endif | |
72 | ||
73 | ||
74 | #if defined (POSIX) || defined (HAVE_DIRENT_H) || defined (__GNU_LIBRARY__) | |
75 | #include <dirent.h> | |
76 | #ifndef __GNU_LIBRARY__ | |
77 | #define D_NAMLEN(d) strlen((d)->d_name) | |
78 | #else /* GNU C library. */ | |
79 | #define D_NAMLEN(d) ((d)->d_namlen) | |
80 | #endif /* Not GNU C library. */ | |
81 | #else /* Not POSIX or HAVE_DIRENT_H. */ | |
82 | #define direct dirent | |
83 | #define D_NAMLEN(d) ((d)->d_namlen) | |
84 | #ifdef HAVE_SYS_NDIR_H | |
85 | #include <sys/ndir.h> | |
86 | #endif /* HAVE_SYS_NDIR_H */ | |
87 | #ifdef HAVE_SYS_DIR_H | |
88 | #include <sys/dir.h> | |
89 | #endif /* HAVE_SYS_DIR_H */ | |
90 | #ifdef HAVE_NDIR_H | |
91 | #include <ndir.h> | |
92 | #endif /* HAVE_NDIR_H */ | |
93 | #endif /* POSIX or HAVE_DIRENT_H or __GNU_LIBRARY__. */ | |
94 | ||
95 | #if defined (POSIX) && !defined (__GNU_LIBRARY__) | |
96 | /* Posix does not require that the d_ino field be present, and some | |
97 | systems do not provide it. */ | |
98 | #define REAL_DIR_ENTRY(dp) 1 | |
99 | #else | |
100 | #define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) | |
101 | #endif /* POSIX */ | |
102 | ||
103 | #if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)) | |
104 | #include <stdlib.h> | |
105 | #include <string.h> | |
106 | #define ANSI_STRING | |
107 | #else /* No standard headers. */ | |
108 | ||
3be01400 RM |
109 | extern char *getenv (); |
110 | ||
28f540f4 RM |
111 | #ifdef HAVE_STRING_H |
112 | #include <string.h> | |
113 | #define ANSI_STRING | |
114 | #else | |
115 | #include <strings.h> | |
116 | #endif | |
117 | #ifdef HAVE_MEMORY_H | |
118 | #include <memory.h> | |
119 | #endif | |
120 | ||
121 | extern char *malloc (), *realloc (); | |
122 | extern void free (); | |
123 | ||
124 | extern void qsort (); | |
125 | extern void abort (), exit (); | |
126 | ||
127 | #endif /* Standard headers. */ | |
128 | ||
129 | #ifndef ANSI_STRING | |
130 | ||
131 | #ifndef bzero | |
132 | extern void bzero (); | |
133 | #endif | |
134 | #ifndef bcopy | |
135 | extern void bcopy (); | |
136 | #endif | |
137 | ||
138 | #define memcpy(d, s, n) bcopy ((s), (d), (n)) | |
139 | #define strrchr rindex | |
140 | /* memset is only used for zero here, but let's be paranoid. */ | |
141 | #define memset(s, better_be_zero, n) \ | |
142 | ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0))) | |
143 | #endif /* Not ANSI_STRING. */ | |
144 | ||
145 | #ifndef HAVE_STRCOLL | |
146 | #define strcoll strcmp | |
147 | #endif | |
148 | ||
149 | ||
150 | #ifndef __GNU_LIBRARY__ | |
151 | #ifdef __GNUC__ | |
152 | __inline | |
153 | #endif | |
154 | static char * | |
155 | my_realloc (p, n) | |
156 | char *p; | |
157 | unsigned int n; | |
158 | { | |
159 | /* These casts are the for sake of the broken Ultrix compiler, | |
160 | which warns of illegal pointer combinations otherwise. */ | |
161 | if (p == NULL) | |
162 | return (char *) malloc (n); | |
163 | return (char *) realloc (p, n); | |
164 | } | |
165 | #define realloc my_realloc | |
166 | #endif | |
167 | ||
168 | ||
169 | #if !defined(__alloca) && !defined(__GNU_LIBRARY__) | |
170 | ||
171 | #ifdef __GNUC__ | |
172 | #undef alloca | |
173 | #define alloca(n) __builtin_alloca (n) | |
174 | #else /* Not GCC. */ | |
175 | #if defined (sparc) || defined (HAVE_ALLOCA_H) | |
176 | #include <alloca.h> | |
177 | #else /* Not sparc or HAVE_ALLOCA_H. */ | |
178 | #ifndef _AIX | |
179 | extern char *alloca (); | |
180 | #endif /* Not _AIX. */ | |
181 | #endif /* sparc or HAVE_ALLOCA_H. */ | |
182 | #endif /* GCC. */ | |
183 | ||
184 | #define __alloca alloca | |
185 | ||
186 | #endif | |
187 | ||
bf3ccd1a | 188 | #ifndef __GNU_LIBRARY__ |
787e4db9 | 189 | #define __stat stat |
bf3ccd1a RM |
190 | #ifdef STAT_MACROS_BROKEN |
191 | #undef S_ISDIR | |
2bda74ba RM |
192 | #endif |
193 | #ifndef S_ISDIR | |
bf3ccd1a RM |
194 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) |
195 | #endif | |
196 | #endif | |
197 | ||
28f540f4 RM |
198 | #ifndef STDC_HEADERS |
199 | #undef size_t | |
200 | #define size_t unsigned int | |
201 | #endif | |
202 | ||
203 | /* Some system header files erroneously define these. | |
204 | We want our own definitions from <fnmatch.h> to take precedence. */ | |
205 | #undef FNM_PATHNAME | |
206 | #undef FNM_NOESCAPE | |
207 | #undef FNM_PERIOD | |
208 | #include <fnmatch.h> | |
209 | ||
210 | /* Some system header files erroneously define these. | |
211 | We want our own definitions from <glob.h> to take precedence. */ | |
212 | #undef GLOB_ERR | |
213 | #undef GLOB_MARK | |
214 | #undef GLOB_NOSORT | |
215 | #undef GLOB_DOOFFS | |
216 | #undef GLOB_NOCHECK | |
217 | #undef GLOB_APPEND | |
218 | #undef GLOB_NOESCAPE | |
219 | #undef GLOB_PERIOD | |
220 | #include <glob.h> | |
221 | \f | |
28f540f4 RM |
222 | static int glob_pattern_p __P ((const char *pattern, int quote)); |
223 | static int glob_in_dir __P ((const char *pattern, const char *directory, | |
224 | int flags, | |
225 | int (*errfunc) __P ((const char *, int)), | |
226 | glob_t *pglob)); | |
227 | static int prefix_array __P ((const char *prefix, char **array, size_t n)); | |
228 | static int collated_compare __P ((const __ptr_t, const __ptr_t)); | |
229 | ||
230 | /* Do glob searching for PATTERN, placing results in PGLOB. | |
231 | The bits defined above may be set in FLAGS. | |
232 | If a directory cannot be opened or read and ERRFUNC is not nil, | |
233 | it is called with the pathname that caused the error, and the | |
234 | `errno' value from the failing call; if it returns non-zero | |
235 | `glob' returns GLOB_ABEND; if it returns zero, the error is ignored. | |
236 | If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. | |
237 | Otherwise, `glob' returns zero. */ | |
238 | int | |
239 | glob (pattern, flags, errfunc, pglob) | |
240 | const char *pattern; | |
241 | int flags; | |
242 | int (*errfunc) __P ((const char *, int)); | |
243 | glob_t *pglob; | |
244 | { | |
245 | const char *filename; | |
246 | char *dirname; | |
247 | size_t dirlen; | |
248 | int status; | |
249 | int oldcount; | |
250 | ||
251 | if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) | |
252 | { | |
253 | errno = EINVAL; | |
254 | return -1; | |
255 | } | |
256 | ||
787e4db9 RM |
257 | if (flags & GLOB_BRACE) |
258 | { | |
259 | const char *begin = strchr (pattern, '{'); | |
260 | if (begin != NULL) | |
261 | { | |
262 | const char *end = strchr (begin + 1, '}'); | |
263 | if (end != NULL && end != begin + 1) | |
264 | { | |
265 | size_t restlen = strlen (end + 1) + 1; | |
266 | const char *p, *comma; | |
267 | char *buf; | |
268 | size_t bufsz = 0; | |
269 | int firstc; | |
270 | if (!(flags & GLOB_APPEND)) | |
271 | { | |
272 | pglob->gl_pathc = 0; | |
273 | pglob->gl_pathv = NULL; | |
274 | } | |
275 | firstc = pglob->gl_pathc; | |
276 | for (p = begin + 1;; p = comma + 1) | |
277 | { | |
278 | int result; | |
279 | comma = strchr (p, ','); | |
280 | if (comma == NULL) | |
281 | comma = strchr (p, '\0'); | |
282 | if ((begin - pattern) + (comma - p) + 1 > bufsz) | |
283 | { | |
284 | if (bufsz * 2 < comma - p + 1) | |
285 | bufsz *= 2; | |
286 | else | |
287 | bufsz = comma - p + 1; | |
288 | buf = __alloca (bufsz); | |
289 | } | |
290 | memcpy (buf, pattern, begin - pattern); | |
291 | memcpy (buf + (begin - pattern), p, comma - p); | |
292 | memcpy (buf + (begin - pattern) + (comma - p), end, restlen); | |
02ac66c5 | 293 | result = glob (buf, ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) | |
787e4db9 RM |
294 | GLOB_APPEND), errfunc, pglob); |
295 | if (result && result != GLOB_NOMATCH) | |
296 | return result; | |
297 | if (*comma == '\0') | |
298 | break; | |
299 | } | |
300 | if (pglob->gl_pathc == firstc && | |
301 | !(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) | |
302 | return GLOB_NOMATCH; | |
303 | } | |
304 | } | |
305 | } | |
306 | ||
28f540f4 RM |
307 | /* Find the filename. */ |
308 | filename = strrchr (pattern, '/'); | |
309 | if (filename == NULL) | |
310 | { | |
311 | filename = pattern; | |
312 | dirname = (char *) "."; | |
313 | dirlen = 0; | |
314 | } | |
315 | else if (filename == pattern) | |
316 | { | |
317 | /* "/pattern". */ | |
318 | dirname = (char *) "/"; | |
319 | dirlen = 1; | |
320 | ++filename; | |
321 | } | |
322 | else | |
323 | { | |
324 | dirlen = filename - pattern; | |
325 | dirname = (char *) __alloca (dirlen + 1); | |
326 | memcpy (dirname, pattern, dirlen); | |
327 | dirname[dirlen] = '\0'; | |
328 | ++filename; | |
329 | } | |
330 | ||
331 | if (filename[0] == '\0' && dirlen > 1) | |
332 | /* "pattern/". Expand "pattern", appending slashes. */ | |
333 | { | |
334 | int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); | |
335 | if (val == 0) | |
336 | pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK); | |
337 | return val; | |
338 | } | |
339 | ||
340 | if (!(flags & GLOB_APPEND)) | |
341 | { | |
342 | pglob->gl_pathc = 0; | |
343 | pglob->gl_pathv = NULL; | |
344 | } | |
345 | ||
346 | oldcount = pglob->gl_pathc; | |
347 | ||
787e4db9 RM |
348 | if ((flags & GLOB_TILDE) && dirname[0] == '~') |
349 | { | |
350 | if (dirname[1] == '\0') | |
351 | { | |
352 | /* Look up home directory. */ | |
353 | dirname = getenv ("HOME"); | |
354 | if (dirname == NULL || dirname[0] == '\0') | |
355 | { | |
356 | extern char *getlogin (); | |
357 | char *name = getlogin (); | |
358 | if (name != NULL) | |
359 | { | |
360 | struct passwd *p = getpwnam (name); | |
361 | if (p != NULL) | |
362 | dirname = p->pw_dir; | |
363 | } | |
364 | } | |
365 | if (dirname == NULL || dirname[0] == '\0') | |
366 | dirname = (char *) "~"; /* No luck. */ | |
367 | } | |
368 | else | |
369 | { | |
370 | /* Look up specific user's home directory. */ | |
371 | struct passwd *p = getpwnam (dirname + 1); | |
372 | if (p != NULL) | |
373 | dirname = p->pw_dir; | |
374 | } | |
375 | } | |
376 | ||
28f540f4 RM |
377 | if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) |
378 | { | |
379 | /* The directory name contains metacharacters, so we | |
380 | have to glob for the directory, and then glob for | |
381 | the pattern in each directory found. */ | |
382 | glob_t dirs; | |
383 | register int i; | |
384 | ||
385 | status = glob (dirname, | |
386 | ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) | | |
387 | GLOB_NOSORT), | |
388 | errfunc, &dirs); | |
389 | if (status != 0) | |
390 | return status; | |
391 | ||
392 | /* We have successfully globbed the preceding directory name. | |
393 | For each name we found, call glob_in_dir on it and FILENAME, | |
394 | appending the results to PGLOB. */ | |
395 | for (i = 0; i < dirs.gl_pathc; ++i) | |
396 | { | |
397 | int oldcount; | |
398 | ||
399 | #ifdef SHELL | |
400 | { | |
401 | /* Make globbing interruptible in the bash shell. */ | |
402 | extern int interrupt_state; | |
403 | ||
404 | if (interrupt_state) | |
405 | { | |
406 | globfree (&dirs); | |
407 | globfree (&files); | |
408 | return GLOB_ABEND; | |
409 | } | |
410 | } | |
411 | #endif /* SHELL. */ | |
412 | ||
413 | oldcount = pglob->gl_pathc; | |
414 | status = glob_in_dir (filename, dirs.gl_pathv[i], | |
415 | (flags | GLOB_APPEND) & ~GLOB_NOCHECK, | |
416 | errfunc, pglob); | |
417 | if (status == GLOB_NOMATCH) | |
418 | /* No matches in this directory. Try the next. */ | |
419 | continue; | |
420 | ||
421 | if (status != 0) | |
422 | { | |
423 | globfree (&dirs); | |
424 | globfree (pglob); | |
425 | return status; | |
426 | } | |
427 | ||
428 | /* Stick the directory on the front of each name. */ | |
429 | if (prefix_array (dirs.gl_pathv[i], | |
430 | &pglob->gl_pathv[oldcount], | |
431 | pglob->gl_pathc - oldcount)) | |
432 | { | |
433 | globfree (&dirs); | |
434 | globfree (pglob); | |
435 | return GLOB_NOSPACE; | |
436 | } | |
437 | } | |
438 | ||
439 | flags |= GLOB_MAGCHAR; | |
440 | ||
441 | if (pglob->gl_pathc == oldcount) | |
442 | /* No matches. */ | |
443 | if (flags & GLOB_NOCHECK) | |
444 | { | |
445 | size_t len = strlen (pattern) + 1; | |
446 | char *patcopy = (char *) malloc (len); | |
447 | if (patcopy == NULL) | |
448 | return GLOB_NOSPACE; | |
449 | memcpy (patcopy, pattern, len); | |
450 | ||
451 | pglob->gl_pathv | |
452 | = (char **) realloc (pglob->gl_pathv, | |
453 | (pglob->gl_pathc + | |
454 | ((flags & GLOB_DOOFFS) ? | |
455 | pglob->gl_offs : 0) + | |
456 | 1 + 1) * | |
457 | sizeof (char *)); | |
458 | if (pglob->gl_pathv == NULL) | |
459 | { | |
460 | free (patcopy); | |
461 | return GLOB_NOSPACE; | |
462 | } | |
463 | ||
464 | if (flags & GLOB_DOOFFS) | |
465 | while (pglob->gl_pathc < pglob->gl_offs) | |
466 | pglob->gl_pathv[pglob->gl_pathc++] = NULL; | |
467 | ||
468 | pglob->gl_pathv[pglob->gl_pathc++] = patcopy; | |
469 | pglob->gl_pathv[pglob->gl_pathc] = NULL; | |
470 | pglob->gl_flags = flags; | |
471 | } | |
472 | else | |
473 | return GLOB_NOMATCH; | |
474 | } | |
475 | else | |
476 | { | |
477 | status = glob_in_dir (filename, dirname, flags, errfunc, pglob); | |
478 | if (status != 0) | |
479 | return status; | |
480 | ||
481 | if (dirlen > 0) | |
482 | { | |
483 | /* Stick the directory on the front of each name. */ | |
484 | if (prefix_array (dirname, | |
485 | &pglob->gl_pathv[oldcount], | |
486 | pglob->gl_pathc - oldcount)) | |
487 | { | |
488 | globfree (pglob); | |
489 | return GLOB_NOSPACE; | |
490 | } | |
491 | } | |
492 | } | |
493 | ||
bf3ccd1a RM |
494 | if (flags & GLOB_MARK) |
495 | { | |
c043db7a | 496 | /* Append slashes to directory names. */ |
bf3ccd1a RM |
497 | int i; |
498 | struct stat st; | |
499 | for (i = oldcount; i < pglob->gl_pathc; ++i) | |
787e4db9 | 500 | if (((flags & GLOB_ALTDIRFUNC) ? |
3be01400 RM |
501 | (*pglob->gl_stat) (pglob->gl_pathv[i], &st) : |
502 | __stat (pglob->gl_pathv[i], &st)) == 0 && | |
bf3ccd1a | 503 | S_ISDIR (st.st_mode)) |
a993273c RM |
504 | { |
505 | size_t len = strlen (pglob->gl_pathv[i]) + 2; | |
506 | char *new = realloc (pglob->gl_pathv[i], len); | |
507 | if (new == NULL) | |
508 | { | |
509 | globfree (pglob); | |
510 | return GLOB_NOSPACE; | |
511 | } | |
512 | strcpy (&new[len - 2], "/"); | |
513 | pglob->gl_pathv[i] = new; | |
514 | } | |
bf3ccd1a RM |
515 | } |
516 | ||
28f540f4 RM |
517 | if (!(flags & GLOB_NOSORT)) |
518 | /* Sort the vector. */ | |
bf3ccd1a | 519 | qsort ((__ptr_t) &pglob->gl_pathv[oldcount], |
28f540f4 RM |
520 | pglob->gl_pathc - oldcount, |
521 | sizeof (char *), collated_compare); | |
522 | ||
523 | return 0; | |
524 | } | |
525 | ||
526 | ||
527 | /* Free storage allocated in PGLOB by a previous `glob' call. */ | |
528 | void | |
529 | globfree (pglob) | |
530 | register glob_t *pglob; | |
531 | { | |
532 | if (pglob->gl_pathv != NULL) | |
533 | { | |
534 | register int i; | |
535 | for (i = 0; i < pglob->gl_pathc; ++i) | |
536 | if (pglob->gl_pathv[i] != NULL) | |
537 | free ((__ptr_t) pglob->gl_pathv[i]); | |
538 | free ((__ptr_t) pglob->gl_pathv); | |
539 | } | |
540 | } | |
541 | ||
542 | ||
543 | /* Do a collated comparison of A and B. */ | |
544 | static int | |
545 | collated_compare (a, b) | |
546 | const __ptr_t a; | |
547 | const __ptr_t b; | |
548 | { | |
549 | const char *const s1 = *(const char *const * const) a; | |
550 | const char *const s2 = *(const char *const * const) b; | |
551 | ||
552 | if (s1 == s2) | |
553 | return 0; | |
554 | if (s1 == NULL) | |
555 | return 1; | |
556 | if (s2 == NULL) | |
557 | return -1; | |
558 | return strcoll (s1, s2); | |
559 | } | |
560 | ||
561 | ||
562 | /* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's | |
563 | elements in place. Return nonzero if out of memory, zero if successful. | |
564 | A slash is inserted between DIRNAME and each elt of ARRAY, | |
565 | unless DIRNAME is just "/". Each old element of ARRAY is freed. */ | |
566 | static int | |
567 | prefix_array (dirname, array, n) | |
568 | const char *dirname; | |
569 | char **array; | |
570 | size_t n; | |
571 | { | |
572 | register size_t i; | |
573 | size_t dirlen = strlen (dirname); | |
574 | ||
575 | if (dirlen == 1 && dirname[0] == '/') | |
576 | /* DIRNAME is just "/", so normal prepending would get us "//foo". | |
577 | We want "/foo" instead, so don't prepend any chars from DIRNAME. */ | |
578 | dirlen = 0; | |
579 | ||
580 | for (i = 0; i < n; ++i) | |
581 | { | |
582 | size_t eltlen = strlen (array[i]) + 1; | |
583 | char *new = (char *) malloc (dirlen + 1 + eltlen); | |
584 | if (new == NULL) | |
585 | { | |
586 | while (i > 0) | |
587 | free ((__ptr_t) array[--i]); | |
588 | return 1; | |
589 | } | |
590 | ||
591 | memcpy (new, dirname, dirlen); | |
592 | new[dirlen] = '/'; | |
593 | memcpy (&new[dirlen + 1], array[i], eltlen); | |
594 | free ((__ptr_t) array[i]); | |
595 | array[i] = new; | |
596 | } | |
597 | ||
598 | return 0; | |
599 | } | |
600 | ||
601 | ||
602 | /* Return nonzero if PATTERN contains any metacharacters. | |
603 | Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ | |
604 | static int | |
605 | glob_pattern_p (pattern, quote) | |
606 | const char *pattern; | |
607 | int quote; | |
608 | { | |
609 | register const char *p; | |
610 | int open = 0; | |
611 | ||
612 | for (p = pattern; *p != '\0'; ++p) | |
613 | switch (*p) | |
614 | { | |
615 | case '?': | |
616 | case '*': | |
617 | return 1; | |
618 | ||
619 | case '\\': | |
620 | if (quote) | |
621 | ++p; | |
622 | break; | |
623 | ||
624 | case '[': | |
625 | open = 1; | |
626 | break; | |
627 | ||
628 | case ']': | |
629 | if (open) | |
630 | return 1; | |
631 | break; | |
632 | } | |
633 | ||
634 | return 0; | |
635 | } | |
636 | ||
637 | ||
638 | /* Like `glob', but PATTERN is a final pathname component, | |
639 | and matches are searched for in DIRECTORY. | |
640 | The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. | |
641 | The GLOB_APPEND flag is assumed to be set (always appends). */ | |
642 | static int | |
643 | glob_in_dir (pattern, directory, flags, errfunc, pglob) | |
644 | const char *pattern; | |
645 | const char *directory; | |
646 | int flags; | |
647 | int (*errfunc) __P ((const char *, int)); | |
648 | glob_t *pglob; | |
649 | { | |
650 | __ptr_t stream; | |
651 | ||
652 | struct globlink | |
653 | { | |
654 | struct globlink *next; | |
655 | char *name; | |
656 | }; | |
657 | struct globlink *names = NULL; | |
658 | size_t nfound = 0; | |
659 | ||
660 | if (!glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) | |
661 | { | |
662 | stream = NULL; | |
663 | flags |= GLOB_NOCHECK; | |
664 | } | |
665 | else | |
666 | { | |
667 | flags |= GLOB_MAGCHAR; | |
668 | ||
787e4db9 RM |
669 | stream = ((flags & GLOB_ALTDIRFUNC) ? |
670 | (*pglob->gl_opendir) (directory) : | |
faf92f2a | 671 | (__ptr_t) opendir (directory)); |
28f540f4 RM |
672 | if (stream == NULL) |
673 | { | |
674 | if ((errfunc != NULL && (*errfunc) (directory, errno)) || | |
675 | (flags & GLOB_ERR)) | |
676 | return GLOB_ABEND; | |
677 | } | |
678 | else | |
679 | while (1) | |
680 | { | |
681 | const char *name; | |
682 | size_t len; | |
787e4db9 RM |
683 | struct dirent *d = ((flags & GLOB_ALTDIRFUNC) ? |
684 | (*pglob->gl_readdir) (stream) : | |
faf92f2a | 685 | readdir ((DIR *) stream)); |
787e4db9 RM |
686 | if (d == NULL) |
687 | break; | |
688 | if (! REAL_DIR_ENTRY (d)) | |
689 | continue; | |
690 | name = d->d_name; | |
28f540f4 | 691 | #ifdef HAVE_D_NAMLEN |
787e4db9 | 692 | len = d->d_namlen; |
28f540f4 | 693 | #else |
787e4db9 | 694 | len = 0; |
28f540f4 | 695 | #endif |
787e4db9 | 696 | |
28f540f4 RM |
697 | if (fnmatch (pattern, name, |
698 | (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | | |
699 | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)) == 0) | |
700 | { | |
701 | struct globlink *new | |
702 | = (struct globlink *) __alloca (sizeof (struct globlink)); | |
703 | if (len == 0) | |
704 | len = strlen (name); | |
705 | new->name | |
a993273c | 706 | = (char *) malloc (len + 1); |
28f540f4 RM |
707 | if (new->name == NULL) |
708 | goto memory_error; | |
709 | memcpy ((__ptr_t) new->name, name, len); | |
28f540f4 RM |
710 | new->name[len] = '\0'; |
711 | new->next = names; | |
712 | names = new; | |
713 | ++nfound; | |
714 | } | |
715 | } | |
716 | } | |
717 | ||
787e4db9 RM |
718 | if (nfound == 0 && (flags & GLOB_NOMAGIC) && |
719 | ! glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) | |
720 | flags |= GLOB_NOCHECK; | |
721 | ||
28f540f4 RM |
722 | if (nfound == 0 && (flags & GLOB_NOCHECK)) |
723 | { | |
724 | size_t len = strlen (pattern); | |
725 | nfound = 1; | |
726 | names = (struct globlink *) __alloca (sizeof (struct globlink)); | |
727 | names->next = NULL; | |
a993273c | 728 | names->name = (char *) malloc (len + 1); |
28f540f4 RM |
729 | if (names->name == NULL) |
730 | goto memory_error; | |
731 | memcpy (names->name, pattern, len); | |
28f540f4 RM |
732 | names->name[len] = '\0'; |
733 | } | |
734 | ||
735 | pglob->gl_pathv | |
736 | = (char **) realloc (pglob->gl_pathv, | |
737 | (pglob->gl_pathc + | |
738 | ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + | |
739 | nfound + 1) * | |
740 | sizeof (char *)); | |
741 | if (pglob->gl_pathv == NULL) | |
742 | goto memory_error; | |
743 | ||
744 | if (flags & GLOB_DOOFFS) | |
745 | while (pglob->gl_pathc < pglob->gl_offs) | |
746 | pglob->gl_pathv[pglob->gl_pathc++] = NULL; | |
747 | ||
748 | for (; names != NULL; names = names->next) | |
749 | pglob->gl_pathv[pglob->gl_pathc++] = names->name; | |
750 | pglob->gl_pathv[pglob->gl_pathc] = NULL; | |
751 | ||
752 | pglob->gl_flags = flags; | |
753 | ||
754 | if (stream != NULL) | |
755 | { | |
756 | int save = errno; | |
787e4db9 RM |
757 | if (flags & GLOB_ALTDIRFUNC) |
758 | (*pglob->gl_closedir) (stream); | |
28f540f4 | 759 | else |
faf92f2a | 760 | closedir ((DIR *) stream); |
28f540f4 RM |
761 | errno = save; |
762 | } | |
763 | return nfound == 0 ? GLOB_NOMATCH : 0; | |
764 | ||
765 | memory_error: | |
766 | { | |
767 | int save = errno; | |
787e4db9 RM |
768 | if (flags & GLOB_ALTDIRFUNC) |
769 | (*pglob->gl_closedir) (stream); | |
28f540f4 | 770 | else |
faf92f2a | 771 | closedir ((DIR *) stream); |
28f540f4 RM |
772 | errno = save; |
773 | } | |
774 | while (names != NULL) | |
775 | { | |
776 | if (names->name != NULL) | |
777 | free ((__ptr_t) names->name); | |
778 | names = names->next; | |
779 | } | |
780 | return GLOB_NOSPACE; | |
781 | } | |
782 | ||
787e4db9 RM |
783 | #endif /* Not ELIDE_CODE. */ |
784 |