refactor envvars, oserrors; register vmops (#20592)
* refactor envvars, oserrors; register vmops * remove type definitions
This commit is contained in:
parent
b13ef07f58
commit
b07526b2c7
5 changed files with 17 additions and 347 deletions
|
|
@ -22,8 +22,8 @@ when declared(math.signbit):
|
||||||
# ditto
|
# ditto
|
||||||
from std/math as math3 import signbit
|
from std/math as math3 import signbit
|
||||||
|
|
||||||
from std/os import getEnv, existsEnv, delEnv, putEnv, envPairs,
|
from std/envvars import getEnv, existsEnv, delEnv, putEnv, envPairs
|
||||||
dirExists, fileExists, walkDir, getAppFilename, raiseOSError, osLastError
|
from std/os import dirExists, fileExists, walkDir, getAppFilename
|
||||||
|
|
||||||
from std/times import cpuTime
|
from std/times import cpuTime
|
||||||
from std/hashes import hash
|
from std/hashes import hash
|
||||||
|
|
@ -44,6 +44,9 @@ template mathop(op) {.dirty.} =
|
||||||
template osop(op) {.dirty.} =
|
template osop(op) {.dirty.} =
|
||||||
registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
|
registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
|
||||||
|
|
||||||
|
template envvarsop(op) {.dirty.} =
|
||||||
|
registerCallback(c, "stdlib.envvars." & astToStr(op), `op Wrapper`)
|
||||||
|
|
||||||
template timesop(op) {.dirty.} =
|
template timesop(op) {.dirty.} =
|
||||||
registerCallback(c, "stdlib.times." & astToStr(op), `op Wrapper`)
|
registerCallback(c, "stdlib.times." & astToStr(op), `op Wrapper`)
|
||||||
|
|
||||||
|
|
@ -219,10 +222,10 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||||
registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
|
registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
|
||||||
|
|
||||||
when defined(nimcore):
|
when defined(nimcore):
|
||||||
wrap2s(getEnv, osop)
|
wrap2s(getEnv, envvarsop)
|
||||||
wrap1s(existsEnv, osop)
|
wrap1s(existsEnv, envvarsop)
|
||||||
wrap2svoid(putEnv, osop)
|
wrap2svoid(putEnv, envvarsop)
|
||||||
wrap1svoid(delEnv, osop)
|
wrap1svoid(delEnv, envvarsop)
|
||||||
wrap1s(dirExists, osop)
|
wrap1s(dirExists, osop)
|
||||||
wrap1s(fileExists, osop)
|
wrap1s(fileExists, osop)
|
||||||
wrapDangerous(writeFile, ioop)
|
wrapDangerous(writeFile, ioop)
|
||||||
|
|
@ -350,7 +353,7 @@ proc registerAdditionalOps*(c: PCtx) =
|
||||||
let x = a.getFloat(1)
|
let x = a.getFloat(1)
|
||||||
addFloatSprintf(p.strVal, x)
|
addFloatSprintf(p.strVal, x)
|
||||||
|
|
||||||
wrapIterator("stdlib.os.envPairsImplSeq"): envPairs()
|
wrapIterator("stdlib.envvars.envPairsImplSeq"): envPairs()
|
||||||
|
|
||||||
registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) =
|
registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) =
|
||||||
let typ = a.getNode(0).typ
|
let typ = a.getNode(0).typ
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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.}
|
|
||||||
|
|
@ -81,11 +81,6 @@ else:
|
||||||
proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.}
|
proc normalizePathAux(path: var string){.inline, raises: [], noSideEffect.}
|
||||||
|
|
||||||
type
|
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
|
ReadDirEffect* = object of ReadIOEffect ## Effect that denotes a read
|
||||||
## operation from the directory
|
## operation from the directory
|
||||||
## structure.
|
## structure.
|
||||||
|
|
@ -93,8 +88,6 @@ type
|
||||||
## operation to
|
## operation to
|
||||||
## the directory structure.
|
## the directory structure.
|
||||||
|
|
||||||
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
|
||||||
|
|
||||||
import std/private/osseps
|
import std/private/osseps
|
||||||
export osseps
|
export osseps
|
||||||
|
|
||||||
|
|
@ -884,8 +877,11 @@ proc unixToNativePath*(path: string, drive=""): string {.
|
||||||
add result, path[i]
|
add result, path[i]
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
include "includes/oserr"
|
import std/oserrors
|
||||||
include "includes/osenv"
|
export oserrors
|
||||||
|
|
||||||
|
import std/envvars
|
||||||
|
export envvars
|
||||||
|
|
||||||
proc getHomeDir*(): string {.rtl, extern: "nos$1",
|
proc getHomeDir*(): string {.rtl, extern: "nos$1",
|
||||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ template main =
|
||||||
doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
|
doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
|
||||||
doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
|
doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
|
||||||
|
|
||||||
|
static: main()
|
||||||
main()
|
main()
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -69,7 +70,7 @@ when not defined(js) and not defined(nimscript):
|
||||||
|
|
||||||
doAssertRaises(OSError): delEnv("foo=bar")
|
doAssertRaises(OSError): delEnv("foo=bar")
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) and not defined(nimscript):
|
||||||
import std/encodings
|
import std/encodings
|
||||||
|
|
||||||
proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
|
proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue