Merge branch 'master' into macharena

This commit is contained in:
Colin Davidson
2025-07-07 14:34:05 -07:00
170 changed files with 35253 additions and 3220 deletions
+39 -2
View File
@@ -8,7 +8,7 @@ import "base:runtime"
// 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 := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
if key == "" {
return
}
@@ -29,17 +29,54 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
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_buffer :: 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_buffer}
// 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 := context.allocator) -> (value: string) {
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
// set_env sets the value of the environment variable named by the key
set_env :: proc(key, value: string) -> Error {
k := win32.utf8_to_wstring(key)
+4
View File
@@ -35,6 +35,9 @@ General_Error :: enum u32 {
File_Is_Pipe,
Not_Dir,
// Environment variable not found.
Env_Var_Not_Found,
}
@@ -82,6 +85,7 @@ error_string :: proc "contextless" (ferr: Error) -> string {
case .Pattern_Has_Separator: return "pattern has separator"
case .File_Is_Pipe: return "file is pipe"
case .Not_Dir: return "file is not directory"
case .Env_Var_Not_Found: return "environment variable not found"
}
case io.Error:
switch e {
+53
View File
@@ -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)
}
+79 -5
View File
@@ -1,26 +1,49 @@
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 {
@@ -45,4 +68,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)
}
+18 -1
View File
@@ -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
View File
@@ -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(cstring(raw_data(buf)))
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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+1
View File
@@ -269,6 +269,7 @@ _write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (nt: i64, err: Error
return
}
@(no_sanitize_memory)
_file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) {
// TODO: Identify 0-sized "pseudo" files and return No_Size. This would
// eliminate the need for the _read_entire_pseudo_file procs.
+1 -9
View File
@@ -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
+37 -3
View File
@@ -1090,9 +1090,10 @@ flush :: proc(fd: Handle) -> Error {
}
@(require_results)
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
@@ -1101,11 +1102,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
}
@(require_results)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
if len(key) + 1 > len(buf) {
return "", .Buffer_Full
} else {
copy(buf, key)
}
if value = string(_unix_getenv(cstring(raw_data(buf)))); 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_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
set_env :: proc(key, value: string) -> Error {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
key_cstring := strings.clone_to_cstring(key, context.temp_allocator)
@@ -1231,7 +1260,7 @@ _processor_core_count :: proc() -> int {
return 1
}
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for _, i in res {
@@ -1240,6 +1269,11 @@ _alloc_command_line_arguments :: proc() -> []string {
return res
}
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) {
result := _unix_socket(c.int(domain), c.int(type), c.int(protocol))
if result < 0 {
+40 -7
View File
@@ -662,7 +662,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Error) {
return File_Time(modified), nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -674,7 +674,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -688,7 +688,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
s: OS_Stat = ---
result := _unix_fstat(fd, &s)
@@ -827,10 +827,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) {
}
@(require_results)
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
@@ -839,11 +839,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
}
@(require_results)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
if len(key) + 1 > len(buf) {
return "", .Buffer_Full
} else {
copy(buf, key)
}
if value = string(_unix_getenv(cstring(raw_data(buf)))); 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_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
@(require_results)
get_current_directory :: proc(allocator := context.allocator) -> string {
context.allocator = allocator
@@ -936,7 +964,7 @@ _processor_core_count :: proc() -> int {
}
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
@@ -944,3 +972,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
return res
}
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
+41 -6
View File
@@ -316,7 +316,7 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments()
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
@@ -325,7 +325,12 @@ _alloc_command_line_arguments :: proc() -> []string {
return res
}
@(private, require_results)
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
@(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -339,7 +344,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -353,7 +358,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
// deliberately uninitialized
s: OS_Stat = ---
@@ -463,9 +468,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) {
}
@(require_results)
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
@@ -474,11 +480,40 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
}
@(require_results)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
if len(key) + 1 > len(buf) {
return "", .Buffer_Full
} else {
copy(buf, key)
}
if value = string(_unix_getenv(cstring(raw_data(buf)))); 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_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
@(private, require_results)
_processor_core_count :: proc() -> int {
info: haiku.system_info
+22 -2
View File
@@ -250,6 +250,26 @@ current_thread_id :: proc "contextless" () -> int {
return 0
}
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
@(require_results)
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
return "", false
}
}
@(require_results)
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
return "", .Env_Var_Not_Found
}
lookup_env :: proc{lookup_env_alloc, lookup_env_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
+40 -7
View File
@@ -674,7 +674,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
return i64(res), nil
}
@(require_results)
@(require_results, no_sanitize_memory)
file_size :: proc(fd: Handle) -> (i64, Error) {
// deliberately uninitialized; the syscall fills this buffer for us
s: OS_Stat = ---
@@ -794,7 +794,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) {
return File_Time(modified), nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -808,7 +808,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -822,7 +822,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
// deliberately uninitialized; the syscall fills this buffer for us
s: OS_Stat = ---
@@ -946,7 +946,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) {
}
@(require_results)
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
@@ -958,11 +958,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
}
@(require_results)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
if len(key) + 1 > len(buf) {
return "", .Buffer_Full
} else {
copy(buf, key)
}
if value = string(_unix_getenv(cstring(raw_data(buf)))); 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_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
set_env :: proc(key, value: string) -> Error {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
key_cstring := strings.clone_to_cstring(key, context.temp_allocator)
@@ -1069,7 +1097,7 @@ _processor_core_count :: proc() -> int {
return int(_unix_get_nprocs())
}
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
@@ -1078,6 +1106,11 @@ _alloc_command_line_arguments :: proc() -> []string {
return res
}
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
@(require_results)
socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) {
result := unix.sys_socket(domain, type, protocol)
+40 -7
View File
@@ -724,7 +724,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) {
return File_Time(modified), nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -736,7 +736,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -750,7 +750,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
s: OS_Stat = ---
result := _unix_fstat(fd, &s)
@@ -874,10 +874,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) {
}
@(require_results)
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
@@ -886,11 +886,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
}
@(require_results)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
if len(key) + 1 > len(buf) {
return "", .Buffer_Full
} else {
copy(buf, key)
}
if value = string(_unix_getenv(cstring(raw_data(buf)))); 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_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
@(require_results)
get_current_directory :: proc(allocator := context.allocator) -> string {
context.allocator = allocator
@@ -986,7 +1014,7 @@ _processor_core_count :: proc() -> int {
return 1
}
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
@@ -994,3 +1022,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
return res
}
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
+40 -6
View File
@@ -639,7 +639,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) {
return File_Time(modified), nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -653,7 +653,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -667,7 +667,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil
}
@(private, require_results)
@(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
// deliberately uninitialized
s: OS_Stat = ---
@@ -787,9 +787,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) {
}
@(require_results)
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
// NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults.
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
@@ -798,11 +799,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
}
@(require_results)
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
if len(key) + 1 > len(buf) {
return "", .Buffer_Full
} else {
copy(buf, key)
}
if value = string(_unix_getenv(cstring(raw_data(buf)))); 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_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
@(require_results)
get_current_directory :: proc(allocator := context.allocator) -> string {
context.allocator = allocator
@@ -885,7 +914,7 @@ _processor_core_count :: proc() -> int {
return int(_sysconf(_SC_NPROCESSORS_ONLN))
}
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
@@ -893,3 +922,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
return res
}
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
+30 -1
View File
@@ -27,7 +27,7 @@ stderr: Handle = 2
args := _alloc_command_line_arguments()
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> (args: []string) {
args = make([]string, len(runtime.args__))
for &arg, i in args {
@@ -36,6 +36,11 @@ _alloc_command_line_arguments :: proc() -> (args: []string) {
return
}
@(private, fini)
_delete_command_line_arguments :: proc() {
delete(args)
}
// WASI works with "preopened" directories, the environment retrieves directories
// (for example with `wasmtime --dir=. module.wasm`) and those given directories
// are the only ones accessible by the application.
@@ -239,3 +244,27 @@ exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
wasi.proc_exit(wasi.exitcode_t(code))
}
@(require_results)
lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
return "", false
}
@(require_results)
lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
return "", .Env_Var_Not_Found
}
lookup_env :: proc{lookup_env_alloc, lookup_env_buffer}
@(require_results)
get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(require_results)
get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
value, _ = lookup_env(buf, key)
return
}
get_env :: proc{get_env_alloc, get_env_buf}
+9 -1
View File
@@ -193,7 +193,7 @@ current_thread_id :: proc "contextless" () -> int {
@(require_results)
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
arg_count: i32
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count)
@@ -215,6 +215,14 @@ _alloc_command_line_arguments :: proc() -> []string {
return arg_list
}
@(private, fini)
_delete_command_line_arguments :: proc() {
for s in args {
delete(s)
}
delete(args)
}
/*
Windows 11 (preview) has the same major and minor version numbers
as Windows 10: 10 and 0 respectively.