v2 / vlib / os / environment.c.v
123 lines · 115 sloc · 2.89 KB · a87a4d73b9ab25cfff0822f4e94cf2a2d9e64323
Raw
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.
4module os
5
6fn C.getenv(&char) &char
7
8// C.GetEnvironmentStringsW & C.FreeEnvironmentStringsW are defined only on windows
9fn C.GetEnvironmentStringsW() &u16
10
11fn 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 ''.
15pub 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]
22pub 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`.
46pub 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`.
72pub 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.
88pub 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