| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | module os |
| 5 | |
| 6 | fn C.getenv(&char) &char |
| 7 | |
| 8 | // C.GetEnvironmentStringsW & C.FreeEnvironmentStringsW are defined only on windows |
| 9 | fn C.GetEnvironmentStringsW() &u16 |
| 10 | |
| 11 | fn C.FreeEnvironmentStringsW(&u16) i32 |
| 12 | |
| 13 | // getenv returns the value of the environment variable named by the key. |
| 14 | // If there is not one found, it returns an empty string ''. |
| 15 | pub fn getenv(key string) string { |
| 16 | return getenv_opt(key) or { '' } |
| 17 | } |
| 18 | |
| 19 | // getenv_opt returns the value of a given environment variable. |
| 20 | // Returns `none` if the environment variable does not exist. |
| 21 | @[manualfree] |
| 22 | pub fn getenv_opt(key string) ?string { |
| 23 | unsafe { |
| 24 | $if windows { |
| 25 | kw := key.to_wide() |
| 26 | defer { |
| 27 | free(voidptr(kw)) |
| 28 | } |
| 29 | s := C._wgetenv(kw) |
| 30 | if s == 0 { |
| 31 | return none |
| 32 | } |
| 33 | return string_from_wide(s) |
| 34 | } $else { |
| 35 | s := C.getenv(&char(key.str)) |
| 36 | if s == nil { |
| 37 | return none |
| 38 | } |
| 39 | // Note: C.getenv *requires* that the result be copied. |
| 40 | return cstring_to_vstring(s) |
| 41 | } |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | // setenv sets the value of an environment variable with `name` to `value`. |
| 46 | pub fn setenv(name string, value string, overwrite bool) int { |
| 47 | $if windows { |
| 48 | format := '${name}=${value}'.to_wide() |
| 49 | defer { |
| 50 | unsafe { free(voidptr(format)) } |
| 51 | } |
| 52 | if overwrite { |
| 53 | unsafe { |
| 54 | return C._wputenv(format) |
| 55 | } |
| 56 | } else { |
| 57 | if getenv(name).len == 0 { |
| 58 | unsafe { |
| 59 | return C._wputenv(format) |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | return -1 |
| 64 | } $else { |
| 65 | unsafe { |
| 66 | return C.setenv(&char(name.str), &char(value.str), overwrite) |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | // unsetenv clears an environment variable with `name`. |
| 72 | pub fn unsetenv(name string) int { |
| 73 | $if windows { |
| 74 | format := '${name}='.to_wide() |
| 75 | defer { |
| 76 | unsafe { free(voidptr(format)) } |
| 77 | } |
| 78 | return C._wputenv(format) |
| 79 | } $else { |
| 80 | return C.unsetenv(&char(name.str)) |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | // environ returns a map of all the current environment variables. |
| 85 | // See: https://linux.die.net/man/5/environ for Unix platforms. |
| 86 | // See: https://docs.microsoft.com/bg-bg/windows/win32/api/processenv/nf-processenv-getenvironmentstrings |
| 87 | // for Windows OS. |
| 88 | pub fn environ() map[string]string { |
| 89 | // TODO how to declare Virtual C globals? |
| 90 | // const C.environ &&char |
| 91 | mut res := map[string]string{} |
| 92 | $if windows { |
| 93 | mut estrings := C.GetEnvironmentStringsW() |
| 94 | mut eline := '' |
| 95 | for c := estrings; *c != 0; { |
| 96 | eline = unsafe { string_from_wide(c) } |
| 97 | eq_index := eline.index_u8(`=`) |
| 98 | if eq_index > 0 { |
| 99 | res[eline[0..eq_index]] = eline[eq_index + 1..] |
| 100 | } |
| 101 | unsafe { |
| 102 | c = c + eline.len + 1 |
| 103 | } |
| 104 | } |
| 105 | C.FreeEnvironmentStringsW(estrings) |
| 106 | } $else { |
| 107 | start := &&char(voidptr(C.environ)) |
| 108 | mut i := 0 |
| 109 | for { |
| 110 | x := unsafe { start[i] } |
| 111 | if x == 0 { |
| 112 | break |
| 113 | } |
| 114 | eline := unsafe { cstring_to_vstring(x) } |
| 115 | eq_index := eline.index_u8(`=`) |
| 116 | if eq_index > 0 { |
| 117 | res[eline[0..eq_index]] = eline[eq_index + 1..] |
| 118 | } |
| 119 | i++ |
| 120 | } |
| 121 | } |
| 122 | return res |
| 123 | } |
| 124 | |