]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/glob/glob.c
Imported from ../bash-2.01.1.tar.gz.
[thirdparty/bash.git] / lib / glob / glob.c
CommitLineData
726f6388
JA
1/* File-name wildcard pattern matching for GNU.
2 Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 1, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
ccc6cda3 17
726f6388
JA
18/* To whomever it may concern: I have never seen the code which most
19 Unix programs use to perform this function. I wrote this from scratch
20 based on specifications for the pattern matching. --RMS. */
21
ccc6cda3
JA
22#include <config.h>
23
24#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
25 #pragma alloca
26#endif /* _AIX && RISC6000 && !__GNUC__ */
27
28#if defined (HAVE_UNISTD_H)
29# include <unistd.h>
30#endif
31
32#if defined (HAVE_STDLIB_H)
33# include <stdlib.h>
34#else
35# if defined (SHELL)
726f6388 36# include "ansi_stdlib.h"
ccc6cda3 37# endif /* SHELL */
726f6388
JA
38#endif
39
40#include <sys/types.h>
41
726f6388
JA
42#if defined (HAVE_DIRENT_H)
43# include <dirent.h>
726f6388
JA
44# define D_NAMLEN(d) strlen ((d)->d_name)
45#else /* !HAVE_DIRENT_H */
46# define D_NAMLEN(d) ((d)->d_namlen)
ccc6cda3
JA
47# if defined (HAVE_SYS_NDIR_H)
48# include <sys/ndir.h>
49# endif
50# if defined (HAVE_SYS_DIR_H)
726f6388 51# include <sys/dir.h>
ccc6cda3
JA
52# endif /* HAVE_SYS_DIR_H */
53# if defined (HAVE_NDIR_H)
54# include <ndir.h>
55# endif
56# if !defined (dirent)
57# define dirent direct
58# endif
726f6388
JA
59#endif /* !HAVE_DIRENT_H */
60
61#if defined (_POSIX_SOURCE)
62/* Posix does not require that the d_ino field be present, and some
63 systems do not provide it. */
64# define REAL_DIR_ENTRY(dp) 1
65#else
66# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
67#endif /* _POSIX_SOURCE */
68
726f6388
JA
69#if defined (HAVE_STRING_H)
70# include <string.h>
71#else /* !HAVE_STRING_H */
72# include <strings.h>
73#endif /* !HAVE_STRING_H */
74
ccc6cda3
JA
75#if !defined (HAVE_BCOPY)
76# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
77#endif /* !HAVE_BCOPY */
726f6388
JA
78
79/* If the opendir () on your system lets you open non-directory files,
ccc6cda3 80 then we consider that not robust. */
726f6388
JA
81#if defined (OPENDIR_NOT_ROBUST)
82# if defined (SHELL)
83# include "posixstat.h"
84# else /* !SHELL */
85# include <sys/stat.h>
86# endif /* !SHELL */
87#endif /* OPENDIR_NOT_ROBUST */
88
ccc6cda3
JA
89#include "memalloc.h"
90#include "fnmatch.h"
91
92#if !defined (HAVE_STDLIB_H) && !defined (SHELL)
726f6388
JA
93extern char *malloc (), *realloc ();
94extern void free ();
95#endif /* !HAVE_STDLIB_H */
96
97#if !defined (NULL)
98# if defined (__STDC__)
99# define NULL ((void *) 0)
100# else
101# define NULL 0x0
102# endif /* __STDC__ */
103#endif /* !NULL */
104
105#if defined (SHELL)
d166f048
JA
106extern void throw_to_top_level ();
107
726f6388
JA
108extern int interrupt_state;
109#endif /* SHELL */
110
111/* Global variable which controls whether or not * matches .*.
112 Non-zero means don't match .*. */
113int noglob_dot_filenames = 1;
114
115/* Global variable to return to signify an error in globbing. */
116char *glob_error_return;
117
726f6388
JA
118/* Return nonzero if PATTERN has any special globbing chars in it. */
119int
120glob_pattern_p (pattern)
121 char *pattern;
122{
123 register char *p = pattern;
124 register char c;
125 int open = 0;
126
127 while ((c = *p++) != '\0')
128 switch (c)
129 {
130 case '?':
131 case '*':
132 return (1);
133
134 case '[': /* Only accept an open brace if there is a close */
135 open++; /* brace to match it. Bracket expressions must be */
136 continue; /* complete, according to Posix.2 */
137 case ']':
138 if (open)
139 return (1);
140 continue;
141
142 case '\\':
143 if (*p++ == '\0')
144 return (0);
145 }
146
147 return (0);
148}
149
150/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
151static void
152dequote_pathname (pathname)
153 char *pathname;
154{
155 register int i, j;
156
157 for (i = j = 0; pathname && pathname[i]; )
158 {
159 if (pathname[i] == '\\')
160 i++;
161
162 pathname[j++] = pathname[i++];
163
164 if (!pathname[i - 1])
165 break;
166 }
167 pathname[j] = '\0';
168}
169
170\f
171/* Return a vector of names of files in directory DIR
172 whose names match glob pattern PAT.
173 The names are not in any particular order.
174 Wildcards at the beginning of PAT do not match an initial period.
175
176 The vector is terminated by an element that is a null pointer.
177
178 To free the space allocated, first free the vector's elements,
179 then free the vector.
180
181 Return 0 if cannot get enough memory to hold the pointer
182 and the names.
183
184 Return -1 if cannot access directory DIR.
185 Look in errno for more information. */
186
187char **
188glob_vector (pat, dir)
189 char *pat;
190 char *dir;
191{
192 struct globval
193 {
194 struct globval *next;
195 char *name;
196 };
197
198 DIR *d;
ccc6cda3 199 register struct dirent *dp;
726f6388
JA
200 struct globval *lastlink;
201 register struct globval *nextlink;
202 register char *nextname;
203 unsigned int count;
204 int lose, skip;
205 register char **name_vector;
206 register unsigned int i;
207#if defined (OPENDIR_NOT_ROBUST)
208 struct stat finfo;
209
210 if (stat (dir, &finfo) < 0)
211 return ((char **) &glob_error_return);
212
213 if (!S_ISDIR (finfo.st_mode))
214 return ((char **) &glob_error_return);
215#endif /* OPENDIR_NOT_ROBUST */
216
217 d = opendir (dir);
218 if (d == NULL)
219 return ((char **) &glob_error_return);
220
221 lastlink = 0;
222 count = 0;
223 lose = 0;
224 skip = 0;
225
226 /* If PAT is empty, skip the loop, but return one (empty) filename. */
227 if (!pat || !*pat)
228 {
229 nextlink = (struct globval *)alloca (sizeof (struct globval));
230 nextlink->next = lastlink;
231 nextname = (char *) malloc (1);
232 if (!nextname)
233 lose = 1;
234 else
235 {
236 lastlink = nextlink;
237 nextlink->name = nextname;
238 nextname[0] = '\0';
239 count++;
240 }
241 skip = 1;
242 }
243
244 /* Scan the directory, finding all names that match.
245 For each name that matches, allocate a struct globval
246 on the stack and store the name in it.
247 Chain those structs together; lastlink is the front of the chain. */
248 while (!skip)
249 {
250 int flags; /* Flags passed to fnmatch (). */
251#if defined (SHELL)
252 /* Make globbing interruptible in the bash shell. */
253 if (interrupt_state)
254 {
255 closedir (d);
256 lose = 1;
257 goto lost;
258 }
259#endif /* SHELL */
260
261 dp = readdir (d);
262 if (dp == NULL)
263 break;
264
265 /* If this directory entry is not to be used, try again. */
266 if (!REAL_DIR_ENTRY (dp))
267 continue;
268
269 /* If a dot must be explicity matched, check to see if they do. */
d166f048
JA
270 if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' &&
271 (pat[0] != '\\' || pat[1] != '.'))
726f6388
JA
272 continue;
273
274 flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
275
276 if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH)
277 {
278 nextlink = (struct globval *) alloca (sizeof (struct globval));
279 nextlink->next = lastlink;
280 nextname = (char *) malloc (D_NAMLEN (dp) + 1);
281 if (nextname == NULL)
282 {
283 lose = 1;
284 break;
285 }
286 lastlink = nextlink;
287 nextlink->name = nextname;
288 bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
289 ++count;
290 }
291 }
292 (void) closedir (d);
293
294 if (!lose)
295 {
296 name_vector = (char **) malloc ((count + 1) * sizeof (char *));
297 lose |= name_vector == NULL;
298 }
299
300 /* Have we run out of memory? */
d166f048 301#if defined (SHELL)
726f6388 302 lost:
d166f048 303#endif
726f6388
JA
304 if (lose)
305 {
306 /* Here free the strings we have got. */
307 while (lastlink)
308 {
309 free (lastlink->name);
310 lastlink = lastlink->next;
311 }
312#if defined (SHELL)
313 if (interrupt_state)
314 throw_to_top_level ();
315#endif /* SHELL */
316 return (NULL);
317 }
318
319 /* Copy the name pointers from the linked list into the vector. */
320 for (i = 0; i < count; ++i)
321 {
322 name_vector[i] = lastlink->name;
323 lastlink = lastlink->next;
324 }
325
326 name_vector[count] = NULL;
327 return (name_vector);
328}
329\f
330/* Return a new array which is the concatenation of each string in ARRAY
331 to DIR. This function expects you to pass in an allocated ARRAY, and
332 it takes care of free()ing that array. Thus, you might think of this
333 function as side-effecting ARRAY. */
334static char **
335glob_dir_to_array (dir, array)
336 char *dir, **array;
337{
338 register unsigned int i, l;
339 int add_slash;
340 char **result;
341
342 l = strlen (dir);
343 if (l == 0)
344 return (array);
345
346 add_slash = dir[l - 1] != '/';
347
348 i = 0;
349 while (array[i] != NULL)
350 ++i;
351
352 result = (char **) malloc ((i + 1) * sizeof (char *));
353 if (result == NULL)
354 return (NULL);
355
356 for (i = 0; array[i] != NULL; i++)
357 {
358 result[i] = (char *) malloc (l + (add_slash ? 1 : 0)
359 + strlen (array[i]) + 1);
360 if (result[i] == NULL)
361 return (NULL);
ccc6cda3
JA
362#if 1
363 strcpy (result[i], dir);
364 if (add_slash)
365 result[i][l] = '/';
366 strcpy (result[i] + l + add_slash, array[i]);
367#else
368 (void)sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]);
369#endif
726f6388
JA
370 }
371 result[i] = NULL;
372
373 /* Free the input array. */
374 for (i = 0; array[i] != NULL; i++)
375 free (array[i]);
376 free ((char *) array);
377
378 return (result);
379}
380\f
381/* Do globbing on PATHNAME. Return an array of pathnames that match,
382 marking the end of the array with a null-pointer as an element.
383 If no pathnames match, then the array is empty (first element is null).
384 If there isn't enough memory, then return NULL.
385 If a file system error occurs, return -1; `errno' has the error code. */
386char **
387glob_filename (pathname)
388 char *pathname;
389{
390 char **result;
391 unsigned int result_size;
392 char *directory_name, *filename;
393 unsigned int directory_len;
394
395 result = (char **) malloc (sizeof (char *));
396 result_size = 1;
397 if (result == NULL)
398 return (NULL);
399
400 result[0] = NULL;
401
402 /* Find the filename. */
403 filename = strrchr (pathname, '/');
404 if (filename == NULL)
405 {
406 filename = pathname;
407 directory_name = "";
408 directory_len = 0;
409 }
410 else
411 {
412 directory_len = (filename - pathname) + 1;
413 directory_name = (char *) alloca (directory_len + 1);
414
415 bcopy (pathname, directory_name, directory_len);
416 directory_name[directory_len] = '\0';
417 ++filename;
418 }
419
420 /* If directory_name contains globbing characters, then we
421 have to expand the previous levels. Just recurse. */
422 if (glob_pattern_p (directory_name))
423 {
424 char **directories;
425 register unsigned int i;
426
427 if (directory_name[directory_len - 1] == '/')
428 directory_name[directory_len - 1] = '\0';
429
430 directories = glob_filename (directory_name);
431
432 if (directories == NULL)
433 goto memory_error;
434 else if (directories == (char **)&glob_error_return)
435 {
ccc6cda3 436 free ((char *) result);
726f6388
JA
437 return ((char **) &glob_error_return);
438 }
439 else if (*directories == NULL)
440 {
441 free ((char *) directories);
442 free ((char *) result);
443 return ((char **) &glob_error_return);
444 }
445
446 /* We have successfully globbed the preceding directory name.
447 For each name in DIRECTORIES, call glob_vector on it and
448 FILENAME. Concatenate the results together. */
449 for (i = 0; directories[i] != NULL; ++i)
450 {
451 char **temp_results;
452
453 /* Scan directory even on a NULL pathname. That way, `*h/'
454 returns only directories ending in `h', instead of all
455 files ending in `h' with a `/' appended. */
456 temp_results = glob_vector (filename, directories[i]);
457
458 /* Handle error cases. */
459 if (temp_results == NULL)
460 goto memory_error;
461 else if (temp_results == (char **)&glob_error_return)
462 /* This filename is probably not a directory. Ignore it. */
463 ;
464 else
465 {
466 char **array;
467 register unsigned int l;
468
469 array = glob_dir_to_array (directories[i], temp_results);
470 l = 0;
471 while (array[l] != NULL)
472 ++l;
473
474 result =
475 (char **)realloc (result, (result_size + l) * sizeof (char *));
476
477 if (result == NULL)
478 goto memory_error;
479
480 for (l = 0; array[l] != NULL; ++l)
481 result[result_size++ - 1] = array[l];
482
483 result[result_size - 1] = NULL;
484
485 /* Note that the elements of ARRAY are not freed. */
486 free ((char *) array);
487 }
488 }
489 /* Free the directories. */
490 for (i = 0; directories[i]; i++)
491 free (directories[i]);
492
493 free ((char *) directories);
494
495 return (result);
496 }
497
498 /* If there is only a directory name, return it. */
499 if (*filename == '\0')
500 {
501 result = (char **) realloc ((char *) result, 2 * sizeof (char *));
502 if (result == NULL)
503 return (NULL);
504 result[0] = (char *) malloc (directory_len + 1);
505 if (result[0] == NULL)
506 goto memory_error;
507 bcopy (directory_name, result[0], directory_len + 1);
508 result[1] = NULL;
509 return (result);
510 }
511 else
512 {
513 char **temp_results;
514
515 /* There are no unquoted globbing characters in DIRECTORY_NAME.
516 Dequote it before we try to open the directory since there may
517 be quoted globbing characters which should be treated verbatim. */
518 if (directory_len > 0)
519 dequote_pathname (directory_name);
520
521 /* We allocated a small array called RESULT, which we won't be using.
522 Free that memory now. */
523 free (result);
524
525 /* Just return what glob_vector () returns appended to the
526 directory name. */
527 temp_results =
528 glob_vector (filename, (directory_len == 0 ? "." : directory_name));
529
530 if (temp_results == NULL || temp_results == (char **)&glob_error_return)
531 return (temp_results);
532
533 return (glob_dir_to_array (directory_name, temp_results));
534 }
535
536 /* We get to memory_error if the program has run out of memory, or
537 if this is the shell, and we have been interrupted. */
538 memory_error:
539 if (result != NULL)
540 {
541 register unsigned int i;
542 for (i = 0; result[i] != NULL; ++i)
543 free (result[i]);
544 free ((char *) result);
545 }
546#if defined (SHELL)
547 if (interrupt_state)
548 throw_to_top_level ();
549#endif /* SHELL */
550 return (NULL);
551}
552\f
553#if defined (TEST)
554
555main (argc, argv)
556 int argc;
557 char **argv;
558{
559 unsigned int i;
560
561 for (i = 1; i < argc; ++i)
562 {
563 char **value = glob_filename (argv[i]);
564 if (value == NULL)
565 puts ("Out of memory.");
566 else if (value == &glob_error_return)
567 perror (argv[i]);
568 else
569 for (i = 0; value[i] != NULL; i++)
570 puts (value[i]);
571 }
572
573 exit (0);
574}
575#endif /* TEST. */