diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bed693..4b53330 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ add_executable(test_simplearchiver src/test.c src/parser.c src/helpers.c + src/archiver.c src/algorithms/linear_congruential_gen.c src/data_structures/linked_list.c src/data_structures/hash_map.c diff --git a/src/archiver.c b/src/archiver.c index b50a8b8..b151dca 100644 --- a/src/archiver.c +++ b/src/archiver.c @@ -767,46 +767,8 @@ int write_files_fn(void *data, void *ud) { // fprintf(stderr, "DEBUG: abs_path: %s\nDEBUG: link_abs_path: %s\n", // (char*)abs_path, (char*)link_abs_path); - // Compare paths to get relative path. - // Get first non-common char. - size_t idx; - size_t last_slash; - for (idx = 0, last_slash = 0; - idx < strlen(abs_path) && idx < strlen(link_abs_path); ++idx) { - if (((const char *)abs_path)[idx] != - ((const char *)link_abs_path)[idx]) { - break; - } else if (((const char *)abs_path)[idx] == '/') { - last_slash = idx + 1; - } - } - // Get substrings of both paths. - char *link_substr = (char *)link_abs_path + last_slash; - char *dest_substr = (char *)abs_path + last_slash; - rel_path = malloc(strlen(dest_substr) + 1); - strncpy(rel_path, dest_substr, strlen(dest_substr) + 1); - // fprintf(stderr, "DEBUG: link_substr: %s\nDEBUG: dest_substr: %s\n", - // link_substr, dest_substr); - - // Generate the relative path. - int_fast8_t has_slash = 0; - idx = 0; - do { - for (; link_substr[idx] != '/' && link_substr[idx] != 0; ++idx); - if (link_substr[idx] == 0) { - has_slash = 0; - } else { - has_slash = 1; - char *new_rel_path = malloc(strlen(rel_path) + 1 + 3); - new_rel_path[0] = '.'; - new_rel_path[1] = '.'; - new_rel_path[2] = '/'; - strncpy(new_rel_path + 3, rel_path, strlen(rel_path) + 1); - free(rel_path); - rel_path = new_rel_path; - ++idx; - } - } while (has_slash); + rel_path = + simple_archiver_filenames_to_relative_path(link_abs_path, abs_path); } } @@ -3015,3 +2977,53 @@ int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2], return 1; #endif } + +char *simple_archiver_filenames_to_relative_path(const char *from_abs, + const char *to_abs) { + if (!from_abs || !to_abs) { + return NULL; + } + + // Get first non-common char and last slash before it. + uint_fast32_t idx; + uint_fast32_t last_slash; + for (idx = 0, last_slash = 0; idx < strlen(from_abs) && idx < strlen(to_abs); + ++idx) { + if (((const char *)to_abs)[idx] != ((const char *)from_abs)[idx]) { + break; + } else if (((const char *)to_abs)[idx] == '/') { + last_slash = idx + 1; + } + } + + // Get substrings of both paths. + char *link_substr = (char *)from_abs + last_slash; + char *dest_substr = (char *)to_abs + last_slash; + char *rel_path = malloc(strlen(dest_substr) + 1); + strncpy(rel_path, dest_substr, strlen(dest_substr) + 1); + + // fprintf(stderr, "DEBUG: link_substr \"%s\", dest_substr \"%s\"\n", + // link_substr, dest_substr); + + // Get the relative path finally. + int_fast8_t has_slash = 0; + idx = 0; + do { + for (; link_substr[idx] != '/' && link_substr[idx] != 0; ++idx); + if (link_substr[idx] == 0) { + has_slash = 0; + } else { + has_slash = 1; + char *new_rel_path = malloc(strlen(rel_path) + 1 + 3); + new_rel_path[0] = '.'; + new_rel_path[1] = '.'; + new_rel_path[2] = '/'; + strncpy(new_rel_path + 3, rel_path, strlen(rel_path) + 1); + free(rel_path); + rel_path = new_rel_path; + ++idx; + } + } while (has_slash); + + return rel_path; +} diff --git a/src/archiver.h b/src/archiver.h index 2b8fbf2..6039852 100644 --- a/src/archiver.h +++ b/src/archiver.h @@ -88,4 +88,8 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2], const char *cmd, void *pid_out); +/// If returns non-NULL, must be free'd. +char *simple_archiver_filenames_to_relative_path(const char *from_abs, + const char *to_abs); + #endif diff --git a/src/test.c b/src/test.c index 869816f..13caba9 100644 --- a/src/test.c +++ b/src/test.c @@ -23,6 +23,7 @@ #include // Local includes. +#include "archiver.h" #include "helpers.h" #include "parser_internal.h" @@ -241,6 +242,21 @@ int main(void) { free(out); } + // Test archiver. + { + __attribute__(( + cleanup(simple_archiver_helper_cleanup_c_string))) char *rel_path = + simple_archiver_filenames_to_relative_path( + "/one/two/three/four/five", "/one/two/branch/other/path"); + CHECK_STREQ(rel_path, "../../branch/other/path"); + simple_archiver_helper_cleanup_c_string(&rel_path); + + rel_path = simple_archiver_filenames_to_relative_path( + "/one/two/three/four/five", "/one/two/three/other/dir/"); + CHECK_STREQ(rel_path, "../other/dir/"); + simple_archiver_helper_cleanup_c_string(&rel_path); + } + printf("Checks checked: %u\n", checks_checked); printf("Checks passed: %u\n", checks_passed); return checks_passed == checks_checked ? 0 : 1;