Add normalizePath and tests
This commit is contained in:
parent
352b8a4844
commit
d65429d857
2 changed files with 105 additions and 2 deletions
|
|
@ -298,8 +298,8 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
||||||
|
|
||||||
proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||||
tags: [ReadDirEffect].} =
|
tags: [ReadDirEffect].} =
|
||||||
## Returns the full (`absolute`:idx:) path of the file `filename`,
|
## Returns the full (`absolute`:idx:) path of an existing file `filename`,
|
||||||
## raises OSError in case of an error.
|
## raises OSError in case of an error. Follows symlinks.
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var bufsize = MAX_PATH.int32
|
var bufsize = MAX_PATH.int32
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
|
|
@ -338,6 +338,47 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||||
result = $r
|
result = $r
|
||||||
c_free(cast[pointer](r))
|
c_free(cast[pointer](r))
|
||||||
|
|
||||||
|
proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} =
|
||||||
|
## Normalize a path.
|
||||||
|
##
|
||||||
|
## Consecutive directory separators are collapsed, including an initial double slash.
|
||||||
|
##
|
||||||
|
## On relative paths, double dot (..) sequences are collapsed if possible.
|
||||||
|
## On absolute paths they are always collapsed.
|
||||||
|
##
|
||||||
|
## Warning: URL-encoded and Unicode attempts at directory traversal are not detected.
|
||||||
|
## Triple dot is not handled.
|
||||||
|
let isAbs = isAbsolute(path)
|
||||||
|
var stack: seq[string] = @[]
|
||||||
|
for p in split(path, {DirSep}):
|
||||||
|
case p
|
||||||
|
of "", ".":
|
||||||
|
continue
|
||||||
|
of "..":
|
||||||
|
if stack.len == 0:
|
||||||
|
if isAbs:
|
||||||
|
discard # collapse all double dots on absoluta paths
|
||||||
|
else:
|
||||||
|
stack.add(p)
|
||||||
|
elif stack[^1] == "..":
|
||||||
|
stack.add(p)
|
||||||
|
else:
|
||||||
|
discard stack.pop()
|
||||||
|
else:
|
||||||
|
stack.add(p)
|
||||||
|
|
||||||
|
if isAbs:
|
||||||
|
path = DirSep & join(stack, $DirSep)
|
||||||
|
elif stack.len > 0:
|
||||||
|
path = join(stack, $DirSep)
|
||||||
|
else:
|
||||||
|
path = "."
|
||||||
|
|
||||||
|
proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} =
|
||||||
|
## Returns a normalized path for the current OS. See `<#normalizePath>`_
|
||||||
|
result = path
|
||||||
|
normalizePath(result)
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
|
proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
|
||||||
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
|
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
|
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
# test os path creation, iteration, and deletion
|
# test os path creation, iteration, and deletion
|
||||||
|
|
@ -137,8 +138,69 @@ import times
|
||||||
let tm = fromUnix(0) + 100.microseconds
|
let tm = fromUnix(0) + 100.microseconds
|
||||||
writeFile("a", "")
|
writeFile("a", "")
|
||||||
setLastModificationTime("a", tm)
|
setLastModificationTime("a", tm)
|
||||||
|
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
echo "true"
|
echo "true"
|
||||||
else:
|
else:
|
||||||
echo getLastModificationTime("a") == tm
|
echo getLastModificationTime("a") == tm
|
||||||
removeFile("a")
|
removeFile("a")
|
||||||
|
|
||||||
|
when defined(Linux) or defined(osx):
|
||||||
|
|
||||||
|
block normalizedPath:
|
||||||
|
block relative:
|
||||||
|
doAssert normalizedPath(".") == "."
|
||||||
|
doAssert normalizedPath("..") == ".."
|
||||||
|
doAssert normalizedPath("../") == ".."
|
||||||
|
doAssert normalizedPath("../..") == "../.."
|
||||||
|
doAssert normalizedPath("../a/..") == ".."
|
||||||
|
doAssert normalizedPath("../a/../") == ".."
|
||||||
|
doAssert normalizedPath("./") == "."
|
||||||
|
|
||||||
|
block absolute:
|
||||||
|
doAssert normalizedPath("/") == "/"
|
||||||
|
doAssert normalizedPath("/.") == "/"
|
||||||
|
doAssert normalizedPath("/..") == "/"
|
||||||
|
doAssert normalizedPath("/../") == "/"
|
||||||
|
doAssert normalizedPath("/../..") == "/"
|
||||||
|
doAssert normalizedPath("/../../") == "/"
|
||||||
|
doAssert normalizedPath("/../../../") == "/"
|
||||||
|
doAssert normalizedPath("/a/b/../../foo") == "/foo"
|
||||||
|
doAssert normalizedPath("/a/b/../../../foo") == "/foo"
|
||||||
|
doAssert normalizedPath("/./") == "/"
|
||||||
|
doAssert normalizedPath("//") == "/"
|
||||||
|
doAssert normalizedPath("///") == "/"
|
||||||
|
doAssert normalizedPath("/a//b") == "/a/b"
|
||||||
|
doAssert normalizedPath("/a///b") == "/a/b"
|
||||||
|
doAssert normalizedPath("/a/b/c/..") == "/a/b"
|
||||||
|
doAssert normalizedPath("/a/b/c/../") == "/a/b"
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
block normalizedPath:
|
||||||
|
block relative:
|
||||||
|
doAssert normalizedPath(".") == "."
|
||||||
|
doAssert normalizedPath("..") == ".."
|
||||||
|
doAssert normalizedPath("..\\") == ".."
|
||||||
|
doAssert normalizedPath("..\\..") == "..\\.."
|
||||||
|
doAssert normalizedPath("..\\a\\..") == ".."
|
||||||
|
doAssert normalizedPath("..\\a\\..\\") == ".."
|
||||||
|
doAssert normalizedPath(".\\") == "."
|
||||||
|
|
||||||
|
block absolute:
|
||||||
|
doAssert normalizedPath("\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\.") == "\\"
|
||||||
|
doAssert normalizedPath("\\..") == "\\"
|
||||||
|
doAssert normalizedPath("\\..\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\..\\..") == "\\"
|
||||||
|
doAssert normalizedPath("\\..\\..\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\..\\..\\..\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\a\\b\\..\\..\\foo") == "\\foo"
|
||||||
|
doAssert normalizedPath("\\a\\b\\..\\..\\..\\foo") == "\\foo"
|
||||||
|
doAssert normalizedPath("\\.\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\\\\\") == "\\"
|
||||||
|
doAssert normalizedPath("\\a\\\\b") == "\\a\\b"
|
||||||
|
doAssert normalizedPath("\\a\\\\\\b") == "\\a\\b"
|
||||||
|
doAssert normalizedPath("\\a\\b\\c\\..") == "\\a\\b"
|
||||||
|
doAssert normalizedPath("\\a\\b\\c\\..\\") == "\\a\\b"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue