Get env stuff working on Windows

This commit is contained in:
gingerBill
2022-02-21 12:35:52 +00:00
parent 14cb19c2df
commit 345032f804
6 changed files with 112 additions and 86 deletions
+3 -12
View File
@@ -1,20 +1,11 @@
package os2
// 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
get_env :: proc(key: string, allocator := context.allocator) -> string {
value, _ := lookup_env(key, allocator)
return value
}
// lookup_env gets the value of the environment variable named by the key
// get_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
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
return _lookup_env(key, allocator)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
return _get_env(key, allocator)
}
// set_env sets the value of the environment variable named by the key
+44 -28
View File
@@ -1,50 +1,56 @@
//+private
package os2
import "core:runtime"
import "core:mem"
import win32 "core:sys/windows"
_lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
_get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
if key == "" {
return
}
wkey := win32.utf8_to_wstring(key)
b := make([dynamic]u16, 100, context.temp_allocator)
for {
n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
if n == 0 {
err := win32.GetLastError()
if err == win32.ERROR_ENVVAR_NOT_FOUND {
return "", false
}
}
if n <= u32(len(b)) {
value = win32.utf16_to_utf8(b[:n], allocator)
found = true
return
}
resize(&b, len(b)*2)
// https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentvariablew
buf_len := win32.GetEnvironmentVariableW(wkey, nil, 0)
if buf_len == 0 {
return
}
buf := make([dynamic]u16, buf_len, context.temp_allocator)
n := win32.GetEnvironmentVariableW(wkey, raw_data(buf), buf_len)
if n == 0 {
if win32.GetLastError() == win32.ERROR_ENVVAR_NOT_FOUND {
return "", false
}
value = ""
found = true
return
}
value = win32.utf16_to_utf8(buf[:n], allocator)
found = true
return
}
_set_env :: proc(key, value: string) -> bool {
k := win32.utf8_to_wstring(key)
v := win32.utf8_to_wstring(value)
// https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew
return bool(win32.SetEnvironmentVariableW(k, v))
}
_unset_env :: proc(key: string) -> bool {
k := win32.utf8_to_wstring(key)
// https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew
return bool(win32.SetEnvironmentVariableW(k, nil))
}
_clear_env :: proc() {
envs := environ(context.temp_allocator)
for env in envs {
for j in 1..<len(env) {
#no_bounds_check for j in 1..<len(env) {
if env[j] == '=' {
unset_env(env[0:j])
break
@@ -54,23 +60,33 @@ _clear_env :: proc() {
}
_environ :: proc(allocator := context.allocator) -> []string {
envs := win32.GetEnvironmentStringsW()
envs := ([^]u16)(win32.GetEnvironmentStringsW())
if envs == nil {
return nil
}
defer win32.FreeEnvironmentStringsW(envs)
r := make([dynamic]string, 0, 50, allocator)
for from, i, p := 0, 0, envs; true; i += 1 {
c := (^u16)(uintptr(p) + uintptr(i*2))^
if c == 0 {
if i <= from {
break
length := 0
n := 0
count_loop: for {
if envs[length] == 0 {
n += 1
if envs[length+1] == 0 {
break count_loop
}
w := mem.slice_ptr(mem.ptr_offset(p, from), i-from)
}
append(&r, win32.utf16_to_utf8(w, allocator))
from = i + 1
length += 1
}
r := make([dynamic]string, 0, n, allocator)
for offset, i := 0, 0; i < length && len(r) < n; i += 1 {
c := envs[i]
if c == 0 {
wstr := envs[offset:i]
append(&r, win32.utf16_to_utf8(wstr, allocator))
i += 1
offset = i
}
}
+33 -23
View File
@@ -63,31 +63,41 @@ is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
error_string :: proc(ferr: Error) -> string {
switch ferr {
case nil: return ""
case .Invalid_Argument: return "invalid argument"
case .Permission_Denied: return "permission denied"
case .Exist: return "file already exists"
case .Not_Exist: return "file does not exist"
case .Closed: return "file already closed"
case .Timeout: return "i/o timeout"
case .EOF: return "eof"
case .Unexpected_EOF: return "unexpected eof"
case .Short_Write: return "short write"
case .Invalid_Write: return "invalid write result"
case .Short_Buffer: return "short buffer"
case .No_Progress: return "multiple read calls return no data or error"
case .Invalid_Whence: return "invalid whence"
case .Invalid_Offset: return "invalid offset"
case .Invalid_Unread: return "invalid unread"
case .Negative_Read: return "negative read"
case .Negative_Write: return "negative write"
case .Negative_Count: return "negative count"
case .Buffer_Full: return "buffer full"
@static general_error_strings := [General_Error]string{
.Invalid_Argument = "invalid argument",
.Permission_Denied = "permission denied",
.Exist = "file already exists",
.Not_Exist = "file does not exist",
.Closed = "file already closed",
.Timeout = "i/o timeout",
}
if errno, ok := is_platform_error(ferr); ok {
return _error_string(errno)
@static io_error_strings := [io.Error]string{
.None = "",
.EOF = "eof",
.Unexpected_EOF = "unexpected eof",
.Short_Write = "short write",
.Invalid_Write = "invalid write result",
.Short_Buffer = "short buffer",
.No_Progress = "multiple read calls return no data or error",
.Invalid_Whence = "invalid whence",
.Invalid_Offset = "invalid offset",
.Invalid_Unread = "invalid unread",
.Negative_Read = "negative read",
.Negative_Write = "negative write",
.Negative_Count = "negative count",
.Buffer_Full = "buffer full",
.Unknown = "unknown i/o error",
.Empty = "empty i/o error",
}
if ferr == nil {
return ""
}
switch err in ferr {
case General_Error: return general_error_strings[err]
case io.Error: return io_error_strings[err]
case Platform_Error: return _error_string(err.err)
}
return "unknown error"
+21 -10
View File
@@ -19,14 +19,25 @@ File_Mode_Char_Device :: File_Mode(1<<19)
File_Mode_Sym_Link :: File_Mode(1<<20)
O_RDONLY :: int( 0)
O_WRONLY :: int( 1)
O_RDWR :: int( 2)
O_APPEND :: int( 4)
O_CREATE :: int( 8)
O_EXCL :: int(16)
O_SYNC :: int(32)
O_TRUNC :: int(64)
File_Flag :: enum u32 {
Read = 0,
Write = 1,
Append = 2,
Create = 3,
Excl = 4,
Sync = 5,
Trunc = 6,
}
File_Flags :: distinct bit_set[File_Flag; u32]
O_RDONLY :: File_Flags{.Read}
O_WRONLY :: File_Flags{.Write}
O_RDWR :: File_Flags{.Read, .Write}
O_APPEND :: File_Flags{.Append}
O_CREATE :: File_Flags{.Create}
O_EXCL :: File_Flags{.Excl}
O_SYNC :: File_Flags{.Sync}
O_TRUNC :: File_Flags{.Trunc}
@@ -43,8 +54,8 @@ open :: proc(name: string) -> (Handle, Error) {
return _open(name)
}
open_file :: proc(name: string, flag: int, perm: File_Mode) -> (Handle, Error) {
return _open_file(name, flag, perm)
open_file :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
return _open_file(name, flags, perm)
}
close :: proc(fd: Handle) -> Error {
+1 -1
View File
@@ -12,7 +12,7 @@ _open :: proc(name: string) -> (Handle, Error) {
return 0, nil
}
_open_file :: proc(name: string, flag: int, perm: File_Mode) -> (Handle, Error) {
_open_file :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
return 0, nil
}
+10 -12
View File
@@ -5,19 +5,19 @@ import "core:strings"
user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
#partial switch ODIN_OS {
case .Windows:
dir = get_env("LocalAppData")
dir = get_env("LocalAppData") or_return
if dir != "" {
dir = strings.clone(dir, allocator)
}
case .Darwin:
dir = get_env("HOME")
dir = get_env("HOME") or_return
if dir != "" {
dir = strings.concatenate({dir, "/Library/Caches"}, allocator)
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME")
dir = get_env("XDG_CACHE_HOME") or_return
if dir == "" {
dir = get_env("HOME")
dir = get_env("HOME") or_return
if dir == "" {
return
}
@@ -31,19 +31,19 @@ user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defin
user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
#partial switch ODIN_OS {
case .Windows:
dir = get_env("AppData")
dir = get_env("AppData") or_return
if dir != "" {
dir = strings.clone(dir, allocator)
}
case .Darwin:
dir = get_env("HOME")
dir = get_env("HOME") or_return
if dir != "" {
dir = strings.concatenate({dir, "/Library/Application Support"}, allocator)
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME")
dir = get_env("XDG_CACHE_HOME") or_return
if dir == "" {
dir = get_env("HOME")
dir = get_env("HOME") or_return
if dir == "" {
return
}
@@ -60,9 +60,7 @@ user_home_dir :: proc() -> (dir: string, is_defined: bool) {
case .Windows:
env = "USERPROFILE"
}
if v := get_env(env); v != "" {
return v, true
}
return "", false
v := get_env(env) or_return
return v, true
}