From 08e7520d332b700392248227bc07a68c429dc2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20Ikl=C3=A9?= Date: Sun, 29 May 2022 16:34:02 +0200 Subject: [PATCH] fixing #29 windows path root separator normalization --- CMakeLists.txt | 4 ++- README.md | 2 +- docs/reference/cwk_path_get_relative.md | 11 ++++--- docs/reference/cwk_path_normalize.md | 7 ++-- src/cwalk.c | 44 ++++++++++++++++++++++--- test/normalize_test.c | 19 +++++++++++ test/relative_test.c | 20 +++++++++++ 7 files changed, 92 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d9ad9cf..5be0652 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.9.2) # set project name project(cwalk - VERSION 1.2.5 + VERSION 1.2.7 DESCRIPTION "A simple path library" LANGUAGES C) @@ -175,6 +175,7 @@ if(ENABLE_TESTS) create_test(DEFAULT normalize empty) create_test(DEFAULT normalize only_separators) create_test(DEFAULT normalize back_after_root) + create_test(DEFAULT normalize forward_slashes) create_test(DEFAULT relative simple) create_test(DEFAULT relative relative) create_test(DEFAULT relative long_base) @@ -191,6 +192,7 @@ if(ENABLE_TESTS) create_test(DEFAULT relative check) create_test(DEFAULT relative root_path_unix) create_test(DEFAULT relative root_path_windows) + create_test(DEFAULT relative root_forward_slashes) create_test(DEFAULT root absolute) create_test(DEFAULT root unc) create_test(DEFAULT root device_unc) diff --git a/README.md b/README.md index 6d9eec8..1cf4baf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![Travis Build](https://img.shields.io/travis/likle/cwalk/master.svg?maxAge=2592000&label=Linux%20%26%20MacOS)](https://travis-ci.org/likle/cwalk) +[![Travis Build](https://img.shields.io/travis/likle/cwalk/master.svg?maxAge=2592000&label=Linux%20%26%20MacOS)](https://travis-ci.com/likle/cwalk) [![Appveyor Build](https://img.shields.io/appveyor/ci/likle/cwalk/master.svg?label=Windows)](https://ci.appveyor.com/project/likle/cwalk) [![codecov](https://img.shields.io/codecov/c/github/likle/cwalk/master.svg?label=Coverage)](https://codecov.io/gh/likle/cwalk) [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/likle/cwalk.svg?label=Code%20Quality)](https://lgtm.com/projects/g/likle/cwalk/context:cpp) diff --git a/docs/reference/cwk_path_get_relative.md b/docs/reference/cwk_path_get_relative.md index f9ccb56..f4477ac 100644 --- a/docs/reference/cwk_path_get_relative.md +++ b/docs/reference/cwk_path_get_relative.md @@ -64,8 +64,9 @@ The relative path is: ../world ## Changelog -| Version | Description | -|------------|--------------------------------------------------------| -| **v1.2.5** | Fixed calls with path without segments. | -| **v1.2.5** | Fixed calls with unequal roots in paths. | -| **v1.0.0** | The function is introduced. | +| Version | Description | +|------------|---------------------------------------------------| +| **v1.2.7** | Fixed windows paths with forward slashes in root. | +| **v1.2.5** | Fixed calls with path without segments. | +| **v1.2.5** | Fixed calls with unequal roots in paths. | +| **v1.0.0** | The function is introduced. | diff --git a/docs/reference/cwk_path_normalize.md b/docs/reference/cwk_path_normalize.md index 0828850..03ded2c 100644 --- a/docs/reference/cwk_path_normalize.md +++ b/docs/reference/cwk_path_normalize.md @@ -68,6 +68,7 @@ Output: ## Changelog -| Version | Description | -|------------|--------------------------------------------------------| -| **v1.0.0** | The function is introduced. | \ No newline at end of file +| Version | Description | +|------------|---------------------------------------------------| +| **v1.2.7** | Fixed windows paths with forward slashes in root. | +| **v1.0.0** | The function is introduced. | \ No newline at end of file diff --git a/src/cwalk.c b/src/cwalk.c index fe96c79..f681b52 100755 --- a/src/cwalk.c +++ b/src/cwalk.c @@ -124,7 +124,9 @@ static void cwk_path_terminate_output(char *buffer, size_t buffer_size, static bool cwk_path_is_string_equal(const char *first, const char *second, size_t first_size, size_t second_size) { - // THe two strings are not equal if the sizes are not equal. + bool are_both_separators; + + // The two strings are not equal if the sizes are not equal. if (first_size != second_size) { return false; } @@ -140,11 +142,18 @@ static bool cwk_path_is_string_equal(const char *first, const char *second, // own. while (*first && *second && first_size > 0) { // We can consider the string to be not equal if the two lowercase - // characters are not equal. - if (tolower(*first++) != tolower(*second++)) { + // characters are not equal. The two chars may also be separators, which + // means they would be equal. + are_both_separators = strchr(separators[path_style], *first) != NULL && + strchr(separators[path_style], *second) != NULL; + + if (tolower(*first) != tolower(*second) && !are_both_separators) { return false; } + first++; + second++; + --first_size; } @@ -482,7 +491,7 @@ static void cwk_path_get_root_windows(const char *path, size_t *length) if (cwk_path_is_separator(c)) { ++c; - // Check whether the path starts with a single back slash, which means this + // Check whether the path starts with a single backslash, which means this // is not a network path - just a normal path starting with a backslash. if (!cwk_path_is_separator(c)) { // Okay, this is not a network path but we still use the backslash as a @@ -570,6 +579,29 @@ static bool cwk_path_is_root_absolute(const char *path, size_t length) return cwk_path_is_separator(&path[length - 1]); } +static void cwk_path_fix_root(char *buffer, size_t buffer_size, size_t length) +{ + size_t i; + + // This only affects windows. + if (path_style != CWK_STYLE_WINDOWS) { + return; + } + + // Make sure we are not writing further than we are actually allowed to. + if (length > buffer_size) { + length = buffer_size; + } + + // Replace all forward slashes with backwards slashes. Since this is windows + // we can't have any forward slashes in the root. + for (i = 0; i < length; ++i) { + if (cwk_path_is_separator(&buffer[i])) { + buffer[i] = *separators[CWK_STYLE_WINDOWS]; + } + } +} + static size_t cwk_path_join_and_normalize_multiple(const char **paths, char *buffer, size_t buffer_size) { @@ -584,8 +616,10 @@ static size_t cwk_path_join_and_normalize_multiple(const char **paths, // later on whether we can remove superfluous "../" or not. absolute = cwk_path_is_root_absolute(paths[0], pos); - // First copy the root to the output. We will not modify the root. + // First copy the root to the output. After copying, we will normalize the + // root. cwk_path_output_sized(buffer, buffer_size, 0, paths[0], pos); + cwk_path_fix_root(buffer, buffer_size, pos); // So we just grab the first segment. If there is no segment we will always // output a "/", since we currently only support absolute paths here. diff --git a/test/normalize_test.c b/test/normalize_test.c index 4ab4c25..508c9d6 100644 --- a/test/normalize_test.c +++ b/test/normalize_test.c @@ -6,6 +6,25 @@ #include #include +int normalize_forward_slashes() +{ + size_t count; + char result[FILENAME_MAX]; + char *input, *expected; + + cwk_path_set_style(CWK_STYLE_WINDOWS); + + input = "C:/this/is/a/test/path"; + strcpy(result, input); + expected = "C:\\this\\is\\a\\test\\path"; + count = cwk_path_normalize(result, result, sizeof(result)); + if (count != strlen(expected) || strcmp(result, expected) != 0) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + int normalize_back_after_root() { size_t count; diff --git a/test/relative_test.c b/test/relative_test.c index 9fceb50..2303738 100755 --- a/test/relative_test.c +++ b/test/relative_test.c @@ -6,6 +6,26 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +int relative_root_forward_slashes() +{ + char result[FILENAME_MAX]; + size_t length; + + cwk_path_set_style(CWK_STYLE_WINDOWS); + + length = cwk_path_get_relative("C:\\foo\\bar\\baz\\", "C:/foo/bar/file.txt", + result, sizeof(result)); + if (length != 11) { + return EXIT_FAILURE; + } + + if (strcmp(result, "..\\file.txt") != 0) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + int relative_root_path_windows() { char result[FILENAME_MAX];