]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/glob/glob.c
Imported from ../bash-2.0.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)
106extern int interrupt_state;
107#endif /* SHELL */
108
109/* Global variable which controls whether or not * matches .*.
110 Non-zero means don't match .*. */
111int noglob_dot_filenames = 1;
112
113/* Global variable to return to signify an error in globbing. */
114char *glob_error_return;
115
726f6388
JA
116/* Return nonzero if PATTERN has any special globbing chars in it. */
117int
118glob_pattern_p (pattern)
119 char *pattern;
120{
121 register char *p = pattern;
122 register char c;
123 int open = 0;
124
125 while ((c = *p++) != '\0')
126 switch (c)
127 {
128 case '?':
129 case '*':
130 return (1);
131
132 case '[': /* Only accept an open brace if there is a close */
133 open++; /* brace to match it. Bracket expressions must be */
134 continue; /* complete, according to Posix.2 */
135 case ']':
136 if (open)
137 return (1);
138 continue;
139
140 case '\\':
141 if (*p++ == '\0')
142 return (0);
143 }
144
145 return (0);
146}
147
148/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
149static void
150dequote_pathname (pathname)
151 char *pathname;
152{
153 register int i, j;
154
155 for (i = j = 0; pathname && pathname[i]; )
156 {
157 if (pathname[i] == '\\')
158 i++;
159
160 pathname[j++] = pathname[i++];
161
162 if (!pathname[i - 1])
163 break;
164 }
165 pathname[j] = '\0';
166}
167
168\f
169/* Return a vector of names of files in directory DIR
170 whose names match glob pattern PAT.
171 The names are not in any particular order.
172 Wildcards at the beginning of PAT do not match an initial period.
173
174 The vector is terminated by an element that is a null pointer.
175
176 To free the space allocated, first free the vector's elements,
177 then free the vector.
178
179 Return 0 if cannot get enough memory to hold the pointer
180 and the names.
181
182 Return -1 if cannot access directory DIR.
183 Look in errno for more information. */
184
185char **
186glob_vector (pat, dir)
187 char *pat;
188 char *dir;
189{
190 struct globval
191 {
192 struct globval *next;
193 char *name;
194 };
195
196 DIR *d;
ccc6cda3 197 register struct dirent *dp;
726f6388
JA
198 struct globval *lastlink;
199 register struct globval *nextlink;
200 register char *nextname;
201 unsigned int count;
202 int lose, skip;
203 register char **name_vector;
204 register unsigned int i;
205#if defined (OPENDIR_NOT_ROBUST)
206 struct stat finfo;
207
208 if (stat (dir, &finfo) < 0)
209 return ((char **) &glob_error_return);
210
211 if (!S_ISDIR (finfo.st_mode))
212 return ((char **) &glob_error_return);
213#endif /* OPENDIR_NOT_ROBUST */
214
215 d = opendir (dir);
216 if (d == NULL)
217 return ((char **) &glob_error_return);
218
219 lastlink = 0;
220 count = 0;
221 lose = 0;
222 skip = 0;
223
224 /* If PAT is empty, skip the loop, but return one (empty) filename. */
225 if (!pat || !*pat)
226 {
227 nextlink = (struct globval *)alloca (sizeof (struct globval));
228 nextlink->next = lastlink;
229 nextname = (char *) malloc (1);
230 if (!nextname)
231 lose = 1;
232 else
233 {
234 lastlink = nextlink;
235 nextlink->name = nextname;
236 nextname[0] = '\0';
237 count++;
238 }
239 skip = 1;
240 }
241
242 /* Scan the directory, finding all names that match.
243 For each name that matches, allocate a struct globval
244 on the stack and store the name in it.
245 Chain those structs together; lastlink is the front of the chain. */
246 while (!skip)
247 {
248 int flags; /* Flags passed to fnmatch (). */
249#if defined (SHELL)
250 /* Make globbing interruptible in the bash shell. */
251 if (interrupt_state)
252 {
253 closedir (d);
254 lose = 1;
255 goto lost;
256 }
257#endif /* SHELL */
258
259 dp = readdir (d);
260 if (dp == NULL)
261 break;
262
263 /* If this directory entry is not to be used, try again. */
264 if (!REAL_DIR_ENTRY (dp))
265 continue;
266
267 /* If a dot must be explicity matched, check to see if they do. */
268 if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.')
269 continue;
270
271 flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
272
273 if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH)
274 {
275 nextlink = (struct globval *) alloca (sizeof (struct globval));
276 nextlink->next = lastlink;
277 nextname = (char *) malloc (D_NAMLEN (dp) + 1);
278 if (nextname == NULL)
279 {
280 lose = 1;
281 break;
282 }
283 lastlink = nextlink;
284 nextlink->name = nextname;
285 bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
286 ++count;
287 }
288 }
289 (void) closedir (d);
290
291 if (!lose)
292 {
293 name_vector = (char **) malloc ((count + 1) * sizeof (char *));
294 lose |= name_vector == NULL;
295 }
296
297 /* Have we run out of memory? */
298 lost:
299 if (lose)
300 {
301 /* Here free the strings we have got. */
302 while (lastlink)
303 {
304 free (lastlink->name);
305 lastlink = lastlink->next;
306 }
307#if defined (SHELL)
308 if (interrupt_state)
309 throw_to_top_level ();
310#endif /* SHELL */
311 return (NULL);
312 }
313
314 /* Copy the name pointers from the linked list into the vector. */
315 for (i = 0; i < count; ++i)
316 {
317 name_vector[i] = lastlink->name;
318 lastlink = lastlink->next;
319 }
320
321 name_vector[count] = NULL;
322 return (name_vector);
323}
324\f
325/* Return a new array which is the concatenation of each string in ARRAY
326 to DIR. This function expects you to pass in an allocated ARRAY, and
327 it takes care of free()ing that array. Thus, you might think of this
328 function as side-effecting ARRAY. */
329static char **
330glob_dir_to_array (dir, array)
331 char *dir, **array;
332{
333 register unsigned int i, l;
334 int add_slash;
335 char **result;
336
337 l = strlen (dir);
338 if (l == 0)
339 return (array);
340
341 add_slash = dir[l - 1] != '/';
342
343 i = 0;
344 while (array[i] != NULL)
345 ++i;
346
347 result = (char **) malloc ((i + 1) * sizeof (char *));
348 if (result == NULL)
349 return (NULL);
350
351 for (i = 0; array[i] != NULL; i++)
352 {
353 result[i] = (char *) malloc (l + (add_slash ? 1 : 0)
354 + strlen (array[i]) + 1);
355 if (result[i] == NULL)
356 return (NULL);
ccc6cda3
JA
357#if 1
358 strcpy (result[i], dir);
359 if (add_slash)
360 result[i][l] = '/';
361 strcpy (result[i] + l + add_slash, array[i]);
362#else
363 (void)sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]);
364#endif
726f6388
JA
365 }
366 result[i] = NULL;
367
368 /* Free the input array. */
369 for (i = 0; array[i] != NULL; i++)
370 free (array[i]);
371 free ((char *) array);
372
373 return (result);
374}
375\f
376/* Do globbing on PATHNAME. Return an array of pathnames that match,
377 marking the end of the array with a null-pointer as an element.
378 If no pathnames match, then the array is empty (first element is null).
379 If there isn't enough memory, then return NULL.
380 If a file system error occurs, return -1; `errno' has the error code. */
381char **
382glob_filename (pathname)
383 char *pathname;
384{
385 char **result;
386 unsigned int result_size;
387 char *directory_name, *filename;
388 unsigned int directory_len;
389
390 result = (char **) malloc (sizeof (char *));
391 result_size = 1;
392 if (result == NULL)
393 return (NULL);
394
395 result[0] = NULL;
396
397 /* Find the filename. */
398 filename = strrchr (pathname, '/');
399 if (filename == NULL)
400 {
401 filename = pathname;
402 directory_name = "";
403 directory_len = 0;
404 }
405 else
406 {
407 directory_len = (filename - pathname) + 1;
408 directory_name = (char *) alloca (directory_len + 1);
409
410 bcopy (pathname, directory_name, directory_len);
411 directory_name[directory_len] = '\0';
412 ++filename;
413 }
414
415 /* If directory_name contains globbing characters, then we
416 have to expand the previous levels. Just recurse. */
417 if (glob_pattern_p (directory_name))
418 {
419 char **directories;
420 register unsigned int i;
421
422 if (directory_name[directory_len - 1] == '/')
423 directory_name[directory_len - 1] = '\0';
424
425 directories = glob_filename (directory_name);
426
427 if (directories == NULL)
428 goto memory_error;
429 else if (directories == (char **)&glob_error_return)
430 {
ccc6cda3 431 free ((char *) result);
726f6388
JA
432 return ((char **) &glob_error_return);
433 }
434 else if (*directories == NULL)
435 {
436 free ((char *) directories);
437 free ((char *) result);
438 return ((char **) &glob_error_return);
439 }
440
441 /* We have successfully globbed the preceding directory name.
442 For each name in DIRECTORIES, call glob_vector on it and
443 FILENAME. Concatenate the results together. */
444 for (i = 0; directories[i] != NULL; ++i)
445 {
446 char **temp_results;
447
448 /* Scan directory even on a NULL pathname. That way, `*h/'
449 returns only directories ending in `h', instead of all
450 files ending in `h' with a `/' appended. */
451 temp_results = glob_vector (filename, directories[i]);
452
453 /* Handle error cases. */
454 if (temp_results == NULL)
455 goto memory_error;
456 else if (temp_results == (char **)&glob_error_return)
457 /* This filename is probably not a directory. Ignore it. */
458 ;
459 else
460 {
461 char **array;
462 register unsigned int l;
463
464 array = glob_dir_to_array (directories[i], temp_results);
465 l = 0;
466 while (array[l] != NULL)
467 ++l;
468
469 result =
470 (char **)realloc (result, (result_size + l) * sizeof (char *));
471
472 if (result == NULL)
473 goto memory_error;
474
475 for (l = 0; array[l] != NULL; ++l)
476 result[result_size++ - 1] = array[l];
477
478 result[result_size - 1] = NULL;
479
480 /* Note that the elements of ARRAY are not freed. */
481 free ((char *) array);
482 }
483 }
484 /* Free the directories. */
485 for (i = 0; directories[i]; i++)
486 free (directories[i]);
487
488 free ((char *) directories);
489
490 return (result);
491 }
492
493 /* If there is only a directory name, return it. */
494 if (*filename == '\0')
495 {
496 result = (char **) realloc ((char *) result, 2 * sizeof (char *));
497 if (result == NULL)
498 return (NULL);
499 result[0] = (char *) malloc (directory_len + 1);
500 if (result[0] == NULL)
501 goto memory_error;
502 bcopy (directory_name, result[0], directory_len + 1);
503 result[1] = NULL;
504 return (result);
505 }
506 else
507 {
508 char **temp_results;
509
510 /* There are no unquoted globbing characters in DIRECTORY_NAME.
511 Dequote it before we try to open the directory since there may
512 be quoted globbing characters which should be treated verbatim. */
513 if (directory_len > 0)
514 dequote_pathname (directory_name);
515
516 /* We allocated a small array called RESULT, which we won't be using.
517 Free that memory now. */
518 free (result);
519
520 /* Just return what glob_vector () returns appended to the
521 directory name. */
522 temp_results =
523 glob_vector (filename, (directory_len == 0 ? "." : directory_name));
524
525 if (temp_results == NULL || temp_results == (char **)&glob_error_return)
526 return (temp_results);
527
528 return (glob_dir_to_array (directory_name, temp_results));
529 }
530
531 /* We get to memory_error if the program has run out of memory, or
532 if this is the shell, and we have been interrupted. */
533 memory_error:
534 if (result != NULL)
535 {
536 register unsigned int i;
537 for (i = 0; result[i] != NULL; ++i)
538 free (result[i]);
539 free ((char *) result);
540 }
541#if defined (SHELL)
542 if (interrupt_state)
543 throw_to_top_level ();
544#endif /* SHELL */
545 return (NULL);
546}
547\f
548#if defined (TEST)
549
550main (argc, argv)
551 int argc;
552 char **argv;
553{
554 unsigned int i;
555
556 for (i = 1; i < argc; ++i)
557 {
558 char **value = glob_filename (argv[i]);
559 if (value == NULL)
560 puts ("Out of memory.");
561 else if (value == &glob_error_return)
562 perror (argv[i]);
563 else
564 for (i = 0; value[i] != NULL; i++)
565 puts (value[i]);
566 }
567
568 exit (0);
569}
570#endif /* TEST. */