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