diff options
author | Araq <rumpf_a@web.de> | 2013-07-31 12:59:22 -0700 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-07-31 12:59:22 -0700 |
commit | 3ae6043e7e77eef8603cab77dda0a5016f0d87fd (patch) | |
tree | bd6e540f8a43d60b51c9abf3f0fc41fde198846c | |
parent | 3ab4b3d58f3c32eb58c133411bbbf4579534e30a (diff) | |
parent | 55bcd0ba1eba91211a7b042e3a10311d5a833803 (diff) | |
download | Nim-3ae6043e7e77eef8603cab77dda0a5016f0d87fd.tar.gz |
Merge pull request #533 from gradha/pr_helper_procs
Adds some helper procs
-rw-r--r-- | lib/pure/os.nim | 52 | ||||
-rw-r--r-- | lib/pure/xmltree.nim | 39 |
2 files changed, 87 insertions, 4 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index bd5e83432..d57331eae 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -836,9 +836,11 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", ## ## If this fails, `EOS` is raised. On the Windows platform this proc will ## copy the source file's attributes into dest. On other platforms you need - ## to use getFilePermissions and setFilePermissions to copy them by hand, - ## otherwise `dest` will inherit the default permissions of a newly created - ## file for the user. + ## to use getFilePermissions and setFilePermissions to copy them by hand (or + ## use the convenience copyFileWithPermissions() proc), otherwise `dest` will + ## inherit the default permissions of a newly created file for the user. If + ## `dest` already exists, the file attributes will be preserved and the + ## content overwritten. when defined(Windows): when useWinUnicode: let s = newWideCString(source) @@ -1383,6 +1385,26 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {. var res2 = SetFileAttributesA(filename, res) if res2 == - 1'i32: OSError(OSLastError()) +proc copyFileWithPermissions*(source, dest: string, + ignorePermissionErrors = true) = + ## Copies a file from `source` to `dest` preserving file permissions. + ## + ## This is a wrapper proc around copyFile, getFilePermissions and + ## setFilePermissions on non Windows platform. On windows this proc is just a + ## wrapper for copyFile since that proc already copies attributes. + ## + ## On non windows systems permissions are copied after the file itself has + ## been copied, which won't happen atomically and could lead to a race + ## condition. If ignorePermissionErrors is true, errors while reading/setting + ## file attributes will be ignored, otherwise will raise `OSError`. + copyFile(source, dest) + when not defined(Windows): + try: + setFilePermissions(dest, getFilePermissions(source)) + except: + if not ignorePermissionErrors: + raise + proc inclFilePermissions*(filename: string, permissions: set[TFilePermission]) {. rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} = @@ -1403,6 +1425,9 @@ proc exclFilePermissions*(filename: string, proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = ## Returns the home directory of the current user. + ## + ## This proc is wrapped by the expandTilde proc for the convenience of + ## processing paths coming from user configuration files. when defined(windows): return string(getEnv("USERPROFILE")) & "\\" else: return string(getEnv("HOME")) & "/" @@ -1580,5 +1605,26 @@ proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} = if ExistsFile(x): return x result = "" +proc expandTilde*(path: string): string = + ## Expands a path starting with ``~/`` to a full path. + ## + ## If `path` starts with the tilde character and is followed by `/` or `\\` + ## this proc will return the reminder of the path appended to the result of + ## the getHomeDir() proc, otherwise the input path will be returned without + ## modification. + ## + ## The behaviour of this proc is the same on the Windows platform despite not + ## having this convention. Example: + ## + ## .. code-block:: nimrod + ## let configFile = expandTilde("~" / "appname.cfg") + ## echo configFile + ## # --> C:\Users\amber\appname.cfg + + if len(path) > 1 and path[0] == '~' and (path[1] == '/' or path[1] == '\\'): + result = getHomeDir() / path[2..len(path)-1] + else: + result = path + {.pop.} diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index d5821d8f3..7621094f3 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -24,7 +24,7 @@ type PXmlAttributes* = PStringTable ## an alias for a string to string mapping TXmlNode {.pure, final, acyclic.} = object - case k: TXmlNodeKind + case k: TXmlNodeKind # private, use the kind() proc to read this field. of xnText, xnComment, xnCData, xnEntity: fText: string of xnElement: @@ -297,3 +297,40 @@ proc attr*(n: PXmlNode, name: string): string = assert n.kind == xnElement if n.attrs == nil: return "" return n.attrs[name] + +proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) = + ## Iterates over all the children of `n` returning those matching `tag`. + ## + ## Found nodes satisfying the condition will be appended to the `result` + ## sequence, which can't be nil or the proc will crash. Usage example: + ## + ## .. code-block:: nimrod + ## var + ## html: PXmlNode + ## tags: seq[PXmlNode] = @[] + ## + ## html = buildHtml() + ## findAll(html, "img", tags) + ## for imgTag in tags: + ## process(imgTag) + assert isNil(result) == false + assert n.k == xnElement + for child in n.items(): + if child.k != xnElement: + continue + if child.tag == tag: + result.add(child) + elif child.k == xnElement: + child.findAll(tag, result) + +proc findAll*(n: PXmlNode, tag: string): seq[PXmlNode] = + ## Shortcut version to assign in let blocks. Example: + ## + ## .. code-block:: nimrod + ## var html: PXmlNode + ## + ## html = buildHtml(html) + ## for imgTag in html.findAll("img"): + ## process(imgTag) + newSeq(result, 0) + findAll(n, tag, result) |