mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Merge pull request #6587 from FedericoCeratto/normalizePath
Add normalizePath and tests
This commit is contained in:
@@ -298,8 +298,8 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
||||
|
||||
proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||
tags: [ReadDirEffect].} =
|
||||
## Returns the full (`absolute`:idx:) path of the file `filename`,
|
||||
## raises OSError in case of an error.
|
||||
## Returns the full (`absolute`:idx:) path of an existing file `filename`,
|
||||
## raises OSError in case of an error. Follows symlinks.
|
||||
when defined(windows):
|
||||
var bufsize = MAX_PATH.int32
|
||||
when useWinUnicode:
|
||||
@@ -338,6 +338,47 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||
result = $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):
|
||||
proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
|
||||
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
|
||||
|
||||
@@ -43,6 +43,7 @@ true
|
||||
true
|
||||
true
|
||||
true
|
||||
|
||||
'''
|
||||
"""
|
||||
# test os path creation, iteration, and deletion
|
||||
@@ -137,8 +138,69 @@ import times
|
||||
let tm = fromUnix(0) + 100.microseconds
|
||||
writeFile("a", "")
|
||||
setLastModificationTime("a", tm)
|
||||
|
||||
when defined(macosx):
|
||||
echo "true"
|
||||
else:
|
||||
echo getLastModificationTime("a") == tm
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user