1 | // Copyright (c) 2019-2023 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) int |
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 | // os.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}' |
49 | if overwrite { |
50 | unsafe { |
51 | return C._putenv(&char(format.str)) |
52 | } |
53 | } else { |
54 | if getenv(name).len == 0 { |
55 | unsafe { |
56 | return C._putenv(&char(format.str)) |
57 | } |
58 | } |
59 | } |
60 | return -1 |
61 | } $else { |
62 | unsafe { |
63 | return C.setenv(&char(name.str), &char(value.str), overwrite) |
64 | } |
65 | } |
66 | } |
67 | |
68 | // os.unsetenv clears an environment variable with `name`. |
69 | pub fn unsetenv(name string) int { |
70 | $if windows { |
71 | format := '${name}=' |
72 | return C._putenv(&char(format.str)) |
73 | } $else { |
74 | return C.unsetenv(&char(name.str)) |
75 | } |
76 | } |
77 | |
78 | // See: https://linux.die.net/man/5/environ for unix platforms. |
79 | // See: https://docs.microsoft.com/bg-bg/windows/win32/api/processenv/nf-processenv-getenvironmentstrings |
80 | // os.environ returns a map of all the current environment variables |
81 | |
82 | pub fn environ() map[string]string { |
83 | mut res := map[string]string{} |
84 | $if windows { |
85 | mut estrings := C.GetEnvironmentStringsW() |
86 | mut eline := '' |
87 | for c := estrings; *c != 0; { |
88 | eline = unsafe { string_from_wide(c) } |
89 | eq_index := eline.index_u8(`=`) |
90 | if eq_index > 0 { |
91 | res[eline[0..eq_index]] = eline[eq_index + 1..] |
92 | } |
93 | unsafe { |
94 | c = c + eline.len + 1 |
95 | } |
96 | } |
97 | C.FreeEnvironmentStringsW(estrings) |
98 | } $else { |
99 | start := &&char(C.environ) |
100 | mut i := 0 |
101 | for { |
102 | x := unsafe { start[i] } |
103 | if x == 0 { |
104 | break |
105 | } |
106 | eline := unsafe { cstring_to_vstring(x) } |
107 | eq_index := eline.index_u8(`=`) |
108 | if eq_index > 0 { |
109 | res[eline[0..eq_index]] = eline[eq_index + 1..] |
110 | } |
111 | i++ |
112 | } |
113 | } |
114 | return res |
115 | } |