1 /*
2  * This file contains a function, get_dir_list() that will get a directory
3  * listing and put all the names into a table (an array of char *'s table)
4  * and return it to you (along with the number of entries in the directory
5  * if desired). The table is NULL terminated (i.e. the entry after the last
6  * one is a NULL), and is just like an argv style array.
7  *
8  * If an error occurs (memory allocation, bad directory name, etc), you
9  * will get a NULL back.
10  *
11  * Each entry of the returned table points to a NULL-terminated string
12  * that contains the name of a file in the directory.  If the name is
13  * a directory, it has a slash appended to it.
14  *
15  * When you are done with the table, you should free it manually, or you
16  * can call the function free_table() provided down below.
17  *
18  * See the sample main() down below for how to use it.  Ignore (or steal
19  * if you'd like) the other code that isn't particularly relevant (i.e.
20  * the support functions).
21  *
22  *   Dominic Giampaolo
23  *   dbg@sgi.com
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 
33 
free_table(char ** table,int n)34 void free_table(char **table, int n)
35 {
36   char **orig = table;
37 
38   for(; n > 0; n--, table++)
39    {
40      if (*table)
41        free(*table);
42    }
43 
44   free(orig);
45 }
46 
47 
free_dirlist(char ** table)48 void free_dirlist(char **table)
49 {
50   char **orig = table;
51 
52   while(*table)
53    {
54      free(*table);
55      table++;
56    }
57 
58   free(orig);
59 }
60 
61 
get_file_name(struct dirent * d)62 char *get_file_name(struct dirent *d)
63 {
64   struct stat s;
65   char *name;
66 
67   if (d == NULL)
68    {
69      fprintf(stderr, "BUG BUG BUG (got a NULL in get_file_name()).\n");
70      return NULL;
71    }
72 
73   if (stat(d->d_name, &s) < 0)
74    {
75      perror(d->d_name);
76      return NULL;
77    }
78 
79   if (S_ISDIR(s.st_mode))
80    {
81      name = (char *)malloc(strlen(d->d_name)+2);
82      if (name == NULL)
83        return NULL;
84      sprintf(name, "%s/", d->d_name);
85    }
86   else
87    {
88      name = (char *)strdup(d->d_name);
89    }
90 
91   return name;
92 }
93 
94 
95 
96 
97 #define CHUNK  100
98 
99 
get_dir_list(char * dirname,int * num_entries)100 char **get_dir_list(char *dirname, int *num_entries)
101 {
102   int i,size=CHUNK;
103   char **table, old_dir[MAXPATHLEN];
104   DIR  *dir;
105   struct dirent *dirent;
106 
107   getcwd(old_dir, MAXPATHLEN);
108   if (dirname && chdir(dirname) < 0)
109     return NULL;
110 
111   dir = opendir(".");
112   if (dir == NULL)
113    {
114      chdir(old_dir);
115      return NULL;
116    }
117 
118   table = (char **)calloc(size, sizeof(char *));
119   if (table == NULL)
120    {
121      closedir(dir);
122      chdir(old_dir);
123 
124      return NULL;
125    }
126 
127   dirent = NULL;   i = 0;
128   for(dirent = readdir(dir); dirent != NULL; dirent = readdir(dir))
129    {
130      table[i] = get_file_name(dirent);
131      if (table[i] == NULL)   /* continue if there was an error */
132       {
133 	continue;
134       }
135 
136      i++;
137      if (i == size)
138       {
139 	char **table2;
140 
141 	size *= 2;
142 	table2 = (char **)realloc(table, size * sizeof(char *));
143 	if (table2 == NULL)
144 	 {
145 	   free_table(table, i);
146 	   closedir(dir);
147 	   chdir(old_dir);
148 
149 	   return NULL;
150 	 }
151 
152 	table = table2;
153       }
154    }
155 
156   table[i] = NULL;    /* make sure the table ends with a NULL */
157 
158   if (num_entries)
159     *num_entries = i;
160 
161   closedir(dir);
162   chdir(old_dir);
163 
164   return table;
165 }
166 
167 
168 #ifdef TEST
169 /*
170  * This function is just a wrapper for strcmp(), and is called by qsort()
171  * (if used) down below.
172  */
mystrcmp(char ** a,char ** b)173 int mystrcmp(char **a, char **b)
174 {
175   return strcmp(*a, *b);
176 }
177 
178 
179 
main(int argc,char ** argv)180 main(int argc, char **argv)
181 {
182   int i, num_entries;
183   char *dirname, **table;
184 
185   if (argv[1] == NULL)
186     dirname = ".";
187   else
188     dirname = argv[1];
189 
190   table = get_dir_list(dirname, &num_entries);
191   if (table == NULL)
192     printf("No such directory: %s\n", dirname);
193   else
194    {
195      /*
196       * If you want to sort the table, you would do it as follows:
197       */
198      qsort(table, num_entries, sizeof(char *), mystrcmp);
199 
200      printf("Number of files == %d\n", num_entries);
201      for(i=0; table[i] != NULL; i++)
202        printf("%s\n", table[i]);
203 
204      free_table(table, num_entries);
205    }
206 
207 
208   exit(0);
209 }
210 #endif  /* TEST */
211 
212 
213 
214