diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim index 1a01ab9bcd3e3..4a776eb78756c 100644 --- a/lib/pure/includes/osenv.nim +++ b/lib/pure/includes/osenv.nim @@ -45,7 +45,7 @@ when not defined(nimscript): proc c_getenv(env: cstring): cstring {. importc: "getenv", header: "".} when defined(windows): - proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "".} from std/private/win_setenv import setEnvImpl else: proc c_setenv(envname: cstring, envval: cstring, overwrite: cint): cint {.importc: "setenv", header: "".} @@ -121,7 +121,8 @@ when not defined(nimscript): ]# if key.len == 0 or '=' in key: raise newException(OSError, "invalid key, got: " & key) - if c_putenv_s(key, "") != 0'i32: bail + let envToDel = key & "=" + if c_putenv(cstring envToDel) != 0'i32: bail else: if c_unsetenv(key) != 0'i32: bail diff --git a/lib/std/private/win_setenv.nim b/lib/std/private/win_setenv.nim index 91c3f15b0b4c1..0dfe0ed46dc08 100644 --- a/lib/std/private/win_setenv.nim +++ b/lib/std/private/win_setenv.nim @@ -30,44 +30,45 @@ else: # same as winlean.setEnvironmentVariableA proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "".} - proc c_putenv_s(envname: cstring, envval: cstring): cint {.importc: "_putenv_s", header: "".} + proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "".} proc c_wgetenv(varname: ptr wchar_t): ptr wchar_t {.importc: "_wgetenv", header: "".} var errno {.importc, header: "".}: cint - var gWenviron {.importc:"_wenviron".}: ptr ptr wchar_t + var gWenviron {.importc: "_wenviron".}: ptr ptr wchar_t # xxx `ptr UncheckedArray[WideCString]` did not work - proc mbstowcs_s(pReturnValue: ptr csize_t, wcstr: ptr wchar_t, sizeInWords: csize_t, mbstr: cstring, count: csize_t): cint {.importc: "mbstowcs_s", header: "".} + proc mbstowcs(wcstr: ptr wchar_t, mbstr: cstring, count: csize_t): csize_t {.importc: "mbstowcs", header: "".} # xxx cint vs errno_t? - proc setEnvImpl*(name: cstring, value: cstring, overwrite: cint): cint = + proc setEnvImpl*(name: string, value: string, overwrite: cint): cint = const EINVAL = cint(22) - const MAX_ENV = 32767 - # xxx get it from: `var MAX_ENV {.importc: "_MAX_ENV", header:"".}: cint` - if overwrite == 0 and c_getenv(name) != nil: return 0 - if value[0] != '\0': - let e = c_putenv_s(name, value) + if overwrite == 0 and c_getenv(cstring(name)) != nil: return 0 + if value != "": + let envstring = name & "=" & value + let e = c_putenv(cstring(envstring)) if e != 0: - errno = e + errno = EINVAL return -1 return 0 #[ - We are trying to set the value to an empty string, but `_putenv_s` deletes + We are trying to set the value to an empty string, but `_putenv` deletes entries if the value is an empty string, and just calling SetEnvironmentVariableA doesn't update `_environ`, so we have to do these terrible things. ]# - if c_putenv_s(name, " ") != 0: + let envstring = name & "= " + if c_putenv(cstring(envstring)) != 0: errno = EINVAL return -1 # Here lies the documentation we blatently ignore to make this work. - var s = c_getenv(name) + var s = c_getenv(cstring(name)) s[0] = '\0' #[ This would result in a double null termination, which normally signifies the end of the environment variable list, so we stick a completely empty environment variable into the list instead. ]# + s = c_getenv(cstring(name)) s[1] = '=' #[ If gWenviron is null, the wide environment has not been initialized @@ -77,19 +78,19 @@ else: ]# if gWenviron != nil: # var buf: array[MAX_ENV + 1, WideCString] - var buf: array[MAX_ENV + 1, Utf16Char] + let requiredSize = mbstowcs(nil, cstring(name), 0).int + var buf = newSeq[Utf16Char](requiredSize + 1) let buf2 = cast[ptr wchar_t](buf[0].addr) - var len: csize_t - if mbstowcs_s(len.addr, buf2, buf.len.csize_t, name, MAX_ENV) != 0: + if mbstowcs(buf2, cstring(name), csize_t(requiredSize + 1)) == csize_t(high(uint)): errno = EINVAL return -1 - let ptrToEnv = cast[WideCString](c_wgetenv(buf2)) + var ptrToEnv = cast[WideCString](c_wgetenv(buf2)) ptrToEnv[0] = '\0'.Utf16Char - let ptrToEnv2 = cast[WideCString](c_wgetenv(buf2)) - ptrToEnv2[1] = '='.Utf16Char + ptrToEnv = cast[WideCString](c_wgetenv(buf2)) + ptrToEnv[1] = '='.Utf16Char # And now, we have to update the outer environment to have a proper empty value. - if setEnvironmentVariableA(name, value) == 0: + if setEnvironmentVariableA(cstring(name), cstring(value)) == 0: errno = EINVAL return -1 return 0