summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2022-10-19 01:44:26 +0800
committerGitHub <noreply@github.com>2022-10-18 19:44:26 +0200
commitb07526b2c77c75484d6008ea37d13cf022830c1a (patch)
treea6f01fd1b2270d41b46b173a736cc8fcd35aae3c /lib
parentb13ef07f5827fa63515cbb49d16723b3ae439f95 (diff)
downloadNim-b07526b2c77c75484d6008ea37d13cf022830c1a.tar.gz
refactor envvars, oserrors; register vmops (#20592)
* refactor envvars, oserrors; register vmops

* remove type definitions
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/includes/osenv.nim209
-rw-r--r--lib/pure/includes/oserr.nim121
-rw-r--r--lib/pure/os.nim14
3 files changed, 5 insertions, 339 deletions
diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim
deleted file mode 100644
index a1d906519..000000000
--- a/lib/pure/includes/osenv.nim
+++ /dev/null
@@ -1,209 +0,0 @@
-# Include file that implements 'getEnv' and friends. Do not import it!
-
-when not declared(os):
-  {.error: "This is an include file for os.nim!".}
-
-when not defined(nimscript):
-  when defined(nodejs):
-    proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} =
-      var ret = default.cstring
-      let key2 = key.cstring
-      {.emit: "const value = process.env[`key2`];".}
-      {.emit: "if (value !== undefined) { `ret` = value };".}
-      result = $ret
-
-    proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
-      var key2 = key.cstring
-      var ret: bool
-      {.emit: "`ret` = `key2` in process.env;".}
-      result = ret
-
-    proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
-      var key2 = key.cstring
-      var val2 = val.cstring
-      {.emit: "process.env[`key2`] = `val2`;".}
-
-    proc delEnv*(key: string) {.tags: [WriteEnvEffect].} =
-      var key2 = key.cstring
-      {.emit: "delete process.env[`key2`];".}
-
-    iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} =
-      var num: int
-      var keys: RootObj
-      {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".}
-      for i in 0..<num:
-        var key, value: cstring
-        {.emit: "`key` = `keys`[`i`]; `value` = process.env[`key`];".}
-        yield ($key, $value)
-
-  # commented because it must keep working with js+VM
-  # elif defined(js):
-  #   {.error: "requires -d:nodejs".}
-
-  else:
-
-    when defined(windows):
-      when defined(nimPreviewSlimSystem):
-        import std/widestrs
-      proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "<stdlib.h>".}
-      from std/private/win_setenv import setEnvImpl
-      proc c_wgetenv(varname: WideCString): WideCString {.importc: "_wgetenv",
-          header: "<stdlib.h>".}
-      proc getEnvImpl(env: cstring): WideCString = c_wgetenv(env.newWideCString)
-    else:
-      proc c_getenv(env: cstring): cstring {.
-        importc: "getenv", header: "<stdlib.h>".}
-      proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "<stdlib.h>".}
-      proc c_unsetenv(env: cstring): cint {.importc: "unsetenv", header: "<stdlib.h>".}
-      proc getEnvImpl(env: cstring): cstring = c_getenv(env)
-
-    proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} =
-      ## Returns the value of the `environment variable`:idx: 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`_.
-      ##
-      ## See also:
-      ## * `existsEnv proc`_
-      ## * `putEnv proc`_
-      ## * `delEnv proc`_
-      ## * `envPairs iterator`_
-      runnableExamples:
-        assert getEnv("unknownEnv") == ""
-        assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist"
-
-      let env = getEnvImpl(key)
-      if env == nil: return default
-      result = $env
-
-    proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
-      ## Checks whether the environment variable named `key` exists.
-      ## Returns true if it exists, false otherwise.
-      ##
-      ## See also:
-      ## * `getEnv proc`_
-      ## * `putEnv proc`_
-      ## * `delEnv proc`_
-      ## * `envPairs iterator`_
-      runnableExamples:
-        assert not existsEnv("unknownEnv")
-
-      return getEnvImpl(key) != nil
-
-    proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
-      ## Sets the value of the `environment variable`:idx: named `key` to `val`.
-      ## If an error occurs, `OSError` is raised.
-      ##
-      ## See also:
-      ## * `getEnv proc`_
-      ## * `existsEnv proc`_
-      ## * `delEnv proc`_
-      ## * `envPairs iterator`_
-      when defined(windows):
-        if key.len == 0 or '=' in key:
-          raise newException(OSError, "invalid key, got: " & $(key, val))
-        if setEnvImpl(key, val, 1'i32) != 0'i32:
-          raiseOSError(osLastError(), $(key, val))
-      else:
-        if c_setenv(key, val, 1'i32) != 0'i32:
-          raiseOSError(osLastError(), $(key, val))
-
-    proc delEnv*(key: string) {.tags: [WriteEnvEffect].} =
-      ## Deletes the `environment variable`:idx: named `key`.
-      ## If an error occurs, `OSError` is raised.
-      ##
-      ## See also:ven
-      ## * `getEnv proc`_
-      ## * `existsEnv proc`_
-      ## * `putEnv proc`_
-      ## * `envPairs iterator`_
-      template bail = raiseOSError(osLastError(), key)
-      when defined(windows):
-        #[ 
-        # https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-s-wputenv-s?view=msvc-160
-        > You can remove a variable from the environment by specifying an empty string (that is, "") for value_string
-        note that nil is not legal
-        ]#
-        if key.len == 0 or '=' in key:
-          raise newException(OSError, "invalid key, got: " & key)
-        let envToDel = key & "="
-        if c_putenv(cstring envToDel) != 0'i32: bail
-      else:
-        if c_unsetenv(key) != 0'i32: bail
-
-    when defined(windows):
-      when useWinUnicode:
-        when defined(cpp):
-          proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importcpp: "(NI16*)wcschr((const wchar_t *)#, #)",
-              header: "<string.h>".}
-        else:
-          proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.importc: "wcschr",
-              header: "<string.h>".}
-      else:
-        proc strEnd(cstr: cstring, c = 0'i32): cstring {.importc: "strchr",
-            header: "<string.h>".}
-    elif defined(macosx) and not defined(ios) and not defined(emscripten):
-      # From the manual:
-      # Shared libraries and bundles don't have direct access to environ,
-      # which is only available to the loader ld(1) when a complete program
-      # is being linked.
-      # The environment routines can still be used, but if direct access to
-      # environ is needed, the _NSGetEnviron() routine, defined in
-      # <crt_externs.h>, can be used to retrieve the address of environ
-      # at runtime.
-      proc NSGetEnviron(): ptr cstringArray {.importc: "_NSGetEnviron",
-          header: "<crt_externs.h>".}
-    elif defined(haiku):
-      var gEnv {.importc: "environ", header: "<stdlib.h>".}: cstringArray
-    else:
-      var gEnv {.importc: "environ".}: cstringArray
-
-    iterator envPairsImpl(): tuple[key, value: string] {.tags: [ReadEnvEffect].} =
-      when defined(windows):
-        block:
-          template impl(get_fun, typ, size, zero, free_fun) =
-            let env = get_fun()
-            var e = env
-            if e == nil: break
-            while true:
-              let eend = strEnd(e)
-              let kv = $e
-              let p = find(kv, '=')
-              yield (substr(kv, 0, p-1), substr(kv, p+1))
-              e = cast[typ](cast[ByteAddress](eend)+size)
-              if typeof(zero)(eend[1]) == zero: break
-            discard free_fun(env)
-          when useWinUnicode:
-            impl(getEnvironmentStringsW, WideCString, 2, 0, freeEnvironmentStringsW)
-          else:
-            impl(getEnvironmentStringsA, cstring, 1, '\0', freeEnvironmentStringsA)
-      else:
-        var i = 0
-        when defined(macosx) and not defined(ios) and not defined(emscripten):
-          var gEnv = NSGetEnviron()[]
-        while gEnv[i] != nil:
-          let kv = $gEnv[i]
-          inc(i)
-          let p = find(kv, '=')
-          yield (substr(kv, 0, p-1), substr(kv, p+1))
-
-proc envPairsImplSeq(): seq[tuple[key, value: string]] = discard # vmops
-
-iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} =
-  ## Iterate over all `environments variables`:idx:.
-  ##
-  ## In the first component of the tuple is the name of the current variable stored,
-  ## in the second its value.
-  ##
-  ## Works in native backends, nodejs and vm, like the following APIs:
-  ## * `getEnv proc`_
-  ## * `existsEnv proc`_
-  ## * `putEnv proc`_
-  ## * `delEnv proc`_
-  when nimvm:
-    for ai in envPairsImplSeq(): yield ai
-  else:
-    when defined(nimscript): discard
-    else:
-      for ai in envPairsImpl(): yield ai
diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim
deleted file mode 100644
index c58fdb22c..000000000
--- a/lib/pure/includes/oserr.nim
+++ /dev/null
@@ -1,121 +0,0 @@
-# Include file that implements 'osErrorMsg' and friends. Do not import it!
-
-when not declared(os):
-  {.error: "This is an include file for os.nim!".}
-
-when not defined(nimscript):
-  var errno {.importc, header: "<errno.h>".}: cint
-
-  proc c_strerror(errnum: cint): cstring {.
-    importc: "strerror", header: "<string.h>".}
-
-  when defined(windows):
-    import winlean
-    when useWinUnicode and defined(nimPreviewSlimSystem):
-      import std/widestrs
-
-proc `==`*(err1, err2: OSErrorCode): bool {.borrow.}
-proc `$`*(err: OSErrorCode): string {.borrow.}
-
-proc osErrorMsg*(errorCode: OSErrorCode): string =
-  ## Converts an OS error code into a human readable string.
-  ##
-  ## The error code can be retrieved using the `osLastError proc`_.
-  ##
-  ## If conversion fails, or `errorCode` is `0` then `""` will be
-  ## returned.
-  ##
-  ## On Windows, the `-d:useWinAnsi` compilation flag can be used to
-  ## make this procedure use the non-unicode Win API calls to retrieve the
-  ## message.
-  ##
-  ## See also:
-  ## * `raiseOSError proc`_
-  ## * `osLastError proc`_
-  runnableExamples:
-    when defined(linux):
-      assert osErrorMsg(OSErrorCode(0)) == ""
-      assert osErrorMsg(OSErrorCode(1)) == "Operation not permitted"
-      assert osErrorMsg(OSErrorCode(2)) == "No such file or directory"
-
-  result = ""
-  when defined(nimscript):
-    discard
-  elif defined(windows):
-    if errorCode != OSErrorCode(0'i32):
-      when useWinUnicode:
-        var msgbuf: WideCString
-        if formatMessageW(0x00000100 or 0x00001000 or 0x00000200,
-                        nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
-          result = $msgbuf
-          if msgbuf != nil: localFree(cast[pointer](msgbuf))
-      else:
-        var msgbuf: cstring
-        if formatMessageA(0x00000100 or 0x00001000 or 0x00000200,
-                        nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
-          result = $msgbuf
-          if msgbuf != nil: localFree(msgbuf)
-  else:
-    if errorCode != OSErrorCode(0'i32):
-      result = $c_strerror(errorCode.int32)
-
-proc newOSError*(
-  errorCode: OSErrorCode, additionalInfo = ""
-): owned(ref OSError) {.noinline.} =
-  ## Creates a new `OSError exception <system.html#OSError>`_.
-  ##
-  ## The `errorCode` will determine the
-  ## message, `osErrorMsg proc`_ will be used
-  ## to get this message.
-  ##
-  ## The error code can be retrieved using the `osLastError proc`_.
-  ##
-  ## If the error code is `0` or an error message could not be retrieved,
-  ## the message `unknown OS error` will be used.
-  ##
-  ## See also:
-  ## * `osErrorMsg proc`_
-  ## * `osLastError proc`_
-  var e: owned(ref OSError); new(e)
-  e.errorCode = errorCode.int32
-  e.msg = osErrorMsg(errorCode)
-  if additionalInfo.len > 0:
-    if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n'
-    e.msg.add "Additional info: "
-    e.msg.add additionalInfo
-      # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs.
-  if e.msg == "":
-    e.msg = "unknown OS error"
-  return e
-
-proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} =
-  ## Raises an `OSError exception <system.html#OSError>`_.
-  ##
-  ## Read the description of the `newOSError proc`_ to learn
-  ## how the exception object is created.
-  raise newOSError(errorCode, additionalInfo)
-
-{.push stackTrace:off.}
-proc osLastError*(): OSErrorCode {.sideEffect.} =
-  ## Retrieves the last operating system error code.
-  ##
-  ## This procedure is useful in the event when an OS call fails. In that case
-  ## this procedure will return the error code describing the reason why the
-  ## OS call failed. The `OSErrorMsg` procedure can then be used to convert
-  ## this code into a string.
-  ##
-  ## .. warning:: The behaviour of this procedure varies between Windows and POSIX systems.
-  ##   On Windows some OS calls can reset the error code to `0` causing this
-  ##   procedure to return `0`. It is therefore advised to call this procedure
-  ##   immediately after an OS call fails. On POSIX systems this is not a problem.
-  ##
-  ## See also:
-  ## * `osErrorMsg proc`_
-  ## * `raiseOSError proc`_
-  when defined(nimscript):
-    discard
-  elif defined(windows):
-    result = cast[OSErrorCode](getLastError())
-  else:
-    result = OSErrorCode(errno)
-{.pop.}
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 3e7c7cfc9..2779e8e68 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -81,11 +81,6 @@ else:
 proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.}
 
 type
-  ReadEnvEffect* = object of ReadIOEffect   ## Effect that denotes a read
-                                            ## from an environment variable.
-  WriteEnvEffect* = object of WriteIOEffect ## Effect that denotes a write
-                                            ## to an environment variable.
-
   ReadDirEffect* = object of ReadIOEffect   ## Effect that denotes a read
                                             ## operation from the directory
                                             ## structure.
@@ -93,8 +88,6 @@ type
                                             ## operation to
                                             ## the directory structure.
 
-  OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
-
 import std/private/osseps
 export osseps
 
@@ -884,8 +877,11 @@ proc unixToNativePath*(path: string, drive=""): string {.
         add result, path[i]
         inc(i)
 
-include "includes/oserr"
-include "includes/osenv"
+import std/oserrors
+export oserrors
+
+import std/envvars
+export envvars
 
 proc getHomeDir*(): string {.rtl, extern: "nos$1",
   tags: [ReadEnvEffect, ReadIOEffect].} =