mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
Merge tag 'dev-2025-09'
This commit is contained in:
@@ -47,20 +47,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
branch: edge
|
||||
- name: (Linux) Download LLVM
|
||||
- name: (Linux) Download LLVM and Build Odin
|
||||
run: |
|
||||
apk add --no-cache \
|
||||
musl-dev llvm20-dev clang20 git mold lz4 \
|
||||
libxml2-static llvm20-static zlib-static zstd-static \
|
||||
make
|
||||
shell: alpine.sh --root {0}
|
||||
- name: build odin
|
||||
# NOTE: this build does slow compile times because of musl
|
||||
run: ci/build_linux_static.sh
|
||||
shell: alpine.sh {0}
|
||||
docker run --rm -v "$PWD:/src" -w /src alpine sh -c '
|
||||
apk add --no-cache \
|
||||
musl-dev llvm20-dev clang20 git mold lz4 \
|
||||
libxml2-static llvm20-static zlib-static zstd-static \
|
||||
make &&
|
||||
./ci/build_linux_static.sh
|
||||
'
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
@@ -74,6 +69,7 @@ jobs:
|
||||
cp -r core $FILE
|
||||
cp -r vendor $FILE
|
||||
cp -r examples $FILE
|
||||
./ci/remove_windows_binaries.sh $FILE
|
||||
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
|
||||
tar -czvf dist.tar.gz $FILE
|
||||
- name: Odin run
|
||||
@@ -85,6 +81,46 @@ jobs:
|
||||
with:
|
||||
name: linux_artifacts
|
||||
path: dist.tar.gz
|
||||
build_linux_arm:
|
||||
name: Linux ARM Build
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: (Linux ARM) Download LLVM and Build Odin
|
||||
run: |
|
||||
docker run --rm -v "$PWD:/src" -w /src arm64v8/alpine sh -c '
|
||||
apk add --no-cache \
|
||||
musl-dev llvm20-dev clang20 git mold lz4 \
|
||||
libxml2-static llvm20-static zlib-static zstd-static \
|
||||
make &&
|
||||
./ci/build_linux_static.sh
|
||||
'
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo
|
||||
- name: Copy artifacts
|
||||
run: |
|
||||
FILE="odin-linux-arm64-nightly+$(date -I)"
|
||||
mkdir $FILE
|
||||
cp odin $FILE
|
||||
cp LICENSE $FILE
|
||||
cp -r shared $FILE
|
||||
cp -r base $FILE
|
||||
cp -r core $FILE
|
||||
cp -r vendor $FILE
|
||||
cp -r examples $FILE
|
||||
./ci/remove_windows_binaries.sh $FILE
|
||||
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
|
||||
tar -czvf dist.tar.gz $FILE
|
||||
- name: Odin run
|
||||
run: |
|
||||
FILE="odin-linux-arm64-nightly+$(date -I)"
|
||||
$FILE/odin run examples/demo
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux_arm_artifacts
|
||||
path: dist.tar.gz
|
||||
build_macos:
|
||||
name: MacOS Build
|
||||
if: github.repository == 'odin-lang/Odin'
|
||||
@@ -111,6 +147,7 @@ jobs:
|
||||
cp -r core $FILE
|
||||
cp -r vendor $FILE
|
||||
cp -r examples $FILE
|
||||
./ci/remove_windows_binaries.sh $FILE
|
||||
dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs
|
||||
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
|
||||
tar -czvf dist.tar.gz $FILE
|
||||
@@ -149,6 +186,7 @@ jobs:
|
||||
cp -r core $FILE
|
||||
cp -r vendor $FILE
|
||||
cp -r examples $FILE
|
||||
./ci/remove_windows_binaries.sh $FILE
|
||||
dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs
|
||||
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
|
||||
tar -czvf dist.tar.gz $FILE
|
||||
@@ -163,7 +201,7 @@ jobs:
|
||||
path: dist.tar.gz
|
||||
upload_b2:
|
||||
runs-on: [ubuntu-latest]
|
||||
needs: [build_windows, build_macos, build_macos_arm, build_linux]
|
||||
needs: [build_windows, build_macos, build_macos_arm, build_linux, build_linux_arm]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
@@ -192,6 +230,12 @@ jobs:
|
||||
name: linux_artifacts
|
||||
path: linux_artifacts
|
||||
|
||||
- name: Download Ubuntu ARM artifacts
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
name: linux_arm_artifacts
|
||||
path: linux_arm_artifacts
|
||||
|
||||
- name: Download macOS artifacts
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
@@ -219,6 +263,7 @@ jobs:
|
||||
file linux_artifacts/dist.tar.gz
|
||||
python3 ci/nightly.py artifact windows-amd64 windows_artifacts/
|
||||
python3 ci/nightly.py artifact linux-amd64 linux_artifacts/dist.tar.gz
|
||||
python3 ci/nightly.py artifact linux-arm64 linux_arm_artifacts/dist.tar.gz
|
||||
python3 ci/nightly.py artifact macos-amd64 macos_artifacts/dist.tar.gz
|
||||
python3 ci/nightly.py artifact macos-arm64 macos_arm_artifacts/dist.tar.gz
|
||||
python3 ci/nightly.py prune
|
||||
|
||||
@@ -141,6 +141,7 @@ type_is_quaternion :: proc($T: typeid) -> bool ---
|
||||
type_is_string :: proc($T: typeid) -> bool ---
|
||||
type_is_typeid :: proc($T: typeid) -> bool ---
|
||||
type_is_any :: proc($T: typeid) -> bool ---
|
||||
type_is_string16 :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_endian_platform :: proc($T: typeid) -> bool ---
|
||||
type_is_endian_little :: proc($T: typeid) -> bool ---
|
||||
@@ -232,6 +233,9 @@ type_integer_to_signed :: proc($T: typeid) -> type where type_is_integer(T), t
|
||||
|
||||
type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
|
||||
|
||||
// Returns the canonicalized name of the type, of which is used to produce the pseudo-unique 'typeid'
|
||||
type_canonical_name :: proc($T: typeid) -> string ---
|
||||
|
||||
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||
|
||||
constant_log2 :: proc($v: $T) -> T where type_is_integer(T) ---
|
||||
@@ -380,6 +384,7 @@ objc_register_selector :: proc($name: string) -> objc_SEL ---
|
||||
objc_find_class :: proc($name: string) -> objc_Class ---
|
||||
objc_register_class :: proc($name: string) -> objc_Class ---
|
||||
objc_ivar_get :: proc(self: ^$T) -> ^$U ---
|
||||
objc_block :: proc(invoke: $T, ..any) -> ^Objc_Block(T) where type_is_proc(T) ---
|
||||
|
||||
valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr ---
|
||||
|
||||
|
||||
+17
-1
@@ -61,6 +61,11 @@ Type_Info_Struct_Soa_Kind :: enum u8 {
|
||||
Dynamic = 3,
|
||||
}
|
||||
|
||||
Type_Info_String_Encoding_Kind :: enum u8 {
|
||||
UTF_8 = 0,
|
||||
UTF_16 = 1,
|
||||
}
|
||||
|
||||
// Variant Types
|
||||
Type_Info_Named :: struct {
|
||||
name: string,
|
||||
@@ -73,7 +78,7 @@ Type_Info_Rune :: struct {}
|
||||
Type_Info_Float :: struct {endianness: Platform_Endianness}
|
||||
Type_Info_Complex :: struct {}
|
||||
Type_Info_Quaternion :: struct {}
|
||||
Type_Info_String :: struct {is_cstring: bool}
|
||||
Type_Info_String :: struct {is_cstring: bool, encoding: Type_Info_String_Encoding_Kind}
|
||||
Type_Info_Boolean :: struct {}
|
||||
Type_Info_Any :: struct {}
|
||||
Type_Info_Type_Id :: struct {}
|
||||
@@ -397,6 +402,11 @@ Raw_String :: struct {
|
||||
len: int,
|
||||
}
|
||||
|
||||
Raw_String16 :: struct {
|
||||
data: [^]u16,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Raw_Slice :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
@@ -450,6 +460,12 @@ Raw_Cstring :: struct {
|
||||
}
|
||||
#assert(size_of(Raw_Cstring) == size_of(cstring))
|
||||
|
||||
Raw_Cstring16 :: struct {
|
||||
data: [^]u16,
|
||||
}
|
||||
#assert(size_of(Raw_Cstring16) == size_of(cstring16))
|
||||
|
||||
|
||||
Raw_Soa_Pointer :: struct {
|
||||
data: rawptr,
|
||||
index: int,
|
||||
|
||||
@@ -5,6 +5,11 @@ import "base:intrinsics"
|
||||
@builtin
|
||||
Maybe :: union($T: typeid) {T}
|
||||
|
||||
/*
|
||||
Represents an Objective-C block with a given procedure signature T
|
||||
*/
|
||||
@builtin
|
||||
Objc_Block :: struct($T: typeid) where intrinsics.type_is_proc(T) { using _: intrinsics.objc_object }
|
||||
|
||||
/*
|
||||
Recovers the containing/parent struct from a pointer to one of its fields.
|
||||
@@ -86,11 +91,26 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// `copy_from_string16` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
//
|
||||
// Prefer the procedure group `copy`.
|
||||
@builtin
|
||||
copy_from_string16 :: proc "contextless" (dst: $T/[]$E/u16, src: $S/string16) -> int {
|
||||
n := min(len(dst), len(src))
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(u16))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// `copy` is a built-in procedure that copies elements from a source slice/string `src` to a destination slice `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
@builtin
|
||||
copy :: proc{copy_slice, copy_from_string}
|
||||
copy :: proc{copy_slice, copy_from_string, copy_from_string16}
|
||||
|
||||
|
||||
|
||||
@@ -285,6 +305,15 @@ delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error
|
||||
}
|
||||
|
||||
|
||||
@builtin
|
||||
delete_string16 :: proc(str: string16, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free_with_size(raw_data(str), len(str)*size_of(u16), allocator, loc)
|
||||
}
|
||||
@builtin
|
||||
delete_cstring16 :: proc(str: cstring16, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
return mem_free((^u16)(str), allocator, loc)
|
||||
}
|
||||
|
||||
// `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation.
|
||||
//
|
||||
// Note: Prefer `delete` over the specific `delete_*` procedures where possible.
|
||||
@@ -297,6 +326,8 @@ delete :: proc{
|
||||
delete_map,
|
||||
delete_soa_slice,
|
||||
delete_soa_dynamic_array,
|
||||
delete_string16,
|
||||
delete_cstring16,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -180,8 +180,31 @@ resize_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int length: int, loc := #cal
|
||||
if array == nil {
|
||||
return nil
|
||||
}
|
||||
reserve_soa(array, length, loc) or_return
|
||||
|
||||
footer := raw_soa_footer(array)
|
||||
|
||||
if length > footer.cap {
|
||||
reserve_soa(array, length, loc) or_return
|
||||
} else if size_of(E) > 0 && length > footer.len {
|
||||
ti := type_info_base(type_info_of(typeid_of(T)))
|
||||
si := &ti.variant.(Type_Info_Struct)
|
||||
|
||||
field_count := len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)
|
||||
|
||||
data := (^rawptr)(array)^
|
||||
|
||||
soa_offset := 0
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
|
||||
|
||||
soa_offset = align_forward_int(soa_offset, align_of(E))
|
||||
|
||||
mem_zero(rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len)), type.size * (length - footer.len))
|
||||
|
||||
soa_offset += type.size * footer.cap
|
||||
}
|
||||
}
|
||||
|
||||
footer.len = length
|
||||
return nil
|
||||
}
|
||||
@@ -252,17 +275,77 @@ _reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: boo
|
||||
|
||||
old_data := (^rawptr)(array)^
|
||||
|
||||
resize: if old_data != nil {
|
||||
|
||||
new_bytes, resize_err := array.allocator.procedure(
|
||||
array.allocator.data, .Resize_Non_Zeroed, new_size, max_align,
|
||||
old_data, old_size, loc,
|
||||
)
|
||||
new_data := raw_data(new_bytes)
|
||||
|
||||
#partial switch resize_err {
|
||||
case .Mode_Not_Implemented: break resize
|
||||
case .None: // continue resizing
|
||||
case: return resize_err
|
||||
}
|
||||
|
||||
footer.cap = capacity
|
||||
|
||||
old_offset := 0
|
||||
new_offset := 0
|
||||
|
||||
// Correct data memory
|
||||
// from: |x x y y z z _ _ _|
|
||||
// to: |x x _ y y _ z z _|
|
||||
|
||||
// move old data to the end of the new allocation to avoid overlap
|
||||
old_data = rawptr(uintptr(new_data) + uintptr(new_size - old_size))
|
||||
mem_copy(old_data, new_data, old_size)
|
||||
|
||||
// now: |_ _ _ x x y y z z|
|
||||
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
|
||||
|
||||
old_offset = align_forward_int(old_offset, max_align)
|
||||
new_offset = align_forward_int(new_offset, max_align)
|
||||
|
||||
new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset))
|
||||
old_data_elem := rawptr(uintptr(old_data) + uintptr(old_offset))
|
||||
|
||||
old_size_elem := type.size * old_cap
|
||||
new_size_elem := type.size * capacity
|
||||
|
||||
mem_copy(new_data_elem, old_data_elem, old_size_elem)
|
||||
|
||||
(^rawptr)(uintptr(array) + i*size_of(rawptr))^ = new_data_elem
|
||||
|
||||
if zero_memory {
|
||||
mem_zero(rawptr(uintptr(new_data_elem) + uintptr(old_size_elem)), new_size_elem - old_size_elem)
|
||||
}
|
||||
|
||||
old_offset += old_size_elem
|
||||
new_offset += new_size_elem
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
new_bytes := array.allocator.procedure(
|
||||
array.allocator.data, .Alloc if zero_memory else .Alloc_Non_Zeroed, new_size, max_align,
|
||||
nil, old_size, loc,
|
||||
) or_return
|
||||
new_data := raw_data(new_bytes)
|
||||
|
||||
|
||||
footer.cap = capacity
|
||||
|
||||
old_offset := 0
|
||||
new_offset := 0
|
||||
|
||||
// Correct data memory
|
||||
// from: |x x y y z z| ... |_ _ _ _ _ _ _ _ _|
|
||||
// to: |x x _ y y _ z z _|
|
||||
|
||||
for i in 0..<field_count {
|
||||
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
|
||||
|
||||
@@ -280,10 +363,12 @@ _reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: boo
|
||||
new_offset += type.size * capacity
|
||||
}
|
||||
|
||||
array.allocator.procedure(
|
||||
array.allocator.data, .Free, 0, max_align,
|
||||
old_data, old_size, loc,
|
||||
) or_return
|
||||
if old_data != nil {
|
||||
array.allocator.procedure(
|
||||
array.allocator.data, .Free, 0, max_align,
|
||||
old_data, old_size, loc,
|
||||
) or_return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
return nil, .None
|
||||
}
|
||||
|
||||
nil_allocator :: proc() -> Allocator {
|
||||
@(require_results)
|
||||
nil_allocator :: proc "contextless" () -> Allocator {
|
||||
return Allocator{
|
||||
procedure = nil_allocator_proc,
|
||||
data = nil,
|
||||
@@ -72,6 +73,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
panic_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = panic_allocator_proc,
|
||||
|
||||
@@ -52,10 +52,13 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint
|
||||
return
|
||||
}
|
||||
|
||||
memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) {
|
||||
memory_block_dealloc :: proc "contextless" (block_to_free: ^Memory_Block, loc := #caller_location) {
|
||||
if block_to_free != nil {
|
||||
|
||||
allocator := block_to_free.allocator
|
||||
// sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity)
|
||||
context = default_context()
|
||||
context.allocator = allocator
|
||||
mem_free(block_to_free, allocator, loc)
|
||||
}
|
||||
}
|
||||
@@ -174,7 +177,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
arena.total_used = 0
|
||||
}
|
||||
|
||||
arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
arena_destroy :: proc "contextless" (arena: ^Arena, loc := #caller_location) {
|
||||
for arena.curr_block != nil {
|
||||
free_block := arena.curr_block
|
||||
arena.curr_block = free_block.prev
|
||||
@@ -186,6 +189,7 @@ arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
arena.total_capacity = 0
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
||||
return Allocator{arena_allocator_proc, arena}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {}
|
||||
default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {}
|
||||
|
||||
default_temp_allocator_proc :: nil_allocator_proc
|
||||
|
||||
@@ -28,7 +28,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
_ = arena_init(&s.arena, uint(size), backing_allocator)
|
||||
}
|
||||
|
||||
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {
|
||||
default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {
|
||||
if s != nil {
|
||||
arena_destroy(&s.arena)
|
||||
s^ = {}
|
||||
@@ -61,7 +61,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
}
|
||||
|
||||
@(fini, private)
|
||||
_destroy_temp_allocator_fini :: proc() {
|
||||
_destroy_temp_allocator_fini :: proc "contextless" () {
|
||||
default_temp_allocator_destroy(&global_default_temp_allocator_data)
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc :=
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = default_temp_allocator_proc,
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
|
||||
/*
|
||||
Declarations which are required by the compiler
|
||||
|
||||
## Descriptions of files
|
||||
|
||||
There are a lot of files in this package and below is described roughly what
|
||||
kind of functionality is placed in different files:
|
||||
|
||||
| File pattern | Description
|
||||
|----------------------|------------------------------------------------------|
|
||||
| `core.odin` | Contains the declarations that compiler will require to be present. Contains context-related declarations, `Type_Info` declarations and some other types used to implement the runtime and other packages. |
|
||||
| `core_builtin*.odin` | Contain `@(builtin)` declarations that can be used without importing the package. Most of them aren't required by the compiler |
|
||||
| `default_*.odin` | Contain default implementations for context allocators |
|
||||
| `entry_*.odin` | Contain OS-specific entry points |
|
||||
| `os_specific_*.odin` | Contain OS-specific utility procedures |
|
||||
| `*internal*.odin` | Contain implementations for internal procedures that can be called by the compiler |
|
||||
|
||||
## Implementing custom runtime
|
||||
|
||||
For embedded and kernel development it might be required to re-implement parts
|
||||
of the `base:runtime` package. This can include changing the default printing
|
||||
procedures that handle console output when the program panics, custom
|
||||
entry-points, tailored for a specific platform or execution environment, or
|
||||
simply switching up implementations of some procedures.
|
||||
|
||||
In case this is required, the following is suggested:
|
||||
|
||||
1. Define `$ODIN_ROOT` environment variable to point to a directory within your
|
||||
project that contains the following directories: `base/`, `core/` and `vendor/`.
|
||||
2. Inside the `$ODIN_ROOT/base` subdirectory, implement the *necessary
|
||||
declarations*.
|
||||
|
||||
What constitutes the necessary definitions is described below.
|
||||
|
||||
### Context-related
|
||||
|
||||
The compiler will require these declarations as they concern the `context`
|
||||
variable.
|
||||
|
||||
* `Maybe`
|
||||
* `Source_Code_Location`
|
||||
* `Context`
|
||||
* `Allocator`
|
||||
* `Random_Generator`
|
||||
* `Logger`
|
||||
* `__init_context`
|
||||
|
||||
### Runtime initialization/cleanup
|
||||
|
||||
These are not strictly required for compilation, but if global variables or
|
||||
`@(init)`/`@(fini)` blocks are used, these procedures need to be called inside
|
||||
the entry point.
|
||||
|
||||
* `_startup_runtime`
|
||||
* `_cleanup_runtime`
|
||||
|
||||
### Type assertion check
|
||||
|
||||
These procedures are called every time `.(Type)` expressions are used in order
|
||||
to check the union tag or the underlying type of `any` before returning the
|
||||
value of the underlying type. These are not required if `-no-type-assert` is
|
||||
specified.
|
||||
|
||||
* `type_assertion_check`
|
||||
* `type_assertion_check2` (takes in typeid)
|
||||
|
||||
### Bounds checking procedures
|
||||
|
||||
These procedures are called every time index or slicing expression are used in
|
||||
order to perform bounds-checking before the actual operation. These are not
|
||||
required if the `-no-bounds-check` option is specified.
|
||||
|
||||
* `bounds_check_error`
|
||||
* `matrix_bounds_check_error`
|
||||
* `slice_expr_error_hi`
|
||||
* `slice_expr_error_lo_hi`
|
||||
* `multi_pointer_slice_expr_error`
|
||||
|
||||
### cstring calls
|
||||
|
||||
If `cstring` or `cstring16` types are used, these procedures are required.
|
||||
|
||||
* `cstring_to_string`
|
||||
* `cstring_len`
|
||||
* `cstring16_to_string16`
|
||||
* `cstring16_len`
|
||||
|
||||
### Comparison
|
||||
|
||||
These procedures are required for comparison operators between strings and other
|
||||
compound types to function properly. If strings, structs nor unions are compared,
|
||||
only `string_eq` procedure is required.
|
||||
|
||||
* `memory_equal`
|
||||
* `memory_compare`
|
||||
* `memory_compare_zero`
|
||||
* `cstring_eq`
|
||||
* `cstring16_eq`
|
||||
* `cstring_ne`
|
||||
* `cstring16_ne`
|
||||
* `cstring_lt`
|
||||
* `cstring16_lt`
|
||||
* `cstring_gt`
|
||||
* `cstring16_gt`
|
||||
* `cstring_le`
|
||||
* `cstring16_le`
|
||||
* `cstring_ge`
|
||||
* `cstring16_ge`
|
||||
* `string_eq`
|
||||
* `string16_eq`
|
||||
* `string_ne`
|
||||
* `string16_ne`
|
||||
* `string_lt`
|
||||
* `string16_lt`
|
||||
* `string_gt`
|
||||
* `string16_gt`
|
||||
* `string_le`
|
||||
* `string16_le`
|
||||
* `string_ge`
|
||||
* `string16_ge`
|
||||
* `complex32_eq`
|
||||
* `complex32_ne`
|
||||
* `complex64_eq`
|
||||
* `complex64_ne`
|
||||
* `complex128_eq`
|
||||
* `complex128_ne`
|
||||
* `quaternion64_eq`
|
||||
* `quaternion64_ne`
|
||||
* `quaternion128_eq`
|
||||
* `quaternion128_ne`
|
||||
* `quaternion256_eq`
|
||||
* `quaternion256_ne`
|
||||
|
||||
### for-in `string` type
|
||||
|
||||
These procedures are required to iterate strings using `for ... in` loop. If this
|
||||
kind of loop isn't used, these procedures aren't required.
|
||||
|
||||
* `string_decode_rune`
|
||||
* `string_decode_last_rune` (for `#reverse for`)
|
||||
|
||||
### Required when RTTI is enabled (the vast majority of targets)
|
||||
|
||||
These declarations are required unless the `-no-rtti` compiler option is
|
||||
specified. Note that in order to be useful, some other procedures need to be
|
||||
implemented. Those procedures aren't mentioned here as the compiler won't
|
||||
complain if they're missing.
|
||||
|
||||
* `Type_Info`
|
||||
* `type_table`
|
||||
* `__type_info_of`
|
||||
|
||||
### Hashing
|
||||
|
||||
Required if maps are used
|
||||
|
||||
* `default_hasher`
|
||||
* `default_hasher_cstring`
|
||||
* `default_hasher_string`
|
||||
|
||||
### Pseudo-CRT required procedured due to LLVM but useful in general
|
||||
|
||||
* `memset`
|
||||
* `memcpy`
|
||||
* `memove`
|
||||
|
||||
### Procedures required by the LLVM backend if u128/i128 is used
|
||||
|
||||
* `umodti3`
|
||||
* `udivti3`
|
||||
* `modti3`
|
||||
* `divti3`
|
||||
* `fixdfti`
|
||||
* `fixunsdfti`
|
||||
* `fixunsdfdi`
|
||||
* `floattidf`
|
||||
* `floattidf_unsigned`
|
||||
* `truncsfhf2`
|
||||
* `truncdfhf2`
|
||||
* `gnu_h2f_ieee`
|
||||
* `gnu_f2h_ieee`
|
||||
* `extendhfsf2`
|
||||
|
||||
### Procedures required by the LLVM backend if f16 is used (WASM only)
|
||||
|
||||
* `__ashlti3`
|
||||
* `__multi3`
|
||||
|
||||
### When -no-crt is defined (windows only)
|
||||
|
||||
* `_tls_index`
|
||||
* `_fltused`
|
||||
|
||||
### Arithmetic
|
||||
|
||||
* `quo_complex32`
|
||||
* `quo_complex64`
|
||||
* `quo_complex128`
|
||||
|
||||
* `mul_quaternion64`
|
||||
* `mul_quaternion128`
|
||||
* `mul_quaternion256`
|
||||
|
||||
* `quo_quaternion64`
|
||||
* `quo_quaternion128`
|
||||
* `quo_quaternion256`
|
||||
|
||||
* `abs_complex32`
|
||||
* `abs_complex64`
|
||||
* `abs_complex128`
|
||||
|
||||
* `abs_quaternion64`
|
||||
* `abs_quaternion128`
|
||||
* `abs_quaternion256`
|
||||
|
||||
## Map specific calls
|
||||
|
||||
* `map_seed_from_map_data`
|
||||
* `__dynamic_map_check_grow` (for static map calls)
|
||||
* `map_insert_hash_dynamic` (for static map calls)
|
||||
* `__dynamic_map_get` (for dynamic map calls)
|
||||
* `__dynamic_map_set` (for dynamic map calls)
|
||||
|
||||
## Dynamic literals (`[dynamic]T` and `map[K]V`) (can be disabled with `-no-dynamic-literals`)
|
||||
|
||||
* `__dynamic_array_reserve`
|
||||
* `__dynamic_array_append`
|
||||
* `__dynamic_map_reserve`
|
||||
|
||||
### Objective-C specific
|
||||
|
||||
* `objc_lookUpClass`
|
||||
* `sel_registerName`
|
||||
* `objc_allocateClassPair`
|
||||
|
||||
### Other required declarations
|
||||
|
||||
This is required without conditions.
|
||||
|
||||
* `Load_Directory_File`
|
||||
|
||||
*/
|
||||
package runtime
|
||||
@@ -1,180 +0,0 @@
|
||||
package runtime
|
||||
|
||||
/*
|
||||
|
||||
package runtime has numerous entities (declarations) which are required by the compiler to function.
|
||||
|
||||
|
||||
## Basic types and calls (and anything they rely on)
|
||||
|
||||
Source_Code_Location
|
||||
Context
|
||||
Allocator
|
||||
Logger
|
||||
|
||||
__init_context
|
||||
_cleanup_runtime
|
||||
|
||||
|
||||
## cstring calls
|
||||
|
||||
cstring_to_string
|
||||
cstring_len
|
||||
|
||||
|
||||
|
||||
## Required when RTTI is enabled (the vast majority of targets)
|
||||
|
||||
Type_Info
|
||||
|
||||
type_table
|
||||
__type_info_of
|
||||
|
||||
|
||||
## Hashing
|
||||
|
||||
default_hasher
|
||||
default_hasher_cstring
|
||||
default_hasher_string
|
||||
|
||||
|
||||
## Pseudo-CRT required procedured due to LLVM but useful in general
|
||||
memset
|
||||
memcpy
|
||||
memove
|
||||
|
||||
|
||||
## Procedures required by the LLVM backend if u128/i128 is used
|
||||
umodti3
|
||||
udivti3
|
||||
modti3
|
||||
divti3
|
||||
fixdfti
|
||||
fixunsdfti
|
||||
fixunsdfdi
|
||||
floattidf
|
||||
floattidf_unsigned
|
||||
truncsfhf2
|
||||
truncdfhf2
|
||||
gnu_h2f_ieee
|
||||
gnu_f2h_ieee
|
||||
extendhfsf2
|
||||
|
||||
## Procedures required by the LLVM backend if f16 is used
|
||||
__ashlti3 // wasm specific
|
||||
__multi3 // wasm specific
|
||||
|
||||
|
||||
## Required an entry point is defined (i.e. 'main')
|
||||
|
||||
args__
|
||||
|
||||
|
||||
## When -no-crt is defined (and not a wasm target) (mostly due to LLVM)
|
||||
_tls_index
|
||||
_fltused
|
||||
|
||||
|
||||
## Bounds checking procedures (when not disabled with -no-bounds-check)
|
||||
|
||||
bounds_check_error
|
||||
matrix_bounds_check_error
|
||||
slice_expr_error_hi
|
||||
slice_expr_error_lo_hi
|
||||
multi_pointer_slice_expr_error
|
||||
|
||||
|
||||
## Type assertion check
|
||||
|
||||
type_assertion_check
|
||||
type_assertion_check2 // takes in typeid
|
||||
|
||||
|
||||
## Arithmetic
|
||||
|
||||
quo_complex32
|
||||
quo_complex64
|
||||
quo_complex128
|
||||
|
||||
mul_quaternion64
|
||||
mul_quaternion128
|
||||
mul_quaternion256
|
||||
|
||||
quo_quaternion64
|
||||
quo_quaternion128
|
||||
quo_quaternion256
|
||||
|
||||
abs_complex32
|
||||
abs_complex64
|
||||
abs_complex128
|
||||
|
||||
abs_quaternion64
|
||||
abs_quaternion128
|
||||
abs_quaternion256
|
||||
|
||||
|
||||
## Comparison
|
||||
|
||||
memory_equal
|
||||
memory_compare
|
||||
memory_compare_zero
|
||||
|
||||
cstring_eq
|
||||
cstring_ne
|
||||
cstring_lt
|
||||
cstring_gt
|
||||
cstring_le
|
||||
cstring_gt
|
||||
|
||||
string_eq
|
||||
string_ne
|
||||
string_lt
|
||||
string_gt
|
||||
string_le
|
||||
string_gt
|
||||
|
||||
complex32_eq
|
||||
complex32_ne
|
||||
complex64_eq
|
||||
complex64_ne
|
||||
complex128_eq
|
||||
complex128_ne
|
||||
|
||||
quaternion64_eq
|
||||
quaternion64_ne
|
||||
quaternion128_eq
|
||||
quaternion128_ne
|
||||
quaternion256_eq
|
||||
quaternion256_ne
|
||||
|
||||
|
||||
## Map specific calls
|
||||
|
||||
map_seed_from_map_data
|
||||
__dynamic_map_check_grow // static map calls
|
||||
map_insert_hash_dynamic // static map calls
|
||||
__dynamic_map_get // dynamic map calls
|
||||
__dynamic_map_set // dynamic map calls
|
||||
|
||||
|
||||
## Dynamic literals ([dynamic]T and map[K]V) (can be disabled with -no-dynamic-literals)
|
||||
|
||||
__dynamic_array_reserve
|
||||
__dynamic_array_append
|
||||
|
||||
__dynamic_map_reserve
|
||||
|
||||
|
||||
## Objective-C specific
|
||||
|
||||
objc_lookUpClass
|
||||
sel_registerName
|
||||
objc_allocateClassPair
|
||||
|
||||
|
||||
## for-in `string` type
|
||||
|
||||
string_decode_rune
|
||||
string_decode_last_rune // #reverse for
|
||||
|
||||
*/
|
||||
@@ -2,6 +2,7 @@ package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@(require_results)
|
||||
heap_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = heap_allocator_proc,
|
||||
|
||||
+153
-4
@@ -268,8 +268,8 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
m = (n-i) / 8 * 8
|
||||
for /**/; i < m; i += 8 {
|
||||
m = (n-i) / size_of(uintptr) * size_of(uintptr)
|
||||
for /**/; i < m; i += size_of(uintptr) {
|
||||
if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) {
|
||||
return false
|
||||
}
|
||||
@@ -389,8 +389,8 @@ memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_
|
||||
}
|
||||
}
|
||||
|
||||
m = (n-i) / 8 * 8
|
||||
for /**/; i < m; i += 8 {
|
||||
m = (n-i) / size_of(uintptr) * size_of(uintptr)
|
||||
for /**/; i < m; i += size_of(uintptr) {
|
||||
if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 {
|
||||
return 1
|
||||
}
|
||||
@@ -493,12 +493,40 @@ string_cmp :: proc "contextless" (a, b: string) -> int {
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
string16_eq :: proc "contextless" (lhs, rhs: string16) -> bool {
|
||||
x := transmute(Raw_String16)lhs
|
||||
y := transmute(Raw_String16)rhs
|
||||
if x.len != y.len {
|
||||
return false
|
||||
}
|
||||
return #force_inline memory_equal(x.data, y.data, x.len*size_of(u16))
|
||||
}
|
||||
|
||||
string16_cmp :: proc "contextless" (a, b: string16) -> int {
|
||||
x := transmute(Raw_String16)a
|
||||
y := transmute(Raw_String16)b
|
||||
|
||||
ret := memory_compare(x.data, y.data, min(x.len, y.len)*size_of(u16))
|
||||
if ret == 0 && x.len != y.len {
|
||||
return -1 if x.len < y.len else +1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) }
|
||||
string_lt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) < 0 }
|
||||
string_gt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) > 0 }
|
||||
string_le :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) <= 0 }
|
||||
string_ge :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0 }
|
||||
|
||||
string16_ne :: #force_inline proc "contextless" (a, b: string16) -> bool { return !string16_eq(a, b) }
|
||||
string16_lt :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) < 0 }
|
||||
string16_gt :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) > 0 }
|
||||
string16_le :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) <= 0 }
|
||||
string16_ge :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) >= 0 }
|
||||
|
||||
|
||||
cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||
p0 := uintptr((^byte)(s))
|
||||
p := p0
|
||||
@@ -508,6 +536,16 @@ cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||
return int(p - p0)
|
||||
}
|
||||
|
||||
cstring16_len :: proc "contextless" (s: cstring16) -> int {
|
||||
p := ([^]u16)(s)
|
||||
n := 0
|
||||
for p != nil && p[0] != 0 {
|
||||
p = p[1:]
|
||||
n += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
if s == nil {
|
||||
return ""
|
||||
@@ -517,6 +555,15 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
return transmute(string)Raw_String{ptr, n}
|
||||
}
|
||||
|
||||
cstring16_to_string16 :: proc "contextless" (s: cstring16) -> string16 {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
ptr := (^u16)(s)
|
||||
n := cstring16_len(s)
|
||||
return transmute(string16)Raw_String16{ptr, n}
|
||||
}
|
||||
|
||||
|
||||
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
|
||||
x := ([^]byte)(lhs)
|
||||
@@ -559,6 +606,46 @@ cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return
|
||||
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
|
||||
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
|
||||
|
||||
cstring16_eq :: proc "contextless" (lhs, rhs: cstring16) -> bool {
|
||||
x := ([^]u16)(lhs)
|
||||
y := ([^]u16)(rhs)
|
||||
if x == y {
|
||||
return true
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return false
|
||||
}
|
||||
xn := cstring16_len(lhs)
|
||||
yn := cstring16_len(rhs)
|
||||
if xn != yn {
|
||||
return false
|
||||
}
|
||||
return #force_inline memory_equal(x, y, xn*size_of(u16))
|
||||
}
|
||||
|
||||
cstring16_cmp :: proc "contextless" (lhs, rhs: cstring16) -> int {
|
||||
x := ([^]u16)(lhs)
|
||||
y := ([^]u16)(rhs)
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return -1 if x == nil else +1
|
||||
}
|
||||
xn := cstring16_len(lhs)
|
||||
yn := cstring16_len(rhs)
|
||||
ret := memory_compare(x, y, min(xn, yn)*size_of(u16))
|
||||
if ret == 0 && xn != yn {
|
||||
return -1 if xn < yn else +1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
cstring16_ne :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return !cstring16_eq(a, b) }
|
||||
cstring16_lt :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) < 0 }
|
||||
cstring16_gt :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) > 0 }
|
||||
cstring16_le :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) <= 0 }
|
||||
cstring16_ge :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) >= 0 }
|
||||
|
||||
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
|
||||
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }
|
||||
@@ -694,6 +781,68 @@ string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
|
||||
return r, size
|
||||
}
|
||||
|
||||
|
||||
string16_decode_rune :: #force_inline proc "contextless" (s: string16) -> (rune, int) {
|
||||
REPLACEMENT_CHAR :: '\ufffd'
|
||||
_surr1 :: 0xd800
|
||||
_surr2 :: 0xdc00
|
||||
_surr3 :: 0xe000
|
||||
_surr_self :: 0x10000
|
||||
|
||||
r := rune(REPLACEMENT_CHAR)
|
||||
|
||||
if len(s) < 1 {
|
||||
return r, 0
|
||||
}
|
||||
|
||||
w := 1
|
||||
switch c := s[0]; {
|
||||
case c < _surr1, _surr3 <= c:
|
||||
r = rune(c)
|
||||
case _surr1 <= c && c < _surr2 && 1 < len(s) &&
|
||||
_surr2 <= s[1] && s[1] < _surr3:
|
||||
r1, r2 := rune(c), rune(s[1])
|
||||
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
|
||||
r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self
|
||||
}
|
||||
w += 1
|
||||
}
|
||||
return r, w
|
||||
}
|
||||
|
||||
string16_decode_last_rune :: proc "contextless" (s: string16) -> (rune, int) {
|
||||
REPLACEMENT_CHAR :: '\ufffd'
|
||||
_surr1 :: 0xd800
|
||||
_surr2 :: 0xdc00
|
||||
_surr3 :: 0xe000
|
||||
_surr_self :: 0x10000
|
||||
|
||||
r := rune(REPLACEMENT_CHAR)
|
||||
|
||||
if len(s) < 1 {
|
||||
return r, 0
|
||||
}
|
||||
|
||||
n := len(s)-1
|
||||
c := s[n]
|
||||
w := 1
|
||||
if _surr2 <= c && c < _surr3 {
|
||||
if n >= 1 {
|
||||
r1 := rune(s[n-1])
|
||||
r2 := rune(c)
|
||||
if _surr1 <= r1 && r1 < _surr2 {
|
||||
r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self
|
||||
}
|
||||
w = 2
|
||||
}
|
||||
} else if c < _surr1 || _surr3 <= c {
|
||||
r = rune(c)
|
||||
}
|
||||
return r, w
|
||||
}
|
||||
|
||||
|
||||
|
||||
abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 {
|
||||
p, q := abs(real(x)), abs(imag(x))
|
||||
if p < q {
|
||||
|
||||
@@ -293,7 +293,14 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
print_string("quaternion")
|
||||
print_u64(u64(8*ti.size))
|
||||
case Type_Info_String:
|
||||
if info.is_cstring {
|
||||
print_byte('c')
|
||||
}
|
||||
print_string("string")
|
||||
switch info.encoding {
|
||||
case .UTF_8: /**/
|
||||
case .UTF_16: print_string("16")
|
||||
}
|
||||
case Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: print_string("bool")
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#+private
|
||||
package runtime
|
||||
|
||||
@(priority_index=-1e6)
|
||||
@(priority_index=-1e5)
|
||||
foreign import ObjC "system:objc"
|
||||
|
||||
@(priority_index=-1e6)
|
||||
foreign import libSystem "system:System"
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
objc_id :: ^intrinsics.objc_object
|
||||
@@ -34,3 +37,10 @@ foreign ObjC {
|
||||
object_getClass :: proc "c" (obj: objc_id) -> objc_Class ---
|
||||
}
|
||||
|
||||
foreign libSystem {
|
||||
_NSConcreteGlobalBlock: intrinsics.objc_class
|
||||
_NSConcreteStackBlock: intrinsics.objc_class
|
||||
|
||||
_Block_object_assign :: proc "c" (rawptr, rawptr, i32) ---
|
||||
_Block_object_dispose :: proc "c" (rawptr, i32) ---
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package runtime
|
||||
|
||||
init_default_context_for_js: Context
|
||||
@(init, private="file")
|
||||
init_default_context :: proc() {
|
||||
init_default_context_for_js = context
|
||||
init_default_context :: proc "contextless" () {
|
||||
__init_context(&init_default_context_for_js)
|
||||
}
|
||||
|
||||
@(export)
|
||||
|
||||
@@ -97,7 +97,7 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode,
|
||||
for &v in p {
|
||||
if pos == 0 {
|
||||
val = read_u64(r)
|
||||
pos = 7
|
||||
pos = 8
|
||||
}
|
||||
v = byte(val)
|
||||
val >>= 8
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package runtime
|
||||
|
||||
Thread_Local_Cleaner :: #type proc "odin" ()
|
||||
Thread_Local_Cleaner_Odin :: #type proc "odin" ()
|
||||
Thread_Local_Cleaner_Contextless :: #type proc "contextless" ()
|
||||
|
||||
Thread_Local_Cleaner :: union #shared_nil {Thread_Local_Cleaner_Odin, Thread_Local_Cleaner_Contextless}
|
||||
|
||||
@(private="file")
|
||||
thread_local_cleaners: [8]Thread_Local_Cleaner
|
||||
|
||||
|
||||
// Add a procedure that will be run at the end of a thread for the purpose of
|
||||
// deallocating state marked as `thread_local`.
|
||||
//
|
||||
@@ -29,6 +33,9 @@ run_thread_local_cleaners :: proc "odin" () {
|
||||
if p == nil {
|
||||
break
|
||||
}
|
||||
p()
|
||||
switch v in p {
|
||||
case Thread_Local_Cleaner_Odin: v()
|
||||
case Thread_Local_Cleaner_Contextless: v()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +89,12 @@ wasm_allocator_init :: proc(a: ^WASM_Allocator, alignment: uint = 8) {
|
||||
|
||||
global_default_wasm_allocator_data: WASM_Allocator
|
||||
|
||||
@(require_results)
|
||||
default_wasm_allocator :: proc() -> Allocator {
|
||||
return wasm_allocator(&global_default_wasm_allocator_data)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
wasm_allocator :: proc(a: ^WASM_Allocator) -> Allocator {
|
||||
return {
|
||||
data = a,
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
find "$1" -type f \(\
|
||||
-iname "*.exe" \
|
||||
-o -iname "*.dll" \
|
||||
-o -iname "*.lib" \
|
||||
-o -iname "*.pdb" \
|
||||
\) -delete
|
||||
@@ -72,14 +72,14 @@ when ODIN_OS == .Windows {
|
||||
n_sep_by_space: c.char,
|
||||
p_sign_posn: c.char,
|
||||
n_sign_posn: c.char,
|
||||
_W_decimal_point: [^]u16 `fmt:"s,0"`,
|
||||
_W_thousands_sep: [^]u16 `fmt:"s,0"`,
|
||||
_W_int_curr_symbol: [^]u16 `fmt:"s,0"`,
|
||||
_W_currency_symbol: [^]u16 `fmt:"s,0"`,
|
||||
_W_mon_decimal_point: [^]u16 `fmt:"s,0"`,
|
||||
_W_mon_thousands_sep: [^]u16 `fmt:"s,0"`,
|
||||
_W_positive_sign: [^]u16 `fmt:"s,0"`,
|
||||
_W_negative_sign: [^]u16 `fmt:"s,0"`,
|
||||
_W_decimal_point: cstring16,
|
||||
_W_thousands_sep: cstring16,
|
||||
_W_int_curr_symbol: cstring16,
|
||||
_W_currency_symbol: cstring16,
|
||||
_W_mon_decimal_point: cstring16,
|
||||
_W_mon_thousands_sep: cstring16,
|
||||
_W_positive_sign: cstring16,
|
||||
_W_negative_sign: cstring16,
|
||||
}
|
||||
} else {
|
||||
lconv :: struct {
|
||||
|
||||
@@ -22,7 +22,7 @@ DEFAULT_CAPACITY :: 16
|
||||
/*
|
||||
Initialize a `Queue` with a starting `capacity` and an `allocator`.
|
||||
*/
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error {
|
||||
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator, loc := #caller_location) -> runtime.Allocator_Error {
|
||||
clear(q)
|
||||
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
|
||||
data = nil,
|
||||
@@ -30,7 +30,7 @@ init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := contex
|
||||
cap = 0,
|
||||
allocator = allocator,
|
||||
}
|
||||
return reserve(q, capacity)
|
||||
return reserve(q, capacity, loc)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -114,9 +114,9 @@ Reserve enough space in the queue for at least the specified capacity.
|
||||
|
||||
This may return an error if allocation failed.
|
||||
*/
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int, loc := #caller_location) -> runtime.Allocator_Error {
|
||||
if capacity > space(q^) {
|
||||
return _grow(q, uint(capacity))
|
||||
return _grow(q, uint(capacity), loc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -269,9 +269,9 @@ Example:
|
||||
assert(queue.pop_front(&q) == 3)
|
||||
}
|
||||
*/
|
||||
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
push_back :: proc(q: ^$Q/Queue($T), elem: T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
_grow(q, loc = loc) or_return
|
||||
}
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
q.data[idx] = elem
|
||||
@@ -303,9 +303,9 @@ Example:
|
||||
assert(queue.pop_back(&q) == 1)
|
||||
}
|
||||
*/
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
push_front :: proc(q: ^$Q/Queue($T), elem: T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
_grow(q, loc = loc) or_return
|
||||
}
|
||||
q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
|
||||
q.len += 1
|
||||
@@ -396,10 +396,10 @@ Push many elements at once to the back of the queue.
|
||||
If there is not enough space left and allocation fails to get more, this will
|
||||
return false with an `Allocator_Error`.
|
||||
*/
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) {
|
||||
n := uint(builtin.len(elems))
|
||||
if space(q^) < int(n) {
|
||||
_grow(q, q.len + n) or_return
|
||||
_grow(q, q.len + n, loc) or_return
|
||||
}
|
||||
|
||||
sz := uint(builtin.len(q.data))
|
||||
@@ -465,10 +465,10 @@ clear :: proc(q: ^$Q/Queue($T)) {
|
||||
|
||||
|
||||
// Internal growing procedure
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error {
|
||||
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0, loc := #caller_location) -> runtime.Allocator_Error {
|
||||
new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
|
||||
n := uint(builtin.len(q.data))
|
||||
builtin.resize(&q.data, int(new_capacity)) or_return
|
||||
builtin.resize(&q.data, int(new_capacity), loc) or_return
|
||||
if q.offset + q.len > n {
|
||||
diff := n - q.offset
|
||||
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
|
||||
|
||||
@@ -54,7 +54,7 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (
|
||||
symbol.SizeOfStruct = size_of(symbol^)
|
||||
symbol.MaxNameLen = 255
|
||||
if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
|
||||
fl.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator)
|
||||
fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator)
|
||||
} else {
|
||||
fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ _LIBRARY_FILE_EXTENSION :: "dll"
|
||||
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
||||
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||
wide_path := win32.utf8_to_wstring(path, allocator)
|
||||
defer free(wide_path, allocator)
|
||||
defer free(rawptr(wide_path), allocator)
|
||||
handle := cast(Library)win32.LoadLibraryW(wide_path)
|
||||
return handle, handle != nil
|
||||
}
|
||||
|
||||
@@ -82,14 +82,16 @@ _tag_implementations_id: map[string]Tag_Implementation
|
||||
_tag_implementations_type: map[typeid]Tag_Implementation
|
||||
|
||||
// Register a custom tag implementation to be used when marshalling that type and unmarshalling that tag number.
|
||||
tag_register_type :: proc(impl: Tag_Implementation, nr: Tag_Number, type: typeid) {
|
||||
tag_register_type :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, type: typeid) {
|
||||
context = runtime.default_context()
|
||||
_tag_implementations_nr[nr] = impl
|
||||
_tag_implementations_type[type] = impl
|
||||
}
|
||||
|
||||
// Register a custom tag implementation to be used when marshalling that tag number or marshalling
|
||||
// a field with the struct tag `cbor_tag:"nr"`.
|
||||
tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string) {
|
||||
tag_register_number :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, id: string) {
|
||||
context = runtime.default_context()
|
||||
_tag_implementations_nr[nr] = impl
|
||||
_tag_implementations_id[id] = impl
|
||||
}
|
||||
@@ -98,13 +100,13 @@ tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string
|
||||
INITIALIZE_DEFAULT_TAGS :: #config(CBOR_INITIALIZE_DEFAULT_TAGS, !ODIN_DEFAULT_TO_PANIC_ALLOCATOR && !ODIN_DEFAULT_TO_NIL_ALLOCATOR)
|
||||
|
||||
@(private, init, disabled=!INITIALIZE_DEFAULT_TAGS)
|
||||
tags_initialize_defaults :: proc() {
|
||||
tags_initialize_defaults :: proc "contextless" () {
|
||||
tags_register_defaults()
|
||||
}
|
||||
|
||||
// Registers tags that have implementations provided by this package.
|
||||
// This is done by default and can be controlled with the `CBOR_INITIALIZE_DEFAULT_TAGS` define.
|
||||
tags_register_defaults :: proc() {
|
||||
tags_register_defaults :: proc "contextless" () {
|
||||
tag_register_number({nil, tag_time_unmarshal, tag_time_marshal}, TAG_EPOCH_TIME_NR, TAG_EPOCH_TIME_ID)
|
||||
tag_register_number({nil, tag_base64_unmarshal, tag_base64_marshal}, TAG_BASE64_NR, TAG_BASE64_ID)
|
||||
tag_register_number({nil, tag_cbor_unmarshal, tag_cbor_marshal}, TAG_CBOR_NR, TAG_CBOR_ID)
|
||||
@@ -298,7 +300,7 @@ tag_base64_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number,
|
||||
|
||||
#partial switch t in ti.variant {
|
||||
case reflect.Type_Info_String:
|
||||
|
||||
assert(t.encoding == .UTF_8)
|
||||
if t.is_cstring {
|
||||
length := base64.decoded_len(bytes)
|
||||
builder := strings.builder_make(0, length+1)
|
||||
|
||||
@@ -335,6 +335,8 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a
|
||||
_unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
|
||||
#partial switch t in ti.variant {
|
||||
case reflect.Type_Info_String:
|
||||
assert(t.encoding == .UTF_8)
|
||||
|
||||
bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
|
||||
|
||||
if t.is_cstring {
|
||||
|
||||
@@ -353,10 +353,10 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
#partial switch info in ti.variant {
|
||||
case runtime.Type_Info_String:
|
||||
switch x in v {
|
||||
case string:
|
||||
return x == ""
|
||||
case cstring:
|
||||
return x == nil || x == ""
|
||||
case string: return x == ""
|
||||
case cstring: return x == nil || x == ""
|
||||
case string16: return x == ""
|
||||
case cstring16: return x == nil || x == ""
|
||||
}
|
||||
case runtime.Type_Info_Any:
|
||||
return v.(any) == nil
|
||||
|
||||
@@ -572,7 +572,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
key_ptr: rawptr
|
||||
|
||||
#partial switch tk in t.key.variant {
|
||||
case runtime.Type_Info_String:
|
||||
case runtime.Type_Info_String:
|
||||
assert(tk.encoding == .UTF_8)
|
||||
|
||||
key_ptr = rawptr(&key)
|
||||
key_cstr: cstring
|
||||
if reflect.is_cstring(t.key) {
|
||||
|
||||
@@ -127,6 +127,8 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
|
||||
}
|
||||
|
||||
case runtime.Type_Info_String:
|
||||
assert(specific_type_info.encoding == .UTF_8)
|
||||
|
||||
if specific_type_info.is_cstring {
|
||||
cstr_ptr := (^cstring)(ptr)
|
||||
if cstr_ptr != nil {
|
||||
|
||||
@@ -38,6 +38,6 @@ Note that only one can be active at a time.
|
||||
Inputs:
|
||||
- setter: The type setter. Pass `nil` to disable any previously set setter.
|
||||
*/
|
||||
register_type_setter :: proc(setter: Custom_Type_Setter) {
|
||||
register_type_setter :: proc "contextless" (setter: Custom_Type_Setter) {
|
||||
global_custom_type_setter = setter
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,6 +29,8 @@ Integer:
|
||||
%x base 16, with lower-case letters for a-f
|
||||
%X base 16, with upper-case letters for A-F
|
||||
%U Unicode format: U+1234; same as "U+%04X"
|
||||
%m number of bytes in the best unit of measurement, e.g. 123.45mib
|
||||
%M number of bytes in the best unit of measurement, e.g. 123.45MiB
|
||||
Floating-point, complex numbers, and quaternions:
|
||||
%e scientific notation, e.g. -1.23456e+78
|
||||
%E scientific notation, e.g. -1.23456E+78
|
||||
@@ -38,8 +40,6 @@ Floating-point, complex numbers, and quaternions:
|
||||
%G synonym for %g
|
||||
%h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd)
|
||||
%H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD)
|
||||
%m number of bytes in the best unit of measurement, e.g. 123.45mib
|
||||
%M number of bytes in the best unit of measurement, e.g. 123.45MiB
|
||||
String and slice of bytes
|
||||
%s the uninterpreted bytes of the string or slice
|
||||
%q a double-quoted string safely escaped with Odin syntax
|
||||
|
||||
+84
-8
@@ -1551,6 +1551,79 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) {
|
||||
fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) {
|
||||
fmt_string(fi, string(s), verb)
|
||||
}
|
||||
|
||||
// Formats a string UTF-16 with a specific format.
|
||||
//
|
||||
// Inputs:
|
||||
// - fi: Pointer to the Info struct containing format settings.
|
||||
// - s: The string to format.
|
||||
// - verb: The format specifier character (e.g. 's', 'v', 'q', 'x', 'X').
|
||||
//
|
||||
fmt_string16 :: proc(fi: ^Info, s: string16, verb: rune) {
|
||||
s, verb := s, verb
|
||||
if ol, ok := fi.optional_len.?; ok {
|
||||
s = s[:clamp(ol, 0, len(s))]
|
||||
}
|
||||
if !fi.in_bad && fi.record_level > 0 && verb == 'v' {
|
||||
verb = 'q'
|
||||
}
|
||||
|
||||
switch verb {
|
||||
case 's', 'v':
|
||||
if fi.width_set {
|
||||
if fi.width > len(s) {
|
||||
if fi.minus {
|
||||
io.write_string16(fi.writer, s, &fi.n)
|
||||
}
|
||||
|
||||
for _ in 0..<fi.width - len(s) {
|
||||
io.write_byte(fi.writer, ' ', &fi.n)
|
||||
}
|
||||
|
||||
if !fi.minus {
|
||||
io.write_string16(fi.writer, s, &fi.n)
|
||||
}
|
||||
} else {
|
||||
io.write_string16(fi.writer, s, &fi.n)
|
||||
}
|
||||
} else {
|
||||
io.write_string16(fi.writer, s, &fi.n)
|
||||
}
|
||||
|
||||
case 'q', 'w': // quoted string
|
||||
io.write_quoted_string16(fi.writer, s, '"', &fi.n)
|
||||
|
||||
case 'x', 'X':
|
||||
space := fi.space
|
||||
fi.space = false
|
||||
defer fi.space = space
|
||||
|
||||
for i in 0..<len(s) {
|
||||
if i > 0 && space {
|
||||
io.write_byte(fi.writer, ' ', &fi.n)
|
||||
}
|
||||
char_set := __DIGITS_UPPER
|
||||
if verb == 'x' {
|
||||
char_set = __DIGITS_LOWER
|
||||
}
|
||||
_fmt_int(fi, u64(s[i]), 16, false, bit_size=16, digits=char_set)
|
||||
}
|
||||
|
||||
case:
|
||||
fmt_bad_verb(fi, verb)
|
||||
}
|
||||
}
|
||||
// Formats a C-style UTF-16 string with a specific format.
|
||||
//
|
||||
// Inputs:
|
||||
// - fi: Pointer to the Info struct containing format settings.
|
||||
// - s: The C-style string to format.
|
||||
// - verb: The format specifier character (Ref fmt_string).
|
||||
//
|
||||
fmt_cstring16 :: proc(fi: ^Info, s: cstring16, verb: rune) {
|
||||
fmt_string16(fi, string16(s), verb)
|
||||
}
|
||||
|
||||
// Formats a raw pointer with a specific format.
|
||||
//
|
||||
// Inputs:
|
||||
@@ -2273,14 +2346,14 @@ fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflec
|
||||
}
|
||||
|
||||
switch reflect.type_info_base(elem).id {
|
||||
case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return
|
||||
case u16: print_utf16(fi, ([^]u16)(data)[:n]); return
|
||||
case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
|
||||
case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
|
||||
case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
|
||||
case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
|
||||
case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
|
||||
case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
|
||||
case byte: fmt_string(fi, string (([^]byte)(data)[:n]), verb); return
|
||||
case u16: fmt_string16(fi, string16(([^]u16) (data)[:n]), verb); return
|
||||
case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
|
||||
case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
|
||||
case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
|
||||
case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
|
||||
case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
|
||||
case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
|
||||
}
|
||||
}
|
||||
if verb == 'p' {
|
||||
@@ -3210,6 +3283,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
case string: fmt_string(fi, a, verb)
|
||||
case cstring: fmt_cstring(fi, a, verb)
|
||||
|
||||
case string16: fmt_string16(fi, a, verb)
|
||||
case cstring16: fmt_cstring16(fi, a, verb)
|
||||
|
||||
case typeid: reflect.write_typeid(fi.writer, a, &fi.n)
|
||||
|
||||
case i16le: fmt_int(fi, u64(a), true, 16, verb)
|
||||
|
||||
@@ -741,6 +741,6 @@ destroy :: proc(img: ^Image) {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
_register :: proc() {
|
||||
_register :: proc "contextless" () {
|
||||
image.register(.BMP, load_from_bytes, destroy)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ Destroy_Proc :: #type proc(img: ^Image)
|
||||
_internal_loaders: [Which_File_Type]Loader_Proc
|
||||
_internal_destroyers: [Which_File_Type]Destroy_Proc
|
||||
|
||||
register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
|
||||
assert(loader != nil)
|
||||
assert(destroyer != nil)
|
||||
assert(_internal_loaders[kind] == nil)
|
||||
register :: proc "contextless" (kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
|
||||
assert_contextless(loader != nil)
|
||||
assert_contextless(destroyer != nil)
|
||||
assert_contextless(_internal_loaders[kind] == nil)
|
||||
_internal_loaders[kind] = loader
|
||||
|
||||
assert(_internal_destroyers[kind] == nil)
|
||||
assert_contextless(_internal_destroyers[kind] == nil)
|
||||
_internal_destroyers[kind] = destroyer
|
||||
}
|
||||
|
||||
|
||||
@@ -720,7 +720,7 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
_register :: proc() {
|
||||
_register :: proc "contextless" () {
|
||||
loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) {
|
||||
return load_from_bytes(data, allocator)
|
||||
}
|
||||
|
||||
@@ -1611,6 +1611,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
_register :: proc() {
|
||||
_register :: proc "contextless" () {
|
||||
image.register(.PNG, load_from_bytes, destroy)
|
||||
}
|
||||
|
||||
@@ -371,6 +371,6 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
_register :: proc() {
|
||||
_register :: proc "contextless" () {
|
||||
image.register(.QOI, load_from_bytes, destroy)
|
||||
}
|
||||
|
||||
@@ -406,6 +406,6 @@ IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4
|
||||
IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5
|
||||
|
||||
@(init, private)
|
||||
_register :: proc() {
|
||||
_register :: proc "contextless" () {
|
||||
image.register(.TGA, load_from_bytes, destroy)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package io
|
||||
|
||||
import "base:intrinsics"
|
||||
import "core:unicode/utf8"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
// Seek whence values
|
||||
Seek_From :: enum {
|
||||
@@ -314,6 +315,29 @@ write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int,
|
||||
return write(s, transmute([]byte)str, n_written)
|
||||
}
|
||||
|
||||
// write_string16 writes the contents of the string16 s to w reencoded as utf-8
|
||||
write_string16 :: proc(s: Writer, str: string16, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
for i := 0; i < len(str); i += 1 {
|
||||
r := rune(utf16.REPLACEMENT_CHAR)
|
||||
switch c := str[i]; {
|
||||
case c < utf16._surr1, utf16._surr3 <= c:
|
||||
r = rune(c)
|
||||
case utf16._surr1 <= c && c < utf16._surr2 && i+1 < len(str) &&
|
||||
utf16._surr2 <= str[i+1] && str[i+1] < utf16._surr3:
|
||||
r = utf16.decode_surrogate_pair(rune(c), rune(str[i+1]))
|
||||
i += 1
|
||||
}
|
||||
|
||||
w: int
|
||||
w, err = write_rune(s, r, n_written)
|
||||
n += w
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// write_rune writes a UTF-8 encoded rune to w.
|
||||
write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
|
||||
defer if err == nil && n_written != nil {
|
||||
|
||||
@@ -264,6 +264,33 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
|
||||
return
|
||||
}
|
||||
|
||||
write_quoted_string16 :: proc(w: Writer, str: string16, quote: byte = '"', n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
|
||||
defer if n_written != nil {
|
||||
n_written^ += n
|
||||
}
|
||||
write_byte(w, quote, &n) or_return
|
||||
for width, s := 0, str; len(s) > 0; s = s[width:] {
|
||||
r := rune(s[0])
|
||||
width = 1
|
||||
if r >= utf8.RUNE_SELF {
|
||||
r, width = utf16.decode_rune_in_string(s)
|
||||
}
|
||||
if width == 1 && r == utf8.RUNE_ERROR {
|
||||
write_byte(w, '\\', &n) or_return
|
||||
write_byte(w, 'x', &n) or_return
|
||||
write_byte(w, DIGITS_LOWER[s[0]>>4], &n) or_return
|
||||
write_byte(w, DIGITS_LOWER[s[0]&0xf], &n) or_return
|
||||
continue
|
||||
}
|
||||
|
||||
n_wrapper(write_escaped_rune(w, r, quote, false, nil, for_json), &n) or_return
|
||||
|
||||
}
|
||||
write_byte(w, quote, &n) or_return
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// writer append a quoted rune into the byte buffer, return the written size
|
||||
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) {
|
||||
_write_byte :: #force_inline proc(w: Writer, c: byte) -> int {
|
||||
|
||||
@@ -43,12 +43,14 @@ File_Console_Logger_Data :: struct {
|
||||
@(private) global_subtract_stderr_options: Options
|
||||
|
||||
@(init, private)
|
||||
init_standard_stream_status :: proc() {
|
||||
init_standard_stream_status :: proc "contextless" () {
|
||||
// NOTE(Feoramund): While it is technically possible for these streams to
|
||||
// be redirected during the runtime of the program, the cost of checking on
|
||||
// every single log message is not worth it to support such an
|
||||
// uncommonly-used feature.
|
||||
if terminal.color_enabled {
|
||||
context = runtime.default_context()
|
||||
|
||||
// This is done this way because it's possible that only one of these
|
||||
// streams could be redirected to a file.
|
||||
if !terminal.is_terminal(os.stdout) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package math_big
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import rnd "core:math/rand"
|
||||
|
||||
/*
|
||||
@@ -778,22 +779,23 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
|
||||
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||
|
||||
@(init, private)
|
||||
_init_constants :: proc() {
|
||||
_init_constants :: proc "contextless" () {
|
||||
initialize_constants()
|
||||
}
|
||||
|
||||
initialize_constants :: proc() -> (res: int) {
|
||||
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
|
||||
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable}
|
||||
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
|
||||
initialize_constants :: proc "contextless" () -> (res: int) {
|
||||
context = runtime.default_context()
|
||||
internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
|
||||
internal_int_set_from_integer( INT_ONE, 1); INT_ONE.flags = {.Immutable}
|
||||
internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
|
||||
|
||||
/*
|
||||
We set these special values to -1 or 1 so they don't get mistake for zero accidentally.
|
||||
This allows for shortcut tests of is_zero as .used == 0.
|
||||
*/
|
||||
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
|
||||
internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
|
||||
internal_set(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
|
||||
internal_int_set_from_integer( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
|
||||
internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
|
||||
internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
|
||||
|
||||
return _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
|
||||
package math_big
|
||||
|
||||
import "core:mem"
|
||||
import "base:intrinsics"
|
||||
import rnd "core:math/rand"
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
import "core:mem"
|
||||
import rnd "core:math/rand"
|
||||
|
||||
/*
|
||||
Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7.
|
||||
@@ -2885,12 +2885,12 @@ internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context
|
||||
}
|
||||
internal_clear_if_uninitialized :: proc {internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi, }
|
||||
|
||||
internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) {
|
||||
internal_error_if_immutable_single :: proc "contextless" (arg: ^Int) -> (err: Error) {
|
||||
if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable }
|
||||
return nil
|
||||
}
|
||||
|
||||
internal_error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) {
|
||||
internal_error_if_immutable_multi :: proc "contextless" (args: ..^Int) -> (err: Error) {
|
||||
for i in args {
|
||||
if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable }
|
||||
}
|
||||
|
||||
+18
-31
@@ -56,13 +56,6 @@ query_info :: proc(gen := context.random_generator) -> Generator_Query_Info {
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
_random_u64 :: proc(gen := context.random_generator) -> (res: u64) {
|
||||
ok := runtime.random_generator_read_ptr(gen, &res, size_of(res))
|
||||
assert(ok, "uninitialized gen/context.random_generator")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
@@ -84,7 +77,7 @@ Possible Output:
|
||||
|
||||
*/
|
||||
@(require_results)
|
||||
uint32 :: proc(gen := context.random_generator) -> (val: u32) { return u32(_random_u64(gen)) }
|
||||
uint32 :: proc(gen := context.random_generator) -> (val: u32) {return u32(uint64(gen))}
|
||||
|
||||
/*
|
||||
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
@@ -107,7 +100,11 @@ Possible Output:
|
||||
|
||||
*/
|
||||
@(require_results)
|
||||
uint64 :: proc(gen := context.random_generator) -> (val: u64) { return _random_u64(gen) }
|
||||
uint64 :: proc(gen := context.random_generator) -> (val: u64) {
|
||||
ok := runtime.random_generator_read_ptr(gen, &val, size_of(val))
|
||||
assert(ok, "uninitialized gen/context.random_generator")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
@@ -131,13 +128,13 @@ Possible Output:
|
||||
*/
|
||||
@(require_results)
|
||||
uint128 :: proc(gen := context.random_generator) -> (val: u128) {
|
||||
a := u128(_random_u64(gen))
|
||||
b := u128(_random_u64(gen))
|
||||
a := u128(uint64(gen))
|
||||
b := u128(uint64(gen))
|
||||
return (a<<64) | b
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
||||
|
||||
Returns:
|
||||
@@ -160,7 +157,7 @@ Possible Output:
|
||||
@(require_results) int31 :: proc(gen := context.random_generator) -> (val: i32) { return i32(uint32(gen) << 1 >> 1) }
|
||||
|
||||
/*
|
||||
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
||||
|
||||
Returns:
|
||||
@@ -183,7 +180,7 @@ Possible Output:
|
||||
@(require_results) int63 :: proc(gen := context.random_generator) -> (val: i64) { return i64(uint64(gen) << 1 >> 1) }
|
||||
|
||||
/*
|
||||
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
||||
|
||||
Returns:
|
||||
@@ -480,8 +477,8 @@ Possible Output:
|
||||
}
|
||||
|
||||
/*
|
||||
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
|
||||
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
|
||||
|
||||
Inputs:
|
||||
- p: The byte slice to fill
|
||||
@@ -508,22 +505,12 @@ Possible Output:
|
||||
*/
|
||||
@(require_results)
|
||||
read :: proc(p: []byte, gen := context.random_generator) -> (n: int) {
|
||||
pos := i8(0)
|
||||
val := i64(0)
|
||||
for n = 0; n < len(p); n += 1 {
|
||||
if pos == 0 {
|
||||
val = int63(gen)
|
||||
pos = 7
|
||||
}
|
||||
p[n] = byte(val)
|
||||
val >>= 8
|
||||
pos -= 1
|
||||
}
|
||||
return
|
||||
if !runtime.random_generator_read_bytes(gen, p) {return 0}
|
||||
return len(p)
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
@@ -566,7 +553,7 @@ perm :: proc(n: int, allocator := context.allocator, gen := context.random_gener
|
||||
}
|
||||
|
||||
/*
|
||||
Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used.
|
||||
Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- array: The slice to randomize
|
||||
@@ -607,7 +594,7 @@ shuffle :: proc(array: $T/[]$E, gen := context.random_generator) {
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a random element from the provided slice. If no generator is provided the global random number generator will be used.
|
||||
Returns a random element from the provided slice. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- array: The slice to choose an element from
|
||||
|
||||
@@ -2331,7 +2331,7 @@ buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint)
|
||||
}
|
||||
found.is_free = false
|
||||
data := ([^]byte)(found)[b.alignment:][:size]
|
||||
assert(cast(uintptr)raw_data(data)+cast(uintptr)size < cast(uintptr)buddy_block_next(found), "Buddy_Allocator has made an allocation which overlaps a block header.")
|
||||
assert(cast(uintptr)raw_data(data)+cast(uintptr)(size-1) < cast(uintptr)buddy_block_next(found), "Buddy_Allocator has made an allocation which overlaps a block header.")
|
||||
// ensure_poisoned(data)
|
||||
// sanitizer.address_unpoison(data)
|
||||
return data, nil
|
||||
@@ -2436,6 +2436,7 @@ compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.alloc
|
||||
rra.parent = allocator
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
data = rra,
|
||||
|
||||
@@ -9,7 +9,7 @@ _ :: runtime
|
||||
DEFAULT_PAGE_SIZE := uint(4096)
|
||||
|
||||
@(init, private)
|
||||
platform_memory_init :: proc() {
|
||||
platform_memory_init :: proc "contextless" () {
|
||||
_platform_memory_init()
|
||||
}
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return errno == .NONE
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc() {
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
DEFAULT_PAGE_SIZE = 4096
|
||||
// is power of two
|
||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return false
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc() {
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
}
|
||||
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
|
||||
@@ -28,13 +28,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK
|
||||
}
|
||||
|
||||
_platform_memory_init :: proc() {
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
// NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
|
||||
size := posix.sysconf(._PAGESIZE)
|
||||
DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
|
||||
|
||||
// is power of two
|
||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
|
||||
@@ -72,7 +72,7 @@ foreign Kernel32 {
|
||||
flProtect: u32,
|
||||
dwMaximumSizeHigh: u32,
|
||||
dwMaximumSizeLow: u32,
|
||||
lpName: [^]u16,
|
||||
lpName: cstring16,
|
||||
) -> rawptr ---
|
||||
|
||||
MapViewOfFile :: proc(
|
||||
@@ -146,13 +146,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
_platform_memory_init :: proc() {
|
||||
_platform_memory_init :: proc "contextless" () {
|
||||
sys_info: SYSTEM_INFO
|
||||
GetSystemInfo(&sys_info)
|
||||
DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize))
|
||||
|
||||
// is power of two
|
||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ Shutdown_Manner :: enum c.int {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
ensure_winsock_initialized :: proc() {
|
||||
ensure_winsock_initialized :: proc "contextless" () {
|
||||
win.ensure_winsock_initialized()
|
||||
}
|
||||
|
||||
|
||||
@@ -209,14 +209,14 @@ scan_comment :: proc(t: ^Tokenizer) -> string {
|
||||
scan_file_tag :: proc(t: ^Tokenizer) -> string {
|
||||
offset := t.offset - 1
|
||||
|
||||
for t.ch != '\n' {
|
||||
for t.ch != '\n' && t.ch != utf8.RUNE_EOF {
|
||||
if t.ch == '/' {
|
||||
next := peek_byte(t, 0)
|
||||
|
||||
if next == '/' || next == '*' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
advance_rune(t)
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
||||
defer delete(path)
|
||||
|
||||
find_data := &win32.WIN32_FIND_DATAW{}
|
||||
find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data)
|
||||
find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data)
|
||||
if find_handle == win32.INVALID_HANDLE_VALUE {
|
||||
err = get_last_error()
|
||||
return dfi[:], err
|
||||
|
||||
@@ -16,7 +16,7 @@ MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1
|
||||
global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena
|
||||
|
||||
@(fini, private)
|
||||
temp_allocator_fini :: proc() {
|
||||
temp_allocator_fini :: proc "contextless" () {
|
||||
for &arena in global_default_temp_allocator_arenas {
|
||||
runtime.arena_destroy(&arena)
|
||||
}
|
||||
@@ -69,6 +69,6 @@ _temp_allocator_end :: proc(tmp: runtime.Arena_Temp) {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_thread_local_cleaner :: proc() {
|
||||
init_thread_local_cleaner :: proc "contextless" () {
|
||||
runtime.add_thread_local_cleaner(temp_allocator_fini)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
|
||||
}
|
||||
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
path := concatenate({base_path, `\`, win32_wstring_to_utf8(raw_data(d.cFileName[:]), temp_allocator) or_else ""}, allocator) or_return
|
||||
path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
|
||||
|
||||
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
|
||||
defer win32.CloseHandle(handle)
|
||||
@@ -107,15 +107,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
|
||||
return
|
||||
}
|
||||
|
||||
wpath: []u16
|
||||
{
|
||||
i := 0
|
||||
for impl.wname[i] != 0 {
|
||||
i += 1
|
||||
}
|
||||
wpath = impl.wname[:i]
|
||||
}
|
||||
|
||||
wpath := string16(impl.wname)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
wpath_search := make([]u16, len(wpath)+3, temp_allocator)
|
||||
@@ -124,7 +116,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
|
||||
wpath_search[len(wpath)+1] = '*'
|
||||
wpath_search[len(wpath)+2] = 0
|
||||
|
||||
it.impl.find_handle = win32.FindFirstFileW(raw_data(wpath_search), &it.impl.find_data)
|
||||
it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data)
|
||||
if it.impl.find_handle == win32.INVALID_HANDLE_VALUE {
|
||||
read_directory_iterator_set_error(it, impl.name, _get_platform_error())
|
||||
return
|
||||
|
||||
@@ -31,7 +31,7 @@ _lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value:
|
||||
return "", false
|
||||
}
|
||||
|
||||
value = win32_utf16_to_utf8(b[:n], allocator) or_else ""
|
||||
value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else ""
|
||||
found = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ _stderr := File{
|
||||
}
|
||||
|
||||
@init
|
||||
_standard_stream_init :: proc() {
|
||||
new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
|
||||
_standard_stream_init :: proc "contextless" () {
|
||||
new_std :: proc "contextless" (impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
|
||||
impl.file.impl = impl
|
||||
impl.fd = linux.Fd(fd)
|
||||
impl.allocator = runtime.nil_allocator()
|
||||
|
||||
@@ -25,8 +25,8 @@ File_Impl :: struct {
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_std_files :: proc() {
|
||||
new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
|
||||
init_std_files :: proc "contextless" () {
|
||||
new_std :: proc "contextless" (impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
|
||||
impl.file.impl = impl
|
||||
impl.fd = fd
|
||||
impl.allocator = runtime.nil_allocator()
|
||||
|
||||
@@ -151,7 +151,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
|
||||
n: int
|
||||
n, err = read(f, buffer[:])
|
||||
total += n
|
||||
append_elems(&out_buffer, ..buffer[:n])
|
||||
append_elems(&out_buffer, ..buffer[:n]) or_return
|
||||
if err != nil {
|
||||
if err == .EOF || err == .Broken_Pipe {
|
||||
err = nil
|
||||
|
||||
@@ -30,8 +30,8 @@ Preopen :: struct {
|
||||
preopens: []Preopen
|
||||
|
||||
@(init)
|
||||
init_std_files :: proc() {
|
||||
new_std :: proc(impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
|
||||
init_std_files :: proc "contextless" () {
|
||||
new_std :: proc "contextless" (impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
|
||||
impl.file.impl = impl
|
||||
impl.allocator = runtime.nil_allocator()
|
||||
impl.fd = fd
|
||||
|
||||
@@ -43,8 +43,8 @@ File_Impl :: struct {
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_std_files :: proc() {
|
||||
new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File {
|
||||
init_std_files :: proc "contextless" () {
|
||||
new_std :: proc "contextless" (impl: ^File_Impl, code: u32, name: string) -> ^File {
|
||||
impl.file.impl = impl
|
||||
|
||||
impl.allocator = runtime.nil_allocator()
|
||||
@@ -77,7 +77,7 @@ init_std_files :: proc() {
|
||||
stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "<stderr>")
|
||||
}
|
||||
|
||||
_handle :: proc(f: ^File) -> win32.HANDLE {
|
||||
_handle :: proc "contextless" (f: ^File) -> win32.HANDLE {
|
||||
return win32.HANDLE(_fd(f))
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
|
||||
return _new_file(uintptr(clonefd), name(f), file_allocator())
|
||||
}
|
||||
|
||||
_fd :: proc(f: ^File) -> uintptr {
|
||||
_fd :: proc "contextless" (f: ^File) -> uintptr {
|
||||
if f == nil || f.impl == nil {
|
||||
return INVALID_HANDLE
|
||||
}
|
||||
@@ -247,7 +247,7 @@ _destroy :: proc(f: ^File_Impl) -> Error {
|
||||
}
|
||||
|
||||
a := f.allocator
|
||||
err0 := free(f.wname, a)
|
||||
err0 := free(rawptr(f.wname), a)
|
||||
err1 := delete(f.name, a)
|
||||
err2 := delete(f.r_buf, a)
|
||||
err3 := delete(f.w_buf, a)
|
||||
@@ -619,7 +619,7 @@ _symlink :: proc(old_name, new_name: string) -> Error {
|
||||
return .Unsupported
|
||||
}
|
||||
|
||||
_open_sym_link :: proc(p: [^]u16) -> (handle: win32.HANDLE, err: Error) {
|
||||
_open_sym_link :: proc(p: cstring16) -> (handle: win32.HANDLE, err: Error) {
|
||||
attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
|
||||
handle = win32.CreateFileW(p, 0, 0, nil, win32.OPEN_EXISTING, attrs, nil)
|
||||
@@ -661,7 +661,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
|
||||
}
|
||||
|
||||
|
||||
handle := _open_sym_link(raw_data(p)) or_return
|
||||
handle := _open_sym_link(cstring16(raw_data(p))) or_return
|
||||
defer win32.CloseHandle(handle)
|
||||
|
||||
n := win32.GetFinalPathNameByHandleW(handle, nil, 0, win32.VOLUME_NAME_DOS)
|
||||
@@ -672,7 +672,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([]u16, n+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS)
|
||||
n = win32.GetFinalPathNameByHandleW(handle, cstring16(raw_data(buf)), u32(len(buf)), win32.VOLUME_NAME_DOS)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
@@ -713,7 +713,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
|
||||
switch rdb.ReparseTag {
|
||||
case win32.IO_REPARSE_TAG_SYMLINK:
|
||||
rb := (^win32.SYMBOLIC_LINK_REPARSE_BUFFER)(&rdb.rest)
|
||||
pb := win32.wstring(&rb.PathBuffer)
|
||||
pb := ([^]u16)(&rb.PathBuffer)
|
||||
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
|
||||
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
|
||||
if rb.Flags & win32.SYMLINK_FLAG_RELATIVE != 0 {
|
||||
@@ -723,7 +723,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
|
||||
|
||||
case win32.IO_REPARSE_TAG_MOUNT_POINT:
|
||||
rb := (^win32.MOUNT_POINT_REPARSE_BUFFER)(&rdb.rest)
|
||||
pb := win32.wstring(&rb.PathBuffer)
|
||||
pb := ([^]u16)(&rb.PathBuffer)
|
||||
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
|
||||
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
|
||||
return _normalize_link_path(p, allocator)
|
||||
@@ -874,8 +874,8 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
|
||||
|
||||
|
||||
@(private="package", require_results)
|
||||
win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) {
|
||||
ws = raw_data(win32_utf8_to_utf16(s, allocator) or_return)
|
||||
win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: cstring16, err: runtime.Allocator_Error) {
|
||||
ws = cstring16(raw_data(win32_utf8_to_utf16(s, allocator) or_return))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -909,24 +909,26 @@ win32_utf8_to_utf16 :: proc(s: string, allocator: runtime.Allocator) -> (ws: []u
|
||||
}
|
||||
|
||||
@(private="package", require_results)
|
||||
win32_wstring_to_utf8 :: proc(s: [^]u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
|
||||
if s == nil || s[0] == 0 {
|
||||
win32_wstring_to_utf8 :: proc(s: cstring16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
|
||||
if s == nil || s == "" {
|
||||
return "", nil
|
||||
}
|
||||
n := 0
|
||||
for s[n] != 0 {
|
||||
n += 1
|
||||
}
|
||||
return win32_utf16_to_utf8(s[:n], allocator)
|
||||
return win32_utf16_to_utf8(string16(s), allocator)
|
||||
}
|
||||
|
||||
@(private="package")
|
||||
win32_utf16_to_utf8 :: proc{
|
||||
win32_utf16_string16_to_utf8,
|
||||
win32_utf16_u16_to_utf8,
|
||||
}
|
||||
|
||||
@(private="package", require_results)
|
||||
win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
|
||||
win32_utf16_string16_to_utf8 :: proc(s: string16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
|
||||
if len(s) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), nil, 0, nil, nil)
|
||||
n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil)
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
@@ -938,7 +940,41 @@ win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: str
|
||||
// will not be null terminated.
|
||||
text := make([]byte, n, allocator) or_return
|
||||
|
||||
n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), raw_data(text), n, nil, nil)
|
||||
n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil)
|
||||
if n1 == 0 {
|
||||
delete(text, allocator)
|
||||
return
|
||||
}
|
||||
|
||||
for i in 0..<n {
|
||||
if text[i] == 0 {
|
||||
n = i
|
||||
break
|
||||
}
|
||||
}
|
||||
res = string(text[:n])
|
||||
return
|
||||
}
|
||||
|
||||
@(private="package", require_results)
|
||||
win32_utf16_u16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
|
||||
if len(s) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil)
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// If N < 0 the call to WideCharToMultiByte assume the wide string is null terminated
|
||||
// and will scan it to find the first null terminated character. The resulting string will
|
||||
// also be null terminated.
|
||||
// If N > 0 it assumes the wide string is not null terminated and the resulting string
|
||||
// will not be null terminated.
|
||||
text := make([]byte, n, allocator) or_return
|
||||
|
||||
n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil)
|
||||
if n1 == 0 {
|
||||
delete(text, allocator)
|
||||
return
|
||||
|
||||
@@ -91,11 +91,11 @@ _remove_all :: proc(path: string) -> Error {
|
||||
nil,
|
||||
win32.FO_DELETE,
|
||||
dir,
|
||||
&empty[0],
|
||||
cstring16(&empty[0]),
|
||||
win32.FOF_NOCONFIRMATION | win32.FOF_NOERRORUI | win32.FOF_SILENT,
|
||||
false,
|
||||
nil,
|
||||
&empty[0],
|
||||
cstring16(&empty[0]),
|
||||
}
|
||||
res := win32.SHFileOperationW(&file_op)
|
||||
if res != 0 {
|
||||
@@ -160,7 +160,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
|
||||
can_use_long_paths: bool
|
||||
|
||||
@(init)
|
||||
init_long_path_support :: proc() {
|
||||
init_long_path_support :: proc "contextless" () {
|
||||
can_use_long_paths = false
|
||||
|
||||
key: win32.HKEY
|
||||
@@ -303,13 +303,13 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
|
||||
}
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator)
|
||||
n := win32.GetFullPathNameW(raw_data(rel_utf16), 0, nil, nil)
|
||||
n := win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", Platform_Error(win32.GetLastError())
|
||||
}
|
||||
|
||||
buf := make([]u16, n, temp_allocator) or_return
|
||||
n = win32.GetFullPathNameW(raw_data(rel_utf16), u32(n), raw_data(buf), nil)
|
||||
n = win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), u32(n), cstring16(raw_data(buf)), nil)
|
||||
if n == 0 {
|
||||
return "", Platform_Error(win32.GetLastError())
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ Arguments to the current process.
|
||||
args := get_args()
|
||||
|
||||
@(private="file")
|
||||
get_args :: proc() -> []string {
|
||||
get_args :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
result := make([]string, len(runtime.args__), heap_allocator())
|
||||
for rt_arg, i in runtime.args__ {
|
||||
result[i] = string(rt_arg)
|
||||
@@ -24,6 +25,12 @@ get_args :: proc() -> []string {
|
||||
return result
|
||||
}
|
||||
|
||||
@(fini, private="file")
|
||||
delete_args :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args, heap_allocator())
|
||||
}
|
||||
|
||||
/*
|
||||
Exit the current process.
|
||||
*/
|
||||
|
||||
@@ -13,7 +13,7 @@ import "core:time"
|
||||
foreign import lib "system:System"
|
||||
|
||||
foreign lib {
|
||||
sysctl :: proc(
|
||||
sysctl :: proc "c" (
|
||||
name: [^]i32, namelen: u32,
|
||||
oldp: rawptr, oldlenp: ^uint,
|
||||
newp: rawptr, newlen: uint,
|
||||
|
||||
@@ -175,7 +175,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
info.fields += {.Command_Line}
|
||||
}
|
||||
if .Command_Args in selection {
|
||||
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
|
||||
info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return
|
||||
info.fields += {.Command_Args}
|
||||
}
|
||||
}
|
||||
@@ -286,7 +286,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
info.fields += {.Command_Line}
|
||||
}
|
||||
if .Command_Args in selection {
|
||||
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
|
||||
info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return
|
||||
info.fields += {.Command_Args}
|
||||
}
|
||||
}
|
||||
@@ -610,7 +610,7 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path
|
||||
err =_get_platform_error()
|
||||
return
|
||||
}
|
||||
return win32_wstring_to_utf8(raw_data(entry.szExePath[:]), allocator)
|
||||
return win32_wstring_to_utf8(cstring16(raw_data(entry.szExePath[:])), allocator)
|
||||
}
|
||||
|
||||
_get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) {
|
||||
@@ -650,7 +650,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
|
||||
return strings.concatenate({domain, "\\", username}, allocator)
|
||||
}
|
||||
|
||||
_parse_command_line :: proc(cmd_line_w: [^]u16, allocator: runtime.Allocator) -> (argv: []string, err: Error) {
|
||||
_parse_command_line :: proc(cmd_line_w: cstring16, allocator: runtime.Allocator) -> (argv: []string, err: Error) {
|
||||
argc: i32
|
||||
argv_w := win32.CommandLineToArgvW(cmd_line_w, &argc)
|
||||
if argv_w == nil {
|
||||
|
||||
@@ -49,12 +49,12 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path
|
||||
|
||||
p := win32_utf8_to_utf16(name, temp_allocator) or_return
|
||||
|
||||
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
|
||||
n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
buf := make([]u16, n+1, temp_allocator)
|
||||
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
@@ -140,8 +140,8 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
|
||||
return _cleanpath_from_buf(buf[:n], allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
|
||||
return _cleanpath_from_buf(string16(buf[:n]), allocator)
|
||||
}
|
||||
|
||||
_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
|
||||
@@ -158,12 +158,12 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
|
||||
n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
|
||||
return _cleanpath_strip_prefix(buf[:n]), nil
|
||||
}
|
||||
|
||||
_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
|
||||
buf := buf
|
||||
_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
|
||||
buf := transmute([]u16)buf
|
||||
buf = _cleanpath_strip_prefix(buf)
|
||||
return win32_utf16_to_utf8(buf, allocator)
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Er
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator)
|
||||
n = win32.GetTempPathW(u32(len(b)), raw_data(b))
|
||||
n = win32.GetTempPathW(u32(len(b)), cstring16(raw_data(b)))
|
||||
|
||||
if n == 3 && b[1] == ':' && b[2] == '\\' {
|
||||
|
||||
} else if n > 0 && b[n-1] == '\\' {
|
||||
n -= 1
|
||||
}
|
||||
return win32_utf16_to_utf8(b[:n], allocator)
|
||||
return win32_utf16_to_utf8(string16(b[:n]), allocator)
|
||||
}
|
||||
|
||||
@@ -74,6 +74,5 @@ _get_known_folder_path :: proc(rfid: win32.REFKNOWNFOLDERID, allocator: runtime.
|
||||
return "", .Invalid_Path
|
||||
}
|
||||
|
||||
dir, _ = win32.wstring_to_utf8(path_w, -1, allocator)
|
||||
return
|
||||
return win32_wstring_to_utf8(cstring16(path_w), allocator)
|
||||
}
|
||||
@@ -1226,7 +1226,8 @@ _processor_core_count :: proc() -> int {
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
res := make([]string, len(runtime.args__))
|
||||
for _, i in res {
|
||||
res[i] = string(runtime.args__[i])
|
||||
@@ -1235,7 +1236,8 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
|
||||
@@ -965,7 +965,8 @@ _processor_core_count :: proc() -> int {
|
||||
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
res := make([]string, len(runtime.args__))
|
||||
for _, i in res {
|
||||
res[i] = string(runtime.args__[i])
|
||||
@@ -974,6 +975,7 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
@@ -317,7 +317,8 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
|
||||
args := _alloc_command_line_arguments()
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
res := make([]string, len(runtime.args__))
|
||||
for arg, i in runtime.args__ {
|
||||
res[i] = string(arg)
|
||||
@@ -326,7 +327,8 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
|
||||
@@ -1098,7 +1098,8 @@ _processor_core_count :: proc() -> int {
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
res := make([]string, len(runtime.args__))
|
||||
for _, i in res {
|
||||
res[i] = string(runtime.args__[i])
|
||||
@@ -1107,7 +1108,8 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
|
||||
@@ -1015,7 +1015,8 @@ _processor_core_count :: proc() -> int {
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
res := make([]string, len(runtime.args__))
|
||||
for _, i in res {
|
||||
res[i] = string(runtime.args__[i])
|
||||
@@ -1024,6 +1025,7 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
@@ -915,7 +915,8 @@ _processor_core_count :: proc() -> int {
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
res := make([]string, len(runtime.args__))
|
||||
for _, i in res {
|
||||
res[i] = string(runtime.args__[i])
|
||||
@@ -924,6 +925,7 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
+11
-8
@@ -28,16 +28,18 @@ stderr: Handle = 2
|
||||
args := _alloc_command_line_arguments()
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> (args: []string) {
|
||||
args = make([]string, len(runtime.args__))
|
||||
for &arg, i in args {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
cmd_args := make([]string, len(runtime.args__))
|
||||
for &arg, i in cmd_args {
|
||||
arg = string(runtime.args__[i])
|
||||
}
|
||||
return
|
||||
return cmd_args
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
delete(args)
|
||||
}
|
||||
|
||||
@@ -57,9 +59,8 @@ Preopen :: struct {
|
||||
preopens: []Preopen
|
||||
|
||||
@(init, private)
|
||||
init_preopens :: proc() {
|
||||
|
||||
strip_prefixes :: proc(path: string) -> string {
|
||||
init_preopens :: proc "contextless" () {
|
||||
strip_prefixes :: proc "contextless"(path: string) -> string {
|
||||
path := path
|
||||
loop: for len(path) > 0 {
|
||||
switch {
|
||||
@@ -76,6 +77,8 @@ init_preopens :: proc() {
|
||||
return path
|
||||
}
|
||||
|
||||
context = runtime.default_context()
|
||||
|
||||
dyn_preopens: [dynamic]Preopen
|
||||
loop: for fd := wasi.fd_t(3); ; fd += 1 {
|
||||
desc, err := wasi.fd_prestat_get(fd)
|
||||
|
||||
@@ -194,7 +194,8 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
|
||||
|
||||
@(private, require_results)
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
_alloc_command_line_arguments :: proc "contextless" () -> []string {
|
||||
context = runtime.default_context()
|
||||
arg_count: i32
|
||||
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count)
|
||||
arg_list := make([]string, int(arg_count))
|
||||
@@ -216,7 +217,8 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
|
||||
@(private, fini)
|
||||
_delete_command_line_arguments :: proc() {
|
||||
_delete_command_line_arguments :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
for s in args {
|
||||
delete(s)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
|
||||
buf := make([dynamic]u16, 100)
|
||||
defer delete(buf)
|
||||
for {
|
||||
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
|
||||
if n == 0 {
|
||||
return "", get_last_error()
|
||||
}
|
||||
@@ -154,7 +154,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> (
|
||||
return nil, get_last_error()
|
||||
}
|
||||
buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
|
||||
buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
|
||||
buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0)
|
||||
return buf[:buf_len], nil
|
||||
}
|
||||
@(private, require_results)
|
||||
|
||||
@@ -61,13 +61,13 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
|
||||
}
|
||||
|
||||
p := win32.utf8_to_utf16(name, ta)
|
||||
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
|
||||
n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", os.get_last_error()
|
||||
}
|
||||
|
||||
buf := make([]u16, n, ta)
|
||||
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
|
||||
if n == 0 {
|
||||
delete(buf)
|
||||
return "", os.get_last_error()
|
||||
|
||||
@@ -511,9 +511,12 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
|
||||
io.write_i64(w, i64(8*ti.size), 10, &n) or_return
|
||||
case Type_Info_String:
|
||||
if info.is_cstring {
|
||||
io.write_string(w, "cstring", &n) or_return
|
||||
} else {
|
||||
io.write_string(w, "string", &n) or_return
|
||||
io.write_byte(w, 'c', &n) or_return
|
||||
}
|
||||
io.write_string(w, "string", &n) or_return
|
||||
switch info.encoding {
|
||||
case .UTF_8: /**/
|
||||
case .UTF_16: io.write_string(w, "16", &n) or_return
|
||||
}
|
||||
case Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package objc_Foundation
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@(objc_class="NSBitmapImageRep")
|
||||
BitmapImageRep :: struct { using _: Object }
|
||||
|
||||
@(objc_type=BitmapImageRep, objc_name="alloc", objc_is_class_method=true)
|
||||
BitmapImageRep_alloc :: proc "c" () -> ^BitmapImageRep {
|
||||
return msgSend(^BitmapImageRep, BitmapImageRep, "alloc")
|
||||
}
|
||||
|
||||
@(objc_type=BitmapImageRep, objc_name="initWithBitmapDataPlanes")
|
||||
BitmapImageRep_initWithBitmapDataPlanes :: proc "c" (
|
||||
self: ^BitmapImageRep,
|
||||
bitmapDataPlanes: ^^u8,
|
||||
pixelsWide: Integer,
|
||||
pixelsHigh: Integer,
|
||||
bitsPerSample: Integer,
|
||||
samplesPerPixel: Integer,
|
||||
hasAlpha: bool,
|
||||
isPlanar: bool,
|
||||
colorSpaceName: ^String,
|
||||
bytesPerRow: Integer,
|
||||
bitsPerPixel: Integer) -> ^BitmapImageRep {
|
||||
|
||||
return msgSend(^BitmapImageRep,
|
||||
self,
|
||||
"initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bytesPerRow:bitsPerPixel:",
|
||||
bitmapDataPlanes,
|
||||
pixelsWide,
|
||||
pixelsHigh,
|
||||
bitsPerSample,
|
||||
samplesPerPixel,
|
||||
hasAlpha,
|
||||
isPlanar,
|
||||
colorSpaceName,
|
||||
bytesPerRow,
|
||||
bitsPerPixel)
|
||||
}
|
||||
|
||||
@(objc_type=BitmapImageRep, objc_name="bitmapData")
|
||||
BitmapImageRep_bitmapData :: proc "c" (self: ^BitmapImageRep) -> rawptr {
|
||||
return msgSend(rawptr, self, "bitmapData")
|
||||
}
|
||||
|
||||
@(objc_type=BitmapImageRep, objc_name="CGImage")
|
||||
BitmapImageRep_CGImage :: proc "c" (self: ^BitmapImageRep) -> rawptr {
|
||||
return msgSend(rawptr, self, "CGImage")
|
||||
}
|
||||
@@ -568,6 +568,15 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
@(objc_class="CALayer")
|
||||
Layer :: struct { using _: Object }
|
||||
|
||||
|
||||
@(objc_type=Layer, objc_name="contents")
|
||||
Layer_contents :: proc "c" (self: ^Layer) -> rawptr {
|
||||
return msgSend(rawptr, self, "contents")
|
||||
}
|
||||
@(objc_type=Layer, objc_name="setContents")
|
||||
Layer_setContents :: proc "c" (self: ^Layer, contents: rawptr) {
|
||||
msgSend(nil, self, "setContents:", contents)
|
||||
}
|
||||
@(objc_type=Layer, objc_name="contentsScale")
|
||||
Layer_contentsScale :: proc "c" (self: ^Layer) -> Float {
|
||||
return msgSend(Float, self, "contentsScale")
|
||||
@@ -654,8 +663,12 @@ Window_frame :: proc "c" (self: ^Window) -> Rect {
|
||||
return msgSend(Rect, self, "frame")
|
||||
}
|
||||
@(objc_type=Window, objc_name="setFrame")
|
||||
Window_setFrame :: proc "c" (self: ^Window, frame: Rect) {
|
||||
msgSend(nil, self, "setFrame:", frame)
|
||||
Window_setFrame :: proc "c" (self: ^Window, frame: Rect, display: BOOL) {
|
||||
msgSend(nil, self, "setFrame:display:", frame, display)
|
||||
}
|
||||
@(objc_type=Window, objc_name="setFrameOrigin")
|
||||
Window_setFrameOrigin :: proc "c" (self: ^Window, origin: Point) {
|
||||
msgSend(nil, self, "setFrameOrigin:", origin)
|
||||
}
|
||||
@(objc_type=Window, objc_name="opaque")
|
||||
Window_opaque :: proc "c" (self: ^Window) -> BOOL {
|
||||
@@ -693,6 +706,10 @@ Window_setMovable :: proc "c" (self: ^Window, ok: BOOL) {
|
||||
Window_setMovableByWindowBackground :: proc "c" (self: ^Window, ok: BOOL) {
|
||||
msgSend(nil, self, "setMovableByWindowBackground:", ok)
|
||||
}
|
||||
@(objc_type=Window, objc_name="setAcceptsMouseMovedEvents")
|
||||
Window_setAcceptsMouseMovedEvents :: proc "c" (self: ^Window, ok: BOOL) {
|
||||
msgSend(nil, self, "setAcceptsMouseMovedEvents:", ok)
|
||||
}
|
||||
@(objc_type=Window, objc_name="setStyleMask")
|
||||
Window_setStyleMask :: proc "c" (self: ^Window, style_mask: WindowStyleMask) {
|
||||
msgSend(nil, self, "setStyleMask:", style_mask)
|
||||
|
||||
@@ -52,7 +52,7 @@ CPU :: struct {
|
||||
cpu: CPU
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc "c" () {
|
||||
init_cpu_features :: proc "contextless" () {
|
||||
is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool {
|
||||
return (value>>bit) & 0x1 != 0
|
||||
}
|
||||
@@ -156,7 +156,7 @@ init_cpu_features :: proc "c" () {
|
||||
_cpu_name_buf: [72]u8
|
||||
|
||||
@(init, private)
|
||||
init_cpu_name :: proc "c" () {
|
||||
init_cpu_name :: proc "contextless" () {
|
||||
number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0)
|
||||
if number_of_extended_ids < 0x8000_0004 {
|
||||
return
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
#+build linux
|
||||
package sysinfo
|
||||
|
||||
import "base:runtime"
|
||||
import "core:sys/linux"
|
||||
import "core:strings"
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc() {
|
||||
init_cpu_features :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
fd, err := linux.open("/proc/cpuinfo", {})
|
||||
if err != .NONE { return }
|
||||
defer linux.close(fd)
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
#+build linux
|
||||
package sysinfo
|
||||
|
||||
import "base:runtime"
|
||||
import "core:sys/linux"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(init, private)
|
||||
init_cpu_core_count :: proc() {
|
||||
init_cpu_core_count :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
|
||||
fd, err := linux.open("/proc/cpuinfo", {})
|
||||
if err != .NONE { return }
|
||||
defer linux.close(fd)
|
||||
|
||||
@@ -7,7 +7,7 @@ import "base:intrinsics"
|
||||
import "core:sys/linux"
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc() {
|
||||
init_cpu_features :: proc "contextless" () {
|
||||
_features: CPU_Features
|
||||
defer cpu.features = _features
|
||||
|
||||
@@ -81,11 +81,11 @@ init_cpu_features :: proc() {
|
||||
}
|
||||
err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
|
||||
if err != nil {
|
||||
assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
|
||||
assert_contextless(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
|
||||
return
|
||||
}
|
||||
|
||||
assert(pairs[0].key == .IMA_EXT_0)
|
||||
assert_contextless(pairs[0].key == .IMA_EXT_0)
|
||||
exts := pairs[0].value.ima_ext_0
|
||||
exts -= { .FD, .C, .V }
|
||||
_features += transmute(CPU_Features)exts
|
||||
@@ -97,7 +97,7 @@ init_cpu_features :: proc() {
|
||||
_features += { .Misaligned_Supported }
|
||||
}
|
||||
} else {
|
||||
assert(pairs[1].key == .CPUPERF_0)
|
||||
assert_contextless(pairs[1].key == .CPUPERF_0)
|
||||
if .FAST in pairs[1].value.cpu_perf_0 {
|
||||
_features += { .Misaligned_Supported, .Misaligned_Fast }
|
||||
} else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
|
||||
@@ -108,6 +108,6 @@ init_cpu_features :: proc() {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_cpu_name :: proc() {
|
||||
init_cpu_name :: proc "contextless" () {
|
||||
cpu.name = "RISCV64"
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ package sysinfo
|
||||
|
||||
import sys "core:sys/windows"
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
|
||||
@(init, private)
|
||||
init_cpu_core_count :: proc() {
|
||||
init_cpu_core_count :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
|
||||
infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION
|
||||
defer delete(infos)
|
||||
|
||||
|
||||
@@ -10,7 +10,9 @@ import "base:runtime"
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
init_os_version :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
os_version.platform = .NetBSD
|
||||
} else {
|
||||
@@ -66,7 +68,7 @@ init_os_version :: proc () {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_ram :: proc() {
|
||||
init_ram :: proc "contextless" () {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64}
|
||||
mem_size: u64
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package sysinfo
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:sys/unix"
|
||||
@@ -9,7 +11,8 @@ import NS "core:sys/darwin/Foundation"
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_platform :: proc() {
|
||||
init_platform :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
ws :: strings.write_string
|
||||
wi :: strings.write_int
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ import "base:runtime"
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
init_os_version :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
|
||||
os_version.platform = .FreeBSD
|
||||
|
||||
kernel_version_buf: [1024]u8
|
||||
@@ -68,7 +70,7 @@ init_os_version :: proc () {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_ram :: proc() {
|
||||
init_ram :: proc "contextless" () {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM}
|
||||
mem_size: u64
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sysinfo
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
@@ -10,7 +11,9 @@ import "core:sys/linux"
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
init_os_version :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
|
||||
os_version.platform = .Linux
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
@@ -91,11 +94,11 @@ init_os_version :: proc () {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_ram :: proc() {
|
||||
init_ram :: proc "contextless" () {
|
||||
// Retrieve RAM info using `sysinfo`
|
||||
sys_info: linux.Sys_Info
|
||||
errno := linux.sysinfo(&sys_info)
|
||||
assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
|
||||
assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
|
||||
ram = RAM{
|
||||
total_ram = int(sys_info.totalram) * int(sys_info.mem_unit),
|
||||
free_ram = int(sys_info.freeram) * int(sys_info.mem_unit),
|
||||
|
||||
@@ -12,7 +12,9 @@ import "base:runtime"
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
init_os_version :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
|
||||
/*
|
||||
NOTE(Jeroen):
|
||||
`GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10.
|
||||
@@ -43,6 +45,7 @@ init_os_version :: proc () {
|
||||
os_version.minor = int(osvi.dwMinorVersion)
|
||||
os_version.build[0] = int(osvi.dwBuildNumber)
|
||||
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
strings.write_string(&b, "Windows ")
|
||||
|
||||
@@ -259,7 +262,7 @@ init_os_version :: proc () {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_ram :: proc() {
|
||||
init_ram :: proc "contextless" () {
|
||||
state: sys.MEMORYSTATUSEX
|
||||
|
||||
state.dwLength = size_of(state)
|
||||
@@ -276,10 +279,11 @@ init_ram :: proc() {
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_gpu_info :: proc() {
|
||||
|
||||
init_gpu_info :: proc "contextless" () {
|
||||
GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
|
||||
|
||||
context = runtime.default_context()
|
||||
|
||||
gpu_list: [dynamic]GPU
|
||||
gpu_index: int
|
||||
|
||||
@@ -324,8 +328,8 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok
|
||||
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
cstring16(&key_name_wide[0]),
|
||||
cstring16(&val_name_wide[0]),
|
||||
sys.RRF_RT_REG_SZ,
|
||||
nil,
|
||||
raw_data(result_wide[:]),
|
||||
@@ -359,8 +363,8 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool
|
||||
result_size := sys.DWORD(size_of(i32))
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
cstring16(&key_name_wide[0]),
|
||||
cstring16(&val_name_wide[0]),
|
||||
sys.RRF_RT_REG_DWORD,
|
||||
nil,
|
||||
&res,
|
||||
@@ -386,8 +390,8 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool
|
||||
result_size := sys.DWORD(size_of(i64))
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
cstring16(&key_name_wide[0]),
|
||||
cstring16(&val_name_wide[0]),
|
||||
sys.RRF_RT_REG_QWORD,
|
||||
nil,
|
||||
&res,
|
||||
|
||||
@@ -1838,7 +1838,7 @@ Clock_Id :: enum {
|
||||
Bits for POSIX interval timer flags.
|
||||
*/
|
||||
ITimer_Flags_Bits :: enum {
|
||||
ABSTIME = 1,
|
||||
ABSTIME = 0,
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#+build linux, darwin, openbsd, freebsd, netbsd, haiku
|
||||
package posix
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
@@ -60,7 +60,7 @@ wctomb :: libc.wctomb
|
||||
mbstowcs :: libc.mbstowcs
|
||||
wcstombs :: libc.wcstombs
|
||||
|
||||
free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring {
|
||||
free :: #force_inline proc "c" (ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring {
|
||||
libc.free(rawptr(ptr))
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package unix
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := u64(size_of(T))
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ foreign libc {
|
||||
@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
|
||||
}
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := c.size_t(size_of(T))
|
||||
res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)
|
||||
|
||||
@@ -9,7 +9,7 @@ foreign libc {
|
||||
@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
|
||||
}
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := c.size_t(size_of(T))
|
||||
res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)
|
||||
|
||||
@@ -373,12 +373,32 @@ remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callba
|
||||
return _remove_window_event_listener(event_kind_string[kind], user_data, callback, use_capture)
|
||||
}
|
||||
|
||||
add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
|
||||
@(default_calling_convention="contextless")
|
||||
foreign dom_lib {
|
||||
@(link_name="add_document_event_listener")
|
||||
_add_document_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
|
||||
}
|
||||
return _add_document_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture)
|
||||
}
|
||||
|
||||
remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
|
||||
@(default_calling_convention="contextless")
|
||||
foreign dom_lib {
|
||||
@(link_name="remove_document_event_listener")
|
||||
_remove_document_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
|
||||
}
|
||||
return _remove_document_event_listener(event_kind_string[kind], user_data, callback, use_capture)
|
||||
}
|
||||
|
||||
remove_event_listener_from_event :: proc(e: Event) -> bool {
|
||||
from_use_capture_false: bool
|
||||
from_use_capture_true: bool
|
||||
if e.id == "" {
|
||||
from_use_capture_false = remove_window_event_listener(e.kind, e.user_data, e.callback, false)
|
||||
from_use_capture_true = remove_window_event_listener(e.kind, e.user_data, e.callback, true)
|
||||
from_use_capture_false |= remove_document_event_listener(e.kind, e.user_data, e.callback, false)
|
||||
from_use_capture_true |= remove_document_event_listener(e.kind, e.user_data, e.callback, true)
|
||||
} else {
|
||||
from_use_capture_false = remove_event_listener(e.id, e.kind, e.user_data, e.callback, false)
|
||||
from_use_capture_true = remove_event_listener(e.id, e.kind, e.user_data, e.callback, true)
|
||||
|
||||
@@ -275,6 +275,14 @@ remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callba
|
||||
panic("vendor:wasm/js not supported on non JS targets")
|
||||
}
|
||||
|
||||
add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
|
||||
panic("vendor:wasm/js not supported on non JS targets")
|
||||
}
|
||||
|
||||
remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
|
||||
panic("vendor:wasm/js not supported on non JS targets")
|
||||
}
|
||||
|
||||
remove_event_listener_from_event :: proc(e: Event) -> bool {
|
||||
panic("vendor:wasm/js not supported on non JS targets")
|
||||
}
|
||||
|
||||
@@ -392,6 +392,9 @@ class WebGLInterface {
|
||||
BindTexture: (target, texture) => {
|
||||
this.ctx.bindTexture(target, texture ? this.textures[texture] : null)
|
||||
},
|
||||
BindRenderbuffer: (target, renderbuffer) => {
|
||||
this.ctx.bindRenderbuffer(target, renderbuffer ? this.renderbuffers[renderbuffer] : null)
|
||||
},
|
||||
BlendColor: (red, green, blue, alpha) => {
|
||||
this.ctx.blendColor(red, green, blue, alpha);
|
||||
},
|
||||
@@ -809,6 +812,40 @@ class WebGLInterface {
|
||||
Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); },
|
||||
Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
|
||||
|
||||
Uniform1fv: (location, count, addr) => {
|
||||
let array = this.mem.loadF32Array(addr, 1*count);
|
||||
this.ctx.uniform1fv(this.uniforms[location], array);
|
||||
},
|
||||
Uniform2fv: (location, count, addr) => {
|
||||
let array = this.mem.loadF32Array(addr, 2*count);
|
||||
this.ctx.uniform2fv(this.uniforms[location], array);
|
||||
},
|
||||
Uniform3fv: (location, count, addr) => {
|
||||
let array = this.mem.loadF32Array(addr, 3*count);
|
||||
this.ctx.uniform3fv(this.uniforms[location], array);
|
||||
},
|
||||
Uniform4fv: (location, count, addr) => {
|
||||
let array = this.mem.loadF32Array(addr, 4*count);
|
||||
this.ctx.uniform4fv(this.uniforms[location], array);
|
||||
},
|
||||
|
||||
Uniform1iv: (location, count, addr) => {
|
||||
let array = this.mem.loadI32Array(addr, 1*count);
|
||||
this.ctx.uniform1iv(this.uniforms[location], array);
|
||||
},
|
||||
Uniform2iv: (location, count, addr) => {
|
||||
let array = this.mem.loadI32Array(addr, 2*count);
|
||||
this.ctx.uniform2iv(this.uniforms[location], array);
|
||||
},
|
||||
Uniform3iv: (location, count, addr) => {
|
||||
let array = this.mem.loadI32Array(addr, 3*count);
|
||||
this.ctx.uniform3iv(this.uniforms[location], array);
|
||||
},
|
||||
Uniform4iv: (location, count, addr) => {
|
||||
let array = this.mem.loadI32Array(addr, 4*count);
|
||||
this.ctx.uniform4iv(this.uniforms[location], array);
|
||||
},
|
||||
|
||||
UniformMatrix2fv: (location, addr) => {
|
||||
let array = this.mem.loadF32Array(addr, 2*2);
|
||||
this.ctx.uniformMatrix2fv(this.uniforms[location], false, array);
|
||||
@@ -1701,6 +1738,28 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
|
||||
return true;
|
||||
},
|
||||
|
||||
add_document_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
|
||||
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
|
||||
let element = document;
|
||||
let key = listener_key('document', name, data, callback, !!use_capture);
|
||||
if (wasmMemoryInterface.listenerMap.has(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let listener = (e) => {
|
||||
let event_data = {};
|
||||
event_data.id_ptr = 0;
|
||||
event_data.id_len = 0;
|
||||
event_data.event = e;
|
||||
event_data.name_code = name_code;
|
||||
|
||||
onEventReceived(event_data, data, callback);
|
||||
};
|
||||
wasmMemoryInterface.listenerMap.set(key, listener);
|
||||
element.addEventListener(name, listener, !!use_capture);
|
||||
return true;
|
||||
},
|
||||
|
||||
remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback, use_capture) => {
|
||||
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
|
||||
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
|
||||
@@ -1733,6 +1792,20 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
|
||||
element.removeEventListener(name, listener, !!use_capture);
|
||||
return true;
|
||||
},
|
||||
remove_document_event_listener: (name_ptr, name_len, data, callback, use_capture) => {
|
||||
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
|
||||
let element = document;
|
||||
|
||||
let key = listener_key('document', name, data, callback, !!use_capture);
|
||||
let listener = wasmMemoryInterface.listenerMap.get(key);
|
||||
if (listener === undefined) {
|
||||
return false;
|
||||
}
|
||||
wasmMemoryInterface.listenerMap.delete(key);
|
||||
|
||||
element.removeEventListener(name, listener, !!use_capture);
|
||||
return true;
|
||||
},
|
||||
|
||||
event_stop_propagation: () => {
|
||||
if (event_temp.data && event_temp.data.event) {
|
||||
|
||||
@@ -573,10 +573,10 @@ Button_GetTextMargin :: #force_inline proc "system" (hwnd: HWND, pmargin: ^RECT)
|
||||
return cast(BOOL)SendMessageW(hwnd, BCM_GETTEXTMARGIN, 0, cast(LPARAM)uintptr(pmargin))
|
||||
}
|
||||
Button_SetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR) -> BOOL {
|
||||
return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(psz))
|
||||
return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(rawptr(psz)))
|
||||
}
|
||||
Button_GetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR, pcc: ^c_int) -> BOOL {
|
||||
return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(psz))
|
||||
return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(rawptr(psz)))
|
||||
}
|
||||
Button_GetNoteLength :: #force_inline proc "system" (hwnd: HWND) -> LRESULT {
|
||||
return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0)
|
||||
@@ -604,10 +604,10 @@ EDITBALLOONTIP :: struct {
|
||||
PEDITBALLOONTIP :: ^EDITBALLOONTIP
|
||||
|
||||
Edit_SetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR) -> BOOL {
|
||||
return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(lpcwText))
|
||||
return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(rawptr(lpcwText)))
|
||||
}
|
||||
Edit_SetCueBannerTextFocused :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR, fDrawFocused: BOOL) -> BOOL {
|
||||
return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(lpcwText))
|
||||
return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(rawptr(lpcwText)))
|
||||
}
|
||||
Edit_GetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpwText: LPWSTR, cchText: LONG) -> BOOL {
|
||||
return cast(BOOL)SendMessageW(hwnd, EM_GETCUEBANNER, uintptr(lpwText), cast(LPARAM)cchText)
|
||||
@@ -1197,7 +1197,7 @@ ListView_GetItemPosition :: #force_inline proc "system" (hwnd: HWND, i: c_int, p
|
||||
return cast(BOOL)SendMessageW(hwnd, LVM_GETITEMPOSITION, cast(WPARAM)i, cast(LPARAM)uintptr(ppt))
|
||||
}
|
||||
ListView_GetStringWidth :: #force_inline proc "system" (hwndLV: HWND, psz: LPCWSTR) -> c_int {
|
||||
return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(psz))
|
||||
return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(rawptr(psz)))
|
||||
}
|
||||
ListView_HitTest :: #force_inline proc "system" (hwndLV: HWND, pinfo: ^LV_HITTESTINFO) -> c_int {
|
||||
return cast(c_int)SendMessageW(hwndLV, LVM_HITTEST, 0, cast(LPARAM)uintptr(pinfo))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user