#ifdef SHELL
#include "config.h"
#endif
#include <sys/types.h>
#if defined (USGr3) && !defined (DIRENT)
#define DIRENT
#endif
#if defined (Xenix) && !defined (SYSNDIR)
#define SYSNDIR
#endif
#if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
#include <dirent.h>
#define direct dirent
#define D_NAMLEN(d) strlen((d)->d_name)
#else
#define D_NAMLEN(d) ((d)->d_namlen)
#ifdef USG
#if defined (SYSNDIR)
#include <sys/ndir.h>
#else
#include "ndir.h"
#endif
#else
#include <sys/dir.h>
#endif
#endif
#if defined (_POSIX_SOURCE)
#define REAL_DIR_ENTRY(dp) 1
#else
#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
#endif
#if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)
#include <stdlib.h>
#include <string.h>
#define STDC_STRINGS
#else
#if defined (USG)
#include <string.h>
#ifndef POSIX
#include <memory.h>
#endif
#define STDC_STRINGS
#else
#ifdef NeXT
#include <string.h>
#else
#include <strings.h>
#endif
#endif
extern char *malloc ();
extern char *realloc ();
extern void free ();
#ifndef NULL
#define NULL 0
#endif
#endif
#ifdef STDC_STRINGS
#define bcopy(s, d, n) memcpy ((d), (s), (n))
#define index strchr
#define rindex strrchr
#endif
#ifndef alloca
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
#ifdef sparc
#include <alloca.h>
#else
extern char *alloca ();
#endif
#endif
#endif
int noglob_dot_filenames = 1;
static int glob_match_after_star ();
#ifdef __FreeBSD__
static int collate_range_cmp (a, b)
int a, b;
{
int r;
static char s[2][2];
if ((unsigned char)a == (unsigned char)b)
return 0;
s[0][0] = a;
s[1][0] = b;
if ((r = strcoll(s[0], s[1])) == 0)
r = (unsigned char)a - (unsigned char)b;
return r;
}
#endif
int
glob_pattern_p (pattern)
char *pattern;
{
register char *p = pattern;
register char c;
int open = 0;
while ((c = *p++) != '\0')
switch (c)
{
case '?':
case '*':
return 1;
case '[':
open++;
continue;
case ']':
if (open)
return 1;
continue;
case '\\':
if (*p++ == '\0')
return 0;
}
return 0;
}
int
glob_match (pattern, text, dot_special)
char *pattern, *text;
int dot_special;
{
register char *p = pattern, *t = text;
register char c;
while ((c = *p++) != '\0')
switch (c)
{
case '?':
if (*t == '\0' || (dot_special && t == text && *t == '.'))
return 0;
else
++t;
break;
case '\\':
if (*p++ != *t++)
return 0;
break;
case '*':
if (dot_special && t == text && *t == '.')
return 0;
return glob_match_after_star (p, t);
case '[':
{
register char c1 = *t++;
int invert;
char *cp1 = p;
if (c1 == '\0')
return 0;
invert = (*p == '!');
if (invert)
p++;
c = *p++;
while (1)
{
register char cstart = c, cend = c;
if (c == '\\')
{
cstart = *p++;
cend = cstart;
}
if (cstart == '\0')
{
if (c1 != '[')
return 0;
p = cp1;
goto breakbracket;
}
c = *p++;
if (c == '-')
{
cend = *p++;
if (cend == '\\')
cend = *p++;
if (cend == '\0')
return 0;
c = *p++;
}
#ifdef __FreeBSD__
if ( collate_range_cmp (c1, cstart) >= 0
&& collate_range_cmp (c1, cend) <= 0
)
#else
if (c1 >= cstart && c1 <= cend)
#endif
goto match;
if (c == ']')
break;
}
if (!invert)
return 0;
break;
match:
while (c != ']')
{
if (c == '\0')
return 0;
c = *p++;
if (c == '\0')
return 0;
if (c == '\\')
p++;
}
if (invert)
return 0;
breakbracket:
break;
}
default:
if (c != *t++)
return 0;
}
return *t == '\0';
}
static int
glob_match_after_star (pattern, text)
char *pattern, *text;
{
register char *p = pattern, *t = text;
register char c, c1;
while ((c = *p++) == '?' || c == '*')
if (c == '?' && *t++ == '\0')
return 0;
if (c == '\0')
return 1;
if (c == '\\')
c1 = *p;
else
c1 = c;
--p;
while (1)
{
if ((c == '[' || *t == c1) && glob_match (p, t, 0))
return 1;
if (*t++ == '\0')
return 0;
}
}
char **
glob_vector (pat, dir)
char *pat;
char *dir;
{
struct globval
{
struct globval *next;
char *name;
};
DIR *d;
register struct direct *dp;
struct globval *lastlink;
register struct globval *nextlink;
register char *nextname;
unsigned int count;
int lose;
register char **name_vector;
register unsigned int i;
#ifdef ALLOCA_MISSING
struct globval *templink;
#endif
d = opendir (dir);
if (d == NULL)
return (char **) -1;
lastlink = NULL;
count = 0;
lose = 0;
while (1)
{
#if defined (SHELL)
extern int interrupt_state;
if (interrupt_state)
{
closedir (d);
lose = 1;
goto lost;
}
#endif
dp = readdir (d);
if (dp == NULL)
break;
if (REAL_DIR_ENTRY (dp)
&& glob_match (pat, dp->d_name, noglob_dot_filenames))
{
#ifdef ALLOCA_MISSING
nextlink = (struct globval *) malloc (sizeof (struct globval));
#else
nextlink = (struct globval *) alloca (sizeof (struct globval));
#endif
nextlink->next = lastlink;
i = D_NAMLEN (dp) + 1;
nextname = (char *) malloc (i);
if (nextname == NULL)
{
lose = 1;
break;
}
lastlink = nextlink;
nextlink->name = nextname;
bcopy (dp->d_name, nextname, i);
count++;
}
}
closedir (d);
if (!lose)
{
name_vector = (char **) malloc ((count + 1) * sizeof (char *));
lose |= name_vector == NULL;
}
#ifdef SHELL
lost:
#endif
if (lose)
{
while (lastlink)
{
free (lastlink->name);
#ifdef ALLOCA_MISSING
templink = lastlink->next;
free ((char *) lastlink);
lastlink = templink;
#else
lastlink = lastlink->next;
#endif
}
return NULL;
}
for (i = 0; i < count; ++i)
{
name_vector[i] = lastlink->name;
#ifdef ALLOCA_MISSING
templink = lastlink->next;
free ((char *) lastlink);
lastlink = templink;
#else
lastlink = lastlink->next;
#endif
}
name_vector[count] = NULL;
return name_vector;
}
static char **
glob_dir_to_array (dir, array)
char *dir, **array;
{
register unsigned int i, l;
int add_slash = 0;
char **result;
l = strlen (dir);
if (l == 0)
return array;
if (dir[l - 1] != '/')
add_slash++;
for (i = 0; array[i] != NULL; i++)
;
result = (char **) malloc ((i + 1) * sizeof (char *));
if (result == NULL)
return NULL;
for (i = 0; array[i] != NULL; i++)
{
result[i] = (char *) malloc (1 + l + add_slash + strlen (array[i]));
if (result[i] == NULL)
return NULL;
strcpy (result[i], dir);
if (add_slash)
result[i][l] = '/';
strcpy (result[i] + l + add_slash, array[i]);
}
result[i] = NULL;
for (i = 0; array[i] != NULL; i++)
free (array[i]);
free ((char *) array);
return result;
}
char **
glob_filename (pathname)
char *pathname;
{
char **result;
unsigned int result_size;
char *directory_name, *filename;
unsigned int directory_len;
result = (char **) malloc (sizeof (char *));
result_size = 1;
if (result == NULL)
return NULL;
result[0] = NULL;
filename = rindex (pathname, '/');
if (filename == NULL)
{
filename = pathname;
directory_name = "";
directory_len = 0;
}
else
{
directory_len = (filename - pathname) + 1;
#ifdef ALLOCA_MISSING
directory_name = (char *) malloc (directory_len + 1);
#else
directory_name = (char *) alloca (directory_len + 1);
#endif
bcopy (pathname, directory_name, directory_len);
directory_name[directory_len] = '\0';
++filename;
}
if (glob_pattern_p (directory_name))
{
char **directories;
register unsigned int i;
if (directory_name[directory_len - 1] == '/')
directory_name[directory_len - 1] = '\0';
directories = glob_filename (directory_name);
#ifdef ALLOCA_MISSING
free ((char *) directory_name);
#endif
if (directories == NULL)
goto memory_error;
else if (directories == (char **) -1)
return (char **) -1;
else if (*directories == NULL)
{
free ((char *) directories);
return (char **) -1;
}
for (i = 0; directories[i] != NULL; i++)
{
char **temp_results = glob_vector (filename, directories[i]);
if (temp_results == NULL)
goto memory_error;
else if (temp_results == (char **) -1)
;
else
{
char **array = glob_dir_to_array (directories[i], temp_results);
register unsigned int l;
l = 0;
while (array[l] != NULL)
++l;
result = (char **) realloc (result,
(result_size + l) * sizeof (char *));
if (result == NULL)
goto memory_error;
for (l = 0; array[l] != NULL; ++l)
result[result_size++ - 1] = array[l];
result[result_size - 1] = NULL;
free ((char *) array);
}
}
for (i = 0; directories[i] != NULL; i++)
free (directories[i]);
free ((char *) directories);
return result;
}
if (*filename == '\0')
{
result = (char **) realloc ((char *) result, 2 * sizeof (char *));
if (result != NULL)
{
result[0] = (char *) malloc (directory_len + 1);
if (result[0] == NULL)
{
#ifdef ALLOCA_MISSING
free ((char *) directory_name);
#endif
goto memory_error;
}
bcopy (directory_name, result[0], directory_len + 1);
result[1] = NULL;
}
#ifdef ALLOCA_MISSING
free ((char *) directory_name);
#endif
return result;
}
else
{
char **temp_results = glob_vector (filename,
(directory_len == 0
? "." : directory_name));
if (temp_results == NULL || temp_results == (char **) -1)
{
#ifdef NO_ALLOCA
free ((char *) directory_name);
#endif
return temp_results;
}
temp_results = glob_dir_to_array (directory_name, temp_results);
#ifdef NO_ALLOCA
free ((char *) directory_name);
#endif
return temp_results;
}
memory_error:
if (result != NULL)
{
register unsigned int i;
for (i = 0; result[i] != NULL; ++i)
free (result[i]);
free ((char *) result);
}
#if defined (SHELL)
{
extern int interrupt_state;
if (interrupt_state)
throw_to_top_level ();
}
#endif
return NULL;
}
#ifdef TEST
main (argc, argv)
int argc;
char **argv;
{
char **value;
int i, optind;
for (optind = 1; optind < argc; optind++)
{
value = glob_filename (argv[optind]);
if (value == NULL)
puts ("virtual memory exhausted");
else if (value == (char **) -1)
perror (argv[optind]);
else
for (i = 0; value[i] != NULL; i++)
puts (value[i]);
}
exit (0);
}
#endif