2
0
Эх сурвалжийг харах

Add buffered get_env variants to os2

Jeroen van Rijn 2 сар өмнө
parent
commit
6347c87b5b

+ 2 - 2
core/os/env_windows.odin

@@ -41,13 +41,13 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error)
 	}
 
 	n2 := win32.GetEnvironmentVariableW(wkey, nil, 0)
-	if n2 == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND {
+	if n2 == 0 {
 		return "", .Env_Var_Not_Found
 	}
 
 	val_buf: [513]u16
 	n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:])))
-	if n2 == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND {
+	if n2 == 0 {
 		return "", .Env_Var_Not_Found
 	} else if int(n2) > len(buf) {
 		return "", .Buffer_Full

+ 27 - 5
core/os/os2/env.odin

@@ -3,25 +3,47 @@ package os2
 import "base:runtime"
 import "core:strings"
 
-// get_env retrieves the value of the environment variable named by the key
+// `get_env` retrieves the value of the environment variable named by the key
 // It returns the value, which will be empty if the variable is not present
 // To distinguish between an empty value and an unset value, use lookup_env
 // NOTE: the value will be allocated with the supplied allocator
 @(require_results)
-get_env :: proc(key: string, allocator: runtime.Allocator) -> string {
+get_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> string {
 	value, _ := lookup_env(key, allocator)
 	return value
 }
 
-// lookup_env gets the value of the environment variable named by the key
+// `get_env` retrieves the value of the environment variable named by the key
+// It returns the value, which will be empty if the variable is not present
+// To distinguish between an empty value and an unset value, use lookup_env
+// NOTE: this version takes a backing buffer for the string value
+@(require_results)
+get_env_buf :: proc(buf: []u8, key: string) -> string {
+	value, _ := lookup_env(buf, key)
+	return value
+}
+
+get_env :: proc{get_env_alloc, get_env_buf}
+
+// `lookup_env` gets the value of the environment variable named by the key
 // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true
 // Otherwise the returned value will be empty and the boolean will be false
 // NOTE: the value will be allocated with the supplied allocator
 @(require_results)
-lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
-	return _lookup_env(key, allocator)
+lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
+	return _lookup_env_alloc(key, allocator)
 }
 
+// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer.
+// Note that it is limited to environment names and values of 512 utf-16 values each
+// due to the necessary utf-8 <> utf-16 conversion.
+@(require_results)
+lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
+	return _lookup_env_buf(buf, key)
+}
+
+lookup_env :: proc{lookup_env_alloc, lookup_env_buf}
+
 // set_env sets the value of the environment variable named by the key
 // Returns Error on failure
 set_env :: proc(key, value: string) -> Error {

+ 18 - 1
core/os/os2/env_linux.odin

@@ -41,7 +41,7 @@ _lookup :: proc(key: string) -> (value: string, idx: int) {
 	return "", -1
 }
 
-_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
+_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
 	if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 {
 		_build_env()
 	}
@@ -53,6 +53,23 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
 	return
 }
 
+_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
+	if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 {
+		_build_env()
+	}
+
+	if v, idx := _lookup(key); idx != -1 {
+		if len(buf) >= len(v) {
+			copy(buf, v)
+			return string(buf[:len(v)]), nil
+		}
+		return "", .Buffer_Full
+	}
+	return "", .Env_Var_Not_Found
+}
+
+_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
+
 _set_env :: proc(key, v_new: string) -> Error {
 	if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 {
 		_build_env()

+ 31 - 1
core/os/os2/env_posix.odin

@@ -7,7 +7,7 @@ import "base:runtime"
 import "core:strings"
 import "core:sys/posix"
 
-_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
+_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
 	if key == "" {
 		return
 	}
@@ -26,6 +26,36 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
 	return
 }
 
+_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) {
+	if key == "" {
+		return
+	}
+
+	if len(key) + 1 > len(buf) {
+		return "", .Buffer_Full
+	} else {
+		copy(buf, key)
+	}
+
+	cval := posix.getenv(ckey)
+	if cval == nil {
+		return
+	}
+
+	if value = string(cval); value == "" {
+		return "", .Env_Var_Not_Found
+	} else {
+		if len(value) > len(buf) {
+			return "", .Buffer_Full
+		} else {
+			copy(buf, value)
+			return string(buf[:len(value)]), nil
+		}
+	}
+}
+
+_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
+
 _set_env :: proc(key, value: string) -> (err: Error) {
 	temp_allocator := TEMP_ALLOCATOR_GUARD({})
 

+ 29 - 1
core/os/os2/env_wasi.odin

@@ -67,7 +67,7 @@ delete_string_if_not_original :: proc(str: string) {
 }
 
 @(require_results)
-_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
+_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
 	if err := build_env(); err != nil {
 		return
 	}
@@ -79,6 +79,34 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
 	return
 }
 
+_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) {
+	if key == "" {
+		return
+	}
+
+	if len(key) + 1 > len(buf) {
+		return "", .Buffer_Full
+	} else {
+		copy(buf, key)
+	}
+
+	sync.shared_guard(&g_env_mutex)
+
+	val, ok := g_env[key]
+
+	if !ok {
+		return "", .Env_Var_Not_Found
+	} else {
+		if len(val) > len(buf) {
+			return "", .Buffer_Full
+		} else {
+			copy(buf, val)
+			return string(buf[:len(val)]), nil
+		}
+	}
+}
+_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
+
 @(require_results)
 _set_env :: proc(key, value: string) -> (err: Error) {
 	build_env() or_return

+ 31 - 1
core/os/os2/env_windows.odin

@@ -4,7 +4,7 @@ package os2
 import win32 "core:sys/windows"
 import "base:runtime"
 
-_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
+_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
 	if key == "" {
 		return
 	}
@@ -36,6 +36,36 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
 	return
 }
 
+// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer.
+// Note that it is limited to environment names and values of 512 utf-16 values each
+// due to the necessary utf-8 <> utf-16 conversion.
+@(require_results)
+_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
+	key_buf: [513]u16
+	wkey := win32.utf8_to_wstring(key_buf[:], key)
+	if wkey == nil {
+		return "", .Buffer_Full
+	}
+
+	n2 := win32.GetEnvironmentVariableW(wkey, nil, 0)
+	if n2 == 0 {
+		return "", .Env_Var_Not_Found
+	}
+
+	val_buf: [513]u16
+	n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:])))
+	if n2 == 0 {
+		return "", .Env_Var_Not_Found
+	} else if int(n2) > len(buf) {
+		return "", .Buffer_Full
+	}
+
+	value = win32.utf16_to_utf8(buf, val_buf[:n2])
+
+	return value, nil
+}
+_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
+
 _set_env :: proc(key, value: string) -> Error {
 	temp_allocator := TEMP_ALLOCATOR_GUARD({})
 	k := win32_utf8_to_wstring(key,   temp_allocator) or_return

+ 2 - 2
core/os/os2/errors.odin

@@ -28,7 +28,7 @@ General_Error :: enum u32 {
 	Pattern_Has_Separator,
 
 	No_HOME_Variable,
-	Wordexp_Failed,
+	Env_Var_Not_Found,
 
 	Unsupported,
 }
@@ -77,7 +77,7 @@ error_string :: proc(ferr: Error) -> string {
 		case .Unsupported:            return "unsupported"
 		case .Pattern_Has_Separator:  return "pattern has separator"
 		case .No_HOME_Variable:       return "no $HOME variable"
-		case .Wordexp_Failed:         return "posix.wordexp was unable to expand"
+		case .Env_Var_Not_Found:      return "environment variable not found"
 		}
 	case io.Error:
 		switch e {