diff options
Diffstat (limited to 'lib/pure/os.nim')
-rw-r--r-- | lib/pure/os.nim | 146 |
1 files changed, 123 insertions, 23 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 0b4538abc..44673d3e0 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -955,11 +955,12 @@ 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 (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. + ## to use `getFilePermissions() <#getFilePermissions>`_ and + ## `setFilePermissions() <#setFilePermissions>`_ to copy them by hand (or use + ## the convenience `copyFileWithPermissions() <#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) @@ -1363,7 +1364,13 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", tags: [FWriteIO, FReadIO].} = - ## Copies a directory from `source` to `dest`. If this fails, `EOS` is raised. + ## Copies a directory from `source` to `dest`. + ## + ## If this fails, `EOS` is raised. On the Windows platform this proc will + ## copy the attributes from `source` into `dest`. On other platforms created + ## files and directories will inherit the default permissions of a newly + ## created file/directory for the user. To preserve attributes recursively on + ## these platforms use `copyDirWithPermissions() <#copyDirWithPermissions>`_. createDir(dest) for kind, path in walkDir(source): var noSource = path.substr(source.len()+1) @@ -1450,7 +1457,8 @@ proc parseCmdLine*(c: string): seq[string] {. var a = "" while true: setLen(a, 0) - while c[i] == ' ' or c[i] == '\t': inc(i) + # eat all delimiting whitespace + while c[i] == ' ' or c[i] == '\t' or c [i] == '\l' or c [i] == '\r' : inc(i) when defined(windows): # parse a single argument according to the above rules: if c[i] == '\0': break @@ -1507,14 +1515,17 @@ 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. + ## This is a wrapper proc around `copyFile() <#copyFile>`_, + ## `getFilePermissions() <#getFilePermissions>`_ and `setFilePermissions() + ## <#setFilePermissions>`_ on non Windows platform. On Windows this proc is + ## just a wrapper for `copyFile() <#copyFile>`_ since that proc already + ## copies attributes. ## - ## On non windows systems permissions are copied after the file itself has + ## 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`. + ## 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: @@ -1523,6 +1534,37 @@ proc copyFileWithPermissions*(source, dest: string, if not ignorePermissionErrors: raise +proc copyDirWithPermissions*(source, dest: string, + ignorePermissionErrors = true) {.rtl, extern: "nos$1", + tags: [FWriteIO, FReadIO].} = + ## Copies a directory from `source` to `dest` preserving file permissions. + ## + ## If this fails, `EOS` is raised. This is a wrapper proc around `copyDir() + ## <#copyDir>`_ and `copyFileWithPermissions() <#copyFileWithPermissions>`_ + ## on non Windows platforms. On Windows this proc is just a wrapper for + ## `copyDir() <#copyDir>`_ since that proc already copies attributes. + ## + ## On non Windows systems permissions are copied after the file or directory + ## 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`. + createDir(dest) + when not defined(Windows): + try: + setFilePermissions(dest, getFilePermissions(source)) + except: + if not ignorePermissionErrors: + raise + for kind, path in walkDir(source): + var noSource = path.substr(source.len()+1) + case kind + of pcFile: + copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors) + of pcDir: + copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors) + else: discard + proc inclFilePermissions*(filename: string, permissions: set[TFilePermission]) {. rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} = @@ -1560,7 +1602,52 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = when defined(windows): return string(getEnv("TEMP")) & "\\" else: return "/tmp/" -when defined(windows): +when defined(nimdoc): + # Common forward declaration docstring block for parameter retrieval procs. + proc paramCount*(): int {.tags: [FReadIO].} = + ## Returns the number of `command line arguments`:idx: given to the + ## application. + ## + ## If your binary was called without parameters this will return zero. You + ## can later query each individual paramater with `paramStr() <#paramStr>`_ + ## or retrieve all of them in one go with `commandLineParams() + ## <#commandLineParams>`_. + ## + ## **Availability**: On Posix there is no portable way to get the command + ## line from a DLL and thus the proc isn't defined in this environment. You + ## can test for its availability with `defined() <system.html#defined>`_. + ## Example: + ## + ## .. code-block:: nimrod + ## when defined(paramCount): + ## # Use paramCount() here + ## else: + ## # Do something else! + + proc paramStr*(i: int): TaintedString {.tags: [FReadIO].} = + ## Returns the `i`-th `command line argument`:idx: given to the application. + ## + ## `i` should be in the range `1..paramCount()`, the `EInvalidIndex` + ## exception will be raised for invalid values. Instead of iterating over + ## `paramCount() <#paramCount>`_ with this proc you can call the + ## convenience `commandLineParams() <#commandLineParams>`_. + ## + ## It is possible to call ``paramStr(0)`` but this will return OS specific + ## contents (usually the name of the invoked executable). You should avoid + ## this and call `getAppFilename() <#getAppFilename>`_ instead. + ## + ## **Availability**: On Posix there is no portable way to get the command + ## line from a DLL and thus the proc isn't defined in this environment. You + ## can test for its availability with `defined() <system.html#defined>`_. + ## Example: + ## + ## .. code-block:: nimrod + ## when defined(paramStr): + ## # Use paramStr() here + ## else: + ## # Do something else! + +elif defined(windows): # Since we support GUI applications with Nimrod, we sometimes generate # a WinMain entry proc. But a WinMain proc has no access to the parsed # command line arguments. The way to get them differs. Thus we parse them @@ -1570,18 +1657,13 @@ when defined(windows): ownArgv {.threadvar.}: seq[string] proc paramCount*(): int {.rtl, extern: "nos$1", tags: [FReadIO].} = - ## Returns the number of `command line arguments`:idx: given to the - ## application. + # Docstring in nimdoc block. if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) result = ownArgv.len-1 proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1", tags: [FReadIO].} = - ## Returns the `i`-th `command line argument`:idx: given to the - ## application. - ## - ## `i` should be in the range `1..paramCount()`, else - ## the `EOutOfIndex` exception is raised. + # Docstring in nimdoc block. if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) return TaintedString(ownArgv[i]) @@ -1592,13 +1674,31 @@ elif not defined(createNimRtl): cmdLine {.importc: "cmdLine".}: cstringArray proc paramStr*(i: int): TaintedString {.tags: [FReadIO].} = + # Docstring in nimdoc block. if i < cmdCount and i >= 0: return TaintedString($cmdLine[i]) raise newException(EInvalidIndex, "invalid index") - proc paramCount*(): int {.tags: [FReadIO].} = return cmdCount-1 + proc paramCount*(): int {.tags: [FReadIO].} = + # Docstring in nimdoc block. + result = cmdCount-1 -when defined(paramCount): +when defined(paramCount) or defined(nimdoc): proc commandLineParams*(): seq[TaintedString] = + ## Convenience proc which returns the command line parameters. + ## + ## This returns **only** the parameters. If you want to get the application + ## executable filename, call `getAppFilename() <#getAppFilename>`_. + ## + ## **Availability**: On Posix there is no portable way to get the command + ## line from a DLL and thus the proc isn't defined in this environment. You + ## can test for its availability with `defined() <system.html#defined>`_. + ## Example: + ## + ## .. code-block:: nimrod + ## when defined(commandLineParams): + ## # Use commandLineParams() here + ## else: + ## # Do something else! result = @[] for i in 1..paramCount(): result.add(paramStr(i)) |