# Module os

This module contains basic operating system facilities like retrieving environment variables, reading command line arguments, working with directories, running shell commands, etc.

# Imports

strutils, times, posix

# Types

    FReadEnv = object of FReadIO

  effect that denotes a read from an environment variable

    FWriteEnv = object of FWriteIO

  effect that denotes a write to an environment variable

    FReadDir = object of FReadIO

  effect that denotes a write operation to the directory structure

    FWriteDir = object of FWriteIO

  effect that denotes a write operation to the directory structure

    TPathComponent = enum
      pcFile,                     ## path refers to a file
      pcLinkToFile,               ## path refers to a symbolic link to a file
      pcDir,                      ## path refers to a directory
      pcLinkToDir                 ## path refers to a symbolic link to a directory

  Enumeration specifying a path component.

    TFilePermission = enum
      fpUserExec,                 ## execute access for the file owner
      fpUserWrite,                ## write access for the file owner
      fpUserRead,                 ## read access for the file owner
      fpGroupExec,                ## execute access for the group
      fpGroupWrite,               ## write access for the group
      fpGroupRead,                ## read access for the group
      fpOthersExec,               ## execute access for others
      fpOthersWrite,              ## write access for others
      fpOthersRead                ## read access for others

  file access permission; modelled after UNIX

# Consts

    CurDir = '.'

  The constant string used by the operating system to refer to the current directory.

  For example: '.' for POSIX or ':' for the classic Macintosh.

    ParDir = ".."

  The constant string used by the operating system to refer to the parent directory.

  For example: ".." for POSIX or "::" for the classic Macintosh.

    DirSep = '/'

  The character used by the operating system to separate pathname components, for example, '/' for POSIX or ':' for the classic Macintosh.

    AltSep = '/'

  An alternative character used by the operating system to separate pathname components, or the same as DirSep if only one separator character exists. This is set to '/' on Windows systems where DirSep is a backslash.

    PathSep = ':'

  The character conventionally used by the operating system to separate search patch components (as in PATH), such as ':' for POSIX or ';' for Windows.

    FileSystemCaseSensitive = true

  True if the file system is case sensitive, false otherwise. Used by cmpPaths to compare filenames properly.

    ExeExt = ""

  The file extension of native executables. For example: "" for POSIX, "exe" on Windows.

    ScriptExt = ""

  The file extension of a script file. For example: "" for POSIX, "bat" on Windows.

    DynlibFormat = "lib$1.so"

  The format string to turn a filename into a DLL file (also called shared object on some operating systems).

    ExtSep = '.'

  The character which separates the base filename from the extension; for example, the '.' in `os.nim`.

# Procs

    proc OSErrorMsg(): string {.rtl, extern: "nos$1", raises: [], tags: [].}

  Retrieves the operating system's error flag, `errno`. On Windows `GetLastError` is checked before `errno`. Returns "" if no error occured.

    proc OSError(msg: string = "") {.noinline, rtl, extern: "nos$1",
                                     raises: [EOS, EOS], tags: [].}

  raises an EOS exception with the given message `msg`. If `msg == ""`, the operating system's error flag (`errno`) is converted to a readable error message. On Windows `GetLastError` is checked before `errno`. If no error flag is set, the message `unknown OS error` is used.

    proc UnixToNativePath(path: string): string {.noSideEffect, rtl,
        extern: "nos$1", raises: [], tags: [].}

  Converts an UNIX-like path to a native one.

  On an UNIX system this does nothing. Else it converts '/', '.', '..' to the appropriate things.

    proc existsFile(filename: string): bool {.rtl, extern: "nos$1",
        tags: [FReadDir], raises: [].}

  Returns true if the file exists, false otherwise.

    proc existsDir(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir],
                                        raises: [].}

  Returns true iff the directory dir exists. If dir is a file, false is returned.

    proc getLastModificationTime(file: string): TTime {.rtl, extern: "nos$1",
        raises: [EOS], tags: [].}

  Returns the file's last modification time.

    proc getLastAccessTime(file: string): TTime {.rtl, extern: "nos$1",
        raises: [EOS], tags: [].}

  Returns the file's last read or write access time.

    proc getCreationTime(file: string): TTime {.rtl, extern: "nos$1", raises: [EOS],
        tags: [].}

  Returns the file's creation time.

    proc fileNewer(a, b: string): bool {.rtl, extern: "nos$1", raises: [EOS],
                                         tags: [].}

  Returns true if the file a is newer than file b, i.e. if a's modification time is later than b's.

    proc getCurrentDir(): string {.rtl, extern: "nos$1", tags: [], raises: [EOS].}

  Returns the current working directory.

    proc setCurrentDir(newDir: string) {.inline, tags: [], raises: [EOS].}

  Sets the current working directory; EOS is raised if newDir cannot been set.

    proc JoinPath(head, tail: string): string {.noSideEffect, rtl, extern: "nos$1",
        raises: [], tags: [].}

  Joins two directory names to one.

  For example on Unix:

      JoinPath("usr", "lib")

  results in:

      "usr/lib"

  If head is the empty string, tail is returned. If tail is the empty string, head is returned.

    proc JoinPath(parts: varargs[string]): string {.noSideEffect, rtl,
        extern: "nos$1OpenArray", raises: [], tags: [].}

  The same as JoinPath(head, tail), but works with any number of directory parts.

    proc `/`(head, tail: string): string {.noSideEffect, raises: [], tags: [].}

  The same as `joinPath(head, tail)`

    proc SplitPath(path: string): tuple[head, tail: string] {.noSideEffect, rtl,
        extern: "nos$1", raises: [], tags: [].}

  Splits a directory into (head, tail), so that `JoinPath(head, tail) == path`.

  Examples:

      SplitPath("usr/local/bin") -> ("usr/local", "bin")
      SplitPath("usr/local/bin/") -> ("usr/local/bin", "")
      SplitPath("bin") -> ("", "bin")
      SplitPath("/bin") -> ("", "bin")
      SplitPath("") -> ("", "")

    proc parentDir(path: string): string {.noSideEffect, rtl, extern: "nos$1",
                                           raises: [], tags: [].}

  Returns the parent directory of path.

  This is often the same as the `head` result of `splitPath`. If there is no parent, `path` is returned.

  Example: `parentDir("/usr/local/bin") == "/usr/local"`.
  Example: `parentDir("/usr/local/bin/") == "/usr/local"`.

    proc isRootDir(path: string): bool {.noSideEffect, rtl, extern: "nos$1",
                                         raises: [], tags: [].}

  Checks whether a given path is a root directory

    proc `/../`(head, tail: string): string {.noSideEffect, raises: [], tags: [].}

  The same as `parentDir(head) / tail`

    proc splitFile(path: string): tuple[dir, name, ext: string] {.noSideEffect, rtl,
        extern: "nos$1", raises: [], tags: [].}

  Splits a filename into (dir, filename, extension). dir does not end in DirSep. extension includes the leading dot.

  Example:

      var (dir, name, ext) = splitFile("usr/local/nimrodc.html")
      assert dir == "usr/local"
      assert name == "nimrodc"
      assert ext == ".html"

  If path has no extension, ext is the empty string. If path has no directory component, dir is the empty string. If path has no filename component, name and ext are empty strings.

    proc extractFilename(path: string): string {.noSideEffect, rtl, extern: "nos$1",
        raises: [], tags: [].}

  Extracts the filename of a given path. This is the same as `name & ext` from `splitFile(path)`.

    proc expandFilename(filename: string): string {.rtl, extern: "nos$1",
        tags: [FReadDir], raises: [EOS].}

  Returns the full path of filename, raises EOS in case of an error.

    proc ChangeFileExt(filename, ext: string): string {.noSideEffect, rtl,
        extern: "nos$1", raises: [], tags: [].}

  Changes the file extension to ext.

  If the filename has no extension, ext will be added. If ext == "" then any extension is removed. Ext should be given without the leading '.', because some filesystems may use a different character. (Although I know of none such beast.)

    proc addFileExt(filename, ext: string): string {.noSideEffect, rtl,
        extern: "nos$1", raises: [], tags: [].}

  Adds the file extension ext to filename, unless filename already has an extension.

  Ext should be given without the leading '.', because some filesystems may use a different character. (Although I know of none such beast.)

    proc cmpPaths(pathA, pathB: string): int {.noSideEffect, rtl, extern: "nos$1",
        raises: [], tags: [].}

  Compares two paths.

  On a case-sensitive filesystem this is done case-sensitively otherwise case-insensitively. Returns:

  0 iff pathA == pathB
  < 0 iff pathA < pathB
  > 0 iff pathA > pathB

    proc isAbsolute(path: string): bool {.rtl, noSideEffect, extern: "nos$1",
                                          raises: [], tags: [].}

  Checks whether a given path is absolute.

  On Windows, network paths are considered absolute too.

    proc sameFile(path1, path2: string): bool {.rtl, extern: "nos$1",
        tags: [FReadDir], raises: [EOS].}

  Returns True if both pathname arguments refer to the same physical file or directory. Raises an exception if any of the files does not exist or information about it can not be obtained.

  This proc will return true if given two alternative hard-linked or sym-linked paths to the same file or directory.

    proc sameFileContent(path1, path2: string): bool {.rtl, extern: "nos$1",
        tags: [FReadIO], raises: [EOutOfMemory, E_Base].}

  Returns True if both pathname arguments refer to files with identical binary content.

    proc copyFile(source, dest: string) {.rtl, extern: "nos$1",
                                          tags: [FReadIO, FWriteIO],
                                          raises: [EOutOfMemory, EOS, E_Base].}

  Copies a file from source to dest. If this fails, EOS is raised.

    proc moveFile(source, dest: string) {.rtl, extern: "nos$1",
                                          tags: [FReadIO, FWriteIO], raises: [EOS].}

  Moves a file from source to dest. If this fails, EOS is raised.

    proc removeFile(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir],
                                    raises: [EOS].}

  Removes the file. If this fails, EOS is raised. This does not fail if the file never existed in the first place.

    proc execShellCmd(command: string): int {.rtl, extern: "nos$1", tags: [FExecIO],
        raises: [].}

  Executes a shell command.

  Command has the form 'program args' where args are the command line arguments given to program. The proc returns the error code of the shell when it has finished. The proc does not return until the process has finished. To execute a program without having a shell involved, use the execProcess proc of the osproc module.

    proc getEnv(key: string): TaintedString {.tags: [FReadEnv], raises: [].}

  Returns the value of the environment variable named key.

  If the variable does not exist, "" is returned. To distinguish whether a variable exists or it's value is just "", call existsEnv(key).

    proc existsEnv(key: string): bool {.tags: [FReadEnv], raises: [].}

  Checks whether the environment variable named key exists. Returns true if it exists, false otherwise.

    proc putEnv(key, val: string) {.tags: [FWriteEnv], raises: [EOS].}

  Sets the value of the environment variable named key to val. If an error occurs, EInvalidEnvVar is raised.

    proc removeDir(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir, FReadDir],
                                  raises: [EOS].}

  Removes the directory dir including all subdirectories and files in dir (recursively).

  If this fails, EOS is raised. This does not fail if the directory never existed in the first place.

    proc createDir(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir],
                                  raises: [EOS].}

  Creates the directory dir.

  The directory may contain several subdirectories that do not exist yet. The full path is created. If this fails, EOS is raised. It does not fail if the path already exists because for most usages this does not indicate an error.

    proc copyDir(source, dest: string) {.rtl, extern: "nos$1",
                                         tags: [FWriteIO, FReadIO],
                                         raises: [EOS, EOutOfMemory, E_Base].}

  Copies a directory from source to dest. If this fails, EOS is raised.

    proc parseCmdLine(c: string): seq[string] {.noSideEffect, rtl, extern: "nos$1",
        raises: [], tags: [].}

  Splits a command line into several components; This proc is only occassionally useful, better use the parseopt module.

  On Windows, it uses the following parsing rules (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx ):

  - Arguments are delimited by white space, which is either a space or a tab.
  - The caret character (^) is not recognized as an escape character or delimiter. The character is handled completely by the command-line parser in the operating system before being passed to the argv array in the program.
  - A string surrounded by double quotation marks ("string") is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument.
  - A double quotation mark preceded by a backslash (") is interpreted as a literal double quotation mark character (").
  - Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
  - If an even number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is interpreted as a string delimiter.
  - If an odd number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is "escaped" by the remaining backslash, causing a literal double quotation mark (") to be placed in argv.

  On Posix systems, it uses the following parsing rules: Components are separated by whitespace unless the whitespace occurs within `"` or `'` quotes.

    proc getFilePermissions(filename: string): set[TFilePermission] {.rtl,
        extern: "nos$1", tags: [FReadDir], raises: [EOS].}

  retrieves file permissions for filename. OSError is raised in case of an error. On Windows, only the `readonly` flag is checked, every other permission is available in any case.

    proc setFilePermissions(filename: string; permissions: set[TFilePermission]) {.
        rtl, extern: "nos$1", tags: [FWriteDir], raises: [EOS].}

  sets the file permissions for filename. OSError is raised in case of an error. On Windows, only the `readonly` flag is changed, depending on `fpUserWrite`.

    proc inclFilePermissions(filename: string; permissions: set[TFilePermission]) {.
        rtl, extern: "nos$1", tags: [FReadDir, FWriteDir], raises: [EOS].}

  a convenience procedure for:

      setFilePermissions(filename, getFilePermissions(filename)+permissions)

    proc exclFilePermissions(filename: string; permissions: set[TFilePermission]) {.
        rtl, extern: "nos$1", tags: [FReadDir, FWriteDir], raises: [EOS].}

  a convenience procedure for:

      setFilePermissions(filename, getFilePermissions(filename)-permissions)

    proc getHomeDir(): string {.rtl, extern: "nos$1", tags: [FReadEnv], raises: [].}

  Returns the home directory of the current user.

    proc getConfigDir(): string {.rtl, extern: "nos$1", tags: [FReadEnv], raises: [].}

  Returns the config directory of the current user for applications.

    proc getTempDir(): string {.rtl, extern: "nos$1", tags: [FReadEnv], raises: [].}

  Returns the temporary directory of the current user for applications to save temporary files in.

    proc paramStr(i: int): TaintedString {.tags: [FReadIO], raises: [EInvalidIndex].}

    proc paramCount(): int {.tags: [FReadIO], raises: [].}

    proc getAppFilename(): string {.rtl, extern: "nos$1", tags: [FReadIO],
                                    raises: [].}

  Returns the filename of the application's executable. Note: This does not work reliably on BSD.

    proc getApplicationFilename(): string {.rtl, extern: "nos$1", deprecated,
                                            raises: [], tags: [FReadIO].}

  Returns the filename of the application's executable. Deprecated since version 0.8.12: use `getAppFilename` instead.

    proc getApplicationDir(): string {.rtl, extern: "nos$1", deprecated, raises: [],
                                       tags: [FReadIO].}

  Returns the directory of the application's executable. Deprecated since version 0.8.12: use `getAppDir` instead.

    proc getAppDir(): string {.rtl, extern: "nos$1", tags: [FReadIO], raises: [].}

  Returns the directory of the application's executable. Note: This does not work reliably on BSD.

    proc sleep(milsecs: int) {.rtl, extern: "nos$1", tags: [FTime], raises: [].}

  sleeps milsecs milliseconds.

    proc getFileSize(file: string): BiggestInt {.rtl, extern: "nos$1",
        tags: [FReadIO], raises: [EOutOfMemory, EIO, EOS].}

  returns the file size of file. Can raise `EOS`.

    proc findExe(exe: string): string {.tags: [FReadDir, FReadEnv], raises: [].}

  Searches for exe in the current working directory and then in directories listed in the `PATH` environment variable. Returns "" if the exe cannot be found. On DOS-like platforms, exe is added an `.exe` file extension if it has no extension.

# Iterators

    iterator parentDirs(path: string; fromRoot = false; inclusive = true): string {.
        raises: [], tags: [].}

  Walks over all parent directories of a given path

  If fromRoot is set, the traversal will start from the file system root diretory. If inclusive is set, the original argument will be included in the traversal.

  Relative paths won't be expanded by this proc. Instead, it will traverse only the directories appearing in the relative path.

    iterator envPairs(): tuple[key, value: TaintedString] {.tags: [FReadEnv],
        raises: [].}

  Iterate over all environments variables. In the first component of the tuple is the name of the current variable stored, in the second its value.

    iterator walkFiles(pattern: string): string {.tags: [FReadDir], raises: [].}

  Iterate over all the files that match the pattern. On POSIX this uses the glob call.

  pattern is OS dependent, but at least the "*.ext" notation is supported.

    iterator walkDir(dir: string): tuple[kind: TPathComponent, path: string] {.
        tags: [FReadDir], raises: [].}

  walks over the directory dir and yields for each directory or file in dir. The component type and full path for each item is returned. Walking is not recursive. Example: This directory structure:

      dirA / dirB / fileB1.txt
           / dirC
           / fileA1.txt
           / fileA2.txt

  and this code:

      for kind, path in walkDir("dirA"):
        echo(path)

  produces this output (but not necessarily in this order!):

      dirA/dirB
      dirA/dirC
      dirA/fileA1.txt
      dirA/fileA2.txt

    iterator walkDirRec(dir: string; filter = {pcFile, pcDir}): string {.
        tags: [FReadDir], raises: [].}

  walks over the directory dir and yields for each file in dir. The full path for each file is returned. Walking is recursive. filter controls the behaviour of the iterator:

  filter | meaning
  --- | ---
  `pcFile` | yield real files
  `pcLinkToFile` | yield symbolic links to files
  `pcDir` | follow real directories
  `pcLinkToDir` | follow symbolic links to directories

Generated: 2013-05-21 09:55:07 UTC