MAJOR refactor of dir_list_new.

This commit is contained in:
Themaister 2012-06-18 00:34:47 +02:00
parent e71115151b
commit e455e52e06
3 changed files with 209 additions and 115 deletions

View File

@ -87,9 +87,9 @@ static void find_and_set_first_file(void)
// we can find in the RetroArch cores directory
#if defined(_XBOX)
char ** dir_list = dir_list_new("game:\\", ".xex", false);
char ** dir_list = dir_list_new("game:\\", "xex", false);
#elif defined(__CELLOS_LV2__)
char ** dir_list = dir_list_new(LIBRETRO_DIR_PATH, ".SELF", false);
char ** dir_list = dir_list_new(LIBRETRO_DIR_PATH, "SELF", false);
#endif
if (!dir_list)

View File

@ -417,6 +417,7 @@ static void init_filter(void)
(void (*)(uint32_t*, uint32_t*,
unsigned, const uint16_t*,
unsigned, unsigned, unsigned))dylib_proc(g_extern.filter.lib, "filter_render");
if (!g_extern.filter.psize || !g_extern.filter.prender)
{
RARCH_ERR("Failed to find functions in filter...\n");
@ -428,28 +429,30 @@ static void init_filter(void)
g_extern.filter.active = true;
struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
unsigned width = geom->max_width;
unsigned width = geom->max_width;
unsigned height = geom->max_height;
g_extern.filter.psize(&width, &height);
unsigned pow2_x = next_pow2(width);
unsigned pow2_y = next_pow2(height);
unsigned pow2_x = next_pow2(width);
unsigned pow2_y = next_pow2(height);
unsigned maxsize = pow2_x > pow2_y ? pow2_x : pow2_y;
g_extern.filter.scale = maxsize / RARCH_SCALE_BASE;
g_extern.filter.buffer = (uint32_t*)malloc(RARCH_SCALE_BASE * RARCH_SCALE_BASE * g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.pitch = RARCH_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
g_extern.filter.buffer = (uint32_t*)malloc(RARCH_SCALE_BASE * RARCH_SCALE_BASE *
g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
rarch_assert(g_extern.filter.buffer);
g_extern.filter.colormap = (uint32_t*)malloc(32768 * sizeof(uint32_t));
g_extern.filter.pitch = RARCH_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
g_extern.filter.colormap = (uint32_t*)malloc(0x10000 * sizeof(uint32_t));
rarch_assert(g_extern.filter.colormap);
// Set up conversion map from 16-bit XRGB1555 to 32-bit ARGB.
for (unsigned i = 0; i < 32768; i++)
for (unsigned i = 0; i < 0x10000; i++)
{
unsigned r = (i >> 10) & 31;
unsigned g = (i >> 5) & 31;
unsigned b = (i >> 0) & 31;
unsigned r = (i >> 10) & 0x1f;
unsigned g = (i >> 5) & 0x1f;
unsigned b = (i >> 0) & 0x1f;
r = (r << 3) | (r >> 2);
g = (g << 3) | (g >> 2);
@ -477,9 +480,10 @@ static void init_shader_dir(void)
if (!*g_settings.video.shader_dir)
return;
g_extern.shader_dir.elems = dir_list_new(g_settings.video.shader_dir, ".shader", false);
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
g_extern.shader_dir.elems = dir_list_new(g_settings.video.shader_dir, "shader", false);
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
if (g_extern.shader_dir.elems)
{
while (g_extern.shader_dir.elems[g_extern.shader_dir.size])
@ -495,8 +499,8 @@ static void deinit_shader_dir(void)
// It handles NULL, no worries :D
dir_list_free(g_extern.shader_dir.elems);
g_extern.shader_dir.elems = NULL;
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
g_extern.shader_dir.size = 0;
g_extern.shader_dir.ptr = 0;
}
#endif

View File

@ -43,141 +43,231 @@
#endif
// Yep, this is C alright ;)
struct string_list
{
char **data;
size_t size;
size_t cap;
};
static bool string_list_capacity(struct string_list *list, size_t cap)
{
rarch_assert(cap > list->size);
char **new_data = (char**)realloc(list->data, cap * sizeof(char*));
if (!new_data)
return false;
list->data = new_data;
list->cap = cap;
return true;
}
static bool string_list_init(struct string_list *list)
{
memset(list, 0, sizeof(*list));
return string_list_capacity(list, 32);
}
static bool string_list_append(struct string_list *list, const char *elem)
{
if (list->size + 1 >= list->cap && !string_list_capacity(list, list->cap * 2))
return false;
if (!(list->data[list->size] = strdup(elem)))
return false;
list->size++;
return true;
}
static char **string_list_finalize(struct string_list *list)
{
rarch_assert(list->cap > list->size);
list->data[list->size] = NULL;
return list->data;
}
static void string_list_cleanup(struct string_list *list)
{
for (size_t i = 0; i < list->size; i++)
free(list->data[i]);
free(list->data);
memset(list, 0, sizeof(*list));
}
static void string_list_free(char **list)
{
if (!list)
return;
char **orig = list;
while (*list)
free(*list++);
free(orig);
}
static char **string_split(const char *str, const char *delim)
{
char *copy = NULL;
struct string_list list;
if (!string_list_init(&list))
goto error;
copy = strdup(str);
if (!copy)
return NULL;
const char *tmp = strtok(copy, delim);
while (tmp)
{
if (!string_list_append(&list, tmp))
goto error;
tmp = strtok(NULL, delim);
}
free(copy);
return string_list_finalize(&list);
error:
string_list_cleanup(&list);
free(copy);
return NULL;
}
static bool string_list_find_elem(char * const *list, const char *elem)
{
if (!list)
return false;
for (; *list; list++)
if (strcmp(*list, elem) == 0)
return true;
return false;
}
static const char *path_get_extension(const char *path)
{
const char *ext = strrchr(path, '.');
if (ext)
return ext + 1;
else
return "";
}
#ifdef _WIN32 // Because the API is just fucked up ...
char **dir_list_new(const char *dir, const char *ext, bool include_dirs)
{
size_t cur_ptr = 0;
size_t cur_size = 32;
char **dir_list = NULL;
struct string_list list;
if (!string_list_init(&list))
return NULL;
#ifdef _WIN32
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
char path_buf[PATH_MAX];
snprintf(path_buf, sizeof(path_buf), "%s\\*", dir);
if (strlcpy(path_buf, dir, sizeof(path_buf)) >= sizeof(path_buf))
goto error;
#ifdef _XBOX
if (strlcat(path_buf, "*", sizeof(path_buf)) >= sizeof(path_buf))
#else
if (strlcat(path_buf, "/*", sizeof(path_buf)) >= sizeof(path_buf))
#endif
goto error;
char **ext_list = NULL;
if (ext)
{
if (strlcat(path_buf, ext, sizeof(path_buf)) >= sizeof(path_buf))
goto error;
}
ext_list = string_split(ext, "|");
hFind = FindFirstFile(path_buf, &ffd);
if (hFind == INVALID_HANDLE_VALUE)
goto error;
do
{
const char *name = ffd.cFileName;
const char *file_ext = path_get_extension(name);
if (!include_dirs && path_is_directory(name))
continue;
if (!string_list_find_elem(ext_list, file_ext))
continue;
char file_path[PATH_MAX];
snprintf(file_path, sizeof(file_path), "%s\\%s", dir, name);
if (!string_list_append(&list, file_path))
goto error;
}
while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
string_list_free(ext_list);
return string_list_finalize(&list);
error:
RARCH_ERR("Failed to open directory: \"%s\"\n", dir);
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
string_list_cleanup(&list);
string_list_free(ext_list);
return NULL;
}
#else
char **dir_list_new(const char *dir, const char *ext, bool include_dirs)
{
struct string_list list;
if (!string_list_init(&list))
return NULL;
DIR *directory = NULL;
const struct dirent *entry = NULL;
char **ext_list = NULL;
if (ext)
ext_list = string_split(ext, "|");
directory = opendir(dir);
if (!directory)
goto error;
#endif
dir_list = (char**)calloc(cur_size, sizeof(char*));
if (!dir_list)
goto error;
#ifdef _WIN32 // Hard to read? Blame non-POSIX heathens!
do
#else
while ((entry = readdir(directory)))
#endif
{
// Not a perfect search of course, but hopefully good enough in practice.
#ifdef _WIN32
if (include_dirs)
{
if (ext && !strstr(ffd.cFileName, ext) && !path_is_directory(ffd.cFileName))
continue;
}
else
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
if (ext && !strstr(ffd.cFileName, ext))
continue;
}
#else
if (include_dirs)
{
if (ext && !strstr(entry->d_name, ext) && !path_is_directory(entry->d_name))
continue;
}
else
{
if (ext && !strstr(entry->d_name, ext))
continue;
}
#endif
const char *name = entry->d_name;
const char *file_ext = path_get_extension(name);
dir_list[cur_ptr] = (char*)malloc(PATH_MAX);
if (!dir_list[cur_ptr])
if (!include_dirs && path_is_directory(name))
continue;
if (!string_list_find_elem(ext_list, file_ext))
continue;
char file_path[PATH_MAX];
snprintf(file_path, sizeof(file_path), "%s/%s", dir, name);
if (!string_list_append(&list, file_path))
goto error;
strlcpy(dir_list[cur_ptr], dir, PATH_MAX);
#ifndef _XBOX
strlcat(dir_list[cur_ptr], "/", PATH_MAX);
#endif
#ifdef _WIN32
strlcat(dir_list[cur_ptr], ffd.cFileName, PATH_MAX);
#else
strlcat(dir_list[cur_ptr], entry->d_name, PATH_MAX);
#endif
cur_ptr++;
if (cur_ptr + 1 == cur_size) // Need to reserve for NULL.
{
cur_size *= 2;
dir_list = (char**)realloc(dir_list, cur_size * sizeof(char*));
if (!dir_list)
goto error;
// Make sure it's all NULL'd out since we cannot rely on realloc to do this.
memset(dir_list + cur_ptr, 0, (cur_size - cur_ptr) * sizeof(char*));
}
}
#if defined(_WIN32)
while (FindNextFile(hFind, &ffd) != 0);
#endif
#ifdef _WIN32
FindClose(hFind);
#else
closedir(directory);
#endif
return dir_list;
string_list_free(ext_list);
return string_list_finalize(&list);
error:
RARCH_ERR("Failed to open directory: \"%s\"\n", dir);
#ifdef _WIN32
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
#else
if (directory)
closedir(directory);
#endif
dir_list_free(dir_list);
string_list_cleanup(&list);
string_list_free(ext_list);
return NULL;
}
#endif
void dir_list_free(char **dir_list)
{
if (!dir_list)
return;
char **orig = dir_list;
while (*dir_list)
free(*dir_list++);
free(orig);
string_list_free(dir_list);
}
bool path_is_directory(const char *path)