diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2018-08-26 08:36:11 -0700 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-08-26 17:36:11 +0200 |
commit | b4edfa613b3adeaa091e8aee7d38d9c24fa4e32e (patch) | |
tree | 36bb3a4676bb19955aef01f782d704cfaa38ed89 /lib | |
parent | 96d44fdd0a24bc5cbfe29de6079da6882388aed8 (diff) | |
download | Nim-b4edfa613b3adeaa091e8aee7d38d9c24fa4e32e.tar.gz |
[ospaths] simplify getConfigDir and introduce normalizePathEnd to make (#8680)
sure path endings are normalized with 0 or 1 trailing sep, taking care of edge cases
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/ospaths.nim | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 1bcfd978b..bc6739dd3 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -449,6 +449,31 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} = elif defined(posix): result = path[0] == '/' + +proc normalizePathEnd(path: var string, trailingSep = false) = + ## ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on + ## ``trailingSep``, and taking care of edge cases: it preservers whether + ## a path is absolute or relative, and makes sure trailing sep is `DirSep`, + ## not `AltSep`. + if path.len == 0: return + var i = path.len + while i >= 1 and path[i-1] in {DirSep, AltSep}: dec(i) + if trailingSep: + # foo// => foo + path.setLen(i) + # foo => foo/ + path.add DirSep + elif i>0: + # foo// => foo + path.setLen(i) + else: + # // => / (empty case was already taken care of) + path = $DirSep + +proc normalizePathEnd(path: string, trailingSep = false): string = + result = path + result.normalizePathEnd(trailingSep) + proc unixToNativePath*(path: string, drive=""): string {. noSideEffect, rtl, extern: "nos$1".} = ## Converts an UNIX-like path to a native one. @@ -530,12 +555,12 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## "~/.config/", otherwise. ## ## An OS-dependent trailing slash is always present at the end of the - ## returned string; `\\` on Windows and `/` on all other OSs. + ## returned string; `\` on Windows and `/` on all other OSs. when defined(windows): - result = string(getEnv("APPDATA")) & "\\" + result = getEnv("APPDATA").string else: - result = string(getEnv("XDG_CONFIG_HOME", "")) & "/" - if result == "/": result = string(getEnv("HOME")) & "/.config/" + result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string + result.normalizePathEnd(trailingSep = true) proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = @@ -649,3 +674,24 @@ when isMainModule: when defined(posix): assert quoteShell("") == "''" + + block normalizePathEndTest: + # handle edge cases correctly: shouldn't affect whether path is + # absolute/relative + doAssert "".normalizePathEnd(true) == "" + doAssert "".normalizePathEnd(false) == "" + doAssert "/".normalizePathEnd(true) == $DirSep + doAssert "/".normalizePathEnd(false) == $DirSep + + when defined(posix): + doAssert "//".normalizePathEnd(false) == "/" + doAssert "foo.bar//".normalizePathEnd == "foo.bar" + doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/" + when defined(Windows): + doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo" + doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\" + # this one is controversial: we could argue for returning `D:\` instead, + # but this is simplest. + doAssert r"D:\".normalizePathEnd == r"D:" + doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\" + doAssert "/".normalizePathEnd == r"\" |