1 //go:build nintendoswitch || wasip1
2 3 package syscall
4 5 import (
6 "unsafe"
7 )
8 9 func Environ() []string {
10 11 // This function combines all the environment into a single allocation.
12 // While this optimizes for memory usage and garbage collector
13 // overhead, it does run the risk of potentially pinning a "large"
14 // allocation if a user holds onto a single environment variable or
15 // value. Having each variable be its own allocation would make the
16 // trade-off in the other direction.
17 18 // calculate total memory required
19 var length uintptr
20 var vars int
21 for environ := libc_environ; *environ != nil; {
22 length += libc_strlen(*environ)
23 vars++
24 environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
25 }
26 27 // allocate our backing slice for the strings
28 b := make([]byte, length)
29 // and the slice we're going to return
30 envs := make([]string, 0, vars)
31 32 // loop over the environment again, this time copying over the data to the backing slice
33 for environ := libc_environ; *environ != nil; {
34 length = libc_strlen(*environ)
35 // construct a Go string pointing at the libc-allocated environment variable data
36 var envVar string
37 rawEnvVar := (*struct {
38 ptr unsafe.Pointer
39 length uintptr
40 })(unsafe.Pointer(&envVar))
41 rawEnvVar.ptr = *environ
42 rawEnvVar.length = length
43 // pull off the number of bytes we need for this environment variable
44 var bs []byte
45 bs, b = b[:length], b[length:]
46 // copy over the bytes to the Go heap
47 copy(bs, envVar)
48 // convert trimmed slice to string
49 s := *(*string)(unsafe.Pointer(&bs))
50 // add s to our list of environment variables
51 envs = append(envs, s)
52 // environ++
53 environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
54 }
55 return envs
56 }
57 58 func Getenv(key string) (value string, found bool) {
59 data := cstring(key)
60 raw := libc_getenv(&data[0])
61 if raw == nil {
62 return "", false
63 }
64 65 ptr := uintptr(unsafe.Pointer(raw))
66 for size := uintptr(0); ; size++ {
67 v := *(*byte)(unsafe.Pointer(ptr))
68 if v == 0 {
69 src := *(*[]byte)(unsafe.Pointer(&sliceHeader{buf: raw, len: size, cap: size}))
70 return string(src), true
71 }
72 ptr += unsafe.Sizeof(byte(0))
73 }
74 }
75 76 func Setenv(key, val string) (err error) {
77 if len(key) == 0 {
78 return EINVAL
79 }
80 for i := 0; i < len(key); i++ {
81 if key[i] == '=' || key[i] == 0 {
82 return EINVAL
83 }
84 }
85 for i := 0; i < len(val); i++ {
86 if val[i] == 0 {
87 return EINVAL
88 }
89 }
90 runtimeSetenv(key, val)
91 return
92 }
93 94 func Unsetenv(key string) (err error) {
95 runtimeUnsetenv(key)
96 return
97 }
98 99 func Clearenv() {
100 for _, s := range Environ() {
101 for j := 0; j < len(s); j++ {
102 if s[j] == '=' {
103 Unsetenv(s[0:j])
104 break
105 }
106 }
107 }
108 }
109 110 //go:extern environ
111 var libc_environ *unsafe.Pointer
112