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/>.
25 #elif defined __GNUC__
26 # define alloca __builtin_alloca
28 # define alloca __alloca
29 #elif defined _MSC_VER
31 # define alloca _alloca
37 void *alloca (size_t);
45 # include <sys/types.h>
46 # include <sys/stat.h>
53 # define PATH_DELIM '/'
55 # define PATH_DELIM '\\'
56 # 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)
91 dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
95 if (readdir_r(it->dirp, dp, &dp))
100 while ((dp->d_name[0] == '.') &&
101 ((dp->d_name[1] == '\0') ||
102 ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
104 length = strlen(dp->d_name);
105 name = alloca(length + 2 + it->length);
107 memcpy(name, it->dir, it->length);
108 memcpy(name + it->length, "/", 1);
109 memcpy(name + it->length + 1, dp->d_name, length + 1);
111 *data = (char *)eina_stringshare_add(name);
116 _eina_file_ls_iterator_container(Eina_File_Iterator *it)
122 _eina_file_ls_iterator_free(Eina_File_Iterator *it)
126 EINA_MAGIC_SET(&it->iterator, 0);
130 typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
131 struct _Eina_File_Direct_Iterator
133 Eina_Iterator iterator;
138 Eina_File_Direct_Info info;
144 _eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
149 dp = alloca(offsetof(struct dirent, d_name) + pathconf(it->dir, _PC_NAME_MAX) + 1);
153 if (readdir_r(it->dirp, dp, &dp))
158 length = strlen(dp->d_name);
159 if (it->info.name_start + length + 1 >= PATH_MAX)
162 while ((dp->d_name[0] == '.') &&
163 ((dp->d_name[1] == '\0') ||
164 ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
166 memcpy(it->info.path + it->info.name_start, dp->d_name, length);
167 it->info.name_length = length;
168 it->info.path_length = it->info.name_start + length;
169 it->info.path[it->info.path_length] = '\0';
170 it->info.dirent = dp;
177 _eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
183 _eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
187 EINA_MAGIC_SET(&it->iterator, 0);
191 /*============================================================================*
193 *============================================================================*/
195 /*============================================================================*
197 *============================================================================*/
200 * @addtogroup Eina_File_Group File
202 * @brief Functions to traverse directories and split paths.
204 * @li eina_file_dir_list() list the content of a directory,
205 * recusrsively or not, and can call a callback function for eachfound
207 * @li eina_file_split() split a path into all the subdirectories that
208 * compose it, according to the separator of the file system.
214 * @brief List all files on the directory calling the function for every file found.
216 * @param dir The directory name.
217 * @param recursive Iterate recursively in the directory.
218 * @param cb The callback to be called.
219 * @param data The data to pass to the callback.
220 * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
222 * This function lists all the files in @p dir. To list also all the
223 * sub directoris recursively, @p recursive must be set to #EINA_TRUE,
224 * otherwise it must be set to #EINA_FALSE. For each found file, @p cb
225 * is called and @p data is passed to it.
227 * If @p cb or @p dir are @c NULL, or if @p dir is a string of size 0,
228 * or if @p dir can not be opened, this function returns #EINA_FALSE
229 * immediately. otherwise, it returns #EINA_TRUE.
232 eina_file_dir_list(const char *dir,
234 Eina_File_Dir_List_Cb cb,
241 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
242 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
243 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
249 de = alloca(offsetof(struct dirent, d_name) + pathconf(dir, _PC_NAME_MAX) + 1);
251 while ((!readdir_r(d, de, &de) && de))
253 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
256 cb(de->d_name, dir, data);
257 /* d_type is only available on linux and bsd (_BSD_SOURCE) */
259 if (recursive == EINA_TRUE)
263 path = alloca(strlen(dir) + strlen(de->d_name) + 2);
266 strcat(path, de->d_name);
268 if (de->d_type == DT_UNKNOWN)
276 if (!S_ISDIR(st.st_mode))
281 else if (de->d_type != DT_DIR)
286 eina_file_dir_list(path, recursive, cb, data);
292 WIN32_FIND_DATA file;
298 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
299 EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
300 EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
302 length_dir = strlen(dir);
303 new_dir = (char *)alloca(length_dir + 5);
307 memcpy(new_dir, dir, length_dir);
308 memcpy(new_dir + length_dir, "/*.*", 5);
311 tdir = evil_char_to_wchar(new_dir);
314 #endif /* ! UNICODE */
315 hSearch = FindFirstFile(tdir, &file);
320 if (hSearch == INVALID_HANDLE_VALUE)
328 filename = evil_wchar_to_char(file.cFileName);
330 filename = file.cFileName;
331 #endif /* ! UNICODE */
332 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
335 cb(filename, dir, data);
337 if (recursive == EINA_TRUE)
341 path = alloca(strlen(dir) + strlen(filename) + 2);
344 strcat(path, filename);
346 if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
349 eina_file_dir_list(path, recursive, cb, data);
356 } while (FindNextFile(hSearch, &file));
364 * @brief Split a path according to the delimiter of the filesystem.
366 * @param path The path to split.
367 * @return An array of the parts of the path to split.
369 * This function splits @p path according to the delimiter of the used
370 * filesystem. If @p path is @c NULL or if the array can not be
371 * created, @c NULL is returned, otherwise, an array with the
372 * different parts of @p path is returned.
375 eina_file_split(char *path)
381 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
383 ea = eina_array_new(16);
388 for (current = strchr(path, PATH_DELIM);
390 path = current + 1, current = strchr(path, PATH_DELIM))
392 length = current - path;
397 eina_array_push(ea, path);
402 eina_array_push(ea, path);
408 * Get an iterator to list the content of a directory.
410 * Iterators are cheap to be created and allow interruption at any
411 * iteration. At each iteration, only the next directory entry is read
412 * from the filesystem with readdir_r().
414 * The iterator will handle the user a stringshared value with the
415 * full path. One must call eina_stringshare_del() on it after usage
418 * The eina_file_direct_ls() function will provide a possibly faster
419 * alternative if you need to filter the results somehow, like
420 * checking extension.
422 * The iterator will walk over '.' and '..' without returning them.
424 * The iterator container is the DIR* corresponding to the current walk.
426 * @param dir The name of the directory to list
427 * @return Return an Eina_Iterator that will walk over the files and
428 * directory in the pointed directory. On failure it will
429 * return NULL. The iterator emits stringshared value with the
430 * full path and must be freed with eina_stringshare_del().
432 * @see eina_file_direct_ls()
435 eina_file_ls(const char *dir)
437 Eina_File_Iterator *it;
443 length = strlen(dir);
447 it = calloc(1, sizeof (Eina_File_Iterator) + length);
451 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
453 it->dirp = opendir(dir);
460 memcpy(it->dir, dir, length + 1);
461 if (dir[length - 1] != '/')
464 it->length = length - 1;
466 it->iterator.version = EINA_ITERATOR_VERSION;
467 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
468 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
469 _eina_file_ls_iterator_container);
470 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
472 return &it->iterator;
476 * Get an iterator to list the content of a directory, with direct information.
478 * Iterators are cheap to be created and allow interruption at any
479 * iteration. At each iteration, only the next directory entry is read
480 * from the filesystem with readdir_r().
482 * The iterator returns the direct pointer to couple of useful information in
483 * #Eina_File_Direct_Info and that pointer should not be modified anyhow!
485 * The iterator will walk over '.' and '..' without returning them.
487 * The iterator container is the DIR* corresponding to the current walk.
489 * @param dir The name of the directory to list
491 * @return Return an Eina_Iterator that will walk over the files and
492 * directory in the pointed directory. On failure it will
493 * return NULL. The iterator emits #Eina_File_Direct_Info
494 * pointers that could be used but not modified. The lifetime
495 * of the returned pointer is until the next iteration and
496 * while the iterator is live, deleting the iterator
497 * invalidates the pointer.
499 * @see eina_file_ls()
502 eina_file_direct_ls(const char *dir)
504 Eina_File_Direct_Iterator *it;
510 length = strlen(dir);
514 if (length + NAME_MAX + 2 >= PATH_MAX)
517 it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
521 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
523 it->dirp = opendir(dir);
530 memcpy(it->dir, dir, length + 1);
533 memcpy(it->info.path, dir, length);
534 if (dir[length - 1] == '/')
535 it->info.name_start = length;
538 it->info.path[length] = '/';
539 it->info.name_start = length + 1;
542 it->iterator.version = EINA_ITERATOR_VERSION;
543 it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
544 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
545 _eina_file_direct_ls_iterator_container);
546 it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
548 return &it->iterator;