env_libc.mx raw

   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