1 /* EINA - EFL data type library
2 * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
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.
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.
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/>.
29 #elif defined __GNUC__
30 # define alloca __builtin_alloca
32 # define alloca __alloca
33 #elif defined _MSC_VER
35 # define alloca _alloca
41 void *alloca (size_t);
48 # include <sys/types.h>
49 # include <sys/stat.h>
52 # define WIN32_LEAN_AND_MEAN
54 # undef WIN32_LEAN_AND_MEAN
59 # define PATH_DELIM '/'
61 # define PATH_DELIM '\\'
62 # define NAME_MAX MAX_PATH
65 #include "eina_config.h"
66 #include "eina_private.h"
68 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
69 #include "eina_safety_checks.h"
70 #include "eina_file.h"
71 #include "eina_stringshare.h"
73 typedef struct _Eina_File_Iterator Eina_File_Iterator;
74 struct _Eina_File_Iterator
76 Eina_Iterator iterator;
85 _eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
93 dp = readdir(it->dirp);
94 if (!dp) return EINA_FALSE;
96 while ((dp->d_name[0] == '.') &&
97 ((dp->d_name[1] == '\0') ||
98 ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
100 length = strlen(dp->d_name);
101 name = alloca(length + 2 + it->length);
103 memcpy(name, it->dir, it->length);
104 memcpy(name + it->length, "/", 1);
105 memcpy(name + it->length + 1, dp->d_name, length + 1);
107 *data = (char*) eina_stringshare_add(name);
112 _eina_file_ls_iterator_container(Eina_File_Iterator *it)
118 _eina_file_ls_iterator_free(Eina_File_Iterator *it)
122 EINA_MAGIC_SET(&it->iterator, 0);
126 typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
127 struct _Eina_File_Direct_Iterator
129 Eina_Iterator iterator;
134 Eina_File_Direct_Info info;
140 _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
147 dp = readdir(it->dirp);
148 if (!dp) return EINA_FALSE;
150 length = strlen(dp->d_name);
151 if (it->info.name_start + length + 1 >= PATH_MAX)
154 while ((dp->d_name[0] == '.') &&
155 ((dp->d_name[1] == '\0') ||
156 ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
158 memcpy(it->info.path + it->info.name_start, dp->d_name, length);
159 it->info.name_length = length;
160 it->info.path_length = it->info.name_start + length;
161 it->info.path[it->info.path_length] = '\0';
162 it->info.dirent = dp;
169 _eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
175 _eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
179 EINA_MAGIC_SET(&it->iterator, 0);
183 /*============================================================================*
185 *============================================================================*/
187 /*============================================================================*
189 *============================================================================*/
192 * @addtogroup Eina_File_Group File
194 * @brief Functions to traverse directories and split paths.
196 * @li eina_file_dir_list() list the content of a directory,
197 * recusrsively or not, and can call a callback function for eachfound
199 * @li eina_file_split() split a path into all the subdirectories that
200 * compose it, according to the separator of the file system.
206 * @brief List all files on the directory calling the function for every file found.
208 * @param dir The directory name.
209 * @param recursive Iterate recursively in the directory.
210 * @param cb The callback to be called.
211 * @param data The data to pass to the callback.
212 * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
214 * This function lists all the files in @p dir. To list also all the
215 * sub directoris recursively, @p recursive must be set to #EINA_TRUE,
216 * otherwise it must be set to #EINA_FALSE. For each found file, @p cb
217 * is called and @p data is passed to it.
219 * If @p cb or @p dir are @c NULL, or if @p dir is a string of size 0,
220 * or if @p dir can not be opened, this function returns #EINA_FALSE
221 * immediatly. otherwise, it returns #EINA_TRUE.
224 eina_file_dir_list(const char *dir, Eina_Bool recursive, Eina_File_Dir_List_Cb cb, void *data)
230 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
231 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
232 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
235 if (!d) return EINA_FALSE;
237 while ((de = readdir(d)))
239 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
242 cb(de->d_name, dir, data);
243 /* d_type is only available on linux and bsd (_BSD_SOURCE) */
245 if (recursive == EINA_TRUE) {
248 path = alloca(strlen(dir) + strlen(de->d_name) + 2);
251 strcat(path, de->d_name);
253 if (de->d_type == DT_UNKNOWN) {
260 if (!S_ISDIR(st.st_mode))
263 } else if (de->d_type != DT_DIR) {
268 eina_file_dir_list(path, recursive, cb, data);
274 WIN32_FIND_DATA file;
280 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
281 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
282 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
284 length_dir = strlen(dir);
285 new_dir = (char *)alloca(length_dir + 5);
286 if (!new_dir) return EINA_FALSE;
288 memcpy(new_dir, dir, length_dir);
289 memcpy(new_dir + length_dir, "/*.*", 5);
292 tdir = evil_char_to_wchar(new_dir);
295 #endif /* ! UNICODE */
296 hSearch = FindFirstFile(tdir, &file);
301 if (hSearch == INVALID_HANDLE_VALUE) return EINA_FALSE;
308 filename = evil_wchar_to_char(file.cFileName);
310 filename = file.cFileName;
311 #endif /* ! UNICODE */
312 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
315 cb(filename, dir, data);
317 if (recursive == EINA_TRUE) {
320 path = alloca(strlen(dir) + strlen(filename) + 2);
323 strcat(path, filename);
325 if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
328 eina_file_dir_list(path, recursive, cb, data);
334 } while (FindNextFile(hSearch, &file));
342 * @brief Split a path according to the delimiter of the filesystem.
344 * @param path The path to split.
345 * @return An array of the parts of the path to split.
347 * This function splits @p path according to the delimiter of the used
348 * filesystem. If @p path is @c NULL or if the array can not be
349 * created, @c NULL is returned, otherwise, an array with the
350 * different parts of @p path is returned.
353 eina_file_split(char *path)
359 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
361 ea = eina_array_new(16);
363 if (!ea) return NULL;
365 for (current = strchr(path, PATH_DELIM);
367 path = current + 1, current = strchr(path, PATH_DELIM))
369 length = current - path;
371 if (length <= 0) continue ;
373 eina_array_push(ea, path);
378 eina_array_push(ea, path);
384 * Get an iterator to list the content of a directory.
386 * Iterators are cheap to be created and allow interruption at any
387 * iteration. At each iteration, only the next directory entry is read
388 * from the filesystem with readdir().
390 * The iterator will handle the user a stringshared value with the
391 * full path. One must call eina_stringshare_del() on it after usage
394 * The eina_file_direct_ls() function will provide a possibly faster
395 * alternative if you need to filter the results somehow, like
396 * checking extension.
398 * The iterator will walk over '.' and '..' without returning them.
400 * @param dir The name of the directory to list
401 * @return Return an Eina_Iterator that will walk over the files and
402 * directory in the pointed directory. On failure it will
403 * return NULL. The iterator emits stringshared value with the
404 * full path and must be freed with eina_stringshare_del().
406 * @see eina_file_direct_ls()
409 eina_file_ls(const char *dir)
411 Eina_File_Iterator *it;
414 if (!dir) return NULL;
416 length = strlen(dir);
417 if (length < 1) return NULL;
419 it = malloc(sizeof (Eina_File_Iterator) + length);
420 if (!it) return NULL;
422 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
424 it->dirp = opendir(dir);
431 memcpy(it->dir, dir, length + 1);
432 if (dir[length - 1] != '/')
435 it->length = length - 1;
437 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
438 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_ls_iterator_container);
439 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
441 return &it->iterator;
445 * Get an iterator to list the content of a directory, with direct information.
447 * Iterators are cheap to be created and allow interruption at any
448 * iteration. At each iteration, only the next directory entry is read
449 * from the filesystem with readdir().
451 * The iterator returns the direct pointer to couple of useful information in
452 * #Eina_File_Direct_Info and that pointer should not be modified anyhow!
454 * The iterator will walk over '.' and '..' without returning them.
456 * @param dir The name of the directory to list
458 * @return Return an Eina_Iterator that will walk over the files and
459 * directory in the pointed directory. On failure it will
460 * return NULL. The iterator emits #Eina_File_Direct_Info
461 * pointers that could be used but not modified. The lifetime
462 * of the returned pointer is until the next iteration and
463 * while the iterator is live, deleting the iterator
464 * invalidates the pointer.
466 * @see eina_file_ls()
469 eina_file_direct_ls(const char *dir)
471 Eina_File_Direct_Iterator *it;
474 if (!dir) return NULL;
476 length = strlen(dir);
477 if (length < 1) return NULL;
478 if (length + NAME_MAX + 2 >= PATH_MAX) return NULL;
480 it = malloc(sizeof(Eina_File_Direct_Iterator) + length);
481 if (!it) return NULL;
483 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
485 it->dirp = opendir(dir);
492 memcpy(it->dir, dir, length + 1);
495 memcpy(it->info.path, dir, length);
496 if (dir[length - 1] == '/')
497 it->info.name_start = length;
500 it->info.path[length] = '/';
501 it->info.name_start = length + 1;
504 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
505 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_direct_ls_iterator_container);
506 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
508 return &it->iterator;