diff options
author | havardjohn <havard.mjaavatten@outlook.com> | 2022-08-20 10:30:11 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-20 04:30:11 -0400 |
commit | f4bbf3bf0b5188352ee996831f921150760fb112 (patch) | |
tree | 8916efd708428672c22197f4170f0b5b60f601cf /lib/std/envvars.nim | |
parent | 641381e3d47afba95f99efc77bb9a5ed65d07b3a (diff) | |
download | Nim-f4bbf3bf0b5188352ee996831f921150760fb112.tar.gz |
Add use of Windows Wide CRT API for env. vars (#20084)
* Add use of Windows Wide CRT API for env. vars Replaces use of CRT API `getenv` and `putenv` with respectively `_wgetenv` and `_wputenv`. Motivation is to reliably convert environment variables to UTF-8, and the wide API is best there, because it's reliably UTF-16. Changed the hack in `lib/std/private/win_setenv.nim` by switching the order of the Unicode and MBCS environment update; Unicode first, MBCS second. Because `_wgetenv`/`_wputenv` is now used, the Unicode environment will be initialized, so it should always be updated. Stop updating MBCS environment with the name of `getEnv`. It's not necessarily true that MBCS encoding and the `string` encoding is the same. Instead convert UTF-16 to current Windows code page with `wcstombs`, and use that string to update MBCS. Fixes regression in `6b3c77e` that caused `std/envvars.getEnv` or `std/os.getEnv` on Windows to return non-UTF-8 encoded strings. Add tests that test environment variables with Unicode characters in their name or value. * Fix test issues Fixes * `nim cpp` didn't compile the tests * Nimscript import of `tosenv.nim` from `test_nimscript.nims` failed with "cannot importc" * Fix missing error check on `wcstombs` * Fix ANSI testing errors * Separate ANSI-related testing to their own tests, and only executing them if running process has a specific code page * Setting locale with `setlocale` was not reliable and didn't work on certain machines * Add handling of a "no character representation" error in second `wcstombs` call * tests/newruntime_misc: Increment allocCount Increments overall allocations in `tnewruntime_misc` test. This is because `getEnv` now does an additional allocation: allocation of the UTF-16 string used as parameter to `c_wgetenv`. * Revert "tests/newruntime_misc: Increment allocCount" This reverts commit 4d4fe8bd3edb1bfc6d600f247af797c7552f5477. * tests/newruntime_misc: Increment allocCount on Windows Increments overall allocations in `tnewruntime_misc` test for Windows. This is because `getEnv` on Windows now does an additional allocation: allocation of the UTF-16 string used as parameter to `c_wgetenv`. * Refactor, adding suggestions from code review Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com> * Document, adding suggestions Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com> Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
Diffstat (limited to 'lib/std/envvars.nim')
-rw-r--r-- | lib/std/envvars.nim | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim index 5b135cbd3..d7706c17d 100644 --- a/lib/std/envvars.nim +++ b/lib/std/envvars.nim @@ -57,15 +57,19 @@ when not defined(nimscript): else: - proc c_getenv(env: cstring): cstring {. - importc: "getenv", header: "<stdlib.h>".} when defined(windows): proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "<stdlib.h>".} from std/private/win_setenv import setEnvImpl import winlean + 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`. @@ -83,7 +87,7 @@ when not defined(nimscript): assert getEnv("unknownEnv") == "" assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist" - let env = c_getenv(key) + let env = getEnvImpl(key) if env == nil: return default result = $env @@ -99,7 +103,7 @@ when not defined(nimscript): runnableExamples: assert not existsEnv("unknownEnv") - return c_getenv(key) != nil + return getEnvImpl(key) != nil proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = ## Sets the value of the `environment variable`:idx: named `key` to `val`. |