From 3862555153611cf53b1f0fec72889d4dae64fde2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 13 Jun 2025 17:49:05 +0200 Subject: [PATCH 1/3] Replace core:posix usage in core:os/os2 --- core/net/dns.odin | 26 ++---------------- core/os/os.odin | 53 +++++++++++++++++++++++++++++++++++++ core/os/os2/env.odin | 52 ++++++++++++++++++++++++++++++++++++ core/os/os2/user_posix.odin | 10 +------ 4 files changed, 108 insertions(+), 33 deletions(-) diff --git a/core/net/dns.odin b/core/net/dns.odin index 7eb543db3..a54242549 100644 --- a/core/net/dns.odin +++ b/core/net/dns.odin @@ -49,8 +49,8 @@ init_dns_configuration :: proc() { /* Resolve %ENVIRONMENT% placeholders in their paths. */ - dns_configuration.resolv_conf, _ = replace_environment_path(dns_configuration.resolv_conf) - dns_configuration.hosts_file, _ = replace_environment_path(dns_configuration.hosts_file) + dns_configuration.resolv_conf = os.replace_environment_placeholders(dns_configuration.resolv_conf) + dns_configuration.hosts_file = os.replace_environment_placeholders(dns_configuration.hosts_file) } @(fini, private) @@ -63,28 +63,6 @@ destroy_dns_configuration :: proc() { dns_configuration := DEFAULT_DNS_CONFIGURATION -// Always allocates for consistency. -replace_environment_path :: proc(path: string, allocator := context.allocator) -> (res: string, ok: bool) { - // Nothing to replace. Return a clone of the original. - if strings.count(path, "%") != 2 { - return strings.clone(path, allocator), true - } - - left := strings.index(path, "%") + 1 - assert(left > 0 && left <= len(path)) // should be covered by there being two % - - right := strings.index(path[left:], "%") + 1 - assert(right > 0 && right <= len(path)) // should be covered by there being two % - - env_key := path[left: right] - env_val := os.get_env(env_key, allocator) - defer delete(env_val) - - res, _ = strings.replace(path, path[left - 1: right + 1], env_val, 1, allocator) - return res, true -} - - /* Resolves a hostname to exactly one IP4 and IP6 endpoint. It's then up to you which one you use. diff --git a/core/os/os.odin b/core/os/os.odin index fde48fbf4..fe08edff4 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -4,6 +4,7 @@ import "base:intrinsics" import "base:runtime" import "core:io" import "core:strconv" +import "core:strings" import "core:unicode/utf8" @@ -210,3 +211,55 @@ heap_free :: runtime.heap_free processor_core_count :: proc() -> int { return _processor_core_count() } + +// Always allocates for consistency. +replace_environment_placeholders :: proc(path: string, allocator := context.allocator) -> (res: string) { + path := path + + sb: strings.Builder + strings.builder_init_none(&sb, allocator) + for len(path) > 0 { + switch path[0] { + case '%': // Windows + when ODIN_OS == .Windows { + for r, i in path[1:] { + if r == '%' { + env_key := path[1:i+1] + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[i+1:] // % is part of key, so skip 1 character extra + } + } + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case '$': // Posix + when ODIN_OS != .Windows { + env_key := "" + dollar_loop: for r, i in path[1:] { + switch r { + case 'A'..='Z', 'a'..='z', '0'..='9', '_': // Part of key ident + case: + env_key = path[1:i+1] + break dollar_loop + } + } + if len(env_key) > 0 { + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[len(env_key):] + } + + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case: + strings.write_rune(&sb, rune(path[0])) + } + + path = path[1:] + } + return strings.to_string(sb) +} \ No newline at end of file diff --git a/core/os/os2/env.odin b/core/os/os2/env.odin index 13c107f3c..7d42b040d 100644 --- a/core/os/os2/env.odin +++ b/core/os/os2/env.odin @@ -1,6 +1,7 @@ package os2 import "base:runtime" +import "core:strings" // 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 @@ -45,4 +46,55 @@ environ :: proc(allocator: runtime.Allocator) -> ([]string, Error) { return _environ(allocator) } +// Always allocates for consistency. +replace_environment_placeholders :: proc(path: string, allocator: runtime.Allocator) -> (res: string) { + path := path + sb: strings.Builder + strings.builder_init_none(&sb, allocator) + + for len(path) > 0 { + switch path[0] { + case '%': // Windows + when ODIN_OS == .Windows { + for r, i in path[1:] { + if r == '%' { + env_key := path[1:i+1] + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[i+1:] // % is part of key, so skip 1 character extra + } + } + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case '$': // Posix + when ODIN_OS != .Windows { + env_key := "" + dollar_loop: for r, i in path[1:] { + switch r { + case 'A'..='Z', 'a'..='z', '0'..='9', '_': // Part of key ident + case: + env_key = path[1:i+1] + break dollar_loop + } + } + if len(env_key) > 0 { + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[len(env_key):] + } + + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case: + strings.write_rune(&sb, rune(path[0])) + } + + path = path[1:] + } + return strings.to_string(sb) +} \ No newline at end of file diff --git a/core/os/os2/user_posix.odin b/core/os/os2/user_posix.odin index f271b8913..691745b7a 100644 --- a/core/os/os2/user_posix.odin +++ b/core/os/os2/user_posix.odin @@ -4,7 +4,6 @@ package os2 import "base:runtime" import "core:encoding/ini" import "core:strings" -import "core:sys/posix" _user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { #partial switch ODIN_OS { @@ -169,14 +168,7 @@ _xdg_user_dirs_lookup :: proc(xdg_key: string, allocator: runtime.Allocator) -> for k, v in ini.iterate(&it) { if k == xdg_key { - we: posix.wordexp_t - defer posix.wordfree(&we) - - if _err := posix.wordexp(strings.clone_to_cstring(v, temp_allocator), &we, nil); _err != nil || we.we_wordc != 1 { - return "", .Wordexp_Failed - } - - return strings.clone_from_cstring(we.we_wordv[0], allocator) + return replace_environment_placeholders(v, allocator), nil } } return From 8c8406cc4d53336dd697655a621cadea0b4359c0 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 13 Jun 2025 18:00:30 +0200 Subject: [PATCH 2/3] stub out get_env for js --- core/os/os_js.odin | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/os/os_js.odin b/core/os/os_js.odin index 4d02eef7c..adb0f8061 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -252,4 +252,9 @@ current_thread_id :: proc "contextless" () -> int { lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { return "", false +} + +get_env :: proc(key: string, allocator := context.allocator) -> string { + value, _ := lookup_env(key, allocator) + return value } \ No newline at end of file From 84eaddbd47cc056bbbab834d0764e6da23a45711 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 13 Jun 2025 18:08:35 +0200 Subject: [PATCH 3/3] WASI --- core/os/os_wasi.odin | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 28f470357..a0938e860 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -239,3 +239,12 @@ exit :: proc "contextless" (code: int) -> ! { runtime._cleanup_runtime_contextless() wasi.proc_exit(wasi.exitcode_t(code)) } + +lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + return "", false +} + +get_env :: proc(key: string, allocator := context.allocator) -> string { + value, _ := lookup_env(key, allocator) + return value +} \ No newline at end of file