* minor formatting
[profile/ivi/eina.git] / src / lib / eina_file.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <string.h>
24
25 #ifndef _WIN32
26 # define _GNU_SOURCE
27 # include <sys/types.h>
28 # include <sys/stat.h>
29 # include <unistd.h>
30 # include <dirent.h>
31 #else
32 # define WIN32_LEAN_AND_MEAN
33 # include <windows.h>
34 # undef WIN32_LEAN_AND_MEAN
35 # include <Evil.h>
36 #endif /* _WIN2 */
37
38 #ifdef HAVE_ALLOCA_H
39 # include <alloca.h>
40 #elif defined __GNUC__
41 # define alloca __builtin_alloca
42 #elif defined _AIX
43 # define alloca __alloca
44 #elif defined _MSC_VER
45 # include <malloc.h>
46 # define alloca _alloca
47 #else
48 # include <stddef.h>
49 # ifdef  __cplusplus
50 extern "C"
51 # endif
52 void *alloca (size_t);
53 #endif
54
55 #ifndef _WIN32
56 # define PATH_DELIM '/'
57 #else
58 # define PATH_DELIM '\\'
59 #endif
60
61 #include "eina_file.h"
62 #include "eina_private.h"
63 #include "eina_safety_checks.h"
64
65 /*============================================================================*
66  *                                 Global                                     *
67  *============================================================================*/
68
69 /*============================================================================*
70  *                                   API                                      *
71  *============================================================================*/
72
73 /**
74  * @addtogroup Eina_Tools_Group Tools
75  *
76  * @{
77  */
78
79 /**
80  * @addtogroup Eina_File_Group Memory File
81  *
82  * @brief Functions to traverse directories and split paths.
83  *
84  * @li eina_file_dir_list() list the content of a directory,
85  * recusrsively or not, and can call a callback function for eachfound
86  * file.
87  * @li eina_file_split() split a path into all the subdirectories that
88  * compose it, according to the separator of the file system.
89  *
90  * @warning eina_file_split() uses the @ref Eina_Array_Group module
91  * but does not initialize it. eina_array_init() and
92  * eina_array_shutdown() must be called if this function is used.
93  *
94  * @{
95  */
96
97 /**
98  * @brief List all files on the directory calling the function for every file found.
99  *
100  * @param dir The directory name.
101  * @param recursive Iterate recursively in the directory.
102  * @param cb The callback to be called.
103  * @param data The data to pass to the callback.
104  * @return #EINA_TRUE on success, #EINA_FALSE oterwise.
105  *
106  * This function lists all the files in @p dir. To list also all the
107  * sub directoris recursively, @p recursive must be set to #EINA_TRUE,
108  * otherwise it must be set to #EINA_FALSE. For each found file, @p cb
109  * is called and @p data is passed to it.
110  *
111  * If @p cb or @p dir are @c NULL, or if @p dir is a string of size 0,
112  * or if @p dir can not be opened, this function returns #EINA_FALSE
113  * immediatly. otherwise, it returns #EINA_TRUE.
114  */
115 EAPI Eina_Bool
116 eina_file_dir_list(const char *dir, Eina_Bool recursive, Eina_File_Dir_List_Cb cb, void *data)
117 {
118         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
119         EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
120         EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
121
122 #ifndef _WIN32
123         struct dirent *de;
124         DIR *d;
125
126         d = opendir(dir);
127         if (!d) return EINA_FALSE;
128
129         while ((de = readdir(d)))
130         {
131                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
132                         continue;
133
134                 cb(de->d_name, dir, data);
135                 /* d_type is only available on linux and bsd (_BSD_SOURCE) */
136
137                 if (recursive == EINA_TRUE) {
138                         char *path;
139
140                         path = alloca(strlen(dir) + strlen(de->d_name) + 2);
141                         strcpy(path, dir);
142                         strcat(path, "/");
143                         strcat(path, de->d_name);
144 #ifndef sun
145                         if (de->d_type == DT_UNKNOWN) {
146 #endif
147                                 struct stat st;
148
149                                 if (stat(path, &st))
150                                         continue ;
151
152                                 if (!S_ISDIR(st.st_mode))
153                                         continue ;
154 #ifndef sun
155                         } else if (de->d_type != DT_DIR) {
156                                 continue ;
157                         }
158 #endif
159
160                         eina_file_dir_list(path, recursive, cb, data);
161                 }
162         }
163
164         closedir(d);
165 #else
166         WIN32_FIND_DATA file;
167         HANDLE          hSearch;
168         char           *new_dir;
169         TCHAR          *tdir;
170         size_t          length_dir;
171
172         length_dir = strlen(dir);
173         new_dir = (char *)alloca(length_dir + 5);
174         if (!new_dir) return EINA_FALSE;
175
176         memcpy(new_dir, dir, length_dir);
177         memcpy(new_dir + length_dir, "/*.*", 5);
178
179 #ifdef UNICODE
180         tdir =  evil_char_to_wchar(new_dir);
181 #else
182         tdir = new_dir;
183 #endif /* ! UNICODE */
184         hSearch = FindFirstFile(tdir, &file);
185 #ifdef UNICODE
186         free(tdir);
187 #endif /* UNICODE */
188
189         if (hSearch == INVALID_HANDLE_VALUE) return EINA_FALSE;
190
191         do
192         {
193                 char *filename;
194
195 #ifdef UNICODE
196                 filename = evil_wchar_to_char(file.cFileName);
197 #else
198                 filename = file.cFileName;
199 #endif /* ! UNICODE */
200                 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
201                         continue;
202
203                 cb(filename, dir, data);
204
205                 if (recursive == EINA_TRUE) {
206                         char *path;
207
208                         path = alloca(strlen(dir) + strlen(filename) + 2);
209                         strcpy(path, dir);
210                         strcat(path, "/");
211                         strcat(path, filename);
212
213                         if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
214                                 continue ;
215
216                         eina_file_dir_list(path, recursive, cb, data);
217                 }
218 #ifdef UNICODE
219                 free(filename);
220 #endif /* UNICODE */
221
222         } while (FindNextFile(hSearch, &file));
223         FindClose(hSearch);
224 #endif /* _WIN32 */
225
226         return EINA_TRUE;
227 }
228
229 /**
230  * @brief Split a path according to the delimiter of the filesystem.
231  *
232  * @param path The path to split.
233  * @return An array of the parts of the path to split.
234  *
235  * This function splits @p path according to the delimiter of the used
236  * filesystem. If  @p path is @c NULL or if the array can not be
237  * created, @c NULL is returned, otherwise, an array with the
238  * different parts of @p path is returned.
239  *
240  * @warning This function uses the @ref Eina_Array_Group module but
241  * does not initialize it. eina_array_init() and eina_array_shutdown()
242  * must be called if this function is used.
243  */
244 EAPI Eina_Array *
245 eina_file_split(char *path)
246 {
247         Eina_Array *ea;
248         char *current;
249         size_t length;
250
251         EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
252
253         ea = eina_array_new(16);
254
255         if (!ea) return NULL;
256
257         for (current = strchr(path, PATH_DELIM);
258              current != NULL;
259              path = current + 1, current = strchr(path, PATH_DELIM))
260         {
261                 length = current - path;
262
263                 if (length <= 0) continue ;
264
265                 eina_array_push(ea, path);
266                 *current = '\0';
267         }
268
269         if (*path != '\0')
270                 eina_array_push(ea, path);
271
272         return ea;
273 }
274
275 /**
276  * @}
277  */
278
279 /**
280  * @}
281  */