From 62c113ebc7ba6fa1594b24158a6cc3e1170f4030 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 5 Mar 2020 15:31:22 +0100 Subject: fix #13579 joinPath("/foo/", "../a") is now /a (#13586) --- compiler/pathutils.nim | 2 ++ lib/pure/os.nim | 1 + lib/pure/pathnorm.nim | 5 +++++ tests/stdlib/tos.nim | 13 +++++++++++++ 4 files changed, 21 insertions(+) diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index 1c35eb0b2..888e0a572 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -102,6 +102,8 @@ when true: when isMainModule: doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" + doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" + doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim" doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim" doAssert $RelativeDir"foo/bar" == "foo/bar" doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar" diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 3db518273..ba092da05 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -127,6 +127,7 @@ template endsWith(a: string, b: set[char]): bool = proc joinPathImpl(result: var string, state: var int, tail: string) = let trailingSep = tail.endsWith({DirSep, AltSep}) or tail.len == 0 and result.endsWith({DirSep, AltSep}) + normalizePathEnd(result, trailingSep=false) addNormalizePath(tail, result, state, DirSep) normalizePathEnd(result, trailingSep=trailingSep) diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 3659e85e6..8763ba878 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -76,6 +76,11 @@ proc addNormalizePath*(x: string; result: var string; state: var int; if (state shr 1) >= 1: var d = result.len # f/.. + # We could handle stripping trailing sep here: foo// => foo like this: + # while (d-1) > (state and 1) and result[d-1] in {DirSep, AltSep}: dec d + # but right now we instead handle it inside os.joinPath + + # strip path component: foo/bar => foo while (d-1) > (state and 1) and result[d-1] notin {DirSep, AltSep}: dec d if d > 0: diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index c649749e3..d713bfe0c 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -389,6 +389,19 @@ block ospaths: doAssert joinPath("foo", "./") == unixToNativePath"foo/" doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/" + # issue #13579 + doAssert joinPath("/foo", "../a") == unixToNativePath"/a" + doAssert joinPath("/foo/", "../a") == unixToNativePath"/a" + doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a" + doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a" + doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/" + doAssert joinPath("foo/", "../a") == unixToNativePath"a" + + when doslikeFileSystem: + doAssert joinPath("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", "..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + doAssert joinPath("C:\\foo", "..\\a") == r"C:\a" + doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a" + block getTempDir: block TMPDIR: # TMPDIR env var is not used if either of these are defined. -- cgit 1.4.1-2-gfad0