diff --git a/driver.c b/driver.c index 388c36b5f6..9e68309839 100644 --- a/driver.c +++ b/driver.c @@ -484,28 +484,31 @@ static void deinit_filter(void) #endif #ifdef HAVE_XML +static void deinit_shader_dir(void) +{ + // It handles NULL, no worries :D + dir_list_free(g_extern.shader_dir.list); + g_extern.shader_dir.list = NULL; + g_extern.shader_dir.ptr = 0; +} + 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 = dir_list_size(g_extern.shader_dir.elems); - g_extern.shader_dir.ptr = 0; + g_extern.shader_dir.list = dir_list_new(g_settings.video.shader_dir, "shader", false); + if (g_extern.shader_dir.list->size == 0) + { + deinit_shader_dir(); + return; + } - dir_list_sort(g_extern.shader_dir.elems, false); + g_extern.shader_dir.ptr = 0; + dir_list_sort(g_extern.shader_dir.list, false); - for (unsigned i = 0; i < g_extern.shader_dir.size; i++) - RARCH_LOG("Found shader \"%s\"\n", g_extern.shader_dir.elems[i]); -} - -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; + for (unsigned i = 0; i < g_extern.shader_dir.list->size; i++) + RARCH_LOG("Found shader \"%s\"\n", g_extern.shader_dir.list->elems[i].data); } #endif diff --git a/file.h b/file.h index b4f4179bb0..467f5b75a8 100644 --- a/file.h +++ b/file.h @@ -36,13 +36,30 @@ void save_ram_file(const char *path, int type); bool init_rom_file(enum rarch_game_type type); -// Returns a NULL-terminated list of files in a directory with full paths. -// If ext is NULL, any file will be picked. -// If non-NULL, only files with extension ext are added. -char **dir_list_new(const char *dir, const char *ext, bool include_dirs); -size_t dir_list_size(char * const *dir_list); -void dir_list_sort(char **dir_list, bool dir_first); -void dir_list_free(char **dir_list); +// Yep, this is C alright ;) +union string_list_elem_attr +{ + bool b; + int i; + void *p; +}; + +struct string_list_elem +{ + char *data; + union string_list_elem_attr attr; +}; + +struct string_list +{ + struct string_list_elem *elems; + size_t size; + size_t cap; +}; + +struct string_list *dir_list_new(const char *dir, const char *ext, bool include_dirs); +void dir_list_sort(struct string_list *list, bool dir_first); +void dir_list_free(struct string_list *list); bool path_is_directory(const char *path); bool path_file_exists(const char *path); diff --git a/file_path.c b/file_path.c index 860f3cf69e..c19ee2050b 100644 --- a/file_path.c +++ b/file_path.c @@ -43,111 +43,105 @@ #include #endif -// Yep, this is C alright ;) -struct string_list +static void string_list_free(struct string_list *list) { - char **data; - size_t size; - size_t cap; -}; + if (!list) + return; + + for (size_t i = 0; i < list->size; i++) + free(list->elems[i].data); + free(list->elems); + free(list); +} 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*)); + struct string_list_elem *new_data = (struct string_list_elem*)realloc(list->elems, cap * sizeof(*new_data)); if (!new_data) return false; - list->data = new_data; - list->cap = cap; + list->elems = new_data; + list->cap = cap; return true; } -static bool string_list_init(struct string_list *list) +static struct string_list *string_list_new(void) { - memset(list, 0, sizeof(*list)); - return string_list_capacity(list, 32); + struct string_list *list = (struct string_list*)calloc(1, sizeof(*list)); + if (!list) + return NULL; + + if (!string_list_capacity(list, 32)) + { + string_list_free(list); + return NULL; + } + + return list; } -static bool string_list_append(struct string_list *list, const char *elem) +static bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr) { - if (list->size + 1 >= list->cap && !string_list_capacity(list, list->cap * 2)) + if (list->size >= list->cap && + !string_list_capacity(list, list->cap * 2)) return false; - if (!(list->data[list->size] = strdup(elem))) + char *dup = strdup(elem); + if (!dup) return false; + list->elems[list->size].data = dup; + list->elems[list->size].attr = attr; + 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) +static struct string_list *string_split(const char *str, const char *delim) { char *copy = NULL; const char *tmp = NULL; - struct string_list list; - - if (!string_list_init(&list)) + struct string_list *list = string_list_new(); + if (!list) goto error; copy = strdup(str); if (!copy) - return NULL; + goto error; tmp = strtok(copy, delim); while (tmp) { - if (!string_list_append(&list, tmp)) + union string_list_elem_attr attr; + memset(&attr, 0, sizeof(attr)); + + if (!string_list_append(list, tmp, attr)) goto error; tmp = strtok(NULL, delim); } free(copy); - return string_list_finalize(&list); + return list; error: - string_list_cleanup(&list); + string_list_free(list); free(copy); return NULL; } -static bool string_list_find_elem(char * const *list, const char *elem) +static bool string_list_find_elem(const struct string_list *list, const char *elem) { if (!list) return false; - for (; *list; list++) - if (strcmp(*list, elem) == 0) + for (size_t i = 0; i < list->size; i++) + { + if (strcmp(list->elems[i].data, elem) == 0) return true; + } return false; } @@ -161,50 +155,42 @@ static const char *path_get_extension(const char *path) return ""; } -size_t dir_list_size(char * const *dir_list) +static int qstrcmp_plain(const void *a_, const void *b_) { - if (!dir_list) - return 0; + const struct string_list_elem *a = (const struct string_list_elem*)a_; + const struct string_list_elem *b = (const struct string_list_elem*)b_; - size_t size = 0; - while (*dir_list++) - size++; - - return size; -} - -static int qstrcmp_plain(const void *a, const void *b) -{ - return strcasecmp(*(const char * const*)a, *(const char * const*)b); + return strcasecmp(a->data, b->data); } static int qstrcmp_dir(const void *a_, const void *b_) { - const char *a = *(const char * const*)a_; - const char *b = *(const char * const*)b_; + const struct string_list_elem *a = (const struct string_list_elem*)a_; + const struct string_list_elem *b = (const struct string_list_elem*)b_; // Sort directories before files. - int a_dir = path_is_directory(a); - int b_dir = path_is_directory(b); + int a_dir = a->attr.b; + int b_dir = b->attr.b; if (a_dir != b_dir) return b_dir - a_dir; - - return strcasecmp(a, b); + else + return strcasecmp(a->data, b->data); } -void dir_list_sort(char **dir_list, bool dir_first) +void dir_list_sort(struct string_list *list, bool dir_first) { - if (!dir_list) + if (!list) return; - qsort(dir_list, dir_list_size(dir_list), sizeof(char*), dir_first ? qstrcmp_dir : qstrcmp_plain); + qsort(list->elems, list->size, sizeof(struct string_list_elem), + dir_first ? qstrcmp_dir : qstrcmp_plain); } #ifdef _WIN32 // Because the API is just fucked up ... -char **dir_list_new(const char *dir, const char *ext, bool include_dirs) +struct string_list *dir_list_new(const char *dir, const char *ext, bool include_dirs) { - struct string_list list; - if (!string_list_init(&list)) + struct string_list *list = string_list_new(); + if (!list) return NULL; HANDLE hFind = INVALID_HANDLE_VALUE; @@ -213,7 +199,7 @@ char **dir_list_new(const char *dir, const char *ext, bool include_dirs) char path_buf[PATH_MAX]; snprintf(path_buf, sizeof(path_buf), "%s\\*", dir); - char **ext_list = NULL; + struct string_list *ext_list = NULL; if (ext) ext_list = string_split(ext, "|"); @@ -236,35 +222,38 @@ char **dir_list_new(const char *dir, const char *ext, bool include_dirs) char file_path[PATH_MAX]; snprintf(file_path, sizeof(file_path), "%s\\%s", dir, name); - if (!string_list_append(&list, file_path)) + union string_list_elem_attr attr; + attr.b = is_dir; + + if (!string_list_append(list, file_path, attr)) goto error; } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); string_list_free(ext_list); - return string_list_finalize(&list); + return 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(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 *dir_list_new(const char *dir, const char *ext, bool include_dirs) { - struct string_list list; - if (!string_list_init(&list)) + struct string_list *list = string_list_new(); + if (!list) return NULL; DIR *directory = NULL; const struct dirent *entry = NULL; - char **ext_list = NULL; + struct string_list *ext_list = NULL; if (ext) ext_list = string_split(ext, "|"); @@ -287,14 +276,17 @@ char **dir_list_new(const char *dir, const char *ext, bool include_dirs) char file_path[PATH_MAX]; snprintf(file_path, sizeof(file_path), "%s/%s", dir, name); - if (!string_list_append(&list, file_path)) + union string_list_elem_attr attr; + attr.b = is_dir; + + if (!string_list_append(list, file_path, attr)) goto error; } closedir(directory); string_list_free(ext_list); - return string_list_finalize(&list); + return list; error: RARCH_ERR("Failed to open directory: \"%s\"\n", dir); @@ -302,15 +294,15 @@ error: if (directory) closedir(directory); - string_list_cleanup(&list); + string_list_free(list); string_list_free(ext_list); return NULL; } #endif -void dir_list_free(char **dir_list) +void dir_list_free(struct string_list *list) { - string_list_free(dir_list); + string_list_free(list); } bool path_is_directory(const char *path) diff --git a/general.h b/general.h index 8a4f022c4e..fb40bc17ff 100644 --- a/general.h +++ b/general.h @@ -449,8 +449,7 @@ struct global struct { - char **elems; - size_t size; + struct string_list *list; size_t ptr; } shader_dir; diff --git a/retroarch.c b/retroarch.c index 36f8b6478b..e54ac4c89a 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1513,6 +1513,9 @@ static void set_savestate_auto_index(void) if (!g_settings.savestate_auto_index) return; + // Find the file in the same directory as g_extern.savestate_name with the largest numeral suffix. + // E.g. /foo/path/game.state, will try to find /foo/path/game.state%d, where %d is the largest number available. + char state_path[PATH_MAX]; strlcpy(state_path, g_extern.savestate_name, sizeof(state_path)); @@ -1527,22 +1530,23 @@ static void set_savestate_auto_index(void) *split = '\0'; base = split + 1; } + else + dir = "."; unsigned max_index = 0; - char **dir_list = dir_list_new(dir, NULL, false); + struct string_list *dir_list = dir_list_new(dir, NULL, false); if (!dir_list) return; - unsigned index = 0; - const char *dir_elem; - while ((dir_elem = dir_list[index++])) + for (size_t i = 0; i < dir_list->size; i++) { - if (!strstr(dir_elem, base)) + const char *dir_elem = dir_list->elems[i].data; + if (strstr(dir_elem, base) != dir_elem) continue; const char *end = dir_elem + strlen(dir_elem); - while ((end != dir_elem) && isdigit(end[-1])) end--; + while ((end > dir_elem) && isdigit(end[-1])) end--; unsigned index = strtoul(end, NULL, 0); if (index > max_index) @@ -2128,7 +2132,7 @@ static void check_shader_dir(void) static bool old_pressed_next = false; static bool old_pressed_prev = false; - if (!g_extern.shader_dir.elems || !driver.video->xml_shader) + if (!g_extern.shader_dir.list || !driver.video->xml_shader) return; bool should_apply = false; @@ -2137,20 +2141,20 @@ static void check_shader_dir(void) if (pressed_next && !old_pressed_next) { should_apply = true; - g_extern.shader_dir.ptr = (g_extern.shader_dir.ptr + 1) % g_extern.shader_dir.size; + g_extern.shader_dir.ptr = (g_extern.shader_dir.ptr + 1) % g_extern.shader_dir.list->size; } else if (pressed_prev && !old_pressed_prev) { should_apply = true; if (g_extern.shader_dir.ptr == 0) - g_extern.shader_dir.ptr = g_extern.shader_dir.size - 1; + g_extern.shader_dir.ptr = g_extern.shader_dir.list->size - 1; else g_extern.shader_dir.ptr--; } if (should_apply) { - const char *shader = g_extern.shader_dir.elems[g_extern.shader_dir.ptr]; + const char *shader = g_extern.shader_dir.list->elems[g_extern.shader_dir.ptr].data; strlcpy(g_settings.video.bsnes_shader_path, shader, sizeof(g_settings.video.bsnes_shader_path)); g_settings.video.shader_type = RARCH_SHADER_BSNES;