1#ifdef __APPLE__
2#include <glob.h>
3#include <stdlib.h>
4#include <string.h>
5
6char **
7glob_filename (const char *pathname)
8{
9	char **result = NULL;
10	glob_t g;
11	int i;
12
13	if (glob(pathname, 0, NULL, &g) == 0) {
14		result = malloc((g.gl_pathc + 1) * sizeof(char *));
15		for (i = 0; i < g.gl_pathc; i++) {
16			result[i] = strdup(g.gl_pathv[i]);
17		}
18		result[g.gl_pathc] = NULL;
19		globfree(&g);
20	}
21
22	return result;
23}
24#else
25/* File-name wildcard pattern matching for GNU.
26   Copyright (C) 1985, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
27
28   This program is free software; you can redistribute it and/or modify
29   it under the terms of the GNU General Public License as published by
30   the Free Software Foundation; either version 1, or (at your option)
31   any later version.
32
33   This program is distributed in the hope that it will be useful,
34   but WITHOUT ANY WARRANTY; without even the implied warranty of
35   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36   GNU General Public License for more details.
37
38   You should have received a copy of the GNU General Public License
39   along with this program; if not, write to the Free Software
40   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
41
42/* To whomever it may concern: I have never seen the code which most
43   Unix programs use to perform this function.  I wrote this from scratch
44   based on specifications for the pattern matching.  --RMS.  */
45
46#ifdef SHELL
47#include "config.h"
48#endif /* SHELL */
49
50#include <sys/types.h>
51
52#if defined (USGr3) && !defined (DIRENT)
53#define DIRENT
54#endif /* USGr3 */
55#if defined (Xenix) && !defined (SYSNDIR)
56#define SYSNDIR
57#endif /* Xenix */
58
59#if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
60#include <dirent.h>
61#define direct dirent
62#define D_NAMLEN(d) strlen((d)->d_name)
63#else /* not POSIX or DIRENT or __GNU_LIBRARY__ */
64#define D_NAMLEN(d) ((d)->d_namlen)
65#ifdef USG
66#if defined (SYSNDIR)
67#include <sys/ndir.h>
68#else /* SYSNDIR */
69#include "ndir.h"
70#endif /* not SYSNDIR */
71#else /* not USG */
72#include <sys/dir.h>
73#endif /* USG */
74#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
75
76#ifdef __QNX__
77#define REAL_DIR_ENTRY(dp) (dp->d_stat.st_ino != 0)
78#elif defined (_POSIX_SOURCE)
79/* Posix does not require that the d_ino field be present, and some
80   systems do not provide it. */
81#define REAL_DIR_ENTRY(dp) 1
82#else
83#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
84#endif /* _POSIX_SOURCE */
85
86#if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)
87#include <stdlib.h>
88#include <string.h>
89#define STDC_STRINGS
90#else /* STDC_HEADERS or __GNU_LIBRARY__ */
91
92#if defined (USG)
93#include <string.h>
94#ifndef POSIX
95#include <memory.h>
96#endif /* POSIX */
97#define STDC_STRINGS
98#else /* not USG */
99#ifdef NeXT
100#include <string.h>
101#else /* NeXT */
102#include <strings.h>
103#endif /* NeXT */
104/* Declaring bcopy causes errors on systems whose declarations are different.
105   If the declaration is omitted, everything works fine.  */
106#endif /* not USG */
107
108extern char *malloc ();
109extern char *realloc ();
110extern void free ();
111
112#ifndef NULL
113#define NULL 0
114#endif
115#endif	/* Not STDC_HEADERS or __GNU_LIBRARY__.  */
116
117#ifdef STDC_STRINGS
118#define bcopy(s, d, n) memcpy ((d), (s), (n))
119#define index strchr
120#define rindex strrchr
121#endif /* STDC_STRINGS */
122
123#ifndef	alloca
124#ifdef __GNUC__
125#define alloca __builtin_alloca
126#else /* Not GCC.  */
127#ifdef sparc
128#include <alloca.h>
129#else /* Not sparc.  */
130extern char *alloca ();
131#endif /* sparc.  */
132#endif /* GCC.  */
133#endif
134
135/* Nonzero if '*' and '?' do not match an initial '.' for glob_filename.  */
136int noglob_dot_filenames = 1;
137
138static int glob_match_after_star ();
139
140/* Return nonzero if PATTERN has any special globbing chars in it.  */
141
142int
143glob_pattern_p (pattern)
144     char *pattern;
145{
146  register char *p = pattern;
147  register char c;
148  int open = 0;
149
150  while ((c = *p++) != '\0')
151    switch (c)
152      {
153      case '?':
154      case '*':
155	return 1;
156
157      case '[':		/* Only accept an open brace if there is a close */
158	open++;		/* brace to match it.  Bracket expressions must be */
159	continue;	/* complete, according to Posix.2 */
160      case ']':
161	if (open)
162	  return 1;
163	continue;
164
165      case '\\':
166	if (*p++ == '\0')
167	  return 0;
168      }
169
170  return 0;
171}
172
173
174/* Match the pattern PATTERN against the string TEXT;
175   return 1 if it matches, 0 otherwise.
176
177   A match means the entire string TEXT is used up in matching.
178
179   In the pattern string, `*' matches any sequence of characters,
180   `?' matches any character, [SET] matches any character in the specified set,
181   [!SET] matches any character not in the specified set.
182
183   A set is composed of characters or ranges; a range looks like
184   character hyphen character (as in 0-9 or A-Z).
185   [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
186   Any other character in the pattern must be matched exactly.
187
188   To suppress the special syntactic significance of any of `[]*?!-\',
189   and match the character exactly, precede it with a `\'.
190
191   If DOT_SPECIAL is nonzero,
192   `*' and `?' do not match `.' at the beginning of TEXT.  */
193
194int
195glob_match (pattern, text, dot_special)
196     char *pattern, *text;
197     int dot_special;
198{
199  register char *p = pattern, *t = text;
200  register char c;
201
202  while ((c = *p++) != '\0')
203    switch (c)
204      {
205      case '?':
206	if (*t == '\0' || (dot_special && t == text && *t == '.'))
207	  return 0;
208	else
209	  ++t;
210	break;
211
212      case '\\':
213	if (*p++ != *t++)
214	  return 0;
215	break;
216
217      case '*':
218	if (dot_special && t == text && *t == '.')
219	  return 0;
220	return glob_match_after_star (p, t);
221
222      case '[':
223	{
224	  register char c1 = *t++;
225	  int invert;
226
227	  if (c1 == '\0')
228	    return 0;
229
230	  invert = (*p == '!');
231
232	  if (invert)
233	    p++;
234
235	  c = *p++;
236	  while (1)
237	    {
238	      register char cstart = c, cend = c;
239
240	      if (c == '\\')
241		{
242		  cstart = *p++;
243		  cend = cstart;
244		}
245
246	      if (cstart == '\0')
247		return 0;	/* Missing ']'. */
248
249	      c = *p++;
250
251	      if (c == '-')
252		{
253		  cend = *p++;
254		  if (cend == '\\')
255		    cend = *p++;
256		  if (cend == '\0')
257		    return 0;
258		  c = *p++;
259		}
260	      if (c1 >= cstart && c1 <= cend)
261		goto match;
262	      if (c == ']')
263		break;
264	    }
265	  if (!invert)
266	    return 0;
267	  break;
268
269	match:
270	  /* Skip the rest of the [...] construct that already matched.  */
271	  while (c != ']')
272	    {
273	      if (c == '\0')
274		return 0;
275	      c = *p++;
276	      if (c == '\0')
277		return 0;
278	      if (c == '\\')
279		p++;
280	    }
281	  if (invert)
282	    return 0;
283	  break;
284	}
285
286      default:
287	if (c != *t++)
288	  return 0;
289      }
290
291  return *t == '\0';
292}
293
294/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
295
296static int
297glob_match_after_star (pattern, text)
298     char *pattern, *text;
299{
300  register char *p = pattern, *t = text;
301  register char c, c1;
302
303  while ((c = *p++) == '?' || c == '*')
304    if (c == '?' && *t++ == '\0')
305      return 0;
306
307  if (c == '\0')
308    return 1;
309
310  if (c == '\\')
311    c1 = *p;
312  else
313    c1 = c;
314
315  --p;
316  while (1)
317    {
318      if ((c == '[' || *t == c1) && glob_match (p, t, 0))
319	return 1;
320      if (*t++ == '\0')
321	return 0;
322    }
323}
324
325/* Return a vector of names of files in directory DIR
326   whose names match glob pattern PAT.
327   The names are not in any particular order.
328   Wildcards at the beginning of PAT do not match an initial period
329   if noglob_dot_filenames is nonzero.
330
331   The vector is terminated by an element that is a null pointer.
332
333   To free the space allocated, first free the vector's elements,
334   then free the vector.
335
336   Return NULL if cannot get enough memory to hold the pointer
337   and the names.
338
339   Return -1 if cannot access directory DIR.
340   Look in errno for more information.  */
341
342char **
343glob_vector (pat, dir)
344     char *pat;
345     char *dir;
346{
347  struct globval
348  {
349    struct globval *next;
350    char *name;
351  };
352
353  DIR *d;
354  register struct direct *dp;
355  struct globval *lastlink;
356  register struct globval *nextlink;
357  register char *nextname;
358  unsigned int count;
359  int lose;
360  register char **name_vector = 0;
361  register unsigned int i;
362#ifdef ALLOCA_MISSING
363  struct globval *templink;
364#endif
365
366  d = opendir (dir);
367  if (d == NULL)
368    return (char **) -1;
369
370  lastlink = NULL;
371  count = 0;
372  lose = 0;
373
374  /* Scan the directory, finding all names that match.
375     For each name that matches, allocate a struct globval
376     on the stack and store the name in it.
377     Chain those structs together; lastlink is the front of the chain.  */
378  while (1)
379    {
380#if defined (SHELL)
381      /* Make globbing interruptible in the bash shell. */
382      extern int interrupt_state;
383
384      if (interrupt_state)
385	{
386	  closedir (d);
387	  lose = 1;
388	  goto lost;
389	}
390#endif /* SHELL */
391
392      dp = readdir (d);
393      if (dp == NULL)
394	break;
395      if (REAL_DIR_ENTRY (dp)
396	  && glob_match (pat, dp->d_name, noglob_dot_filenames))
397	{
398#ifdef ALLOCA_MISSING
399	  nextlink = (struct globval *) malloc (sizeof (struct globval));
400#else
401	  nextlink = (struct globval *) alloca (sizeof (struct globval));
402#endif
403	  nextlink->next = lastlink;
404	  i = D_NAMLEN (dp) + 1;
405	  nextname = (char *) malloc (i);
406	  if (nextname == NULL)
407	    {
408	      lose = 1;
409	      break;
410	    }
411	  lastlink = nextlink;
412	  nextlink->name = nextname;
413	  bcopy (dp->d_name, nextname, i);
414	  count++;
415	}
416    }
417  closedir (d);
418
419  if (!lose)
420    {
421      name_vector = (char **) malloc ((count + 1) * sizeof (char *));
422      lose |= name_vector == NULL;
423    }
424
425  /* Have we run out of memory?  */
426#ifdef	SHELL
427 lost:
428#endif
429  if (lose)
430    {
431      /* Here free the strings we have got.  */
432      while (lastlink)
433	{
434	  free (lastlink->name);
435#ifdef ALLOCA_MISSING
436	  templink = lastlink->next;
437	  free ((char *) lastlink);
438	  lastlink = templink;
439#else
440	  lastlink = lastlink->next;
441#endif
442	}
443      return NULL;
444    }
445
446  /* Copy the name pointers from the linked list into the vector.  */
447  for (i = 0; i < count; ++i)
448    {
449      name_vector[i] = lastlink->name;
450#ifdef ALLOCA_MISSING
451      templink = lastlink->next;
452      free ((char *) lastlink);
453      lastlink = templink;
454#else
455      lastlink = lastlink->next;
456#endif
457    }
458
459  name_vector[count] = NULL;
460  return name_vector;
461}
462
463/* Return a new array, replacing ARRAY, which is the concatenation
464   of each string in ARRAY to DIR.
465   Return NULL if out of memory.  */
466
467static char **
468glob_dir_to_array (dir, array)
469     char *dir, **array;
470{
471  register unsigned int i, l;
472  int add_slash = 0;
473  char **result;
474
475  l = strlen (dir);
476  if (l == 0)
477    return array;
478
479  if (dir[l - 1] != '/')
480    add_slash++;
481
482  for (i = 0; array[i] != NULL; i++)
483    ;
484
485  result = (char **) malloc ((i + 1) * sizeof (char *));
486  if (result == NULL)
487    return NULL;
488
489  for (i = 0; array[i] != NULL; i++)
490    {
491      result[i] = (char *) malloc (1 + l + add_slash + strlen (array[i]));
492      if (result[i] == NULL)
493	return NULL;
494      strcpy (result[i], dir);
495      if (add_slash)
496	result[i][l] = '/';
497      strcpy (result[i] + l + add_slash, array[i]);
498    }
499  result[i] = NULL;
500
501  /* Free the input array.  */
502  for (i = 0; array[i] != NULL; i++)
503    free (array[i]);
504  free ((char *) array);
505  return result;
506}
507
508/* Do globbing on PATHNAME.  Return an array of pathnames that match,
509   marking the end of the array with a null-pointer as an element.
510   If no pathnames match, then the array is empty (first element is null).
511   If there isn't enough memory, then return NULL.
512   If a file system error occurs, return -1; `errno' has the error code.
513
514   Wildcards at the beginning of PAT, or following a slash,
515   do not match an initial period if noglob_dot_filenames is nonzero.  */
516
517char **
518glob_filename (const char *pathname)
519{
520  char **result;
521  unsigned int result_size;
522  char *directory_name;
523  const char *filename;
524  unsigned int directory_len;
525
526  result = (char **) malloc (sizeof (char *));
527  result_size = 1;
528  if (result == NULL)
529    return NULL;
530
531  result[0] = NULL;
532
533  /* Find the filename.  */
534  filename = rindex (pathname, '/');
535  if (filename == NULL)
536    {
537      filename = pathname;
538      directory_name = "";
539      directory_len = 0;
540    }
541  else
542    {
543      directory_len = (filename - pathname) + 1;
544#ifdef ALLOCA_MISSING
545      directory_name = (char *) malloc (directory_len + 1);
546#else
547      directory_name = (char *) alloca (directory_len + 1);
548#endif
549      bcopy (pathname, directory_name, directory_len);
550      directory_name[directory_len] = '\0';
551      ++filename;
552    }
553
554  /* If directory_name contains globbing characters, then we
555     have to expand the previous levels.  Just recurse. */
556  if (glob_pattern_p (directory_name))
557    {
558      char **directories;
559      register unsigned int i;
560
561      if (directory_name[directory_len - 1] == '/')
562	directory_name[directory_len - 1] = '\0';
563
564      directories = glob_filename (directory_name);
565#ifdef ALLOCA_MISSING
566      free ((char *) directory_name);
567#endif
568      if (directories == NULL)
569	goto memory_error;
570      else if (directories == (char **) -1)
571	return (char **) -1;
572      else if (*directories == NULL)
573	{
574	  free ((char *) directories);
575	  return (char **) -1;
576	}
577
578      /* We have successfully globbed the preceding directory name.
579	 For each name in DIRECTORIES, call glob_vector on it and
580	 FILENAME.  Concatenate the results together.  */
581      for (i = 0; directories[i] != NULL; i++)
582	{
583	  char **temp_results = glob_vector (filename, directories[i]);
584	  if (temp_results == NULL)
585	    goto memory_error;
586	  else if (temp_results == (char **) -1)
587	    /* This filename is probably not a directory.  Ignore it.  */
588	    ;
589	  else
590	    {
591	      char **array = glob_dir_to_array (directories[i], temp_results);
592	      register unsigned int l;
593
594	      l = 0;
595	      while (array[l] != NULL)
596		++l;
597
598	      result = (char **) realloc (result,
599					  (result_size + l) * sizeof (char *));
600	      if (result == NULL)
601		goto memory_error;
602
603	      for (l = 0; array[l] != NULL; ++l)
604		result[result_size++ - 1] = array[l];
605	      result[result_size - 1] = NULL;
606	      free ((char *) array);
607	    }
608	}
609      /* Free the directories.  */
610      for (i = 0; directories[i] != NULL; i++)
611	free (directories[i]);
612      free ((char *) directories);
613
614      return result;
615    }
616
617  /* If there is only a directory name, return it. */
618  if (*filename == '\0')
619    {
620      result = (char **) realloc ((char *) result, 2 * sizeof (char *));
621      if (result != NULL)
622	{
623	  result[0] = (char *) malloc (directory_len + 1);
624	  if (result[0] == NULL)
625	    {
626#ifdef ALLOCA_MISSING
627	      free ((char *) directory_name);
628#endif
629	      goto memory_error;
630	    }
631	  bcopy (directory_name, result[0], directory_len + 1);
632	  result[1] = NULL;
633	}
634#ifdef ALLOCA_MISSING
635      free ((char *) directory_name);
636#endif
637      return result;
638    }
639  else
640    {
641      /* Otherwise, just return what glob_vector
642	 returns appended to the directory name. */
643      char **temp_results = glob_vector (filename,
644					 (directory_len == 0
645					  ? "." : directory_name));
646
647      if (temp_results == NULL || temp_results == (char **) -1)
648	{
649#ifdef NO_ALLOCA
650	  free ((char *) directory_name);
651#endif
652	  return temp_results;
653	}
654
655      temp_results = glob_dir_to_array (directory_name, temp_results);
656#ifdef NO_ALLOCA
657      free ((char *) directory_name);
658#endif
659      return temp_results;
660    }
661
662  /* We get to memory error if the program has run out of memory, or
663     if this is the shell, and we have been interrupted. */
664 memory_error:
665  if (result != NULL)
666    {
667      register unsigned int i;
668      for (i = 0; result[i] != NULL; ++i)
669	free (result[i]);
670      free ((char *) result);
671    }
672#if defined (SHELL)
673  {
674    extern int interrupt_state;
675
676    if (interrupt_state)
677      throw_to_top_level ();
678  }
679#endif /* SHELL */
680  return NULL;
681}
682
683#ifdef TEST
684
685main (argc, argv)
686     int argc;
687     char **argv;
688{
689  char **value;
690  int i, optind;
691
692  for (optind = 1; optind < argc; optind++)
693    {
694      value = glob_filename (argv[optind]);
695      if (value == NULL)
696	puts ("virtual memory exhausted");
697      else if (value == (char **) -1)
698	perror (argv[optind]);
699      else
700	for (i = 0; value[i] != NULL; i++)
701	  puts (value[i]);
702    }
703  exit (0);
704}
705
706#endif /* TEST */
707#endif
708