From: Richard Russon Date: Wed, 15 Aug 2018 10:56:43 +0000 (+0100) Subject: add path manipulation functions X-Git-Tag: 2019-10-25~701 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=67d06e6c6912e48924c9744dc98b6577075b011c;p=neomutt add path manipulation functions --- diff --git a/Makefile.autosetup b/Makefile.autosetup index 7e99cc4da..8367548fc 100644 --- a/Makefile.autosetup +++ b/Makefile.autosetup @@ -248,8 +248,8 @@ LIBMUTT= libmutt.a LIBMUTTOBJS= mutt/base64.o mutt/buffer.o mutt/charset.o mutt/date.o \ mutt/envlist.o mutt/exit.o mutt/file.o mutt/hash.o \ mutt/history.o mutt/list.o mutt/logging.o mutt/mapping.o \ - mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/regex.o mutt/sha1.o \ - mutt/signal.o mutt/string.o + mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/path.o mutt/regex.o \ + mutt/sha1.o mutt/signal.o mutt/string.o CLEANFILES+= $(LIBMUTT) $(LIBMUTTOBJS) MUTTLIBS+= $(LIBMUTT) ALLOBJS+= $(LIBMUTTOBJS) diff --git a/mutt/path.c b/mutt/path.c new file mode 100644 index 000000000..43be8e191 --- /dev/null +++ b/mutt/path.c @@ -0,0 +1,163 @@ +/** + * @file + * Path manipulation functions + * + * @authors + * Copyright (C) 2018 Richard Russon + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include "mutt/mutt.h" +#include "email/email.h" +#include "alias.h" +#include "globals.h" +#include "hook.h" +#include "imap/imap.h" +#include "mx.h" + +/** + * mutt_path_tidy_slash - Remove unnecessary slashes and dots + * @param[in,out] buf Path to modify + * @retval true Success + * + * Collapse repeated '//' and '/./' + */ +bool mutt_path_tidy_slash(char *buf) +{ + if (!buf) + return false; + + char *r = buf; + char *w = buf; + + while (*r != '\0') + { + *w++ = *r++; + + if (r[-1] == '/') + { + for (; (r[0] == '/') || (r[0] == '.'); r++) + { + if (r[0] == '/') + continue; + if (r[0] == '.') + { + if (r[1] == '/') + { + r++; + continue; + } + else if (r[1] == '\0') + { + r[0] = '\0'; + } + break; + } + } + } + } + + if ((w[-1] == '/') && (w != (buf + 1))) + w--; + + *w = '\0'; + + return true; +} + +/** + * mutt_path_tidy_dotdot - Remove dot-dot-slash from a path + * @param[in,out] buf Path to modify + * @retval true Success + * + * Collapse dot-dot patterns, like '/dir/../' + */ +bool mutt_path_tidy_dotdot(char *buf) +{ + if (!buf || (buf[0] != '/')) + return false; + + char *dd = buf; + + mutt_debug(3, "Collapse path: %s\n", buf); + while ((dd = strstr(dd, "/.."))) + { + if (dd[3] == '/') /* paths follow dots */ + { + char *dest = NULL; + if (dd != buf) /* not at start of string */ + { + dd[0] = '\0'; + dest = strrchr(buf, '/'); + } + if (!dest) + dest = buf; + + memmove(dest, dd + 3, strlen(dd + 3) + 1); + } + else if (dd[3] == '\0') /* dots at end of string */ + { + if (dd == buf) /* at start of string */ + { + dd[1] = '\0'; + } + else + { + dd[0] = '\0'; + char *s = strrchr(buf, '/'); + if (s == buf) + s[1] = '\0'; + else if (s) + s[0] = '\0'; + } + } + else + { + dd += 3; /* skip over '/..dir/' */ + continue; + } + + dd = buf; /* restart at the beginning */ + } + + mutt_debug(3, "Collapsed to: %s\n", buf); + return true; +} + +/** + * mutt_path_tidy - Remove unnecessary parts of a path + * @param[in,out] buf Path to modify + * @retval true Success + * + * Remove unnecessary dots and slashes from a path + */ +bool mutt_path_tidy(char *buf) +{ + if (!buf || (buf[0] != '/')) + return false; + + if (!mutt_path_tidy_slash(buf)) + return false; + + return mutt_path_tidy_dotdot(buf); +} diff --git a/mutt/path.h b/mutt/path.h new file mode 100644 index 000000000..df52e97a4 --- /dev/null +++ b/mutt/path.h @@ -0,0 +1,33 @@ +/** + * @file + * Path manipulation functions + * + * @authors + * Copyright (C) 2017 Richard Russon + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef _MUTT_PATH_H +#define _MUTT_PATH_H + +#include +#include + +bool mutt_path_tidy (char *buf); +bool mutt_path_tidy_dotdot(char *buf); +bool mutt_path_tidy_slash (char *buf); + +#endif /* _MUTT_PATH_H */ diff --git a/test/Makefile.autosetup b/test/Makefile.autosetup index b3fb7247e..a8cba97ee 100644 --- a/test/Makefile.autosetup +++ b/test/Makefile.autosetup @@ -1,6 +1,7 @@ TEST_OBJS = test/main.o \ test/base64.o \ test/md5.o \ + test/path.o \ test/rfc2047.o \ test/string.o \ test/address.o diff --git a/test/main.c b/test/main.c index f64835159..ea1c620f6 100644 --- a/test/main.c +++ b/test/main.c @@ -13,7 +13,10 @@ NEOMUTT_TEST_ITEM(test_md5_ctx_bytes) \ NEOMUTT_TEST_ITEM(test_string_strfcpy) \ NEOMUTT_TEST_ITEM(test_string_strnfcpy) \ - NEOMUTT_TEST_ITEM(test_addr_mbox_to_udomain) + NEOMUTT_TEST_ITEM(test_addr_mbox_to_udomain) \ + NEOMUTT_TEST_ITEM(test_mutt_path_tidy_slash) \ + NEOMUTT_TEST_ITEM(test_mutt_path_tidy_dotdot) \ + NEOMUTT_TEST_ITEM(test_mutt_path_tidy) /****************************************************************************** * You probably don't need to touch what follows. diff --git a/test/path.c b/test/path.c new file mode 100644 index 000000000..358dd46fa --- /dev/null +++ b/test/path.c @@ -0,0 +1,227 @@ +#define TEST_NO_MAIN +#include "acutest.h" +#include "mutt/memory.h" +#include "mutt/path.h" +#include "mutt/string2.h" + +void test_mutt_path_tidy_slash(void) +{ + static const char *tests[][2] = + { + { NULL, NULL, }, + { "/", "/", }, + { "//", "/", }, + { "///", "/", }, + { "/apple/", "/apple", }, + { "/apple//", "/apple", }, + { "/apple///", "/apple", }, + { "/apple/banana", "/apple/banana", }, + { "/apple//banana", "/apple/banana", }, + { "/apple///banana", "/apple/banana", }, + { "/apple/banana/", "/apple/banana", }, + { "/apple/banana//", "/apple/banana", }, + { "/apple/banana///", "/apple/banana", }, + { "//.///././apple/banana", "/apple/banana", }, + { "/apple/.///././banana", "/apple/banana", }, + { "/apple/banana/.///././", "/apple/banana", }, + { "/apple/banana/", "/apple/banana", }, + { "/apple/banana/.", "/apple/banana", }, + { "/apple/banana/./", "/apple/banana", }, + { "/apple/banana//", "/apple/banana", }, + { "/apple/banana//.", "/apple/banana", }, + { "/apple/banana//./", "/apple/banana", }, + { "////apple/banana", "/apple/banana", }, + { "/.//apple/banana", "/apple/banana", }, + }; + + char buf[64]; + for (size_t i = 0; i < mutt_array_size(tests); i++) + { + mutt_str_strfcpy(buf, tests[i][0], sizeof(buf)); + mutt_path_tidy_slash(buf); + if (!TEST_CHECK(mutt_str_strcmp(buf, tests[i][1]) == 0)) + { + TEST_MSG("Input: %s", tests[i][0]); + TEST_MSG("Expected: %s", tests[i][1]); + TEST_MSG("Actual: %s", buf); + } + } +} + +void test_mutt_path_tidy_dotdot(void) +{ + static const char *tests[][2] = + { + { NULL, NULL, }, + { "/", "/", }, + { "/apple", "/apple", }, + { "/apple/banana", "/apple/banana", }, + { "/..", "/", }, + { "/apple/..", "/", }, + { "/apple/banana/..", "/apple", }, + { "/../cherry", "/cherry", }, + { "/apple/../cherry", "/cherry", }, + { "/apple/banana/../cherry", "/apple/cherry", }, + { "/apple/..", "/", }, + { "/apple/../..", "/", }, + { "/apple/../../..", "/", }, + { "/apple/../../../..", "/", }, + { "/apple/banana/..", "/apple", }, + { "/apple/banana/../..", "/", }, + { "/apple/banana/../../..", "/", }, + { "/apple/banana/../../../..", "/", }, + { "/../apple", "/apple", }, + { "/../../apple", "/apple", }, + { "/../../../apple", "/apple", }, + { "/../apple/banana/cherry/damson", "/apple/banana/cherry/damson", }, + { "/apple/../banana/cherry/damson", "/banana/cherry/damson", }, + { "/apple/banana/../cherry/damson", "/apple/cherry/damson", }, + { "/apple/banana/cherry/../damson", "/apple/banana/damson", }, + { "/apple/banana/cherry/damson/..", "/apple/banana/cherry", }, + { "/../../apple/banana/cherry/damson", "/apple/banana/cherry/damson", }, + { "/apple/../../banana/cherry/damson", "/banana/cherry/damson", }, + { "/apple/banana/../../cherry/damson", "/cherry/damson", }, + { "/apple/banana/cherry/../../damson", "/apple/damson", }, + { "/apple/banana/cherry/damson/../..", "/apple/banana", }, + { "/../apple/../banana/cherry/damson", "/banana/cherry/damson", }, + { "/apple/../banana/../cherry/damson", "/cherry/damson", }, + { "/apple/banana/../cherry/../damson", "/apple/damson", }, + { "/apple/banana/cherry/../damson/..", "/apple/banana", }, + { "/apple/..banana/cherry/../damson", "/apple/..banana/damson", }, + { "/..apple/..banana/..cherry/../damson", "/..apple/..banana/damson", }, + }; + + char buf[64]; + for (size_t i = 0; i < mutt_array_size(tests); i++) + { + mutt_str_strfcpy(buf, tests[i][0], sizeof(buf)); + mutt_path_tidy_dotdot(buf); + if (!TEST_CHECK(mutt_str_strcmp(buf, tests[i][1]) == 0)) + { + TEST_MSG("Input: %s", tests[i][0]); + TEST_MSG("Expected: %s", tests[i][1]); + TEST_MSG("Actual: %s", buf); + } + } +} + +void test_mutt_path_tidy(void) +{ + static const char *tests[][2] = + { + { "/..apple/./../////./banana/banana/./banana/..apple/./banana/..apple/banana///banana/..apple/banana/..apple/banana/banana/..apple", "/banana/banana/banana/..apple/banana/..apple/banana/banana/..apple/banana/..apple/banana/banana/..apple", }, + { "/../../banana///..apple///..apple///banana///banana/banana/banana/..apple/banana/banana/banana/./banana/banana/banana/..apple/banana", "/banana/..apple/..apple/banana/banana/banana/banana/..apple/banana/banana/banana/banana/banana/banana/..apple/banana", }, + { "///banana/banana/banana/./..apple/../banana/..apple/../..apple/./banana/./..apple", "/banana/banana/banana/banana/..apple/banana/..apple", }, + { "/./banana/banana/../banana/banana/.///banana/..apple/..apple", "/banana/banana/banana/banana/..apple/..apple", }, + { "/../banana/banana/banana/banana///..apple///..apple/banana/banana/////./..apple/./../.././banana/banana///banana/banana", "/banana/banana/banana/banana/..apple/..apple/banana/banana/banana/banana/banana", }, + { "/banana/banana/./././..apple/banana///./banana/banana/banana/banana/banana/banana/../////banana/banana/banana/./..apple/..apple/..///..apple", "/banana/banana/..apple/banana/banana/banana/banana/banana/banana/banana/banana/banana/..apple/..apple", }, + { "/banana///..apple///../banana/banana/banana///////banana/banana/./..apple/..apple/./..apple/..apple/banana", "/banana/banana/banana/banana/banana/banana/..apple/..apple/..apple/..apple/banana", }, + { "/banana/..apple/..apple/..apple/..apple/banana///../..apple///banana/banana/banana/banana///./../..apple/../banana/..apple/../banana/banana/./..apple", "/banana/..apple/..apple/..apple/..apple/..apple/banana/banana/banana/banana/banana/banana/..apple", }, + { "/banana/banana/..///../banana/../banana/banana/..apple/./../banana/../../banana/.", "/banana/banana", }, + { "/banana/banana/../..apple/banana/././banana///banana/banana", "/banana/..apple/banana/banana/banana/banana", }, + { "/////banana/banana/banana///..apple/./banana/..apple/./banana/banana", "/banana/banana/banana/..apple/banana/..apple/banana/banana", }, + { "/..apple/..apple/banana///banana/././//.///./banana///./banana/..apple/./banana", "/..apple/..apple/banana/banana/banana/banana/..apple/banana", }, + { "///./..apple/banana/./../banana/././..apple///./../../../////banana/banana/../..apple/banana/banana/../banana/banana/../.", "/banana/..apple/banana/banana", }, + { "/banana/./../././../..apple/banana/banana/..///../.", "/..apple", }, + { "/./..apple/banana///./banana/..///../banana//", "/..apple/banana", }, + { "/.///banana///..apple/banana/banana/../.././banana/../..apple///banana/banana/./banana/banana/..//", "/banana/..apple/..apple/banana/banana/banana", }, + { "/..apple/..apple/../banana/banana/..apple/./banana/../banana///banana", "/..apple/banana/banana/..apple/banana/banana", }, + { "/banana/banana/../././banana/banana/banana///./.././//banana/banana/banana/.././banana///..apple/banana//", "/banana/banana/banana/banana/banana/banana/..apple/banana", }, + { "/banana/banana/../banana/./banana/banana/banana/..apple/../banana/.///banana/////../..apple/banana/banana/../..apple/banana/banana/banana///banana", "/banana/banana/banana/banana/banana/banana/..apple/banana/..apple/banana/banana/banana/banana", }, + { "/./..apple/./banana///banana/./banana/..apple/banana///.///././banana", "/..apple/banana/banana/banana/..apple/banana/banana", }, + { "/./banana/..apple/banana/banana/.././.././..apple/banana/banana/..apple/.///..apple/.///banana/banana/..", "/banana/..apple/..apple/banana/banana/..apple/..apple/banana", }, + { "///./../..apple/banana/../banana///banana///..///..apple/../banana/../../banana/..apple/./banana/..apple/banana/..apple/banana//", "/..apple/banana/..apple/banana/..apple/banana/..apple/banana", }, + { "/banana/../..apple/banana///////banana/banana/..apple/../banana/../..", "/..apple/banana/banana", }, + { "/../banana/..apple///banana/banana/..apple/..apple///banana/banana/banana///..apple/banana///../././banana/banana/banana/banana/banana/banana", "/banana/..apple/banana/banana/..apple/..apple/banana/banana/banana/..apple/banana/banana/banana/banana/banana/banana", }, + { "///..apple///.././banana/./..apple///..apple/..", "/banana/..apple", }, + { "///../..apple/./../..apple/banana/banana///..apple/banana///../banana/banana", "/..apple/banana/banana/..apple/banana/banana", }, + { "/../banana/banana/banana/./banana/banana/banana///banana/banana/./banana/.", "/banana/banana/banana/banana/banana/banana/banana/banana/banana", }, + { "/././..apple/./..apple/../banana/./..apple/banana///.././banana/banana/..", "/..apple/banana/..apple/banana", }, + { "/..apple/..apple///banana/banana/..apple/////banana/banana/..apple///./../banana/banana/banana///banana/..apple/banana/..apple////", "/..apple/..apple/banana/banana/..apple/banana/banana/banana/banana/banana/banana/..apple/banana/..apple", }, + { "/..apple/banana/./banana/banana/banana/./banana/banana/../banana/../..///..apple/banana/./.././..///././../..apple/../banana/banana//", "/..apple/banana/banana/banana/banana/banana", }, + { "/banana///../banana/../././..apple/..apple///.///banana/./banana/banana///banana/..apple/.", "/..apple/..apple/banana/banana/banana/banana/..apple", }, + { "/////..apple/banana/banana/..apple/banana///banana//", "/..apple/banana/banana/..apple/banana/banana", }, + { "/..apple///./banana///../../../..apple/..apple/..apple/./banana/banana", "/..apple/..apple/..apple/banana/banana", }, + { "///banana///././..apple/banana/banana/././..apple/..apple/..apple/banana///././banana/././banana/..apple/banana/banana/../banana/./banana", "/banana/..apple/banana/banana/..apple/..apple/..apple/banana/banana/banana/..apple/banana/banana/banana", }, + { "/banana///./banana/banana/..///./banana//", "/banana/banana/banana", }, + { "/banana/////banana/banana/..apple/..apple/////.///..///..apple/banana/banana/..apple/..apple///./banana", "/banana/banana/banana/..apple/..apple/banana/banana/..apple/..apple/banana", }, + { "/..apple/banana///../..apple/////./..apple/./././banana/..apple", "/..apple/..apple/..apple/banana/..apple", }, + { "/banana/banana///banana/../../../..apple/banana///..apple/..apple/../.././banana/..apple/..apple/..///../../..", "/..apple", }, + { "/..apple/./././../banana/..apple/banana/banana/////./..//", "/banana/..apple/banana", }, + { "/../..apple/banana/..apple/banana/.././////banana/../banana/banana/..apple/..apple/banana/banana", "/..apple/banana/..apple/banana/banana/..apple/..apple/banana/banana", }, + { "/..apple/..apple/..apple///banana/banana/../banana/banana/banana/banana/banana/banana/..apple/.///./banana/./..apple/..apple/./..apple/banana/banana/banana/banana/.", "/..apple/..apple/..apple/banana/banana/banana/banana/banana/banana/banana/..apple/banana/..apple/..apple/..apple/banana/banana/banana/banana", }, + { "///..///banana///../..apple/..apple/.///banana/banana/..apple/..apple/banana/././..///banana", "/..apple/..apple/banana/banana/..apple/..apple/banana", }, + { "/banana///banana/..apple/banana/..///.././..apple/banana///banana/banana/..apple///./..apple", "/banana/banana/..apple/banana/banana/banana/..apple/..apple", }, + { "/banana/banana///.././banana/./banana/..apple/.././banana/../banana/////../banana/./banana/../..apple/banana/../banana/./..", "/banana/banana/banana/banana/..apple", }, + { "/banana/..apple/..apple/.././//banana/banana///.////", "/banana/..apple/banana/banana", }, + { "/banana/.././banana/banana/banana/.///../banana/..", "/banana/banana", }, + { "/banana/.///..apple/../banana/banana/banana/../..apple///./banana/banana///./.", "/banana/banana/banana/..apple/banana/banana", }, + { "/..apple/..apple///../..apple/..apple/banana/banana/////../banana/banana/////../banana/./.././banana/..apple", "/..apple/..apple/..apple/banana/banana/banana/..apple", }, + { "/./../banana/banana///banana/////./..apple/./..apple/../././..apple///banana", "/banana/banana/banana/..apple/..apple/banana", }, + { "/..///banana/../banana/./..apple/..apple///././banana", "/banana/..apple/..apple/banana", }, + { "/banana/banana/banana/banana/banana/banana/banana/../banana/banana/banana/banana/banana/banana/..apple/../..apple/..apple", "/banana/banana/banana/banana/banana/banana/banana/banana/banana/banana/banana/banana/..apple/..apple", }, + { "/banana/.././banana/..///banana/..apple/banana/banana/..apple", "/banana/..apple/banana/banana/..apple", }, + { "/../banana/banana/../..///..apple/banana/..apple/../../..apple/banana/..apple/../banana/..apple/banana/..apple///../banana/banana/banana/../banana/..apple/banana/.", "/..apple/..apple/banana/banana/..apple/banana/banana/banana/banana/..apple/banana", }, + { "/banana/banana/..apple/./banana/./././banana/..apple/////..apple/banana/banana/banana////", "/banana/banana/..apple/banana/banana/..apple/..apple/banana/banana/banana", }, + { "/..apple/banana/banana/../banana/banana/../..apple/banana/banana/./..", "/..apple/banana/banana/..apple/banana", }, + { "/.///..apple/banana/banana/banana/../banana/banana///banana/banana///banana/banana/./..apple/..///banana/..apple/banana/banana///../banana/..apple/banana", "/..apple/banana/banana/banana/banana/banana/banana/banana/banana/banana/..apple/banana/banana/..apple/banana", }, + { "/.///./../../banana/../banana///banana/banana///banana///banana///banana", "/banana/banana/banana/banana/banana/banana", }, + { "/banana/banana/./banana/../../../banana/././..apple/.././banana///..apple/../.", "/banana/banana", }, + { "///./../.././../../..apple/banana/..apple/..apple/banana///banana/..apple///../banana/../banana/././..apple/../..apple/./banana/.", "/..apple/banana/..apple/..apple/banana/banana/banana/..apple/banana", }, + { "/./../banana/banana///../banana/..apple/../../banana/banana/banana/banana/banana/../////banana/./banana//", "/banana/banana/banana/banana/banana/banana/banana", }, + { "/banana/./../.././../../banana/../../..apple///.///banana/banana/..apple/./banana/banana/banana/./banana/..apple/banana/..apple", "/..apple/banana/banana/..apple/banana/banana/banana/banana/..apple/banana/..apple", }, + { "/..apple/.././banana/banana/banana/../../././//../../..apple/banana///../..apple/banana/././..apple///././banana", "/..apple/..apple/banana/..apple/banana", }, + { "///../banana/.././banana/../..apple///banana/./../../..apple", "/..apple", }, + { "/banana/banana/banana/////../..apple/banana/////./banana///banana/..apple/banana/..apple/banana/.///banana/../../..", "/banana/banana/..apple/banana/banana/banana/..apple/banana", }, + { "///banana/banana/banana/..apple/banana/./..apple///./..apple/.", "/banana/banana/banana/..apple/banana/..apple/..apple", }, + { "/./././banana/././banana///../////../banana/./../////../banana///..apple///..apple/./.././banana/..apple//", "/banana/..apple/banana/..apple", }, + { "/banana/..apple/./../..apple/..apple/banana///./.././banana/./../..apple/banana/banana", "/banana/..apple/..apple/..apple/banana/banana", }, + { "/..apple/..apple/..apple///////banana/banana/banana/banana/////./banana/banana/./banana///../.", "/..apple/..apple/..apple/banana/banana/banana/banana/banana/banana", }, + { "/..apple/../..apple///////banana/./..apple/./banana/../..apple/../../banana/banana///banana/banana/./..///.././..", "/..apple/banana/banana", }, + { "/./.././////banana/banana/..apple/././banana/banana/banana///./.", "/banana/banana/..apple/banana/banana/banana", }, + { "/banana/./../banana///././..apple/////banana///..///banana/banana///..apple", "/banana/..apple/banana/banana/..apple", }, + { "/banana/../banana/../////..apple/banana///./////banana/./..apple/..apple///banana///banana/../banana///banana/..apple", "/..apple/banana/banana/..apple/..apple/banana/banana/banana/..apple", }, + { "/banana/banana/..apple/banana/./banana/banana/../banana///.", "/banana/banana/..apple/banana/banana/banana", }, + { "/..apple/..apple///./banana/./..apple/../..apple/./../banana/banana/..apple/././banana/..apple/////../../banana", "/..apple/..apple/banana/banana/banana/..apple/banana", }, + { "/..apple/..///banana///..apple/../banana/../..", "/", }, + { "/banana///banana/banana/./banana/../../..apple/./banana/banana/.././//banana/..apple/..apple/banana/banana/.///banana/./banana/..///../..", "/banana/banana/..apple/banana/banana/..apple/..apple/banana", }, + { "/..apple/banana/..apple/.././//./..///banana///banana///../..///banana///..apple///.././../banana/../../.", "/", }, + { "/./banana/..apple/banana/..///./banana/../../.././../../banana/banana/banana/../..apple/banana/banana/..apple/banana/banana/.", "/banana/banana/..apple/banana/banana/..apple/banana/banana", }, + { "/../banana/banana/banana/..apple/..///./banana/..apple///../..apple/././../..apple/banana/./.././..//", "/banana/banana/banana/banana", }, + { "///banana///../../banana///.././//../banana/banana/..apple/banana///banana/banana/banana/..apple/..", "/banana/banana/..apple/banana/banana/banana/banana", }, + { "/banana/../banana/././banana/..apple/./..apple///../..apple/.././////banana/./..apple/./banana", "/banana/banana/..apple/banana/..apple/banana", }, + { "/banana/./..apple/../..apple/./banana/..apple/../banana/banana/banana/banana/banana/banana/banana", "/banana/..apple/banana/banana/banana/banana/banana/banana/banana/banana", }, + { "/.././..apple///banana///..apple///banana/banana/banana/..apple/banana/./banana/.././banana/././/", "/..apple/banana/..apple/banana/banana/banana/..apple/banana/banana", }, + { "///././../banana/./../../..apple/banana/banana/..apple/banana/../..apple/..apple/./banana/./banana/..apple///banana/./..apple/banana///banana", "/..apple/banana/banana/..apple/..apple/..apple/banana/banana/..apple/banana/..apple/banana/banana", }, + { "/..apple/banana/banana/banana///banana/..///./..apple/banana/banana/..apple/banana///.///../banana/..apple", "/..apple/banana/banana/banana/..apple/banana/banana/..apple/banana/..apple", }, + { "/../..apple/banana/../banana/banana/banana/banana///..apple/./..apple/../..apple/..", "/..apple/banana/banana/banana/banana/..apple", }, + { "/../banana/banana/banana/..apple/banana/../banana/banana/../../../..apple///banana/../banana", "/banana/banana/banana/..apple/banana", }, + { "/banana/..apple/..apple/../banana/banana/////../././banana/banana/..apple/..apple/.", "/banana/..apple/banana/banana/banana/..apple/..apple", }, + { "/././//banana/banana/..apple/./banana/./banana///..apple/..", "/banana/banana/..apple/banana/banana", }, + { "/../banana/banana///./..apple/banana/banana///.././banana/banana/.///./banana/banana/banana/banana", "/banana/banana/..apple/banana/banana/banana/banana/banana/banana/banana", }, + { "/banana/banana/banana/..apple/./././../..apple/banana/..apple/..apple/.///.././..", "/banana/banana/banana/..apple/banana", }, + { "///..apple/./..apple/..apple/banana/banana/banana/../////.//", "/..apple/..apple/..apple/banana/banana", }, + { "/../banana/../../..apple/..apple///..apple/././banana/./banana/..apple///./..apple/./banana/banana/banana/./.././banana/../..", "/..apple/..apple/..apple/banana/banana/..apple/..apple/banana", }, + { "/..apple/..apple/banana///..apple///..apple/..apple/banana/.././banana/..apple/././..apple/../..apple///..apple///..apple/banana/../banana/..apple/////banana", "/..apple/..apple/banana/..apple/..apple/..apple/banana/..apple/..apple/..apple/..apple/banana/..apple/banana", }, + { "/../..apple/././banana///../..apple/banana/../.././////banana/banana/../..apple", "/..apple/banana/..apple", }, + { "/banana/..apple/banana/banana///..apple/banana/../banana/.././/", "/banana/..apple/banana/banana/..apple", }, + { "/..apple/banana/banana/banana/./banana/../banana/banana///..apple/banana/..///..///.", "/..apple/banana/banana/banana/banana/banana", }, + { "/..apple/banana/banana/.././banana/..apple/banana/..apple/..apple/../..///..apple///banana/banana/banana///banana/..apple/banana/banana", "/..apple/banana/banana/..apple/banana/..apple/banana/banana/banana/banana/..apple/banana/banana", }, + { "/./banana///../banana/banana/./../..apple/banana/../../banana///banana/..apple/..apple/////..", "/banana/banana/banana/..apple", }, + { "/banana/..apple/banana///banana///./..apple/banana/banana/banana/..apple/banana/banana//", "/banana/..apple/banana/banana/..apple/banana/banana/banana/..apple/banana/banana", }, + }; + + char buf[192]; + for (size_t i = 0; i < mutt_array_size(tests); i++) + { + mutt_str_strfcpy(buf, tests[i][0], sizeof(buf)); + mutt_path_tidy(buf); + if (!TEST_CHECK(mutt_str_strcmp(buf, tests[i][1]) == 0)) + { + TEST_MSG("Input: %s", tests[i][0]); + TEST_MSG("Expected: %s", tests[i][1]); + TEST_MSG("Actual: %s", buf); + } + } +} +