efl/legacy/eina/src/lib/eina_file.c

274 lines
6.6 KiB
C

/* EINA - EFL data type library
* Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifndef _WIN32
# define _GNU_SOURCE
#endif
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
# define alloca __builtin_alloca
#elif defined _AIX
# define alloca __alloca
#elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
#else
# include <stddef.h>
# ifdef __cplusplus
extern "C"
# endif
void *alloca (size_t);
#endif
#include <string.h>
#ifndef _WIN32
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <dirent.h>
#else
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
# include <Evil.h>
#endif /* _WIN2 */
#ifndef _WIN32
# define PATH_DELIM '/'
#else
# define PATH_DELIM '\\'
#endif
#include "eina_config.h"
#include "eina_private.h"
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
#include "eina_safety_checks.h"
#include "eina_file.h"
/*============================================================================*
* Global *
*============================================================================*/
/*============================================================================*
* API *
*============================================================================*/
/**
* @addtogroup Eina_File_Group File
*
* @brief Functions to traverse directories and split paths.
*
* @li eina_file_dir_list() list the content of a directory,
* recusrsively or not, and can call a callback function for eachfound
* file.
* @li eina_file_split() split a path into all the subdirectories that
* compose it, according to the separator of the file system.
*
* @{
*/
/**
* @brief List all files on the directory calling the function for every file found.
*
* @param dir The directory name.
* @param recursive Iterate recursively in the directory.
* @param cb The callback to be called.
* @param data The data to pass to the callback.
* @return #EINA_TRUE on success, #EINA_FALSE oterwise.
*
* This function lists all the files in @p dir. To list also all the
* sub directoris recursively, @p recursive must be set to #EINA_TRUE,
* otherwise it must be set to #EINA_FALSE. For each found file, @p cb
* is called and @p data is passed to it.
*
* If @p cb or @p dir are @c NULL, or if @p dir is a string of size 0,
* or if @p dir can not be opened, this function returns #EINA_FALSE
* immediatly. otherwise, it returns #EINA_TRUE.
*/
EAPI Eina_Bool
eina_file_dir_list(const char *dir, Eina_Bool recursive, Eina_File_Dir_List_Cb cb, void *data)
{
#ifndef _WIN32
struct dirent *de;
DIR *d;
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
d = opendir(dir);
if (!d) return EINA_FALSE;
while ((de = readdir(d)))
{
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
cb(de->d_name, dir, data);
/* d_type is only available on linux and bsd (_BSD_SOURCE) */
if (recursive == EINA_TRUE) {
char *path;
path = alloca(strlen(dir) + strlen(de->d_name) + 2);
strcpy(path, dir);
strcat(path, "/");
strcat(path, de->d_name);
#ifndef sun
if (de->d_type == DT_UNKNOWN) {
#endif
struct stat st;
if (stat(path, &st))
continue ;
if (!S_ISDIR(st.st_mode))
continue ;
#ifndef sun
} else if (de->d_type != DT_DIR) {
continue ;
}
#endif
eina_file_dir_list(path, recursive, cb, data);
}
}
closedir(d);
#else
WIN32_FIND_DATA file;
HANDLE hSearch;
char *new_dir;
TCHAR *tdir;
size_t length_dir;
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
length_dir = strlen(dir);
new_dir = (char *)alloca(length_dir + 5);
if (!new_dir) return EINA_FALSE;
memcpy(new_dir, dir, length_dir);
memcpy(new_dir + length_dir, "/*.*", 5);
#ifdef UNICODE
tdir = evil_char_to_wchar(new_dir);
#else
tdir = new_dir;
#endif /* ! UNICODE */
hSearch = FindFirstFile(tdir, &file);
#ifdef UNICODE
free(tdir);
#endif /* UNICODE */
if (hSearch == INVALID_HANDLE_VALUE) return EINA_FALSE;
do
{
char *filename;
#ifdef UNICODE
filename = evil_wchar_to_char(file.cFileName);
#else
filename = file.cFileName;
#endif /* ! UNICODE */
if (!strcmp(filename, ".") || !strcmp(filename, ".."))
continue;
cb(filename, dir, data);
if (recursive == EINA_TRUE) {
char *path;
path = alloca(strlen(dir) + strlen(filename) + 2);
strcpy(path, dir);
strcat(path, "/");
strcat(path, filename);
if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
continue ;
eina_file_dir_list(path, recursive, cb, data);
}
#ifdef UNICODE
free(filename);
#endif /* UNICODE */
} while (FindNextFile(hSearch, &file));
FindClose(hSearch);
#endif /* _WIN32 */
return EINA_TRUE;
}
/**
* @brief Split a path according to the delimiter of the filesystem.
*
* @param path The path to split.
* @return An array of the parts of the path to split.
*
* This function splits @p path according to the delimiter of the used
* filesystem. If @p path is @c NULL or if the array can not be
* created, @c NULL is returned, otherwise, an array with the
* different parts of @p path is returned.
*/
EAPI Eina_Array *
eina_file_split(char *path)
{
Eina_Array *ea;
char *current;
size_t length;
EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
ea = eina_array_new(16);
if (!ea) return NULL;
for (current = strchr(path, PATH_DELIM);
current != NULL;
path = current + 1, current = strchr(path, PATH_DELIM))
{
length = current - path;
if (length <= 0) continue ;
eina_array_push(ea, path);
*current = '\0';
}
if (*path != '\0')
eina_array_push(ea, path);
return ea;
}
/**
* @}
*/