Merge pull request #533 from gradha/pr_helper_procs

Adds some helper procs
This commit is contained in:
Araq
2013-07-31 12:59:22 -07:00
2 changed files with 87 additions and 4 deletions

View File

@@ -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.}

View File

@@ -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)