diff --git a/src/utils/file_utils.c b/src/utils/file_utils.c index 69c1f98e6..cb559a5bf 100644 --- a/src/utils/file_utils.c +++ b/src/utils/file_utils.c @@ -24,8 +24,6 @@ #include "utils/dirent.h" #define PATH_MAX 260 -// dirname and basename on windows -#include "win_dirname_basename.h" // copied from https://github.com/kindkaktus/libconfig/commit/d6222551c5c01c326abc99627e151d549e0f0958 #ifndef S_ISDIR @@ -69,6 +67,66 @@ char *strip_drive_prefix(char *path) #endif +static inline bool is_path_separator(char c) +{ +#if PLATFORM_WINDOWS + return c == '/' || c == '\'; +#else + return c == '/'; +#endif +} + +/** + * Split a file into path + filename, allocating memory for them and returning them in + * the out params + * 'foo' => '.' / 'foo' + * '/' => false + * '.' => false + * '..' => false + * 'bar/' => false + * + * @param path the path to extract the filename from. + * @param filename_ptr the pointer to return the filename in. + * @param directory_ptr the pointer to return the directory in. + * @return false if only a directory could be found, true otherwise + */ +bool filenamesplit(const char *path, char** filename_ptr, char** directory_ptr) +{ + size_t len = strlen(path); + if (len == 0) return false; + size_t found_at = (size_t)-1; + for (size_t i = len - 1; i > 0; i--) + { + if (is_path_separator(path[i])) + { + found_at = i; + break; + } + } + size_t file_len = (found_at != ((size_t)-1)) ? len - found_at - 1 : len; + if (file_len == 1 && path[0] == '.') return false; + if (file_len == 2 && path[0] == '.' && path[1] == '.') return false; + if (!file_len) return false; + *filename_ptr = strdup(&path[len - file_len]); + if (file_len < len) + { + size_t dir_len = len - file_len; + char *dir = malloc(dir_len + 1); + memcpy(dir, path, dir_len - 1); + dir[dir_len] = 0; + *directory_ptr = dir; + } + else + { + char *dir = malloc(2); + dir[0] = '.'; + dir[1] = 0; + *directory_ptr = dir; + } + return true; +} + + const char *expand_path(const char *path) { @@ -153,15 +211,10 @@ const char *find_lib_dir(void) void path_get_dir_and_filename_from_full(const char *full_path, char **filename, char **dir_path) { - char path[1024]; - size_t path_len = strlen(full_path); - if (path_len >= sizeof(path)) error_exit("Path %s too long.", full_path); - - strcpy(path, full_path); - *filename = strdup(basename(path)); - - strcpy(path, full_path); - *dir_path = strdup(dirname(path)); + if (!filenamesplit(full_path, filename, dir_path)) + { + error_exit("The filename could not be extracted from '%s'.", full_path); + } } diff --git a/src/utils/lib.h b/src/utils/lib.h index 6b14b2ed2..ec5e15e64 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -21,6 +21,7 @@ typedef struct Task_ typedef void *TaskQueueRef; +bool filenamesplit(const char *path, char** filename_ptr, char** directory_ptr); const char* expand_path(const char* path); const char* find_lib_dir(void); char *read_file(const char *path, size_t *return_size); diff --git a/src/utils/win_dirname_basename.h b/src/utils/win_dirname_basename.h deleted file mode 100644 index dee5bbf39..000000000 --- a/src/utils/win_dirname_basename.h +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include - -// TODO I made these super quickly so they probably have some bugs from cases I didn't think of. -// A better implementation of these functions may be necessary. - -char* basename(char* path) -{ - size_t len = strlen(path); - size_t lastSlash = 0; - for (size_t i = len - 2; i > 0; i--) - { - if (path[i] == '\\' || path[i] == '/') - { - if (i == len) - { - continue; - } - lastSlash = i; - break; - } - if (i == 0) - { - // according to `man 3 basename` if there is no /, the original path should be returned - char* newStr = (char*)malloc(len); - strcpy(newStr, path); - return newStr; - } - } - size_t newSize = len - lastSlash - 1; - char* newStr = (char*)malloc(newSize); - strncpy(newStr, path + lastSlash + 1, newSize); - return newStr; -} - -char* dirname(char* path) -{ - size_t len = strlen(path); - size_t lastSlash = 0; - for (size_t i = len - 2; i > 0; i--) - { - if (path[i] == '\\' || path[i] == '/') - { - if (i == len) - { - continue; - } - lastSlash = i; - break; - } - if (i == 0) - { - // according to `man 3 basename` if there is no /, "." should be returned - char* newStr = (char*)malloc(2); - strcpy(newStr, "."); - return newStr; - } - } - // size_t newSize = len - lastSlash - 1; - char* newStr = (char*)malloc(lastSlash); - strncpy(newStr, path, lastSlash); - return newStr; -} \ No newline at end of file