mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-25 23:14:59 -07:00
Get env stuff working on Windows
This commit is contained in:
+3
-12
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user