From 7036ca55e6cffd2db7bb78ef380b78f92a65205f Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 10 Mar 2020 15:25:16 +0200 Subject: [PATCH] os: implement os.environ() (part 2/2) (#3971) --- vlib/os/environment.v | 80 ++++++++++++++++++++++++++++++++++++++ vlib/os/environment_test.v | 36 +++++++++++++++++ vlib/os/os.v | 42 -------------------- vlib/os/os_test.v | 19 --------- 4 files changed, 116 insertions(+), 61 deletions(-) create mode 100644 vlib/os/environment.v create mode 100644 vlib/os/environment_test.v diff --git a/vlib/os/environment.v b/vlib/os/environment.v new file mode 100644 index 0000000000..c41b13aaf1 --- /dev/null +++ b/vlib/os/environment.v @@ -0,0 +1,80 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module os + +fn C.getenv(byteptr) &char +// C.GetEnvironmentStringsW & C.FreeEnvironmentStringsW are defined only on windows +fn C.GetEnvironmentStringsW() &u16 + + +fn C.FreeEnvironmentStringsW(&u16) int +// `getenv` returns the value of the environment variable named by the key. +pub fn getenv(key string) string { + $if windows { + s := C._wgetenv(key.to_wide()) + if s == 0 { + return '' + } + return string_from_wide(s) + } $else { + s := C.getenv(key.str) + if s == 0 { + return '' + } + // NB: C.getenv *requires* that the result be copied. + return cstring_to_vstring(byteptr(s)) + } +} + +// os.setenv sets the value of an environment variable with `name` to `value`. +pub fn setenv(name string, value string, overwrite bool) int { + $if windows { + format := '$name=$value' + if overwrite { + return C._putenv(format.str) + } + return -1 + } $else { + return C.setenv(name.str, value.str, overwrite) + } +} + +// os.unsetenv clears an environment variable with `name`. +pub fn unsetenv(name string) int { + $if windows { + format := '${name}=' + return C._putenv(format.str) + } $else { + return C.unsetenv(name.str) + } +} + +// See: https://linux.die.net/man/5/environ for unix platforms. +// See: https://docs.microsoft.com/bg-bg/windows/win32/api/processenv/nf-processenv-getenvironmentstrings +// os.environ returns a map of all the current environment variables +pub fn environ() map[string]string { + mut res := map[string]string + $if windows { + mut estrings := C.GetEnvironmentStringsW() + mut eline := '' + for c := estrings; *c != 0; c = c + eline.len + 1 { + eline = string_from_wide(c) + eq_index := eline.index_byte(`=`) + if eq_index > 0 { + res[eline[0..eq_index]] = eline[eq_index + 1..] + } + } + C.FreeEnvironmentStringsW(estrings) + } $else { + e := &byteptr(&C.environ) + for i := 0; !isnil(e[i]); i++ { + eline := cstring_to_vstring(e[i]) + eq_index := eline.index_byte(`=`) + if eq_index > 0 { + res[eline[0..eq_index]] = eline[eq_index + 1..] + } + } + } + return res +} diff --git a/vlib/os/environment_test.v b/vlib/os/environment_test.v new file mode 100644 index 0000000000..6b0d9e351f --- /dev/null +++ b/vlib/os/environment_test.v @@ -0,0 +1,36 @@ +import os + +fn test_getenv() { + // VEXE is set by the V builtin test runner + assert os.getenv('VEXE').len > 0 + assert os.getenv('PATH').len > 0 +} + +fn test_setenv() { + os.setenv('foo', 'bar', true) + assert os.getenv('foo') == 'bar' + // `setenv` should not set if `overwrite` is false + os.setenv('foo', 'bar2', false) + assert os.getenv('foo') == 'bar' + // `setenv` should overwrite if `overwrite` is true + os.setenv('foo', 'bar2', true) + assert os.getenv('foo') == 'bar2' +} + +fn test_unsetenv() { + os.setenv('foo', 'bar', true) + os.unsetenv('foo') + assert os.getenv('foo') == '' +} + +fn test_environ() { + os.setenv('myvar1', 'bar1', true) + os.setenv('myvar2', 'bar2', true) + assert os.getenv('myvar1') == 'bar1' + assert os.getenv('myvar2') == 'bar2' + assert os.getenv('myvar_not_defined') == '' + all := os.environ() + assert all['myvar1'] == 'bar1' + assert all['myvar2'] == 'bar2' + assert all['myvar_not_defined'] == '' +} diff --git a/vlib/os/os.v b/vlib/os/os.v index 2b40756b39..ce4bcb6ab4 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -65,9 +65,6 @@ fn C.getline(voidptr, voidptr, voidptr) int fn C.ftell(fp voidptr) int -fn C.getenv(byteptr) &char - - fn C.sigaction(int, voidptr, int) @@ -507,45 +504,6 @@ pub fn sigint_to_signal_name(si int) string { return 'unknown' } -// `getenv` returns the value of the environment variable named by the key. -pub fn getenv(key string) string { - $if windows { - s := C._wgetenv(key.to_wide()) - if s == 0 { - return '' - } - return string_from_wide(s) - } $else { - s := C.getenv(key.str) - if s == 0 { - return '' - } - // NB: C.getenv *requires* that the result be copied. - return cstring_to_vstring(byteptr(s)) - } -} - -pub fn setenv(name string, value string, overwrite bool) int { - $if windows { - format := '$name=$value' - if overwrite { - return C._putenv(format.str) - } - return -1 - } $else { - return C.setenv(name.str, value.str, overwrite) - } -} - -pub fn unsetenv(name string) int { - $if windows { - format := '${name}=' - return C._putenv(format.str) - } $else { - return C.unsetenv(name.str) - } -} - const ( F_OK = 0 X_OK = 1 diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index ec16ad0d13..1997486d57 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -8,25 +8,6 @@ fn testsuite_end() { cleanup_leftovers() } -fn test_setenv() { - os.setenv('foo', 'bar', true) - assert os.getenv('foo') == 'bar' - - // `setenv` should not set if `overwrite` is false - os.setenv('foo', 'bar2', false) - assert os.getenv('foo') == 'bar' - - // `setenv` should overwrite if `overwrite` is true - os.setenv('foo', 'bar2', true) - assert os.getenv('foo') == 'bar2' -} - -fn test_unsetenv() { - os.setenv('foo', 'bar', true) - os.unsetenv('foo') - assert os.getenv('foo') == '' -} - fn test_open_file() { filename := './test1.txt' hello := 'hello world!'