#include #include #include #include static const path Empty = (path){0, 0}; path path_new(const char* str) { assert(str); const size_t size = strlen(str); if (size > 0) { char* data = calloc(size + 1, sizeof(char)); // +1 for null memcpy(data, str, size); data[size] = 0; return (path){data, size}; } return Empty; } void path_del(path* path) { if (path) { free(path->data); path->data = 0; path->size = 0; } } path path_parent_dir(path p) { assert(p.data); if (p.size == 0) { return Empty; } size_t i = p.size - 1; // If the path ends with '/', skip the characters. while ((i > 0) && (p.data[i] == '/')) { i--; } // Search backwards for the parent dir. for (; i > 0; --i) { if (p.data[i] == '/') { return (path){p.data, i + 1}; } } return Empty; // No parent. } path path_concat(path left, path right) { assert(left.data); assert(right.data); // +1 for separator. const size_t out_size = left.size + right.size + 1; // +1 for null. char* out = calloc(out_size + 1, sizeof(char)); ASSERT(out); memcpy(out, left.data, left.size); out[left.size] = '/'; memcpy(out + left.size + 1, right.data, right.size); out[out_size] = 0; return (path){out, out_size}; } bool path_make_relative( const char* filepath, const char* path, char* relative, size_t relative_length) { assert(filepath); assert(path); assert(relative); const size_t filepath_len = strlen(filepath); const size_t path_len = strlen(path); assert(filepath_len < relative_length); assert(path_len < relative_length); // Handle empty filepath. if (filepath_len == 0) { memcpy(relative, path, path_len); return true; } // Search for the last / in the file path to get its parent directory. assert(filepath_len > 0); size_t tm_dir_len = 0; for (tm_dir_len = strlen(filepath) - 1; tm_dir_len > 0; --tm_dir_len) { if (filepath[tm_dir_len] == '/') { break; } } tm_dir_len++; // Preserve the backslash. // Copy the file path where the parent dir ends. // Make sure there is enough space in the output. if ((tm_dir_len + path_len + 1) >= relative_length) { return false; } memcpy(relative, filepath, tm_dir_len); memcpy(&relative[tm_dir_len], path, path_len); return true; }