mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
Merge tag 'dev-2024-12'
# Conflicts: # vendor/raylib/windows/raylib.dll # vendor/raylib/windows/raylibdll.lib
This commit is contained in:
@@ -6,7 +6,7 @@ jobs:
|
||||
name: NetBSD Build, Check, and Test
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PKGSRC_BRANCH: 2024Q2
|
||||
PKGSRC_BRANCH: 2024Q3
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build, Check, and Test
|
||||
|
||||
@@ -171,14 +171,6 @@ Type_Info_Simd_Vector :: struct {
|
||||
elem_size: int,
|
||||
count: int,
|
||||
}
|
||||
Type_Info_Relative_Pointer :: struct {
|
||||
pointer: ^Type_Info, // ^T
|
||||
base_integer: ^Type_Info,
|
||||
}
|
||||
Type_Info_Relative_Multi_Pointer :: struct {
|
||||
pointer: ^Type_Info, // [^]T
|
||||
base_integer: ^Type_Info,
|
||||
}
|
||||
Type_Info_Matrix :: struct {
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
@@ -241,8 +233,6 @@ Type_Info :: struct {
|
||||
Type_Info_Map,
|
||||
Type_Info_Bit_Set,
|
||||
Type_Info_Simd_Vector,
|
||||
Type_Info_Relative_Pointer,
|
||||
Type_Info_Relative_Multi_Pointer,
|
||||
Type_Info_Matrix,
|
||||
Type_Info_Soa_Pointer,
|
||||
Type_Info_Bit_Field,
|
||||
@@ -275,8 +265,6 @@ Typeid_Kind :: enum u8 {
|
||||
Map,
|
||||
Bit_Set,
|
||||
Simd_Vector,
|
||||
Relative_Pointer,
|
||||
Relative_Multi_Pointer,
|
||||
Matrix,
|
||||
Soa_Pointer,
|
||||
Bit_Field,
|
||||
|
||||
@@ -388,7 +388,7 @@ _make_dynamic_array_len_cap :: proc(array: ^Raw_Dynamic_Array, size_of_elem, ali
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_map :: proc($T: typeid/map[$K]$E, allocator := context.allocator) -> (m: T) {
|
||||
make_map :: proc($T: typeid/map[$K]$E, allocator := context.allocator, loc := #caller_location) -> (m: T) {
|
||||
m.allocator = allocator
|
||||
return m
|
||||
}
|
||||
@@ -399,7 +399,7 @@ make_map :: proc($T: typeid/map[$K]$E, allocator := context.allocator) -> (m: T)
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_map_cap :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_map_cap :: proc($T: typeid/map[$K]$E, #any_int capacity: int, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_map_expr_error_loc(loc, capacity)
|
||||
context.allocator = allocator
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ make_soa_slice :: proc($T: typeid/#soa[]$E, #any_int length: int, allocator := c
|
||||
@(builtin, require_results)
|
||||
make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
context.allocator = allocator
|
||||
array.allocator = allocator
|
||||
reserve_soa(&array, 0, loc) or_return
|
||||
return array, nil
|
||||
}
|
||||
@@ -149,6 +150,7 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.
|
||||
@(builtin, require_results)
|
||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
context.allocator = allocator
|
||||
array.allocator = allocator
|
||||
resize_soa(&array, length, loc) or_return
|
||||
return array, nil
|
||||
}
|
||||
|
||||
@@ -486,18 +486,6 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
print_u64(u64(info.count))
|
||||
print_byte(']')
|
||||
print_type(info.elem)
|
||||
|
||||
case Type_Info_Relative_Pointer:
|
||||
print_string("#relative(")
|
||||
print_type(info.base_integer)
|
||||
print_string(") ")
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
print_string("#relative(")
|
||||
print_type(info.base_integer)
|
||||
print_string(") ")
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Matrix:
|
||||
print_string("matrix[")
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2024 Epic Games Tools
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the “Software”), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Binary file not shown.
@@ -19,7 +19,11 @@ if "%VSCMD_ARG_TGT_ARCH%" neq "x64" (
|
||||
)
|
||||
)
|
||||
|
||||
for /f %%i in ('powershell get-date -format "{yyyyMMdd}"') do (
|
||||
pushd misc
|
||||
cl /nologo get-date.c
|
||||
popd
|
||||
|
||||
for /f %%i in ('misc\get-date') do (
|
||||
set CURR_DATE_TIME=%%i
|
||||
)
|
||||
set curr_year=%CURR_DATE_TIME:~0,4%
|
||||
@@ -58,7 +62,6 @@ set V4=0
|
||||
set odin_version_full="%V1%.%V2%.%V3%.%V4%"
|
||||
set odin_version_raw="dev-%V1%-%V2%"
|
||||
|
||||
|
||||
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
|
||||
rem Parse source code as utf-8 even on shift-jis and other codepages
|
||||
rem See https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170
|
||||
|
||||
+17
-10
@@ -25,7 +25,8 @@ error() {
|
||||
|
||||
# Brew advises people not to add llvm to their $PATH, so try and use brew to find it.
|
||||
if [ -z "$LLVM_CONFIG" ] && [ -n "$(command -v brew)" ]; then
|
||||
if [ -n "$(command -v $(brew --prefix llvm@18)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@18)/bin/llvm-config"
|
||||
if [ -n "$(command -v $(brew --prefix llvm@19)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@19)/bin/llvm-config"
|
||||
elif [ -n "$(command -v $(brew --prefix llvm@18)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@18)/bin/llvm-config"
|
||||
elif [ -n "$(command -v $(brew --prefix llvm@17)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@17)/bin/llvm-config"
|
||||
elif [ -n "$(command -v $(brew --prefix llvm@14)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@14)/bin/llvm-config"
|
||||
fi
|
||||
@@ -33,13 +34,15 @@ fi
|
||||
|
||||
if [ -z "$LLVM_CONFIG" ]; then
|
||||
# darwin, linux, openbsd
|
||||
if [ -n "$(command -v llvm-config-18)" ]; then LLVM_CONFIG="llvm-config-18"
|
||||
if [ -n "$(command -v llvm-config-19)" ]; then LLVM_CONFIG="llvm-config-19"
|
||||
elif [ -n "$(command -v llvm-config-18)" ]; then LLVM_CONFIG="llvm-config-18"
|
||||
elif [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17"
|
||||
elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14"
|
||||
elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13"
|
||||
elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12"
|
||||
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
|
||||
# freebsd
|
||||
elif [ -n "$(command -v llvm-config19)" ]; then LLVM_CONFIG="llvm-config19"
|
||||
elif [ -n "$(command -v llvm-config18)" ]; then LLVM_CONFIG="llvm-config18"
|
||||
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config17"
|
||||
elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config14"
|
||||
@@ -66,15 +69,15 @@ LLVM_VERSION_MAJOR="$(echo $LLVM_VERSION | awk -F. '{print $1}')"
|
||||
LLVM_VERSION_MINOR="$(echo $LLVM_VERSION | awk -F. '{print $2}')"
|
||||
LLVM_VERSION_PATCH="$(echo $LLVM_VERSION | awk -F. '{print $3}')"
|
||||
|
||||
if [ $LLVM_VERSION_MAJOR -lt 11 ] || ([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]) || [ $LLVM_VERSION_MAJOR -gt 18 ]; then
|
||||
error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14, 17 or 18"
|
||||
if [ $LLVM_VERSION_MAJOR -lt 11 ] || ([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]) || [ $LLVM_VERSION_MAJOR -gt 19 ]; then
|
||||
error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14, 17, 18 or 19"
|
||||
fi
|
||||
|
||||
case "$OS_NAME" in
|
||||
Darwin)
|
||||
if [ "$OS_ARCH" = "arm64" ]; then
|
||||
if [ $LLVM_VERSION_MAJOR -lt 13 ]; then
|
||||
error "Invalid LLVM version $LLVM_VERSION: Darwin Arm64 requires LLVM 13, 14, 17 or 18"
|
||||
error "Invalid LLVM version $LLVM_VERSION: Darwin Arm64 requires LLVM 13, 14, 17, 18 or 19"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -152,9 +155,7 @@ build_odin() {
|
||||
}
|
||||
|
||||
run_demo() {
|
||||
if [ $# -eq 0 ] || [ "$1" = "debug" ]; then
|
||||
./odin run examples/demo -vet -strict-style -- Hellope World
|
||||
fi
|
||||
./odin run examples/demo -vet -strict-style -- Hellope World
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
@@ -166,14 +167,20 @@ if [ $# -eq 0 ]; then
|
||||
elif [ $# -eq 1 ]; then
|
||||
case $1 in
|
||||
report)
|
||||
[ ! -f "./odin" ] && build_odin debug
|
||||
if [ ! -f "./odin" ]; then
|
||||
build_odin debug
|
||||
run_demo
|
||||
fi
|
||||
./odin report
|
||||
;;
|
||||
debug)
|
||||
build_odin debug
|
||||
run_demo
|
||||
;;
|
||||
*)
|
||||
build_odin $1
|
||||
;;
|
||||
esac
|
||||
run_demo
|
||||
else
|
||||
error "Too many arguments!"
|
||||
fi
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package c_frontend_preprocess
|
||||
|
||||
import "core:c/frontend/tokenizer"
|
||||
|
||||
const_expr :: proc(rest: ^^Token, tok: ^Token) -> i64 {
|
||||
// TODO(bill): Handle const_expr correctly
|
||||
// This is effectively a mini-parser
|
||||
|
||||
assert(rest != nil)
|
||||
assert(tok != nil)
|
||||
rest^ = tokenizer.new_eof(tok)
|
||||
switch v in tok.val {
|
||||
case i64:
|
||||
return v
|
||||
case f64:
|
||||
return i64(v)
|
||||
case string:
|
||||
return 0
|
||||
case []u16:
|
||||
// TODO
|
||||
case []u32:
|
||||
// TODO
|
||||
}
|
||||
return 0
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,154 +0,0 @@
|
||||
package c_frontend_preprocess
|
||||
|
||||
import "core:unicode/utf8"
|
||||
|
||||
unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
|
||||
hex_to_int :: proc(c: byte) -> int {
|
||||
switch c {
|
||||
case '0'..='9': return int(c-'0')
|
||||
case 'a'..='f': return int(c-'a')+10
|
||||
case 'A'..='F': return int(c-'A')+10
|
||||
}
|
||||
return -1
|
||||
}
|
||||
w: int
|
||||
|
||||
if str[0] == quote && quote == '"' {
|
||||
return
|
||||
} else if str[0] >= 0x80 {
|
||||
r, w = utf8.decode_rune_in_string(str)
|
||||
return r, true, str[w:], true
|
||||
} else if str[0] != '\\' {
|
||||
return rune(str[0]), false, str[1:], true
|
||||
}
|
||||
|
||||
if len(str) <= 1 {
|
||||
return
|
||||
}
|
||||
s := str
|
||||
c := s[1]
|
||||
s = s[2:]
|
||||
|
||||
switch c {
|
||||
case: r = rune(c)
|
||||
|
||||
case 'a': r = '\a'
|
||||
case 'b': r = '\b'
|
||||
case 'e': r = '\e'
|
||||
case 'f': r = '\f'
|
||||
case 'n': r = '\n'
|
||||
case 'r': r = '\r'
|
||||
case 't': r = '\t'
|
||||
case 'v': r = '\v'
|
||||
case '\\': r = '\\'
|
||||
|
||||
case '"': r = '"'
|
||||
case '\'': r = '\''
|
||||
|
||||
case '0'..='7':
|
||||
v := int(c-'0')
|
||||
if len(s) < 2 {
|
||||
return
|
||||
}
|
||||
for i in 0..<len(s) {
|
||||
d := int(s[i]-'0')
|
||||
if d < 0 || d > 7 {
|
||||
return
|
||||
}
|
||||
v = (v<<3) | d
|
||||
}
|
||||
s = s[2:]
|
||||
if v > 0xff {
|
||||
return
|
||||
}
|
||||
r = rune(v)
|
||||
|
||||
case 'x', 'u', 'U':
|
||||
count: int
|
||||
switch c {
|
||||
case 'x': count = 2
|
||||
case 'u': count = 4
|
||||
case 'U': count = 8
|
||||
}
|
||||
|
||||
if len(s) < count {
|
||||
return
|
||||
}
|
||||
|
||||
for i in 0..<count {
|
||||
d := hex_to_int(s[i])
|
||||
if d < 0 {
|
||||
return
|
||||
}
|
||||
r = (r<<4) | rune(d)
|
||||
}
|
||||
s = s[count:]
|
||||
if c == 'x' {
|
||||
break
|
||||
}
|
||||
if r > utf8.MAX_RUNE {
|
||||
return
|
||||
}
|
||||
multiple_bytes = true
|
||||
}
|
||||
|
||||
success = true
|
||||
tail_string = s
|
||||
return
|
||||
}
|
||||
|
||||
unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: string, allocated, success: bool) {
|
||||
contains_rune :: proc(s: string, r: rune) -> int {
|
||||
for c, offset in s {
|
||||
if c == r {
|
||||
return offset
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
assert(len(lit) >= 2)
|
||||
|
||||
s := lit
|
||||
quote := '"'
|
||||
|
||||
if s == `""` {
|
||||
return "", false, true
|
||||
}
|
||||
|
||||
if contains_rune(s, '\n') >= 0 {
|
||||
return s, false, false
|
||||
}
|
||||
|
||||
if contains_rune(s, '\\') < 0 && contains_rune(s, quote) < 0 {
|
||||
if quote == '"' {
|
||||
return s, false, true
|
||||
}
|
||||
}
|
||||
s = s[1:len(s)-1]
|
||||
|
||||
|
||||
buf_len := 3*len(s) / 2
|
||||
buf := make([]byte, buf_len, allocator)
|
||||
offset := 0
|
||||
for len(s) > 0 {
|
||||
r, multiple_bytes, tail_string, ok := unquote_char(s, byte(quote))
|
||||
if !ok {
|
||||
delete(buf)
|
||||
return s, false, false
|
||||
}
|
||||
s = tail_string
|
||||
if r < 0x80 || !multiple_bytes {
|
||||
buf[offset] = byte(r)
|
||||
offset += 1
|
||||
} else {
|
||||
b, w := utf8.encode_rune(r)
|
||||
copy(buf[offset:], b[:w])
|
||||
offset += w
|
||||
}
|
||||
}
|
||||
|
||||
new_string := string(buf[:offset])
|
||||
|
||||
return new_string, true, true
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
Example:
|
||||
package demo
|
||||
|
||||
import tokenizer "core:c/frontend/tokenizer"
|
||||
import preprocessor "core:c/frontend/preprocessor"
|
||||
import "core:fmt"
|
||||
|
||||
main :: proc() {
|
||||
t := &tokenizer.Tokenizer{};
|
||||
tokenizer.init_defaults(t);
|
||||
|
||||
cpp := &preprocessor.Preprocessor{};
|
||||
cpp.warn, cpp.err = t.warn, t.err;
|
||||
preprocessor.init_lookup_tables(cpp);
|
||||
preprocessor.init_default_macros(cpp);
|
||||
cpp.include_paths = {"my/path/to/include"};
|
||||
|
||||
tok := tokenizer.tokenize_file(t, "the/source/file.c", 1);
|
||||
|
||||
tok = preprocessor.preprocess(cpp, tok);
|
||||
if tok != nil {
|
||||
for t := tok; t.kind != .EOF; t = t.next {
|
||||
fmt.println(t.lit);
|
||||
}
|
||||
}
|
||||
|
||||
fmt.println("[Done]");
|
||||
}
|
||||
*/
|
||||
package c_frontend_tokenizer
|
||||
@@ -1,68 +0,0 @@
|
||||
package c_frontend_tokenizer
|
||||
|
||||
// NOTE(bill): This is a really dumb approach for a hide set,
|
||||
// but it's really simple and probably fast enough in practice
|
||||
|
||||
|
||||
Hide_Set :: struct {
|
||||
next: ^Hide_Set,
|
||||
name: string,
|
||||
}
|
||||
|
||||
|
||||
new_hide_set :: proc(name: string) -> ^Hide_Set {
|
||||
hs := new(Hide_Set)
|
||||
hs.name = name
|
||||
return hs
|
||||
}
|
||||
|
||||
hide_set_contains :: proc(hs: ^Hide_Set, name: string) -> bool {
|
||||
for h := hs; h != nil; h = h.next {
|
||||
if h.name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
hide_set_union :: proc(a, b: ^Hide_Set) -> ^Hide_Set {
|
||||
head: Hide_Set
|
||||
curr := &head
|
||||
|
||||
for h := a; h != nil; h = h.next {
|
||||
curr.next = new_hide_set(h.name)
|
||||
curr = curr.next
|
||||
}
|
||||
curr.next = b
|
||||
return head.next
|
||||
}
|
||||
|
||||
|
||||
hide_set_intersection :: proc(a, b: ^Hide_Set) -> ^Hide_Set {
|
||||
head: Hide_Set
|
||||
curr := &head
|
||||
|
||||
for h := a; h != nil; h = h.next {
|
||||
if hide_set_contains(b, h.name) {
|
||||
curr.next = new_hide_set(h.name)
|
||||
curr = curr.next
|
||||
}
|
||||
}
|
||||
return head.next
|
||||
}
|
||||
|
||||
|
||||
add_hide_set :: proc(tok: ^Token, hs: ^Hide_Set) -> ^Token {
|
||||
head: Token
|
||||
curr := &head
|
||||
|
||||
tok := tok
|
||||
for ; tok != nil; tok = tok.next {
|
||||
t := copy_token(tok)
|
||||
t.hide_set = hide_set_union(t.hide_set, hs)
|
||||
curr.next = t
|
||||
curr = curr.next
|
||||
}
|
||||
return head.next
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package c_frontend_tokenizer
|
||||
|
||||
|
||||
Pos :: struct {
|
||||
file: string,
|
||||
line: int,
|
||||
column: int,
|
||||
offset: int,
|
||||
}
|
||||
|
||||
Token_Kind :: enum {
|
||||
Invalid,
|
||||
Ident,
|
||||
Punct,
|
||||
Keyword,
|
||||
Char,
|
||||
String,
|
||||
Number,
|
||||
PP_Number,
|
||||
Comment,
|
||||
EOF,
|
||||
}
|
||||
|
||||
File :: struct {
|
||||
name: string,
|
||||
id: int,
|
||||
src: []byte,
|
||||
|
||||
display_name: string,
|
||||
line_delta: int,
|
||||
}
|
||||
|
||||
|
||||
Token_Type_Hint :: enum u8 {
|
||||
None,
|
||||
|
||||
Int,
|
||||
Long,
|
||||
Long_Long,
|
||||
|
||||
Unsigned_Int,
|
||||
Unsigned_Long,
|
||||
Unsigned_Long_Long,
|
||||
|
||||
Float,
|
||||
Double,
|
||||
Long_Double,
|
||||
|
||||
UTF_8,
|
||||
UTF_16,
|
||||
UTF_32,
|
||||
UTF_Wide,
|
||||
}
|
||||
|
||||
Token_Value :: union {
|
||||
i64,
|
||||
f64,
|
||||
string,
|
||||
[]u16,
|
||||
[]u32,
|
||||
}
|
||||
|
||||
Token :: struct {
|
||||
kind: Token_Kind,
|
||||
next: ^Token,
|
||||
lit: string,
|
||||
|
||||
pos: Pos,
|
||||
file: ^File,
|
||||
line_delta: int,
|
||||
at_bol: bool,
|
||||
has_space: bool,
|
||||
|
||||
type_hint: Token_Type_Hint,
|
||||
val: Token_Value,
|
||||
prefix: string,
|
||||
|
||||
// Preprocessor values
|
||||
hide_set: ^Hide_Set,
|
||||
origin: ^Token,
|
||||
}
|
||||
|
||||
Is_Keyword_Proc :: #type proc(tok: ^Token) -> bool
|
||||
|
||||
copy_token :: proc(tok: ^Token) -> ^Token {
|
||||
t, _ := new_clone(tok^)
|
||||
t.next = nil
|
||||
return t
|
||||
}
|
||||
|
||||
new_eof :: proc(tok: ^Token) -> ^Token {
|
||||
t, _ := new_clone(tok^)
|
||||
t.kind = .EOF
|
||||
t.lit = ""
|
||||
return t
|
||||
}
|
||||
|
||||
default_is_keyword :: proc(tok: ^Token) -> bool {
|
||||
if tok.kind == .Keyword {
|
||||
return true
|
||||
}
|
||||
if len(tok.lit) > 0 {
|
||||
return default_keyword_set[tok.lit]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
token_name := [Token_Kind]string {
|
||||
.Invalid = "invalid",
|
||||
.Ident = "ident",
|
||||
.Punct = "punct",
|
||||
.Keyword = "keyword",
|
||||
.Char = "char",
|
||||
.String = "string",
|
||||
.Number = "number",
|
||||
.PP_Number = "preprocessor number",
|
||||
.Comment = "comment",
|
||||
.EOF = "eof",
|
||||
}
|
||||
|
||||
default_keyword_set := map[string]bool{
|
||||
"auto" = true,
|
||||
"break" = true,
|
||||
"case" = true,
|
||||
"char" = true,
|
||||
"const" = true,
|
||||
"continue" = true,
|
||||
"default" = true,
|
||||
"do" = true,
|
||||
"double" = true,
|
||||
"else" = true,
|
||||
"enum" = true,
|
||||
"extern" = true,
|
||||
"float" = true,
|
||||
"for" = true,
|
||||
"goto" = true,
|
||||
"if" = true,
|
||||
"int" = true,
|
||||
"long" = true,
|
||||
"register" = true,
|
||||
"restrict" = true,
|
||||
"return" = true,
|
||||
"short" = true,
|
||||
"signed" = true,
|
||||
"sizeof" = true,
|
||||
"static" = true,
|
||||
"struct" = true,
|
||||
"switch" = true,
|
||||
"typedef" = true,
|
||||
"union" = true,
|
||||
"unsigned" = true,
|
||||
"void" = true,
|
||||
"volatile" = true,
|
||||
"while" = true,
|
||||
"_Alignas" = true,
|
||||
"_Alignof" = true,
|
||||
"_Atomic" = true,
|
||||
"_Bool" = true,
|
||||
"_Generic" = true,
|
||||
"_Noreturn" = true,
|
||||
"_Thread_local" = true,
|
||||
"__restrict" = true,
|
||||
"typeof" = true,
|
||||
"asm" = true,
|
||||
"__restrict__" = true,
|
||||
"__thread" = true,
|
||||
"__attribute__" = true,
|
||||
}
|
||||
@@ -1,667 +0,0 @@
|
||||
package c_frontend_tokenizer
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
|
||||
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any)
|
||||
|
||||
|
||||
Tokenizer :: struct {
|
||||
// Immutable data
|
||||
path: string,
|
||||
src: []byte,
|
||||
|
||||
|
||||
// Tokenizing state
|
||||
ch: rune,
|
||||
offset: int,
|
||||
read_offset: int,
|
||||
line_offset: int,
|
||||
line_count: int,
|
||||
|
||||
// Extra information for tokens
|
||||
at_bol: bool,
|
||||
has_space: bool,
|
||||
|
||||
// Mutable data
|
||||
err: Error_Handler,
|
||||
warn: Error_Handler,
|
||||
error_count: int,
|
||||
warning_count: int,
|
||||
}
|
||||
|
||||
init_defaults :: proc(t: ^Tokenizer, err: Error_Handler = default_error_handler, warn: Error_Handler = default_warn_handler) {
|
||||
t.err = err
|
||||
t.warn = warn
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> (pos: Pos) {
|
||||
pos.file = t.path
|
||||
pos.offset = offset
|
||||
pos.line = t.line_count
|
||||
pos.column = offset - t.line_offset + 1
|
||||
return
|
||||
}
|
||||
|
||||
default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
|
||||
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column)
|
||||
fmt.eprintf(msg, ..args)
|
||||
fmt.eprintf("\n")
|
||||
}
|
||||
|
||||
default_warn_handler :: proc(pos: Pos, msg: string, args: ..any) {
|
||||
fmt.eprintf("%s(%d:%d) warning: ", pos.file, pos.line, pos.column)
|
||||
fmt.eprintf(msg, ..args)
|
||||
fmt.eprintf("\n")
|
||||
}
|
||||
|
||||
error_offset :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
|
||||
pos := offset_to_pos(t, offset)
|
||||
if t.err != nil {
|
||||
t.err(pos, msg, ..args)
|
||||
}
|
||||
t.error_count += 1
|
||||
}
|
||||
|
||||
warn_offset :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
|
||||
pos := offset_to_pos(t, offset)
|
||||
if t.warn != nil {
|
||||
t.warn(pos, msg, ..args)
|
||||
}
|
||||
t.warning_count += 1
|
||||
}
|
||||
|
||||
error :: proc(t: ^Tokenizer, tok: ^Token, msg: string, args: ..any) {
|
||||
pos := tok.pos
|
||||
if t.err != nil {
|
||||
t.err(pos, msg, ..args)
|
||||
}
|
||||
t.error_count += 1
|
||||
}
|
||||
|
||||
warn :: proc(t: ^Tokenizer, tok: ^Token, msg: string, args: ..any) {
|
||||
pos := tok.pos
|
||||
if t.warn != nil {
|
||||
t.warn(pos, msg, ..args)
|
||||
}
|
||||
t.warning_count += 1
|
||||
}
|
||||
|
||||
|
||||
advance_rune :: proc(t: ^Tokenizer) {
|
||||
if t.read_offset < len(t.src) {
|
||||
t.offset = t.read_offset
|
||||
if t.ch == '\n' {
|
||||
t.at_bol = true
|
||||
t.line_offset = t.offset
|
||||
t.line_count += 1
|
||||
}
|
||||
r, w := rune(t.src[t.read_offset]), 1
|
||||
switch {
|
||||
case r == 0:
|
||||
error_offset(t, t.offset, "illegal character NUL")
|
||||
case r >= utf8.RUNE_SELF:
|
||||
r, w = utf8.decode_rune(t.src[t.read_offset:])
|
||||
if r == utf8.RUNE_ERROR && w == 1 {
|
||||
error_offset(t, t.offset, "illegal UTF-8 encoding")
|
||||
} else if r == utf8.RUNE_BOM && t.offset > 0 {
|
||||
error_offset(t, t.offset, "illegal byte order mark")
|
||||
}
|
||||
}
|
||||
t.read_offset += w
|
||||
t.ch = r
|
||||
} else {
|
||||
t.offset = len(t.src)
|
||||
if t.ch == '\n' {
|
||||
t.at_bol = true
|
||||
t.line_offset = t.offset
|
||||
t.line_count += 1
|
||||
}
|
||||
t.ch = -1
|
||||
}
|
||||
}
|
||||
|
||||
advance_rune_n :: proc(t: ^Tokenizer, n: int) {
|
||||
for _ in 0..<n {
|
||||
advance_rune(t)
|
||||
}
|
||||
}
|
||||
|
||||
is_digit :: proc(r: rune) -> bool {
|
||||
return '0' <= r && r <= '9'
|
||||
}
|
||||
|
||||
skip_whitespace :: proc(t: ^Tokenizer) {
|
||||
for {
|
||||
switch t.ch {
|
||||
case ' ', '\t', '\r', '\v', '\f', '\n':
|
||||
t.has_space = true
|
||||
advance_rune(t)
|
||||
case:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scan_comment :: proc(t: ^Tokenizer) -> string {
|
||||
offset := t.offset-1
|
||||
next := -1
|
||||
general: {
|
||||
if t.ch == '/'{ // line comments
|
||||
advance_rune(t)
|
||||
for t.ch != '\n' && t.ch >= 0 {
|
||||
advance_rune(t)
|
||||
}
|
||||
|
||||
next = t.offset
|
||||
if t.ch == '\n' {
|
||||
next += 1
|
||||
}
|
||||
break general
|
||||
}
|
||||
|
||||
/* style comment */
|
||||
advance_rune(t)
|
||||
for t.ch >= 0 {
|
||||
ch := t.ch
|
||||
advance_rune(t)
|
||||
if ch == '*' && t.ch == '/' {
|
||||
advance_rune(t)
|
||||
next = t.offset
|
||||
break general
|
||||
}
|
||||
}
|
||||
|
||||
error_offset(t, offset, "comment not terminated")
|
||||
}
|
||||
|
||||
lit := t.src[offset : t.offset]
|
||||
|
||||
// NOTE(bill): Strip CR for line comments
|
||||
for len(lit) > 2 && lit[1] == '/' && lit[len(lit)-1] == '\r' {
|
||||
lit = lit[:len(lit)-1]
|
||||
}
|
||||
|
||||
|
||||
return string(lit)
|
||||
}
|
||||
|
||||
scan_identifier :: proc(t: ^Tokenizer) -> string {
|
||||
offset := t.offset
|
||||
|
||||
for is_ident1(t.ch) {
|
||||
advance_rune(t)
|
||||
}
|
||||
|
||||
return string(t.src[offset : t.offset])
|
||||
}
|
||||
|
||||
scan_string :: proc(t: ^Tokenizer) -> string {
|
||||
offset := t.offset-1
|
||||
|
||||
for {
|
||||
ch := t.ch
|
||||
if ch == '\n' || ch < 0 {
|
||||
error_offset(t, offset, "string literal was not terminated")
|
||||
break
|
||||
}
|
||||
advance_rune(t)
|
||||
if ch == '"' {
|
||||
break
|
||||
}
|
||||
if ch == '\\' {
|
||||
scan_escape(t)
|
||||
}
|
||||
}
|
||||
|
||||
return string(t.src[offset : t.offset])
|
||||
}
|
||||
|
||||
digit_val :: proc(r: rune) -> int {
|
||||
switch r {
|
||||
case '0'..='9':
|
||||
return int(r-'0')
|
||||
case 'A'..='F':
|
||||
return int(r-'A' + 10)
|
||||
case 'a'..='f':
|
||||
return int(r-'a' + 10)
|
||||
}
|
||||
return 16
|
||||
}
|
||||
|
||||
scan_escape :: proc(t: ^Tokenizer) -> bool {
|
||||
offset := t.offset
|
||||
|
||||
esc := t.ch
|
||||
n: int
|
||||
base, max: u32
|
||||
switch esc {
|
||||
case 'a', 'b', 'e', 'f', 'n', 't', 'v', 'r', '\\', '\'', '"':
|
||||
advance_rune(t)
|
||||
return true
|
||||
|
||||
case '0'..='7':
|
||||
for digit_val(t.ch) < 8 {
|
||||
advance_rune(t)
|
||||
}
|
||||
return true
|
||||
case 'x':
|
||||
advance_rune(t)
|
||||
for digit_val(t.ch) < 16 {
|
||||
advance_rune(t)
|
||||
}
|
||||
return true
|
||||
case 'u':
|
||||
advance_rune(t)
|
||||
n, base, max = 4, 16, utf8.MAX_RUNE
|
||||
case 'U':
|
||||
advance_rune(t)
|
||||
n, base, max = 8, 16, utf8.MAX_RUNE
|
||||
case:
|
||||
if t.ch < 0 {
|
||||
error_offset(t, offset, "escape sequence was not terminated")
|
||||
} else {
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
x: u32
|
||||
main_loop: for n > 0 {
|
||||
d := u32(digit_val(t.ch))
|
||||
if d >= base {
|
||||
if t.ch == '"' || t.ch == '\'' {
|
||||
break main_loop
|
||||
}
|
||||
if t.ch < 0 {
|
||||
error_offset(t, t.offset, "escape sequence was not terminated")
|
||||
} else {
|
||||
error_offset(t, t.offset, "illegal character '%r' : %d in escape sequence", t.ch, t.ch)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
x = x*base + d
|
||||
advance_rune(t)
|
||||
n -= 1
|
||||
}
|
||||
|
||||
if x > max || 0xd800 <= x && x <= 0xdfff {
|
||||
error_offset(t, offset, "escape sequence is an invalid Unicode code point")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
scan_rune :: proc(t: ^Tokenizer) -> string {
|
||||
offset := t.offset-1
|
||||
valid := true
|
||||
n := 0
|
||||
for {
|
||||
ch := t.ch
|
||||
if ch == '\n' || ch < 0 {
|
||||
if valid {
|
||||
error_offset(t, offset, "rune literal not terminated")
|
||||
valid = false
|
||||
}
|
||||
break
|
||||
}
|
||||
advance_rune(t)
|
||||
if ch == '\'' {
|
||||
break
|
||||
}
|
||||
n += 1
|
||||
if ch == '\\' {
|
||||
if !scan_escape(t) {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if valid && n != 1 {
|
||||
error_offset(t, offset, "illegal rune literal")
|
||||
}
|
||||
|
||||
return string(t.src[offset : t.offset])
|
||||
}
|
||||
|
||||
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
|
||||
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
|
||||
for digit_val(t.ch) < base {
|
||||
advance_rune(t)
|
||||
}
|
||||
}
|
||||
scan_exponent :: proc(t: ^Tokenizer) {
|
||||
if t.ch == 'e' || t.ch == 'E' || t.ch == 'p' || t.ch == 'P' {
|
||||
advance_rune(t)
|
||||
if t.ch == '-' || t.ch == '+' {
|
||||
advance_rune(t)
|
||||
}
|
||||
if digit_val(t.ch) < 10 {
|
||||
scan_mantissa(t, 10)
|
||||
} else {
|
||||
error_offset(t, t.offset, "illegal floating-point exponent")
|
||||
}
|
||||
}
|
||||
}
|
||||
scan_fraction :: proc(t: ^Tokenizer) -> (early_exit: bool) {
|
||||
if t.ch == '.' && peek(t) == '.' {
|
||||
return true
|
||||
}
|
||||
if t.ch == '.' {
|
||||
advance_rune(t)
|
||||
scan_mantissa(t, 10)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
check_end := true
|
||||
|
||||
|
||||
offset := t.offset
|
||||
seen_point := seen_decimal_point
|
||||
|
||||
if seen_point {
|
||||
offset -= 1
|
||||
scan_mantissa(t, 10)
|
||||
scan_exponent(t)
|
||||
} else {
|
||||
if t.ch == '0' {
|
||||
int_base :: proc(t: ^Tokenizer, base: int, msg: string) {
|
||||
prev := t.offset
|
||||
advance_rune(t)
|
||||
scan_mantissa(t, base)
|
||||
if t.offset - prev <= 1 {
|
||||
error_offset(t, t.offset, msg)
|
||||
}
|
||||
}
|
||||
|
||||
advance_rune(t)
|
||||
switch t.ch {
|
||||
case 'b', 'B':
|
||||
int_base(t, 2, "illegal binary integer")
|
||||
case 'x', 'X':
|
||||
int_base(t, 16, "illegal hexadecimal integer")
|
||||
case:
|
||||
seen_point = false
|
||||
scan_mantissa(t, 10)
|
||||
if t.ch == '.' {
|
||||
seen_point = true
|
||||
if scan_fraction(t) {
|
||||
check_end = false
|
||||
}
|
||||
}
|
||||
if check_end {
|
||||
scan_exponent(t)
|
||||
check_end = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if check_end {
|
||||
scan_mantissa(t, 10)
|
||||
|
||||
if !scan_fraction(t) {
|
||||
scan_exponent(t)
|
||||
}
|
||||
}
|
||||
|
||||
return .Number, string(t.src[offset : t.offset])
|
||||
}
|
||||
|
||||
scan_punct :: proc(t: ^Tokenizer, ch: rune) -> (kind: Token_Kind) {
|
||||
kind = .Punct
|
||||
switch ch {
|
||||
case:
|
||||
kind = .Invalid
|
||||
|
||||
case '<', '>':
|
||||
if t.ch == ch {
|
||||
advance_rune(t)
|
||||
}
|
||||
if t.ch == '=' {
|
||||
advance_rune(t)
|
||||
}
|
||||
case '!', '+', '-', '*', '/', '%', '^', '=':
|
||||
if t.ch == '=' {
|
||||
advance_rune(t)
|
||||
}
|
||||
case '#':
|
||||
if t.ch == '#' {
|
||||
advance_rune(t)
|
||||
}
|
||||
case '&':
|
||||
if t.ch == '=' || t.ch == '&' {
|
||||
advance_rune(t)
|
||||
}
|
||||
case '|':
|
||||
if t.ch == '=' || t.ch == '|' {
|
||||
advance_rune(t)
|
||||
}
|
||||
case '(', ')', '[', ']', '{', '}':
|
||||
// okay
|
||||
case '~', ',', ':', ';', '?':
|
||||
// okay
|
||||
case '`':
|
||||
// okay
|
||||
case '.':
|
||||
if t.ch == '.' && peek(t) == '.' {
|
||||
advance_rune(t)
|
||||
advance_rune(t) // consume last '.'
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
peek :: proc(t: ^Tokenizer) -> byte {
|
||||
if t.read_offset < len(t.src) {
|
||||
return t.src[t.read_offset]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
peek_str :: proc(t: ^Tokenizer, str: string) -> bool {
|
||||
if t.read_offset < len(t.src) {
|
||||
return strings.has_prefix(string(t.src[t.offset:]), str)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
scan_literal_prefix :: proc(t: ^Tokenizer, str: string, prefix: ^string) -> bool {
|
||||
if peek_str(t, str) {
|
||||
offset := t.offset
|
||||
for _ in str {
|
||||
advance_rune(t)
|
||||
}
|
||||
prefix^ = string(t.src[offset:][:len(str)-1])
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
allow_next_to_be_newline :: proc(t: ^Tokenizer) -> bool {
|
||||
if t.ch == '\n' {
|
||||
advance_rune(t)
|
||||
return true
|
||||
} else if t.ch == '\r' && peek(t) == '\n' { // allow for MS-DOS style line endings
|
||||
advance_rune(t) // \r
|
||||
advance_rune(t) // \n
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
scan :: proc(t: ^Tokenizer, f: ^File) -> ^Token {
|
||||
skip_whitespace(t)
|
||||
|
||||
offset := t.offset
|
||||
|
||||
kind: Token_Kind
|
||||
lit: string
|
||||
prefix: string
|
||||
|
||||
switch ch := t.ch; {
|
||||
case scan_literal_prefix(t, `u8"`, &prefix):
|
||||
kind = .String
|
||||
lit = scan_string(t)
|
||||
case scan_literal_prefix(t, `u"`, &prefix):
|
||||
kind = .String
|
||||
lit = scan_string(t)
|
||||
case scan_literal_prefix(t, `L"`, &prefix):
|
||||
kind = .String
|
||||
lit = scan_string(t)
|
||||
case scan_literal_prefix(t, `U"`, &prefix):
|
||||
kind = .String
|
||||
lit = scan_string(t)
|
||||
case scan_literal_prefix(t, `u'`, &prefix):
|
||||
kind = .Char
|
||||
lit = scan_rune(t)
|
||||
case scan_literal_prefix(t, `L'`, &prefix):
|
||||
kind = .Char
|
||||
lit = scan_rune(t)
|
||||
case scan_literal_prefix(t, `U'`, &prefix):
|
||||
kind = .Char
|
||||
lit = scan_rune(t)
|
||||
|
||||
case is_ident0(ch):
|
||||
lit = scan_identifier(t)
|
||||
kind = .Ident
|
||||
case '0' <= ch && ch <= '9':
|
||||
kind, lit = scan_number(t, false)
|
||||
case:
|
||||
advance_rune(t)
|
||||
switch ch {
|
||||
case -1:
|
||||
kind = .EOF
|
||||
case '\\':
|
||||
kind = .Punct
|
||||
if allow_next_to_be_newline(t) {
|
||||
t.at_bol = true
|
||||
t.has_space = false
|
||||
return scan(t, f)
|
||||
}
|
||||
|
||||
case '.':
|
||||
if is_digit(t.ch) {
|
||||
kind, lit = scan_number(t, true)
|
||||
} else {
|
||||
kind = scan_punct(t, ch)
|
||||
}
|
||||
case '"':
|
||||
kind = .String
|
||||
lit = scan_string(t)
|
||||
case '\'':
|
||||
kind = .Char
|
||||
lit = scan_rune(t)
|
||||
case '/':
|
||||
if t.ch == '/' || t.ch == '*' {
|
||||
kind = .Comment
|
||||
lit = scan_comment(t)
|
||||
t.has_space = true
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case:
|
||||
kind = scan_punct(t, ch)
|
||||
if kind == .Invalid && ch != utf8.RUNE_BOM {
|
||||
error_offset(t, t.offset, "illegal character '%r': %d", ch, ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if lit == "" {
|
||||
lit = string(t.src[offset : t.offset])
|
||||
}
|
||||
|
||||
if kind == .Comment {
|
||||
return scan(t, f)
|
||||
}
|
||||
|
||||
tok := new(Token)
|
||||
tok.kind = kind
|
||||
tok.lit = lit
|
||||
tok.pos = offset_to_pos(t, offset)
|
||||
tok.file = f
|
||||
tok.prefix = prefix
|
||||
tok.at_bol = t.at_bol
|
||||
tok.has_space = t.has_space
|
||||
|
||||
t.at_bol, t.has_space = false, false
|
||||
|
||||
return tok
|
||||
}
|
||||
|
||||
tokenize :: proc(t: ^Tokenizer, f: ^File) -> ^Token {
|
||||
setup_tokenizer: {
|
||||
t.src = f.src
|
||||
t.ch = ' '
|
||||
t.offset = 0
|
||||
t.read_offset = 0
|
||||
t.line_offset = 0
|
||||
t.line_count = len(t.src) > 0 ? 1 : 0
|
||||
t.error_count = 0
|
||||
t.path = f.name
|
||||
|
||||
|
||||
advance_rune(t)
|
||||
if t.ch == utf8.RUNE_BOM {
|
||||
advance_rune(t)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
t.at_bol = true
|
||||
t.has_space = false
|
||||
|
||||
head: Token
|
||||
curr := &head
|
||||
for {
|
||||
tok := scan(t, f)
|
||||
if tok == nil {
|
||||
break
|
||||
}
|
||||
curr.next = tok
|
||||
curr = curr.next
|
||||
if tok.kind == .EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return head.next
|
||||
}
|
||||
|
||||
add_new_file :: proc(t: ^Tokenizer, name: string, src: []byte, id: int) -> ^File {
|
||||
file := new(File)
|
||||
file.id = id
|
||||
file.src = src
|
||||
file.name = name
|
||||
file.display_name = name
|
||||
return file
|
||||
}
|
||||
|
||||
tokenize_file :: proc(t: ^Tokenizer, path: string, id: int, loc := #caller_location) -> ^Token {
|
||||
src, ok := os.read_entire_file(path)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return tokenize(t, add_new_file(t, path, src, id))
|
||||
}
|
||||
|
||||
|
||||
inline_tokenize :: proc(t: ^Tokenizer, tok: ^Token, src: []byte) -> ^Token {
|
||||
file := new(File)
|
||||
file.src = src
|
||||
if tok.file != nil {
|
||||
file.id = tok.file.id
|
||||
file.name = tok.file.name
|
||||
file.display_name = tok.file.name
|
||||
}
|
||||
|
||||
return tokenize(t, file)
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package c_frontend_tokenizer
|
||||
|
||||
|
||||
in_range :: proc(range: []rune, c: rune) -> bool #no_bounds_check {
|
||||
for i := 0; range[i] != -1; i += 2 {
|
||||
if range[i] <= c && c <= range[i+1] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// [https://www.sigbus.info/n1570#D] C11 allows ASCII and some multibyte characters in certan Unicode ranges to be used in an identifier.
|
||||
//
|
||||
// is_ident0 returns true if a given character is acceptable as the first character of an identifier.
|
||||
is_ident0 :: proc(c: rune) -> bool {
|
||||
return in_range(_range_ident0, c)
|
||||
}
|
||||
// is_ident0 returns true if a given character is acceptable as a non-first character of an identifier.
|
||||
is_ident1 :: proc(c: rune) -> bool {
|
||||
return is_ident0(c) || in_range(_range_ident1, c)
|
||||
}
|
||||
|
||||
// Returns the number of columns needed to display a given character in a fixed-width font.
|
||||
// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
char_width :: proc(c: rune) -> int {
|
||||
switch {
|
||||
case in_range(_range_width0, c):
|
||||
return 0
|
||||
case in_range(_range_width2, c):
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
display_width :: proc(str: string) -> (w: int) {
|
||||
for c in str {
|
||||
w += char_width(c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
_range_ident0 := []rune{
|
||||
'_', '_', 'a', 'z', 'A', 'Z', '$', '$',
|
||||
0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,
|
||||
0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,
|
||||
0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,
|
||||
0x1681, 0x180D, 0x180F, 0x1DBF, 0x1E00, 0x1FFF, 0x200B, 0x200D,
|
||||
0x202A, 0x202E, 0x203F, 0x2040, 0x2054, 0x2054, 0x2060, 0x206F,
|
||||
0x2070, 0x20CF, 0x2100, 0x218F, 0x2460, 0x24FF, 0x2776, 0x2793,
|
||||
0x2C00, 0x2DFF, 0x2E80, 0x2FFF, 0x3004, 0x3007, 0x3021, 0x302F,
|
||||
0x3031, 0x303F, 0x3040, 0xD7FF, 0xF900, 0xFD3D, 0xFD40, 0xFDCF,
|
||||
0xFDF0, 0xFE1F, 0xFE30, 0xFE44, 0xFE47, 0xFFFD,
|
||||
0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD,
|
||||
0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD,
|
||||
0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD,
|
||||
0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD,
|
||||
-1,
|
||||
}
|
||||
|
||||
_range_ident1 := []rune{
|
||||
'0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F,
|
||||
-1,
|
||||
}
|
||||
|
||||
|
||||
_range_width0 := []rune{
|
||||
0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486,
|
||||
0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2,
|
||||
0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615,
|
||||
0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8,
|
||||
0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A,
|
||||
0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C,
|
||||
0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963,
|
||||
0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD,
|
||||
0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42,
|
||||
0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82,
|
||||
0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD,
|
||||
0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F,
|
||||
0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82,
|
||||
0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48,
|
||||
0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF,
|
||||
0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43,
|
||||
0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6,
|
||||
0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1,
|
||||
0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19,
|
||||
0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E,
|
||||
0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC,
|
||||
0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037,
|
||||
0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F,
|
||||
0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773,
|
||||
0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3,
|
||||
0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922,
|
||||
0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18,
|
||||
0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C,
|
||||
0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF,
|
||||
0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F,
|
||||
0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806,
|
||||
0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F,
|
||||
0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03,
|
||||
0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F,
|
||||
0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,
|
||||
0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,
|
||||
-1,
|
||||
}
|
||||
|
||||
_range_width2 := []rune{
|
||||
0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,
|
||||
0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19,
|
||||
0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,
|
||||
0x20000, 0x2FFFD, 0x30000, 0x3FFFD,
|
||||
-1,
|
||||
}
|
||||
@@ -13,6 +13,7 @@ Example:
|
||||
package main
|
||||
|
||||
import "core:bytes"
|
||||
import "core:compress/zlib"
|
||||
import "core:fmt"
|
||||
|
||||
main :: proc() {
|
||||
@@ -36,7 +37,7 @@ Example:
|
||||
buf: bytes.Buffer
|
||||
|
||||
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
|
||||
err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
|
||||
err := zlib.inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
|
||||
defer bytes.buffer_destroy(&buf)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -21,12 +21,14 @@ Symbols :: struct {
|
||||
main :: proc() {
|
||||
sym: Symbols
|
||||
|
||||
LIB_PATH :: "lib." + dynlib.LIBRARY_FILE_EXTENSION
|
||||
|
||||
// Load symbols from `lib.dll` into Symbols struct.
|
||||
// Each struct field is prefixed with `foo_` before lookup in the DLL's symbol table.
|
||||
// The library's Handle (to unload) will be stored in `sym._my_lib_handle`. This way you can load multiple DLLs in one struct.
|
||||
count, ok := dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_my_lib_handle")
|
||||
count, ok := dynlib.initialize_symbols(&sym, LIB_PATH, "foo_", "_my_lib_handle")
|
||||
defer dynlib.unload_library(sym._my_lib_handle)
|
||||
fmt.printf("(Initial DLL Load) ok: %v. %v symbols loaded from lib.dll (%p).\n", ok, count, sym._my_lib_handle)
|
||||
fmt.printf("(Initial DLL Load) ok: %v. %v symbols loaded from " + LIB_PATH + " (%p).\n", ok, count, sym._my_lib_handle)
|
||||
|
||||
if count > 0 {
|
||||
fmt.println("42 + 42 =", sym.add(42, 42))
|
||||
@@ -34,12 +36,12 @@ main :: proc() {
|
||||
fmt.println("hellope =", sym.hellope^)
|
||||
}
|
||||
|
||||
count, ok = dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_my_lib_handle")
|
||||
fmt.printf("(DLL Reload) ok: %v. %v symbols loaded from lib.dll (%p).\n", ok, count, sym._my_lib_handle)
|
||||
count, ok = dynlib.initialize_symbols(&sym, LIB_PATH, "foo_", "_my_lib_handle")
|
||||
fmt.printf("(DLL Reload) ok: %v. %v symbols loaded from " + LIB_PATH + " (%p).\n", ok, count, sym._my_lib_handle)
|
||||
|
||||
if count > 0 {
|
||||
fmt.println("42 + 42 =", sym.add(42, 42))
|
||||
fmt.println("84 - 13 =", sym.sub(84, 13))
|
||||
fmt.println("hellope =", sym.hellope^)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-16
@@ -12,6 +12,11 @@ A handle to a dynamically loaded library.
|
||||
*/
|
||||
Library :: distinct rawptr
|
||||
|
||||
/*
|
||||
The file extension for dynamic libraries on the target OS.
|
||||
*/
|
||||
LIBRARY_FILE_EXTENSION :: _LIBRARY_FILE_EXTENSION
|
||||
|
||||
/*
|
||||
Loads a dynamic library from the filesystem. The paramater `global_symbols` makes the symbols in the loaded
|
||||
library available to resolve references in subsequently loaded libraries.
|
||||
@@ -123,31 +128,36 @@ initialize_symbols :: proc(
|
||||
) -> (count: int = -1, ok: bool = false) where intrinsics.type_is_struct(T) {
|
||||
assert(symbol_table != nil)
|
||||
|
||||
handle := load_library(library_path) or_return
|
||||
// First, (re)load the library.
|
||||
handle: Library
|
||||
for field in reflect.struct_fields_zipped(T) {
|
||||
if field.name == handle_field_name {
|
||||
field_ptr := rawptr(uintptr(symbol_table) + field.offset)
|
||||
|
||||
// We appear to be hot reloading. Unload previous incarnation of the library.
|
||||
if old_handle := (^Library)(field_ptr)^; old_handle != nil {
|
||||
unload_library(old_handle) or_return
|
||||
}
|
||||
|
||||
handle = load_library(library_path) or_return
|
||||
(^Library)(field_ptr)^ = handle
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer to concatenate the prefix + symbol name.
|
||||
prefixed_symbol_buf: [2048]u8 = ---
|
||||
|
||||
count = 0
|
||||
for field in reflect.struct_fields_zipped(T) {
|
||||
// If we're not the library handle, the field needs to be a pointer type, be it a procedure pointer or an exported global.
|
||||
if field.name == handle_field_name || !(reflect.is_procedure(field.type) || reflect.is_pointer(field.type)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Calculate address of struct member
|
||||
field_ptr := rawptr(uintptr(symbol_table) + field.offset)
|
||||
|
||||
// If we've come across the struct member for the handle, store it and continue scanning for other symbols.
|
||||
if field.name == handle_field_name {
|
||||
// We appear to be hot reloading. Unload previous incarnation of the library.
|
||||
if old_handle := (^Library)(field_ptr)^; old_handle != nil {
|
||||
unload_library(old_handle) or_return
|
||||
}
|
||||
(^Library)(field_ptr)^ = handle
|
||||
continue
|
||||
}
|
||||
|
||||
// We're not the library handle, so the field needs to be a pointer type, be it a procedure pointer or an exported global.
|
||||
if !(reflect.is_procedure(field.type) || reflect.is_pointer(field.type)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Let's look up or construct the symbol name to find in the library
|
||||
prefixed_name: string
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ package dynlib
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
_LIBRARY_FILE_EXTENSION :: ""
|
||||
|
||||
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import "base:runtime"
|
||||
import "core:strings"
|
||||
import "core:sys/posix"
|
||||
|
||||
_LIBRARY_FILE_EXTENSION :: "dylib" when ODIN_OS == .Darwin else "so"
|
||||
|
||||
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
||||
flags := posix.RTLD_Flags{.NOW}
|
||||
if global_symbols {
|
||||
|
||||
@@ -8,6 +8,8 @@ import win32 "core:sys/windows"
|
||||
import "core:strings"
|
||||
import "core:reflect"
|
||||
|
||||
_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)
|
||||
|
||||
@@ -117,7 +117,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
||||
layer.name = read_name(r) or_return
|
||||
layer.components = read_value(r, u8) or_return
|
||||
type := read_value(r, Layer_Data_Type) or_return
|
||||
if type > max(type) {
|
||||
if type > max(Layer_Data_Type) {
|
||||
if r.print_error {
|
||||
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is %d\n",
|
||||
r.filename, u8(type), u8(max(Layer_Data_Type)))
|
||||
|
||||
@@ -192,12 +192,6 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
|
||||
case runtime.Type_Info_Simd_Vector:
|
||||
return .Unsupported_Type
|
||||
|
||||
case runtime.Type_Info_Relative_Pointer:
|
||||
return .Unsupported_Type
|
||||
|
||||
case runtime.Type_Info_Relative_Multi_Pointer:
|
||||
return .Unsupported_Type
|
||||
|
||||
case runtime.Type_Info_Matrix:
|
||||
return .Unsupported_Type
|
||||
|
||||
@@ -259,6 +259,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
skip_digits(t)
|
||||
}
|
||||
if t.r == 'e' || t.r == 'E' {
|
||||
token.kind = .Float
|
||||
switch r := next_rune(t); r {
|
||||
case '+', '-':
|
||||
next_rune(t)
|
||||
@@ -485,7 +486,7 @@ is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
|
||||
case '"':
|
||||
// okay
|
||||
case '\'':
|
||||
if spec != .JSON {
|
||||
if spec == .JSON {
|
||||
return false
|
||||
}
|
||||
// okay
|
||||
|
||||
@@ -172,20 +172,33 @@ assign_float :: proc(val: any, f: $T) -> bool {
|
||||
|
||||
|
||||
@(private)
|
||||
unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> bool {
|
||||
unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> (ok: bool, err: Error) {
|
||||
val := val
|
||||
switch &dst in val {
|
||||
case string:
|
||||
dst = str
|
||||
return true
|
||||
return true, nil
|
||||
case cstring:
|
||||
if str == "" {
|
||||
dst = strings.clone_to_cstring("", p.allocator)
|
||||
a_err: runtime.Allocator_Error
|
||||
dst, a_err = strings.clone_to_cstring("", p.allocator)
|
||||
#partial switch a_err {
|
||||
case nil:
|
||||
// okay
|
||||
case .Out_Of_Memory:
|
||||
err = .Out_Of_Memory
|
||||
case:
|
||||
err = .Invalid_Allocator
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// NOTE: This is valid because 'clone_string' appends a NUL terminator
|
||||
dst = cstring(raw_data(str))
|
||||
}
|
||||
return true
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
#partial switch variant in ti.variant {
|
||||
@@ -193,31 +206,37 @@ unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.T
|
||||
for name, i in variant.names {
|
||||
if name == str {
|
||||
assign_int(val, variant.values[i])
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
// TODO(bill): should this be an error or not?
|
||||
return true
|
||||
return true, nil
|
||||
|
||||
case reflect.Type_Info_Integer:
|
||||
i := strconv.parse_i128(str) or_return
|
||||
i, pok := strconv.parse_i128(str)
|
||||
if !pok {
|
||||
return false, nil
|
||||
}
|
||||
if assign_int(val, i) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
if assign_float(val, i) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
case reflect.Type_Info_Float:
|
||||
f := strconv.parse_f64(str) or_return
|
||||
f, pok := strconv.parse_f64(str)
|
||||
if !pok {
|
||||
return false, nil
|
||||
}
|
||||
if assign_int(val, f) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
if assign_float(val, f) {
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +323,7 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
||||
case .Ident:
|
||||
advance_token(p)
|
||||
if p.spec == .MJSON {
|
||||
if unmarshal_string_token(p, any{v.data, ti.id}, token.text, ti) {
|
||||
if unmarshal_string_token(p, any{v.data, ti.id}, token.text, ti) or_return {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -314,7 +333,7 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
||||
advance_token(p)
|
||||
str := unquote_string(token, p.spec, p.allocator) or_return
|
||||
dest := any{v.data, ti.id}
|
||||
if !unmarshal_string_token(p, dest, str, ti) {
|
||||
if !(unmarshal_string_token(p, dest, str, ti) or_return) {
|
||||
delete(str, p.allocator)
|
||||
return UNSUPPORTED_TYPE
|
||||
}
|
||||
@@ -398,15 +417,15 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
if .raw_union in t.flags {
|
||||
return UNSUPPORTED_TYPE
|
||||
}
|
||||
|
||||
|
||||
fields := reflect.struct_fields_zipped(ti.id)
|
||||
|
||||
struct_loop: for p.curr_token.kind != end_token {
|
||||
key, _ := parse_object_key(p, p.allocator)
|
||||
key := parse_object_key(p, p.allocator) or_return
|
||||
defer delete(key, p.allocator)
|
||||
|
||||
unmarshal_expect_token(p, .Colon)
|
||||
|
||||
fields := reflect.struct_fields_zipped(ti.id)
|
||||
|
||||
field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool {
|
||||
prev_set := field_used[offset/8] & byte(offset&7) != 0
|
||||
field_used[offset/8] |= byte(offset&7)
|
||||
|
||||
@@ -3002,18 +3002,6 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
fmt_bit_set(fi, v, verb = verb)
|
||||
|
||||
case runtime.Type_Info_Relative_Pointer:
|
||||
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id)
|
||||
absolute_ptr := any{ptr, info.pointer.id}
|
||||
|
||||
fmt_value(fi, absolute_ptr, verb)
|
||||
|
||||
case runtime.Type_Info_Relative_Multi_Pointer:
|
||||
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id)
|
||||
absolute_ptr := any{ptr, info.pointer.id}
|
||||
|
||||
fmt_value(fi, absolute_ptr, verb)
|
||||
|
||||
case runtime.Type_Info_Matrix:
|
||||
fmt_matrix(fi, v, verb, info)
|
||||
|
||||
|
||||
@@ -37,30 +37,30 @@ File_Console_Logger_Data :: struct {
|
||||
ident: string,
|
||||
}
|
||||
|
||||
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger {
|
||||
data := new(File_Console_Logger_Data)
|
||||
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
|
||||
data := new(File_Console_Logger_Data, allocator)
|
||||
data.file_handle = h
|
||||
data.ident = ident
|
||||
return Logger{file_console_logger_proc, data, lowest, opt}
|
||||
}
|
||||
|
||||
destroy_file_logger :: proc(log: Logger) {
|
||||
destroy_file_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
data := cast(^File_Console_Logger_Data)log.data
|
||||
if data.file_handle != os.INVALID_HANDLE {
|
||||
os.close(data.file_handle)
|
||||
}
|
||||
free(data)
|
||||
free(data, allocator)
|
||||
}
|
||||
|
||||
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "") -> Logger {
|
||||
data := new(File_Console_Logger_Data)
|
||||
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
|
||||
data := new(File_Console_Logger_Data, allocator)
|
||||
data.file_handle = os.INVALID_HANDLE
|
||||
data.ident = ident
|
||||
return Logger{file_console_logger_proc, data, lowest, opt}
|
||||
}
|
||||
|
||||
destroy_console_logger :: proc(log: Logger) {
|
||||
free(log.data)
|
||||
destroy_console_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
free(log.data, allocator)
|
||||
}
|
||||
|
||||
file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
|
||||
@@ -5,17 +5,17 @@ Multi_Logger_Data :: struct {
|
||||
loggers: []Logger,
|
||||
}
|
||||
|
||||
create_multi_logger :: proc(logs: ..Logger) -> Logger {
|
||||
data := new(Multi_Logger_Data)
|
||||
data.loggers = make([]Logger, len(logs))
|
||||
create_multi_logger :: proc(logs: ..Logger, allocator := context.allocator) -> Logger {
|
||||
data := new(Multi_Logger_Data, allocator)
|
||||
data.loggers = make([]Logger, len(logs), allocator)
|
||||
copy(data.loggers, logs)
|
||||
return Logger{multi_logger_proc, data, Level.Debug, nil}
|
||||
}
|
||||
|
||||
destroy_multi_logger :: proc(log: Logger) {
|
||||
destroy_multi_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
data := (^Multi_Logger_Data)(log.data)
|
||||
delete(data.loggers)
|
||||
free(data)
|
||||
delete(data.loggers, allocator)
|
||||
free(data, allocator)
|
||||
}
|
||||
|
||||
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
||||
|
||||
@@ -53,15 +53,15 @@ vector_dot :: proc "contextless" (a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E)
|
||||
}
|
||||
@(require_results)
|
||||
quaternion64_dot :: proc "contextless" (a, b: $T/quaternion64) -> (c: f16) {
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
return a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
}
|
||||
@(require_results)
|
||||
quaternion128_dot :: proc "contextless" (a, b: $T/quaternion128) -> (c: f32) {
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
return a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
}
|
||||
@(require_results)
|
||||
quaternion256_dot :: proc "contextless" (a, b: $T/quaternion256) -> (c: f64) {
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
return a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
}
|
||||
|
||||
dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quaternion256_dot}
|
||||
@@ -167,6 +167,18 @@ vector_triple_product :: proc "contextless" (a, b, c: $T/[$N]$E) -> T where IS_N
|
||||
length :: proc{vector_length, quaternion_length}
|
||||
length2 :: proc{vector_length2, quaternion_length2}
|
||||
|
||||
|
||||
@(require_results)
|
||||
clamp_length :: proc "contextless" (v: $T/[$N]$E, a: E) -> T where IS_FLOAT(E) {
|
||||
if a <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
m2 := length2(v)
|
||||
return v if (m2 <= a*a) else (v / sqrt(m2) * a) // returns original when m2 is 0
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
projection :: proc "contextless" (x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
||||
return dot(x, normal) / dot(normal, normal) * normal
|
||||
|
||||
+1
-1
@@ -1271,7 +1271,7 @@ binomial :: proc "contextless" (n, k: int) -> int {
|
||||
}
|
||||
|
||||
b := n
|
||||
for i in 2..<k {
|
||||
for i in 2..=k {
|
||||
b = (b * (n+1-i))/i
|
||||
}
|
||||
return b
|
||||
|
||||
@@ -189,12 +189,12 @@ sincos_f64 :: proc "contextless" (x: f64) -> (sin, cos: f64) #no_bounds_check {
|
||||
// sin coefficients
|
||||
@(private="file")
|
||||
_sin := [?]f64{
|
||||
0h3de5d8fd1fd19ccd, // 1.58962301576546568060e-10
|
||||
0hbe5ae5e5a9291f5d, // -2.50507477628578072866e-8
|
||||
0h3ec71de3567d48a1, // 2.75573136213857245213e-6
|
||||
0hbf2a01a019bfdf03, // -1.98412698295895385996e-4
|
||||
0h3f8111111110f7d0, // 8.33333333332211858878e-3
|
||||
0hbfc5555555555548, // -1.66666666666666307295e-1
|
||||
0h3de5d8fd1fd19ccd, // 1.58962301576546568060e-10
|
||||
0hbe5ae5e5a9291f5d, // -2.50507477628578072866e-8
|
||||
0h3ec71de3567d48a1, // 2.75573136213857245213e-6
|
||||
0hbf2a01a019bfdf03, // -1.98412698295895385996e-4
|
||||
0h3f8111111110f7d0, // 8.33333333332211858878e-3
|
||||
0hbfc5555555555548, // -1.66666666666666307295e-1
|
||||
}
|
||||
|
||||
// cos coefficients
|
||||
|
||||
@@ -6,17 +6,13 @@ import "core:sys/posix"
|
||||
|
||||
// Define non-posix needed flags:
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
|
||||
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
|
||||
|
||||
MADV_FREE :: 5 /* pages unneeded, discard contents */
|
||||
MADV_FREE :: 5 /* pages unneeded, discard contents */
|
||||
} else when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
|
||||
MAP_ANONYMOUS :: 0x1000
|
||||
|
||||
MADV_FREE :: 6
|
||||
MADV_FREE :: 6
|
||||
}
|
||||
|
||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
flags := posix.Map_Flags{ .PRIVATE } + transmute(posix.Map_Flags)i32(MAP_ANONYMOUS)
|
||||
flags := posix.Map_Flags{ .ANONYMOUS, .PRIVATE }
|
||||
result := posix.mmap(nil, size, {}, flags)
|
||||
if result == posix.MAP_FAILED {
|
||||
return nil, .Out_Of_Memory
|
||||
|
||||
@@ -17,6 +17,9 @@ Build_Kind :: struct {
|
||||
arch: runtime.Odin_Arch_Types,
|
||||
}
|
||||
|
||||
// empty build kind acts as a marker for separating multiple lines with build tags
|
||||
BUILD_KIND_NEWLINE_MARKER :: Build_Kind{}
|
||||
|
||||
File_Tags :: struct {
|
||||
build_project_name: [][]string,
|
||||
build: []Build_Kind,
|
||||
@@ -147,6 +150,11 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags
|
||||
append(build_project_names, build_project_name_strings[index_start:])
|
||||
}
|
||||
case "build":
|
||||
|
||||
if len(build_kinds) > 0 {
|
||||
append(build_kinds, BUILD_KIND_NEWLINE_MARKER)
|
||||
}
|
||||
|
||||
kinds_loop: for {
|
||||
os_positive: runtime.Odin_OS_Types
|
||||
os_negative: runtime.Odin_OS_Types
|
||||
@@ -248,10 +256,20 @@ match_build_tags :: proc(file_tags: File_Tags, target: Build_Target) -> bool {
|
||||
project_name_correct ||= group_correct
|
||||
}
|
||||
|
||||
os_and_arch_correct := len(file_tags.build) == 0
|
||||
os_and_arch_correct := true
|
||||
|
||||
for kind in file_tags.build {
|
||||
os_and_arch_correct ||= target.os in kind.os && target.arch in kind.arch
|
||||
if len(file_tags.build) > 0 {
|
||||
os_and_arch_correct_line := false
|
||||
|
||||
for kind in file_tags.build {
|
||||
if kind == BUILD_KIND_NEWLINE_MARKER {
|
||||
os_and_arch_correct &&= os_and_arch_correct_line
|
||||
os_and_arch_correct_line = false
|
||||
} else {
|
||||
os_and_arch_correct_line ||= target.os in kind.os && target.arch in kind.arch
|
||||
}
|
||||
}
|
||||
os_and_arch_correct &&= os_and_arch_correct_line
|
||||
}
|
||||
|
||||
return !file_tags.ignore && project_name_correct && os_and_arch_correct
|
||||
|
||||
@@ -1,584 +0,0 @@
|
||||
package os
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
@(require_results)
|
||||
is_path_separator :: proc(c: byte) -> bool {
|
||||
return c == '/' || c == '\\'
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) {
|
||||
if len(path) == 0 {
|
||||
return INVALID_HANDLE, General_Error.Not_Exist
|
||||
}
|
||||
|
||||
access: u32
|
||||
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
||||
case O_RDONLY: access = win32.FILE_GENERIC_READ
|
||||
case O_WRONLY: access = win32.FILE_GENERIC_WRITE
|
||||
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE
|
||||
}
|
||||
|
||||
if mode&O_CREATE != 0 {
|
||||
access |= win32.FILE_GENERIC_WRITE
|
||||
}
|
||||
if mode&O_APPEND != 0 {
|
||||
access &~= win32.FILE_GENERIC_WRITE
|
||||
access |= win32.FILE_APPEND_DATA
|
||||
}
|
||||
|
||||
share_mode := win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE
|
||||
sa: ^win32.SECURITY_ATTRIBUTES = nil
|
||||
sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true}
|
||||
if mode&O_CLOEXEC == 0 {
|
||||
sa = &sa_inherit
|
||||
}
|
||||
|
||||
create_mode: u32
|
||||
switch {
|
||||
case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
|
||||
create_mode = win32.CREATE_NEW
|
||||
case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
|
||||
create_mode = win32.CREATE_ALWAYS
|
||||
case mode&O_CREATE == O_CREATE:
|
||||
create_mode = win32.OPEN_ALWAYS
|
||||
case mode&O_TRUNC == O_TRUNC:
|
||||
create_mode = win32.TRUNCATE_EXISTING
|
||||
case:
|
||||
create_mode = win32.OPEN_EXISTING
|
||||
}
|
||||
wide_path := win32.utf8_to_wstring(path)
|
||||
handle := Handle(win32.CreateFileW(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS, nil))
|
||||
if handle != INVALID_HANDLE {
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
return INVALID_HANDLE, get_last_error()
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) -> Error {
|
||||
if !win32.CloseHandle(win32.HANDLE(fd)) {
|
||||
return get_last_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
flush :: proc(fd: Handle) -> (err: Error) {
|
||||
if !win32.FlushFileBuffers(win32.HANDLE(fd)) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
single_write_length: win32.DWORD
|
||||
total_write: i64
|
||||
length := i64(len(data))
|
||||
|
||||
for total_write < length {
|
||||
remaining := length - total_write
|
||||
to_write := win32.DWORD(min(i32(remaining), MAX_RW))
|
||||
|
||||
e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil)
|
||||
if single_write_length <= 0 || !e {
|
||||
return int(total_write), get_last_error()
|
||||
}
|
||||
total_write += i64(single_write_length)
|
||||
}
|
||||
return int(total_write), nil
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) {
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
BUF_SIZE :: 386
|
||||
buf16: [BUF_SIZE]u16
|
||||
buf8: [4*BUF_SIZE]u8
|
||||
|
||||
for n < len(b) && err == nil {
|
||||
min_read := max(len(b)/4, 1 if len(b) > 0 else 0)
|
||||
max_read := u32(min(BUF_SIZE, min_read))
|
||||
if max_read == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
single_read_length: u32
|
||||
ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
|
||||
if !ok {
|
||||
err = get_last_error()
|
||||
}
|
||||
|
||||
buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length])
|
||||
src := buf8[:buf8_len]
|
||||
|
||||
ctrl_z := false
|
||||
for i := 0; i < len(src) && n < len(b); i += 1 {
|
||||
x := src[i]
|
||||
if x == 0x1a { // ctrl-z
|
||||
ctrl_z = true
|
||||
break
|
||||
}
|
||||
b[n] = x
|
||||
n += 1
|
||||
}
|
||||
if ctrl_z || single_read_length < max_read {
|
||||
break
|
||||
}
|
||||
|
||||
// NOTE(bill): if the last two values were a newline, then it is expected that
|
||||
// this is the end of the input
|
||||
if n >= 2 && single_read_length == max_read && string(b[n-2:n]) == "\r\n" {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Error) {
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
handle := win32.HANDLE(fd)
|
||||
|
||||
m: u32
|
||||
is_console := win32.GetConsoleMode(handle, &m)
|
||||
length := len(data)
|
||||
|
||||
// NOTE(Jeroen): `length` can't be casted to win32.DWORD here because it'll overflow if > 4 GiB and return 0 if exactly that.
|
||||
to_read := min(i64(length), MAX_RW)
|
||||
|
||||
if is_console {
|
||||
total_read, err = read_console(handle, data[total_read:][:to_read])
|
||||
if err != nil {
|
||||
return total_read, err
|
||||
}
|
||||
} else {
|
||||
// NOTE(Jeroen): So we cast it here *after* we've ensured that `to_read` is at most MAX_RW (1 GiB)
|
||||
bytes_read: win32.DWORD
|
||||
if e := win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &bytes_read, nil); e {
|
||||
// Successful read can mean two things, including EOF, see:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file
|
||||
if bytes_read == 0 {
|
||||
return 0, .EOF
|
||||
} else {
|
||||
return int(bytes_read), nil
|
||||
}
|
||||
} else {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
}
|
||||
return total_read, nil
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
|
||||
w: u32
|
||||
switch whence {
|
||||
case 0: w = win32.FILE_BEGIN
|
||||
case 1: w = win32.FILE_CURRENT
|
||||
case 2: w = win32.FILE_END
|
||||
case:
|
||||
return 0, .Invalid_Whence
|
||||
}
|
||||
hi := i32(offset>>32)
|
||||
lo := i32(offset)
|
||||
ft := win32.GetFileType(win32.HANDLE(fd))
|
||||
if ft == win32.FILE_TYPE_PIPE {
|
||||
return 0, .File_Is_Pipe
|
||||
}
|
||||
|
||||
dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w)
|
||||
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
|
||||
err := get_last_error()
|
||||
return 0, err
|
||||
}
|
||||
return i64(hi)<<32 + i64(dw_ptr), nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
file_size :: proc(fd: Handle) -> (i64, Error) {
|
||||
length: win32.LARGE_INTEGER
|
||||
err: Error
|
||||
if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return i64(length), err
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
MAX_RW :: 1<<30
|
||||
|
||||
@(private)
|
||||
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
curr_off := seek(fd, 0, 1) or_return
|
||||
defer seek(fd, curr_off, 0)
|
||||
|
||||
buf := data
|
||||
if len(buf) > MAX_RW {
|
||||
buf = buf[:MAX_RW]
|
||||
}
|
||||
|
||||
o := win32.OVERLAPPED{
|
||||
OffsetHigh = u32(offset>>32),
|
||||
Offset = u32(offset),
|
||||
}
|
||||
|
||||
// TODO(bill): Determine the correct behaviour for consoles
|
||||
|
||||
h := win32.HANDLE(fd)
|
||||
done: win32.DWORD
|
||||
e: Error
|
||||
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
||||
e = get_last_error()
|
||||
done = 0
|
||||
}
|
||||
return int(done), e
|
||||
}
|
||||
@(private)
|
||||
pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
curr_off := seek(fd, 0, 1) or_return
|
||||
defer seek(fd, curr_off, 0)
|
||||
|
||||
buf := data
|
||||
if len(buf) > MAX_RW {
|
||||
buf = buf[:MAX_RW]
|
||||
}
|
||||
|
||||
o := win32.OVERLAPPED{
|
||||
OffsetHigh = u32(offset>>32),
|
||||
Offset = u32(offset),
|
||||
}
|
||||
|
||||
h := win32.HANDLE(fd)
|
||||
done: win32.DWORD
|
||||
e: Error
|
||||
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
||||
e = get_last_error()
|
||||
done = 0
|
||||
}
|
||||
return int(done), e
|
||||
}
|
||||
|
||||
/*
|
||||
read_at returns n: 0, err: 0 on EOF
|
||||
*/
|
||||
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
b, offset := data, offset
|
||||
for len(b) > 0 {
|
||||
m, e := pread(fd, b, offset)
|
||||
if e == ERROR_EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
if e != nil {
|
||||
err = e
|
||||
break
|
||||
}
|
||||
n += m
|
||||
b = b[m:]
|
||||
offset += i64(m)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
b, offset := data, offset
|
||||
for len(b) > 0 {
|
||||
m := pwrite(fd, b, offset) or_return
|
||||
n += m
|
||||
b = b[m:]
|
||||
offset += i64(m)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
stdin := get_std_handle(uint(win32.STD_INPUT_HANDLE))
|
||||
stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE))
|
||||
stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE))
|
||||
|
||||
|
||||
@(require_results)
|
||||
get_std_handle :: proc "contextless" (h: uint) -> Handle {
|
||||
fd := win32.GetStdHandle(win32.DWORD(h))
|
||||
return Handle(fd)
|
||||
}
|
||||
|
||||
|
||||
exists :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
return attribs != win32.INVALID_FILE_ATTRIBUTES
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_file :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
if attribs != win32.INVALID_FILE_ATTRIBUTES {
|
||||
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_dir :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
if attribs != win32.INVALID_FILE_ATTRIBUTES {
|
||||
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
|
||||
@private cwd_lock := win32.SRWLOCK{} // zero is initialized
|
||||
|
||||
@(require_results)
|
||||
get_current_directory :: proc(allocator := context.allocator) -> string {
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
|
||||
dir_buf_wstr, _ := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL.
|
||||
|
||||
sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr))
|
||||
assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL.
|
||||
|
||||
win32.ReleaseSRWLockExclusive(&cwd_lock)
|
||||
|
||||
return win32.utf16_to_utf8(dir_buf_wstr, allocator) or_else ""
|
||||
}
|
||||
|
||||
set_current_directory :: proc(path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wstr := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
if !win32.SetCurrentDirectoryW(wstr) {
|
||||
err = get_last_error()
|
||||
}
|
||||
|
||||
win32.ReleaseSRWLockExclusive(&cwd_lock)
|
||||
|
||||
return
|
||||
}
|
||||
change_directory :: set_current_directory
|
||||
|
||||
make_directory :: proc(path: string, mode: u32 = 0) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
// Mode is unused on Windows, but is needed on *nix
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.CreateDirectoryW(wpath, nil) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
remove_directory :: proc(path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.RemoveDirectoryW(wpath) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private, require_results)
|
||||
is_abs :: proc(path: string) -> bool {
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
return true
|
||||
}
|
||||
when ODIN_OS == .Windows {
|
||||
if len(path) > 2 {
|
||||
switch path[0] {
|
||||
case 'A'..='Z', 'a'..='z':
|
||||
return path[1] == ':' && is_path_separator(path[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
fix_long_path :: proc(path: string) -> string {
|
||||
if len(path) < 248 {
|
||||
return path
|
||||
}
|
||||
|
||||
if len(path) >= 2 && path[:2] == `\\` {
|
||||
return path
|
||||
}
|
||||
if !is_abs(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
prefix :: `\\?`
|
||||
|
||||
path_buf, _ := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator)
|
||||
copy(path_buf, prefix)
|
||||
n := len(path)
|
||||
r, w := 0, len(prefix)
|
||||
for r < n {
|
||||
switch {
|
||||
case is_path_separator(path[r]):
|
||||
r += 1
|
||||
case path[r] == '.' && (r+1 == n || is_path_separator(path[r+1])):
|
||||
r += 1
|
||||
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || is_path_separator(path[r+2])):
|
||||
return path
|
||||
case:
|
||||
path_buf[w] = '\\'
|
||||
w += 1
|
||||
for ; r < n && !is_path_separator(path[r]); r += 1 {
|
||||
path_buf[w] = path[r]
|
||||
w += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if w == len(`\\?\c:`) {
|
||||
path_buf[w] = '\\'
|
||||
w += 1
|
||||
}
|
||||
return string(path_buf[:w])
|
||||
}
|
||||
|
||||
|
||||
link :: proc(old_name, new_name: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
n := win32.utf8_to_wstring(fix_long_path(new_name))
|
||||
o := win32.utf8_to_wstring(fix_long_path(old_name))
|
||||
return Platform_Error(win32.CreateHardLinkW(n, o, nil))
|
||||
}
|
||||
|
||||
unlink :: proc(path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.DeleteFileW(wpath) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
rename :: proc(old_path, new_path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
from := win32.utf8_to_wstring(old_path, context.temp_allocator)
|
||||
to := win32.utf8_to_wstring(new_path, context.temp_allocator)
|
||||
|
||||
if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ftruncate :: proc(fd: Handle, length: i64) -> (err: Error) {
|
||||
curr_off := seek(fd, 0, 1) or_return
|
||||
defer seek(fd, curr_off, 0)
|
||||
_= seek(fd, length, 0) or_return
|
||||
ok := win32.SetEndOfFile(win32.HANDLE(fd))
|
||||
if !ok {
|
||||
return get_last_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
truncate :: proc(path: string, length: i64) -> (err: Error) {
|
||||
fd := open(path, O_WRONLY|O_CREATE, 0o666) or_return
|
||||
defer close(fd)
|
||||
return ftruncate(fd, length)
|
||||
}
|
||||
|
||||
|
||||
remove :: proc(name: string) -> Error {
|
||||
p := win32.utf8_to_wstring(fix_long_path(name))
|
||||
err, err1: win32.DWORD
|
||||
if !win32.DeleteFileW(p) {
|
||||
err = win32.GetLastError()
|
||||
}
|
||||
if err == 0 {
|
||||
return nil
|
||||
}
|
||||
if !win32.RemoveDirectoryW(p) {
|
||||
err1 = win32.GetLastError()
|
||||
}
|
||||
if err1 == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != err1 {
|
||||
a := win32.GetFileAttributesW(p)
|
||||
if a == ~u32(0) {
|
||||
err = win32.GetLastError()
|
||||
} else {
|
||||
if a & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
err = err1
|
||||
} else if a & win32.FILE_ATTRIBUTE_READONLY != 0 {
|
||||
if win32.SetFileAttributesW(p, a &~ win32.FILE_ATTRIBUTE_READONLY) {
|
||||
err = 0
|
||||
if !win32.DeleteFileW(p) {
|
||||
err = win32.GetLastError()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Platform_Error(err)
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
pipe :: proc() -> (r, w: Handle, err: Error) {
|
||||
sa: win32.SECURITY_ATTRIBUTES
|
||||
sa.nLength = size_of(win32.SECURITY_ATTRIBUTES)
|
||||
sa.bInheritHandle = true
|
||||
if !win32.CreatePipe((^win32.HANDLE)(&r), (^win32.HANDLE)(&w), &sa, 0) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
|
||||
@(require_results)
|
||||
_read_directory_iterator_create :: proc(f: ^File) -> (Read_Directory_Iterator, Error) {
|
||||
return {}, nil
|
||||
return {}, .Unsupported
|
||||
}
|
||||
|
||||
_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
|
||||
|
||||
@@ -16,28 +16,25 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
|
||||
}
|
||||
path := concatenate({base_path, `\`, win32_utf16_to_utf8(d.cFileName[:], temp_allocator()) or_else ""}, allocator) or_return
|
||||
|
||||
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
|
||||
defer win32.CloseHandle(handle)
|
||||
|
||||
fi.fullpath = path
|
||||
fi.name = basename(path)
|
||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
||||
|
||||
fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, d.dwReserved0)
|
||||
fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, handle, d.dwReserved0)
|
||||
|
||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||
|
||||
|
||||
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
|
||||
defer win32.CloseHandle(handle)
|
||||
|
||||
if file_id_info: win32.FILE_ID_INFO; handle != nil && win32.GetFileInformationByHandleEx(handle, .FileIdInfo, &file_id_info, size_of(file_id_info)) {
|
||||
#assert(size_of(fi.inode) == size_of(file_id_info.FileId))
|
||||
#assert(size_of(fi.inode) == 16)
|
||||
runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16)
|
||||
}
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,5 +134,6 @@ _read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
|
||||
return
|
||||
}
|
||||
file_info_delete(it.impl.prev_fi, file_allocator())
|
||||
delete(it.impl.path, file_allocator())
|
||||
win32.FindClose(it.impl.find_handle)
|
||||
}
|
||||
|
||||
@@ -200,22 +200,21 @@ _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: wi
|
||||
} else {
|
||||
mode |= 0o666
|
||||
}
|
||||
|
||||
is_sym := false
|
||||
if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
||||
is_sym = false
|
||||
} else {
|
||||
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
|
||||
}
|
||||
|
||||
if is_sym {
|
||||
type = .Symlink
|
||||
} else {
|
||||
if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
type = .Directory
|
||||
mode |= 0o111
|
||||
}
|
||||
if h != nil {
|
||||
type = file_type(h)
|
||||
}
|
||||
} else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
type = .Directory
|
||||
mode |= 0o111
|
||||
} else if h != nil {
|
||||
type = file_type(h)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -679,7 +679,7 @@ get_last_error_string :: proc() -> string {
|
||||
|
||||
|
||||
@(require_results)
|
||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (handle: Handle, err: Error) {
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (handle: Handle, err: Error) {
|
||||
isDir := is_dir_path(path)
|
||||
flags := flags
|
||||
if isDir {
|
||||
|
||||
+578
-3
@@ -4,15 +4,13 @@ package os
|
||||
import win32 "core:sys/windows"
|
||||
import "base:runtime"
|
||||
import "base:intrinsics"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
Handle :: distinct uintptr
|
||||
File_Time :: distinct u64
|
||||
|
||||
|
||||
INVALID_HANDLE :: ~Handle(0)
|
||||
|
||||
|
||||
|
||||
O_RDONLY :: 0x00000
|
||||
O_WRONLY :: 0x00001
|
||||
O_RDWR :: 0x00002
|
||||
@@ -278,3 +276,580 @@ is_windows_11 :: proc "contextless" () -> bool {
|
||||
osvi := get_windows_version_w()
|
||||
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_path_separator :: proc(c: byte) -> bool {
|
||||
return c == '/' || c == '\\'
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) {
|
||||
if len(path) == 0 {
|
||||
return INVALID_HANDLE, General_Error.Not_Exist
|
||||
}
|
||||
|
||||
access: u32
|
||||
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
|
||||
case O_RDONLY: access = win32.FILE_GENERIC_READ
|
||||
case O_WRONLY: access = win32.FILE_GENERIC_WRITE
|
||||
case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE
|
||||
}
|
||||
|
||||
if mode&O_CREATE != 0 {
|
||||
access |= win32.FILE_GENERIC_WRITE
|
||||
}
|
||||
if mode&O_APPEND != 0 {
|
||||
access &~= win32.FILE_GENERIC_WRITE
|
||||
access |= win32.FILE_APPEND_DATA
|
||||
}
|
||||
|
||||
share_mode := win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE
|
||||
sa: ^win32.SECURITY_ATTRIBUTES = nil
|
||||
sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true}
|
||||
if mode&O_CLOEXEC == 0 {
|
||||
sa = &sa_inherit
|
||||
}
|
||||
|
||||
create_mode: u32
|
||||
switch {
|
||||
case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
|
||||
create_mode = win32.CREATE_NEW
|
||||
case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
|
||||
create_mode = win32.CREATE_ALWAYS
|
||||
case mode&O_CREATE == O_CREATE:
|
||||
create_mode = win32.OPEN_ALWAYS
|
||||
case mode&O_TRUNC == O_TRUNC:
|
||||
create_mode = win32.TRUNCATE_EXISTING
|
||||
case:
|
||||
create_mode = win32.OPEN_EXISTING
|
||||
}
|
||||
wide_path := win32.utf8_to_wstring(path)
|
||||
handle := Handle(win32.CreateFileW(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS, nil))
|
||||
if handle != INVALID_HANDLE {
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
return INVALID_HANDLE, get_last_error()
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) -> Error {
|
||||
if !win32.CloseHandle(win32.HANDLE(fd)) {
|
||||
return get_last_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
flush :: proc(fd: Handle) -> (err: Error) {
|
||||
if !win32.FlushFileBuffers(win32.HANDLE(fd)) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
single_write_length: win32.DWORD
|
||||
total_write: i64
|
||||
length := i64(len(data))
|
||||
|
||||
for total_write < length {
|
||||
remaining := length - total_write
|
||||
to_write := win32.DWORD(min(i32(remaining), MAX_RW))
|
||||
|
||||
e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil)
|
||||
if single_write_length <= 0 || !e {
|
||||
return int(total_write), get_last_error()
|
||||
}
|
||||
total_write += i64(single_write_length)
|
||||
}
|
||||
return int(total_write), nil
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) {
|
||||
if len(b) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
BUF_SIZE :: 386
|
||||
buf16: [BUF_SIZE]u16
|
||||
buf8: [4*BUF_SIZE]u8
|
||||
|
||||
for n < len(b) && err == nil {
|
||||
min_read := max(len(b)/4, 1 if len(b) > 0 else 0)
|
||||
max_read := u32(min(BUF_SIZE, min_read))
|
||||
if max_read == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
single_read_length: u32
|
||||
ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
|
||||
if !ok {
|
||||
err = get_last_error()
|
||||
}
|
||||
|
||||
buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length])
|
||||
src := buf8[:buf8_len]
|
||||
|
||||
ctrl_z := false
|
||||
for i := 0; i < len(src) && n < len(b); i += 1 {
|
||||
x := src[i]
|
||||
if x == 0x1a { // ctrl-z
|
||||
ctrl_z = true
|
||||
break
|
||||
}
|
||||
b[n] = x
|
||||
n += 1
|
||||
}
|
||||
if ctrl_z || single_read_length < max_read {
|
||||
break
|
||||
}
|
||||
|
||||
// NOTE(bill): if the last two values were a newline, then it is expected that
|
||||
// this is the end of the input
|
||||
if n >= 2 && single_read_length == max_read && string(b[n-2:n]) == "\r\n" {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Error) {
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
handle := win32.HANDLE(fd)
|
||||
|
||||
m: u32
|
||||
is_console := win32.GetConsoleMode(handle, &m)
|
||||
length := len(data)
|
||||
|
||||
// NOTE(Jeroen): `length` can't be casted to win32.DWORD here because it'll overflow if > 4 GiB and return 0 if exactly that.
|
||||
to_read := min(i64(length), MAX_RW)
|
||||
|
||||
if is_console {
|
||||
total_read, err = read_console(handle, data[total_read:][:to_read])
|
||||
if err != nil {
|
||||
return total_read, err
|
||||
}
|
||||
} else {
|
||||
// NOTE(Jeroen): So we cast it here *after* we've ensured that `to_read` is at most MAX_RW (1 GiB)
|
||||
bytes_read: win32.DWORD
|
||||
if e := win32.ReadFile(handle, &data[total_read], win32.DWORD(to_read), &bytes_read, nil); e {
|
||||
// Successful read can mean two things, including EOF, see:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file
|
||||
if bytes_read == 0 {
|
||||
return 0, .EOF
|
||||
} else {
|
||||
return int(bytes_read), nil
|
||||
}
|
||||
} else {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
}
|
||||
return total_read, nil
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
|
||||
w: u32
|
||||
switch whence {
|
||||
case 0: w = win32.FILE_BEGIN
|
||||
case 1: w = win32.FILE_CURRENT
|
||||
case 2: w = win32.FILE_END
|
||||
case:
|
||||
return 0, .Invalid_Whence
|
||||
}
|
||||
hi := i32(offset>>32)
|
||||
lo := i32(offset)
|
||||
ft := win32.GetFileType(win32.HANDLE(fd))
|
||||
if ft == win32.FILE_TYPE_PIPE {
|
||||
return 0, .File_Is_Pipe
|
||||
}
|
||||
|
||||
dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w)
|
||||
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
|
||||
err := get_last_error()
|
||||
return 0, err
|
||||
}
|
||||
return i64(hi)<<32 + i64(dw_ptr), nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
file_size :: proc(fd: Handle) -> (i64, Error) {
|
||||
length: win32.LARGE_INTEGER
|
||||
err: Error
|
||||
if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return i64(length), err
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
MAX_RW :: 1<<30
|
||||
|
||||
@(private)
|
||||
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
curr_off := seek(fd, 0, 1) or_return
|
||||
defer seek(fd, curr_off, 0)
|
||||
|
||||
buf := data
|
||||
if len(buf) > MAX_RW {
|
||||
buf = buf[:MAX_RW]
|
||||
}
|
||||
|
||||
o := win32.OVERLAPPED{
|
||||
OffsetHigh = u32(offset>>32),
|
||||
Offset = u32(offset),
|
||||
}
|
||||
|
||||
// TODO(bill): Determine the correct behaviour for consoles
|
||||
|
||||
h := win32.HANDLE(fd)
|
||||
done: win32.DWORD
|
||||
e: Error
|
||||
if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
||||
e = get_last_error()
|
||||
done = 0
|
||||
}
|
||||
return int(done), e
|
||||
}
|
||||
@(private)
|
||||
pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
curr_off := seek(fd, 0, 1) or_return
|
||||
defer seek(fd, curr_off, 0)
|
||||
|
||||
buf := data
|
||||
if len(buf) > MAX_RW {
|
||||
buf = buf[:MAX_RW]
|
||||
}
|
||||
|
||||
o := win32.OVERLAPPED{
|
||||
OffsetHigh = u32(offset>>32),
|
||||
Offset = u32(offset),
|
||||
}
|
||||
|
||||
h := win32.HANDLE(fd)
|
||||
done: win32.DWORD
|
||||
e: Error
|
||||
if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
|
||||
e = get_last_error()
|
||||
done = 0
|
||||
}
|
||||
return int(done), e
|
||||
}
|
||||
|
||||
/*
|
||||
read_at returns n: 0, err: 0 on EOF
|
||||
*/
|
||||
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
b, offset := data, offset
|
||||
for len(b) > 0 {
|
||||
m, e := pread(fd, b, offset)
|
||||
if e == ERROR_EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
if e != nil {
|
||||
err = e
|
||||
break
|
||||
}
|
||||
n += m
|
||||
b = b[m:]
|
||||
offset += i64(m)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
b, offset := data, offset
|
||||
for len(b) > 0 {
|
||||
m := pwrite(fd, b, offset) or_return
|
||||
n += m
|
||||
b = b[m:]
|
||||
offset += i64(m)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
stdin := get_std_handle(uint(win32.STD_INPUT_HANDLE))
|
||||
stdout := get_std_handle(uint(win32.STD_OUTPUT_HANDLE))
|
||||
stderr := get_std_handle(uint(win32.STD_ERROR_HANDLE))
|
||||
|
||||
|
||||
@(require_results)
|
||||
get_std_handle :: proc "contextless" (h: uint) -> Handle {
|
||||
fd := win32.GetStdHandle(win32.DWORD(h))
|
||||
return Handle(fd)
|
||||
}
|
||||
|
||||
|
||||
exists :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
return attribs != win32.INVALID_FILE_ATTRIBUTES
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_file :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
if attribs != win32.INVALID_FILE_ATTRIBUTES {
|
||||
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_dir :: proc(path: string) -> bool {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
|
||||
if attribs != win32.INVALID_FILE_ATTRIBUTES {
|
||||
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
|
||||
@private cwd_lock := win32.SRWLOCK{} // zero is initialized
|
||||
|
||||
@(require_results)
|
||||
get_current_directory :: proc(allocator := context.allocator) -> string {
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
|
||||
sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
|
||||
dir_buf_wstr, _ := make([]u16, sz_utf16, context.temp_allocator) // the first time, it _includes_ the NUL.
|
||||
|
||||
sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr))
|
||||
assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL.
|
||||
|
||||
win32.ReleaseSRWLockExclusive(&cwd_lock)
|
||||
|
||||
return win32.utf16_to_utf8(dir_buf_wstr, allocator) or_else ""
|
||||
}
|
||||
|
||||
set_current_directory :: proc(path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wstr := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
if !win32.SetCurrentDirectoryW(wstr) {
|
||||
err = get_last_error()
|
||||
}
|
||||
|
||||
win32.ReleaseSRWLockExclusive(&cwd_lock)
|
||||
|
||||
return
|
||||
}
|
||||
change_directory :: set_current_directory
|
||||
|
||||
make_directory :: proc(path: string, mode: u32 = 0) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
// Mode is unused on Windows, but is needed on *nix
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.CreateDirectoryW(wpath, nil) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
remove_directory :: proc(path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.RemoveDirectoryW(wpath) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private, require_results)
|
||||
is_abs :: proc(path: string) -> bool {
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
return true
|
||||
}
|
||||
when ODIN_OS == .Windows {
|
||||
if len(path) > 2 {
|
||||
switch path[0] {
|
||||
case 'A'..='Z', 'a'..='z':
|
||||
return path[1] == ':' && is_path_separator(path[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
fix_long_path :: proc(path: string) -> string {
|
||||
if len(path) < 248 {
|
||||
return path
|
||||
}
|
||||
|
||||
if len(path) >= 2 && path[:2] == `\\` {
|
||||
return path
|
||||
}
|
||||
if !is_abs(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
prefix :: `\\?`
|
||||
|
||||
path_buf, _ := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator)
|
||||
copy(path_buf, prefix)
|
||||
n := len(path)
|
||||
r, w := 0, len(prefix)
|
||||
for r < n {
|
||||
switch {
|
||||
case is_path_separator(path[r]):
|
||||
r += 1
|
||||
case path[r] == '.' && (r+1 == n || is_path_separator(path[r+1])):
|
||||
r += 1
|
||||
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || is_path_separator(path[r+2])):
|
||||
return path
|
||||
case:
|
||||
path_buf[w] = '\\'
|
||||
w += 1
|
||||
for ; r < n && !is_path_separator(path[r]); r += 1 {
|
||||
path_buf[w] = path[r]
|
||||
w += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if w == len(`\\?\c:`) {
|
||||
path_buf[w] = '\\'
|
||||
w += 1
|
||||
}
|
||||
return string(path_buf[:w])
|
||||
}
|
||||
|
||||
|
||||
link :: proc(old_name, new_name: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
n := win32.utf8_to_wstring(fix_long_path(new_name))
|
||||
o := win32.utf8_to_wstring(fix_long_path(old_name))
|
||||
return Platform_Error(win32.CreateHardLinkW(n, o, nil))
|
||||
}
|
||||
|
||||
unlink :: proc(path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
wpath := win32.utf8_to_wstring(path, context.temp_allocator)
|
||||
|
||||
if !win32.DeleteFileW(wpath) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
rename :: proc(old_path, new_path: string) -> (err: Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
from := win32.utf8_to_wstring(old_path, context.temp_allocator)
|
||||
to := win32.utf8_to_wstring(new_path, context.temp_allocator)
|
||||
|
||||
if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ftruncate :: proc(fd: Handle, length: i64) -> (err: Error) {
|
||||
curr_off := seek(fd, 0, 1) or_return
|
||||
defer seek(fd, curr_off, 0)
|
||||
_= seek(fd, length, 0) or_return
|
||||
ok := win32.SetEndOfFile(win32.HANDLE(fd))
|
||||
if !ok {
|
||||
return get_last_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
truncate :: proc(path: string, length: i64) -> (err: Error) {
|
||||
fd := open(path, O_WRONLY|O_CREATE, 0o666) or_return
|
||||
defer close(fd)
|
||||
return ftruncate(fd, length)
|
||||
}
|
||||
|
||||
|
||||
remove :: proc(name: string) -> Error {
|
||||
p := win32.utf8_to_wstring(fix_long_path(name))
|
||||
err, err1: win32.DWORD
|
||||
if !win32.DeleteFileW(p) {
|
||||
err = win32.GetLastError()
|
||||
}
|
||||
if err == 0 {
|
||||
return nil
|
||||
}
|
||||
if !win32.RemoveDirectoryW(p) {
|
||||
err1 = win32.GetLastError()
|
||||
}
|
||||
if err1 == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != err1 {
|
||||
a := win32.GetFileAttributesW(p)
|
||||
if a == ~u32(0) {
|
||||
err = win32.GetLastError()
|
||||
} else {
|
||||
if a & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
err = err1
|
||||
} else if a & win32.FILE_ATTRIBUTE_READONLY != 0 {
|
||||
if win32.SetFileAttributesW(p, a &~ win32.FILE_ATTRIBUTE_READONLY) {
|
||||
err = 0
|
||||
if !win32.DeleteFileW(p) {
|
||||
err = win32.GetLastError()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Platform_Error(err)
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
pipe :: proc() -> (r, w: Handle, err: Error) {
|
||||
sa: win32.SECURITY_ATTRIBUTES
|
||||
sa.nLength = size_of(win32.SECURITY_ATTRIBUTES)
|
||||
sa.bInheritHandle = true
|
||||
if !win32.CreatePipe((^win32.HANDLE)(&r), (^win32.HANDLE)(&w), &sa, 0) {
|
||||
err = get_last_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
+48
-54
@@ -31,8 +31,6 @@ Type_Info_Enum :: runtime.Type_Info_Enum
|
||||
Type_Info_Map :: runtime.Type_Info_Map
|
||||
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
||||
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
|
||||
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
|
||||
Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer
|
||||
Type_Info_Matrix :: runtime.Type_Info_Matrix
|
||||
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
||||
Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field
|
||||
@@ -67,8 +65,6 @@ Type_Kind :: enum {
|
||||
Map,
|
||||
Bit_Set,
|
||||
Simd_Vector,
|
||||
Relative_Pointer,
|
||||
Relative_Multi_Pointer,
|
||||
Matrix,
|
||||
Soa_Pointer,
|
||||
Bit_Field,
|
||||
@@ -80,35 +76,33 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
ti := type_info_of(T)
|
||||
if ti != nil {
|
||||
switch _ in ti.variant {
|
||||
case Type_Info_Named: return .Named
|
||||
case Type_Info_Integer: return .Integer
|
||||
case Type_Info_Rune: return .Rune
|
||||
case Type_Info_Float: return .Float
|
||||
case Type_Info_Complex: return .Complex
|
||||
case Type_Info_Quaternion: return .Quaternion
|
||||
case Type_Info_String: return .String
|
||||
case Type_Info_Boolean: return .Boolean
|
||||
case Type_Info_Any: return .Any
|
||||
case Type_Info_Type_Id: return .Type_Id
|
||||
case Type_Info_Pointer: return .Pointer
|
||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||
case Type_Info_Procedure: return .Procedure
|
||||
case Type_Info_Array: return .Array
|
||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||
case Type_Info_Slice: return .Slice
|
||||
case Type_Info_Parameters: return .Tuple
|
||||
case Type_Info_Struct: return .Struct
|
||||
case Type_Info_Union: return .Union
|
||||
case Type_Info_Enum: return .Enum
|
||||
case Type_Info_Map: return .Map
|
||||
case Type_Info_Bit_Set: return .Bit_Set
|
||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||
case Type_Info_Relative_Pointer: return .Relative_Pointer
|
||||
case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer
|
||||
case Type_Info_Matrix: return .Matrix
|
||||
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||
case Type_Info_Bit_Field: return .Bit_Field
|
||||
case Type_Info_Named: return .Named
|
||||
case Type_Info_Integer: return .Integer
|
||||
case Type_Info_Rune: return .Rune
|
||||
case Type_Info_Float: return .Float
|
||||
case Type_Info_Complex: return .Complex
|
||||
case Type_Info_Quaternion: return .Quaternion
|
||||
case Type_Info_String: return .String
|
||||
case Type_Info_Boolean: return .Boolean
|
||||
case Type_Info_Any: return .Any
|
||||
case Type_Info_Type_Id: return .Type_Id
|
||||
case Type_Info_Pointer: return .Pointer
|
||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||
case Type_Info_Procedure: return .Procedure
|
||||
case Type_Info_Array: return .Array
|
||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||
case Type_Info_Slice: return .Slice
|
||||
case Type_Info_Parameters: return .Tuple
|
||||
case Type_Info_Struct: return .Struct
|
||||
case Type_Info_Union: return .Union
|
||||
case Type_Info_Enum: return .Enum
|
||||
case Type_Info_Map: return .Map
|
||||
case Type_Info_Bit_Set: return .Bit_Set
|
||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||
case Type_Info_Matrix: return .Matrix
|
||||
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||
case Type_Info_Bit_Field: return .Bit_Field
|
||||
}
|
||||
|
||||
}
|
||||
@@ -723,6 +717,27 @@ enum_name_from_value_any :: proc(value: any) -> (name: string, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Returns whether the value given has a defined name in the enum type.
|
||||
*/
|
||||
@(require_results)
|
||||
enum_value_has_name :: proc(value: $T) -> bool where intrinsics.type_is_enum(T) {
|
||||
when len(T) == cap(T) {
|
||||
return value >= min(T) && value <= max(T)
|
||||
} else {
|
||||
if value < min(T) || value > max(T) {
|
||||
return false
|
||||
}
|
||||
|
||||
for valid_value in T {
|
||||
if valid_value == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1467,21 +1482,6 @@ as_string :: proc(a: any) -> (value: string, valid: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
||||
if a == nil { return nil }
|
||||
a := a
|
||||
ti := runtime.type_info_core(type_info_of(a.id))
|
||||
a.id = ti.id
|
||||
|
||||
#partial switch info in ti.variant {
|
||||
case Type_Info_Relative_Pointer:
|
||||
return relative_pointer_to_absolute_raw(a.data, info.base_integer.id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
||||
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
||||
@@ -1543,10 +1543,6 @@ as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||
case cstring: value = rawptr(v)
|
||||
case: valid = false
|
||||
}
|
||||
|
||||
case Type_Info_Relative_Pointer:
|
||||
valid = true
|
||||
value = relative_pointer_to_absolute_raw(a.data, info.base_integer.id)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -1656,8 +1652,6 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
Type_Info_Bit_Set,
|
||||
Type_Info_Enum,
|
||||
Type_Info_Simd_Vector,
|
||||
Type_Info_Relative_Pointer,
|
||||
Type_Info_Relative_Multi_Pointer,
|
||||
Type_Info_Soa_Pointer,
|
||||
Type_Info_Matrix:
|
||||
return runtime.memory_compare(a.data, b.data, t.size) == 0
|
||||
|
||||
@@ -158,14 +158,6 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
case Type_Info_Simd_Vector:
|
||||
y := b.variant.(Type_Info_Simd_Vector) or_return
|
||||
return x.count == y.count && x.elem == y.elem
|
||||
|
||||
case Type_Info_Relative_Pointer:
|
||||
y := b.variant.(Type_Info_Relative_Pointer) or_return
|
||||
return x.base_integer == y.base_integer && x.pointer == y.pointer
|
||||
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
y := b.variant.(Type_Info_Relative_Multi_Pointer) or_return
|
||||
return x.base_integer == y.base_integer && x.pointer == y.pointer
|
||||
|
||||
case Type_Info_Matrix:
|
||||
y := b.variant.(Type_Info_Matrix) or_return
|
||||
@@ -392,18 +384,6 @@ is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_relative_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Multi_Pointer)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
@@ -736,18 +716,6 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
|
||||
io.write_i64(w, i64(info.count), 10, &n) or_return
|
||||
io.write_byte(w, ']', &n) or_return
|
||||
write_type(w, info.elem, &n) or_return
|
||||
|
||||
case Type_Info_Relative_Pointer:
|
||||
io.write_string(w, "#relative(", &n) or_return
|
||||
write_type(w, info.base_integer, &n) or_return
|
||||
io.write_string(w, ") ", &n) or_return
|
||||
write_type(w, info.pointer, &n) or_return
|
||||
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
io.write_string(w, "#relative(", &n) or_return
|
||||
write_type(w, info.base_integer, &n) or_return
|
||||
io.write_string(w, ") ", &n) or_return
|
||||
write_type(w, info.pointer, &n) or_return
|
||||
|
||||
case Type_Info_Matrix:
|
||||
if info.layout == .Row_Major {
|
||||
|
||||
@@ -471,6 +471,12 @@ is_empty :: proc(a: $T/[]$E) -> bool {
|
||||
return len(a) == 0
|
||||
}
|
||||
|
||||
// Gets the byte size of the backing data
|
||||
@(require_results)
|
||||
size :: proc "contextless" (a: $T/[]$E) -> int {
|
||||
return len(a) * size_of(E)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
|
||||
@@ -1872,7 +1872,8 @@ index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) {
|
||||
lowest_index := len(s)
|
||||
found := false
|
||||
for substr in substrs {
|
||||
if i := index(s, substr); i >= 0 {
|
||||
haystack := s[:min(len(s), lowest_index + len(substr))]
|
||||
if i := index(haystack, substr); i >= 0 {
|
||||
if i < lowest_index {
|
||||
lowest_index = i
|
||||
width = len(substr)
|
||||
|
||||
@@ -12,8 +12,8 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||
return s != 0
|
||||
_ = intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
||||
return s != 0
|
||||
return s != 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||
if s >= 1 {
|
||||
return
|
||||
}
|
||||
}
|
||||
_ = intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +38,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
when !intrinsics.has_target_feature("atomics") {
|
||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||
} else {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
||||
if s >= 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
_ = intrinsics.wasm_memory_atomic_notify32((^u32)(f), max(u32))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,16 @@ Application_setMainMenu :: proc "c" (self: ^Application, menu: ^Menu) {
|
||||
msgSend(nil, self, "setMainMenu:", menu)
|
||||
}
|
||||
|
||||
@(objc_type=Application, objc_name="mainWindow")
|
||||
Application_mainWindow :: proc "c" (self: ^Application) -> ^Window {
|
||||
return msgSend(^Window, self, "mainWindow")
|
||||
}
|
||||
|
||||
@(objc_type=Application, objc_name="keyWindow")
|
||||
Application_keyWindow :: proc "c" (self: ^Application) -> ^Window {
|
||||
return msgSend(^Window, self, "keyWindow")
|
||||
}
|
||||
|
||||
@(objc_type=Application, objc_name="windows")
|
||||
Application_windows :: proc "c" (self: ^Application) -> ^Array {
|
||||
return msgSend(^Array, self, "windows")
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package objc_Foundation
|
||||
|
||||
@(objc_class="NSObjectProtocol")
|
||||
ObjectProtocol :: struct {using _: Object}
|
||||
// TODO: implement NSObjectProtocol
|
||||
@@ -0,0 +1,203 @@
|
||||
package objc_Foundation
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
import "core:c"
|
||||
|
||||
@(objc_class="NSProcessInfo")
|
||||
ProcessInfo :: struct {using _: Object}
|
||||
|
||||
// Getting the Process Information Agent
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="processInfo", objc_is_class_method=true)
|
||||
ProcessInfo_processInfo :: proc "c" () -> ^ProcessInfo {
|
||||
return msgSend(^ProcessInfo, ProcessInfo, "processInfo")
|
||||
}
|
||||
|
||||
// Accessing Process Information
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="arguments")
|
||||
ProcessInfo_arguments :: proc "c" (self: ^ProcessInfo) -> ^Array {
|
||||
return msgSend(^Array, self, "arguments")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="environment")
|
||||
ProcessInfo_environment :: proc "c" (self: ^ProcessInfo) -> ^Dictionary {
|
||||
return msgSend(^Dictionary, self, "environment")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="globallyUniqueString")
|
||||
ProcessInfo_globallyUniqueString :: proc "c" (self: ^ProcessInfo) -> ^String {
|
||||
return msgSend(^String, self, "globallyUniqueString")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="isMacCatalystApp")
|
||||
ProcessInfo_isMacCatalystApp :: proc "c" (self: ^ProcessInfo) -> bool {
|
||||
return msgSend(bool, self, "isMacCatalystApp")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="isiOSAppOnMac")
|
||||
ProcessInfo_isiOSAppOnMac :: proc "c" (self: ^ProcessInfo) -> bool {
|
||||
return msgSend(bool, self, "isiOSAppOnMac")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="processIdentifier")
|
||||
ProcessInfo_processIdentifier :: proc "c" (self: ^ProcessInfo) -> c.int {
|
||||
return msgSend(c.int, self, "processIdentifier")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="processName")
|
||||
ProcessInfo_processName :: proc "c" (self: ^ProcessInfo) -> ^String {
|
||||
return msgSend(^String, self, "processName")
|
||||
}
|
||||
|
||||
// Accessing User Information
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="userName")
|
||||
ProcessInfo_userName :: proc "c" (self: ^ProcessInfo) -> ^String {
|
||||
return msgSend(^String, self, "userName")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="fullUserName")
|
||||
ProcessInfo_fullUserName :: proc "c" (self: ^ProcessInfo) -> ^String {
|
||||
return msgSend(^String, self, "fullUserName")
|
||||
}
|
||||
|
||||
// Sudden Application Termination
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="disableSuddenTermination")
|
||||
ProcessInfo_disableSuddenTermination :: proc "c" (self: ^ProcessInfo) {
|
||||
msgSend(nil, self, "disableSuddenTermination")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="enableSuddenTermination")
|
||||
ProcessInfo_enableSuddenTermination :: proc "c" (self: ^ProcessInfo) {
|
||||
msgSend(nil, self, "enableSuddenTermination")
|
||||
}
|
||||
|
||||
// Controlling Automatic Termination
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="disableAutomaticTermination")
|
||||
ProcessInfo_disableAutomaticTermination :: proc "c" (self: ^ProcessInfo, reason: ^String) {
|
||||
msgSend(nil, self, "disableAutomaticTermination:", reason)
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="enableAutomaticTermination")
|
||||
ProcessInfo_enableAutomaticTermination :: proc "c" (self: ^ProcessInfo, reason: ^String) {
|
||||
msgSend(nil, self, "enableAutomaticTermination:", reason)
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="automaticTerminationSupportEnabled")
|
||||
ProcessInfo_automaticTerminationSupportEnabled :: proc "c" (self: ^ProcessInfo) -> bool {
|
||||
return msgSend(bool, self, "automaticTerminationSupportEnabled")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="setAutomaticTerminationSupportEnabled")
|
||||
ProcessInfo_setAutomaticTerminationSupportEnabled :: proc "c" (self: ^ProcessInfo, automaticTerminationSupportEnabled: bool) {
|
||||
msgSend(nil, self, "setAutomaticTerminationSupportEnabled:", automaticTerminationSupportEnabled)
|
||||
}
|
||||
|
||||
// Getting Host Information
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="hostName")
|
||||
ProcessInfo_hostName :: proc "c" (self: ^ProcessInfo) -> ^String {
|
||||
return msgSend(^String, self, "hostName")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="operatingSystemVersionString")
|
||||
ProcessInfo_operatingSystemVersionString :: proc "c" (self: ^ProcessInfo) -> ^String {
|
||||
return msgSend(^String, self, "operatingSystemVersionString")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="operatingSystemVersion")
|
||||
ProcessInfo_operatingSystemVersion :: proc "c" (self: ^ProcessInfo) -> OperatingSystemVersion {
|
||||
return msgSend(OperatingSystemVersion, self, "operatingSystemVersion")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="isOperatingSystemAtLeastVersion")
|
||||
ProcessInfo_isOperatingSystemAtLeastVersion :: proc "c" (self: ^ProcessInfo, version: OperatingSystemVersion) -> bool {
|
||||
return msgSend(bool, self, "isOperatingSystemAtLeastVersion:", version)
|
||||
}
|
||||
|
||||
// Getting Computer Information
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="processorCount")
|
||||
ProcessInfo_processorCount :: proc "c" (self: ^ProcessInfo) -> UInteger {
|
||||
return msgSend(UInteger, self, "processorCount")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="activeProcessorCount")
|
||||
ProcessInfo_activeProcessorCount :: proc "c" (self: ^ProcessInfo) -> UInteger {
|
||||
return msgSend(UInteger, self, "activeProcessorCount")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="physicalMemory")
|
||||
ProcessInfo_physicalMemory :: proc "c" (self: ^ProcessInfo) -> c.ulonglong {
|
||||
return msgSend(c.ulonglong, self, "physicalMemory")
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="systemUptime")
|
||||
ProcessInfo_systemUptime :: proc "c" (self: ^ProcessInfo) -> TimeInterval {
|
||||
return msgSend(TimeInterval, self, "systemUptime")
|
||||
}
|
||||
|
||||
// Managing Activities
|
||||
|
||||
@(private)
|
||||
log2 :: intrinsics.constant_log2
|
||||
|
||||
ActivityOptionsBits :: enum u64 {
|
||||
IdleDisplaySleepDisabled = log2(1099511627776), // Require the screen to stay powered on.
|
||||
IdleSystemSleepDisabled = log2(1048576), // Prevent idle sleep.
|
||||
SuddenTerminationDisabled = log2(16384), // Prevent sudden termination.
|
||||
AutomaticTerminationDisabled = log2(32768), // Prevent automatic termination.
|
||||
AnimationTrackingEnabled = log2(35184372088832), // Track activity with an animation signpost interval.
|
||||
TrackingEnabled = log2(70368744177664), // Track activity with a signpost interval.
|
||||
UserInitiated = log2(16777215), // Performing a user-requested action.
|
||||
UserInitiatedAllowingIdleSystemSleep = log2(15728639), // Performing a user-requested action, but the system can sleep on idle.
|
||||
Background = log2(255), // Initiated some kind of work, but not as the direct result of a user request.
|
||||
LatencyCritical = log2(1095216660480), // Requires the highest amount of timer and I/O precision available.
|
||||
UserInteractive = log2(1095233437695), // Responding to user interaction.
|
||||
}
|
||||
ActivityOptions :: bit_set[ActivityOptionsBits; u64]
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="beginActivityWithOptions")
|
||||
ProcessInfo_beginActivityWithOptions :: proc "c" (self: ^ProcessInfo, options: ActivityOptions, reason: ^String) -> ^ObjectProtocol {
|
||||
return msgSend(^ObjectProtocol, self, "beginActivityWithOptions:reason:", options, reason)
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="endActivity")
|
||||
ProcessInfo_endActivity :: proc "c" (self: ^ProcessInfo, activity: ^ObjectProtocol) {
|
||||
msgSend(nil, self, "endActivity:", activity)
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="performActivityWithOptions")
|
||||
ProcessInfo_performActivityWithOptions :: proc "c" (self: ^ProcessInfo, options: ActivityOptions, reason: ^String, block: proc "c" ()) {
|
||||
msgSend(nil, self, "performActivityWithOptions:reason:usingBlock:", options, reason, block)
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="performExpiringActivityWithReason")
|
||||
ProcessInfo_performExpiringActivityWithReason :: proc "c" (self: ^ProcessInfo, reason: ^String, block: proc "c" (expired: bool)) {
|
||||
msgSend(nil, self, "performExpiringActivityWithReason:usingBlock:", reason, block)
|
||||
}
|
||||
|
||||
// Getting the Thermal State
|
||||
|
||||
ProcessInfoThermalState :: enum c.long {
|
||||
Nominal,
|
||||
Fair,
|
||||
Serious,
|
||||
Critical,
|
||||
}
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="thermalState")
|
||||
ProcessInfo_thermalState :: proc "c" (self: ^ProcessInfo) -> ProcessInfoThermalState {
|
||||
return msgSend(ProcessInfoThermalState, self, "thermalState")
|
||||
}
|
||||
|
||||
// Determining Whether Low Power Mode is Enabled
|
||||
|
||||
@(objc_type=ProcessInfo, objc_name="isLowPowerModeEnabled")
|
||||
ProcessInfo_isLowPowerModeEnabled :: proc "c" (self: ^ProcessInfo) -> bool {
|
||||
return msgSend(bool, self, "isLowPowerModeEnabled")
|
||||
}
|
||||
@@ -20,7 +20,7 @@ BOOL :: bool // TODO(bill): should this be `distinct`?
|
||||
YES :: true
|
||||
NO :: false
|
||||
|
||||
OperatingSystemVersion :: struct #packed {
|
||||
OperatingSystemVersion :: struct #align(8) {
|
||||
majorVersion: Integer,
|
||||
minorVersion: Integer,
|
||||
patchVersion: Integer,
|
||||
@@ -58,4 +58,4 @@ when size_of(Float) == 8 {
|
||||
} else {
|
||||
_POINT_ENCODING :: "{NSPoint=ff}"
|
||||
_SIZE_ENCODING :: "{NSSize=ff}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
Laytan: ARM and RISC-V CPU feature detection.
|
||||
Laytan: ARM and RISC-V CPU feature detection, iOS/macOS platform overhaul.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,581 +1,101 @@
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "base:runtime"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:sys/unix"
|
||||
import NS "core:sys/darwin/Foundation"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .MacOS
|
||||
init_platform :: proc() {
|
||||
ws :: strings.write_string
|
||||
wi :: strings.write_int
|
||||
|
||||
// Start building display version
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_OSVERSION}
|
||||
build_buf: [12]u8
|
||||
version: NS.OperatingSystemVersion
|
||||
{
|
||||
NS.scoped_autoreleasepool()
|
||||
|
||||
ok := sys.sysctl(mib, &build_buf)
|
||||
if !ok {
|
||||
strings.write_string(&b, "macOS Unknown")
|
||||
os_version.as_string = strings.to_string(b)
|
||||
return
|
||||
info := NS.ProcessInfo.processInfo()
|
||||
version = info->operatingSystemVersion()
|
||||
mem := info->physicalMemory()
|
||||
|
||||
ram.total_ram = int(mem)
|
||||
}
|
||||
|
||||
build := string(cstring(&build_buf[0]))
|
||||
macos_version = {int(version.majorVersion), int(version.minorVersion), int(version.patchVersion)}
|
||||
|
||||
// Do we have an exact match?
|
||||
match: Darwin_Match
|
||||
rel, exact := macos_release_map[build]
|
||||
|
||||
if exact {
|
||||
match = .Exact
|
||||
when ODIN_PLATFORM_SUBTARGET == .iOS {
|
||||
os_version.platform = .iOS
|
||||
ws(&b, "iOS")
|
||||
} else {
|
||||
os_version.platform = .MacOS
|
||||
switch version.majorVersion {
|
||||
case 15: ws(&b, "macOS Sequoia")
|
||||
case 14: ws(&b, "macOS Sonoma")
|
||||
case 13: ws(&b, "macOS Ventura")
|
||||
case 12: ws(&b, "macOS Monterey")
|
||||
case 11: ws(&b, "macOS Big Sur")
|
||||
case 10:
|
||||
switch version.minorVersion {
|
||||
case 15: ws(&b, "macOS Catalina")
|
||||
case 14: ws(&b, "macOS Mojave")
|
||||
case 13: ws(&b, "macOS High Sierra")
|
||||
case 12: ws(&b, "macOS Sierra")
|
||||
case 11: ws(&b, "OS X El Capitan")
|
||||
case 10: ws(&b, "OS X Yosemite")
|
||||
case:
|
||||
// `ProcessInfo.operatingSystemVersion` is 10.10 and up.
|
||||
unreachable()
|
||||
}
|
||||
case:
|
||||
// New version not yet added here.
|
||||
assert(version.majorVersion > 15)
|
||||
ws(&b, "macOS Unknown")
|
||||
}
|
||||
}
|
||||
|
||||
ws(&b, " ")
|
||||
wi(&b, int(version.majorVersion))
|
||||
ws(&b, ".")
|
||||
wi(&b, int(version.minorVersion))
|
||||
ws(&b, ".")
|
||||
wi(&b, int(version.patchVersion))
|
||||
|
||||
{
|
||||
build_buf: [12]u8
|
||||
mib := []i32{unix.CTL_KERN, unix.KERN_OSVERSION}
|
||||
ok := unix.sysctl(mib, &build_buf)
|
||||
build := string(cstring(raw_data(build_buf[:]))) if ok else "Unknown"
|
||||
|
||||
ws(&b, " (build ")
|
||||
|
||||
build_start := len(b.buf)
|
||||
ws(&b, build)
|
||||
os_version.version = string(b.buf[build_start:][:len(build)])
|
||||
}
|
||||
|
||||
{
|
||||
// Match on XNU kernel version
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
version_bits: [12]u8 // enough for 999.999.999\x00
|
||||
have_kernel_version := sys.sysctl(mib, &version_bits)
|
||||
mib := []i32{unix.CTL_KERN, unix.KERN_OSRELEASE}
|
||||
ok := unix.sysctl(mib, &version_bits)
|
||||
kernel := string(cstring(raw_data(version_bits[:]))) if ok else "Unknown"
|
||||
|
||||
major_ok, minor_ok, patch_ok: bool
|
||||
major, _, tail := strings.partition(kernel, ".")
|
||||
minor, _, patch := strings.partition(tail, ".")
|
||||
|
||||
tmp := runtime.default_temp_allocator_temp_begin()
|
||||
os_version.major, _ = strconv.parse_int(major, 10)
|
||||
os_version.minor, _ = strconv.parse_int(minor, 10)
|
||||
os_version.patch, _ = strconv.parse_int(patch, 10)
|
||||
|
||||
triplet := strings.split(string(cstring(&version_bits[0])), ".", context.temp_allocator)
|
||||
if len(triplet) != 3 {
|
||||
have_kernel_version = false
|
||||
} else {
|
||||
rel.darwin.x, major_ok = strconv.parse_int(triplet[0])
|
||||
rel.darwin.y, minor_ok = strconv.parse_int(triplet[1])
|
||||
rel.darwin.z, patch_ok = strconv.parse_int(triplet[2])
|
||||
|
||||
if !(major_ok && minor_ok && patch_ok) {
|
||||
have_kernel_version = false
|
||||
}
|
||||
}
|
||||
|
||||
runtime.default_temp_allocator_temp_end(tmp)
|
||||
|
||||
if !have_kernel_version {
|
||||
// We don't know the kernel version, but we do know the build
|
||||
strings.write_string(&b, "macOS Unknown (build ")
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, build)
|
||||
os_version.version = strings.to_string(b)[l:]
|
||||
strings.write_rune(&b, ')')
|
||||
os_version.as_string = strings.to_string(b)
|
||||
return
|
||||
}
|
||||
rel, match = map_darwin_kernel_version_to_macos_release(build, rel.darwin)
|
||||
ws(&b, ", kernel ")
|
||||
ws(&b, kernel)
|
||||
ws(&b, ")")
|
||||
}
|
||||
|
||||
os_version.major = rel.darwin.x
|
||||
os_version.minor = rel.darwin.y
|
||||
os_version.patch = rel.darwin.z
|
||||
|
||||
macos_version = transmute(Version)rel.release.version
|
||||
|
||||
strings.write_string(&b, rel.os_name)
|
||||
if match == .Exact || match == .Nearest {
|
||||
strings.write_rune(&b, ' ')
|
||||
strings.write_string(&b, rel.release.name)
|
||||
strings.write_rune(&b, ' ')
|
||||
strings.write_int(&b, rel.release.version.x)
|
||||
if rel.release.version.y > 0 || rel.release.version.z > 0 {
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.release.version.y)
|
||||
}
|
||||
if rel.release.version.z > 0 {
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.release.version.z)
|
||||
}
|
||||
if match == .Nearest {
|
||||
strings.write_rune(&b, '?')
|
||||
}
|
||||
} else {
|
||||
strings.write_string(&b, " Unknown")
|
||||
}
|
||||
|
||||
strings.write_string(&b, " (build ")
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, build)
|
||||
os_version.version = strings.to_string(b)[l:]
|
||||
|
||||
strings.write_string(&b, ", kernel ")
|
||||
strings.write_int(&b, rel.darwin.x)
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.darwin.y)
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.darwin.z)
|
||||
strings.write_rune(&b, ')')
|
||||
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
|
||||
mib := []i32{sys.CTL_HW, sys.HW_MEMSIZE}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
Darwin_To_Release :: struct {
|
||||
darwin: [3]int, // Darwin kernel triplet
|
||||
os_name: string, // OS X, MacOS
|
||||
release: struct {
|
||||
name: string, // Monterey, Mojave, etc.
|
||||
version: [3]int, // 12.4, etc.
|
||||
},
|
||||
}
|
||||
|
||||
// Important: Order from lowest to highest kernel version
|
||||
@(private)
|
||||
macos_release_map: map[string]Darwin_To_Release = {
|
||||
// MacOS Tiger
|
||||
"8A428" = {{8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
"8A432" = {{8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
"8B15" = {{8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
"8B17" = {{8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
"8C46" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8C47" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E102" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E45" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E90" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8F46" = {{8, 3, 0}, "macOS", {"Tiger", {10, 4, 3}}},
|
||||
"8G32" = {{8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
"8G1165" = {{8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
"8H14" = {{8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
"8G1454" = {{8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
"8I127" = {{8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
"8I1119" = {{8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
"8J135" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8J2135a" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8K1079" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8N5107" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8L127" = {{8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
"8L2127" = {{8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
"8P135" = {{8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
"8P2137" = {{8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
"8R218" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8R2218" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8R2232" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8S165" = {{8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
"8S2167" = {{8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
|
||||
// MacOS Leopard
|
||||
"9A581" = {{9, 0, 0}, "macOS", {"Leopard", {10, 5, 0}}},
|
||||
"9B18" = {{9, 1, 0}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
"9B2117" = {{9, 1, 1}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
"9C31" = {{9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
"9C7010" = {{9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
"9D34" = {{9, 3, 0}, "macOS", {"Leopard", {10, 5, 3}}},
|
||||
"9E17" = {{9, 4, 0}, "macOS", {"Leopard", {10, 5, 4}}},
|
||||
"9F33" = {{9, 5, 0}, "macOS", {"Leopard", {10, 5, 5}}},
|
||||
"9G55" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9G66" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9G71" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9J61" = {{9, 7, 0}, "macOS", {"Leopard", {10, 5, 7}}},
|
||||
"9L30" = {{9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
"9L34" = {{9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
|
||||
// MacOS Snow Leopard
|
||||
"10A432" = {{10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
"10A433" = {{10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
"10B504" = {{10, 1, 0}, "macOS", {"Snow Leopard", {10, 6, 1}}},
|
||||
"10C540" = {{10, 2, 0}, "macOS", {"Snow Leopard", {10, 6, 2}}},
|
||||
"10D573" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10D575" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10D578" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10F569" = {{10, 4, 0}, "macOS", {"Snow Leopard", {10, 6, 4}}},
|
||||
"10H574" = {{10, 5, 0}, "macOS", {"Snow Leopard", {10, 6, 5}}},
|
||||
"10J567" = {{10, 6, 0}, "macOS", {"Snow Leopard", {10, 6, 6}}},
|
||||
"10J869" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10J3250" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10J4138" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10K540" = {{10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
"10K549" = {{10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
|
||||
// MacOS Lion
|
||||
"11A511" = {{11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A511s" = {{11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A2061" = {{11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A2063" = {{11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11B26" = {{11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
"11B2118" = {{11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
"11C74" = {{11, 2, 0}, "macOS", {"Lion", {10, 7, 2}}},
|
||||
"11D50" = {{11, 3, 0}, "macOS", {"Lion", {10, 7, 3}}},
|
||||
"11E53" = {{11, 4, 0}, "macOS", {"Lion", {10, 7, 4}}},
|
||||
"11G56" = {{11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
"11G63" = {{11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
|
||||
// MacOS Mountain Lion
|
||||
"12A269" = {{12, 0, 0}, "macOS", {"Mountain Lion", {10, 8, 0}}},
|
||||
"12B19" = {{12, 1, 0}, "macOS", {"Mountain Lion", {10, 8, 1}}},
|
||||
"12C54" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C60" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C2034" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C3104" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12D78" = {{12, 3, 0}, "macOS", {"Mountain Lion", {10, 8, 3}}},
|
||||
"12E55" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12E3067" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12E4022" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12F37" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F45" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2501" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2518" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2542" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2560" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
|
||||
// MacOS Mavericks
|
||||
"13A603" = {{13, 0, 0}, "macOS", {"Mavericks", {10, 9, 0}}},
|
||||
"13B42" = {{13, 0, 0}, "macOS", {"Mavericks", {10, 9, 1}}},
|
||||
"13C64" = {{13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
"13C1021" = {{13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
"13D65" = {{13, 2, 0}, "macOS", {"Mavericks", {10, 9, 3}}},
|
||||
"13E28" = {{13, 3, 0}, "macOS", {"Mavericks", {10, 9, 4}}},
|
||||
"13F34" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1066" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1077" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1096" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1112" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1134" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1507" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1603" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1712" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1808" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1911" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
|
||||
// MacOS Yosemite
|
||||
"14A389" = {{14, 0, 0}, "macOS", {"Yosemite", {10, 10, 0}}},
|
||||
"14B25" = {{14, 0, 0}, "macOS", {"Yosemite", {10, 10, 1}}},
|
||||
"14C109" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C1510" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C2043" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C1514" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C2513" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14D131" = {{14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
"14D136" = {{14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
"14E46" = {{14, 4, 0}, "macOS", {"Yosemite", {10, 10, 4}}},
|
||||
"14F27" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1021" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1505" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1509" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1605" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1713" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1808" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1909" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1912" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2009" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2109" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2315" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2411" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2511" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
|
||||
// MacOS El Capitan
|
||||
"15A284" = {{15, 0, 0}, "macOS", {"El Capitan", {10, 11, 0}}},
|
||||
"15B42" = {{15, 0, 0}, "macOS", {"El Capitan", {10, 11, 1}}},
|
||||
"15C50" = {{15, 2, 0}, "macOS", {"El Capitan", {10, 11, 2}}},
|
||||
"15D21" = {{15, 3, 0}, "macOS", {"El Capitan", {10, 11, 3}}},
|
||||
"15E65" = {{15, 4, 0}, "macOS", {"El Capitan", {10, 11, 4}}},
|
||||
"15F34" = {{15, 5, 0}, "macOS", {"El Capitan", {10, 11, 5}}},
|
||||
"15G31" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1004" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1011" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1108" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1212" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1217" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1421" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1510" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1611" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G17023" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G18013" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G19009" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G20015" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G21013" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G22010" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
|
||||
// MacOS Sierra
|
||||
"16A323" = {{16, 0, 0}, "macOS", {"Sierra", {10, 12, 0}}},
|
||||
"16B2555" = {{16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
"16B2657" = {{16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
"16C67" = {{16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
"16C68" = {{16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
"16D32" = {{16, 4, 0}, "macOS", {"Sierra", {10, 12, 3}}},
|
||||
"16E195" = {{16, 5, 0}, "macOS", {"Sierra", {10, 12, 4}}},
|
||||
"16F73" = {{16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
"16F2073" = {{16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
"16G29" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1036" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1114" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1212" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1314" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1408" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1510" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1618" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1710" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1815" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1917" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1918" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2016" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2127" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2128" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2136" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
|
||||
// MacOS High Sierra
|
||||
"17A365" = {{17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
"17A405" = {{17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
"17B48" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17B1002" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17B1003" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17C88" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C89" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C205" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C2205" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17D47" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D2047" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D102" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D2102" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17E199" = {{17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
"17E202" = {{17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
"17F77" = {{17, 6, 0}, "macOS", {"High Sierra", {10, 13, 5}}},
|
||||
"17G65" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G2208" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G2307" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G3025" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G4015" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G5019" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G6029" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G6030" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G7024" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8029" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8030" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8037" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G9016" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G10021" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G11023" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G12034" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G13033" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G13035" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14019" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14033" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14042" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
|
||||
// MacOS Mojave
|
||||
"18A391" = {{18, 0, 0}, "macOS", {"Mojave", {10, 14, 0}}},
|
||||
"18B75" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18B2107" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18B3094" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18C54" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 2}}},
|
||||
"18D42" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18D43" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18D109" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18E226" = {{18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
"18E227" = {{18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
"18F132" = {{18, 6, 0}, "macOS", {"Mojave", {10, 14, 5}}},
|
||||
"18G84" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G87" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G95" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G103" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G1012" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G2022" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G3020" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G4032" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G5033" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6020" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6032" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6042" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G7016" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G8012" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G8022" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9028" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9216" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9323" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
|
||||
// MacOS Catalina
|
||||
"19A583" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19A602" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19A603" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19B88" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 1}}},
|
||||
"19C57" = {{19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
"19C58" = {{19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
"19D76" = {{19, 3, 0}, "macOS", {"Catalina", {10, 15, 3}}},
|
||||
"19E266" = {{19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
"19E287" = {{19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
"19F96" = {{19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
"19F101" = {{19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
"19G73" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
"19G2021" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
"19H2" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H4" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H15" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H114" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H512" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H524" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1030" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1217" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1323" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1417" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1419" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1519" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1615" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1713" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1715" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1824" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1922" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H2026" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
|
||||
// MacOS Big Sur
|
||||
"20A2411" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 0}}},
|
||||
"20B29" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
"20B50" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
"20C69" = {{20, 2, 0}, "macOS", {"Big Sur", {11, 1, 0}}},
|
||||
"20D64" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 0}}},
|
||||
"20D74" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
"20D75" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
"20D80" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 2}}},
|
||||
"20D91" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 3}}},
|
||||
"20E232" = {{20, 4, 0}, "macOS", {"Big Sur", {11, 3, 0}}},
|
||||
"20E241" = {{20, 4, 0}, "macOS", {"Big Sur", {11, 3, 1}}},
|
||||
"20F71" = {{20, 5, 0}, "macOS", {"Big Sur", {11, 4, 0}}},
|
||||
"20G71" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 0}}},
|
||||
"20G80" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 1}}},
|
||||
"20G95" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 2}}},
|
||||
"20G165" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 0}}},
|
||||
"20G224" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 1}}},
|
||||
"20G314" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 2}}},
|
||||
"20G415" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 3}}},
|
||||
"20G417" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 4}}},
|
||||
"20G527" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 5}}},
|
||||
"20G624" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 6}}},
|
||||
"20G630" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 7}}},
|
||||
"20G730" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 8}}},
|
||||
"20G817" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 0}}},
|
||||
"20G918" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 1}}},
|
||||
"20G1020" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 2}}},
|
||||
"20G1116" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 3}}},
|
||||
"20G1120" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 4}}},
|
||||
"20G1225" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 5}}},
|
||||
"20G1231" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 6}}},
|
||||
"20G1345" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 7}}},
|
||||
"20G1351" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 8}}},
|
||||
"20G1426" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 9}}},
|
||||
"20G1427" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 7, 10}}},
|
||||
|
||||
// MacOS Monterey
|
||||
"21A344" = {{21, 0, 1}, "macOS", {"Monterey", {12, 0, 0}}},
|
||||
"21A559" = {{21, 1, 0}, "macOS", {"Monterey", {12, 0, 1}}},
|
||||
"21C52" = {{21, 2, 0}, "macOS", {"Monterey", {12, 1, 0}}},
|
||||
"21D49" = {{21, 3, 0}, "macOS", {"Monterey", {12, 2, 0}}},
|
||||
"21D62" = {{21, 3, 0}, "macOS", {"Monterey", {12, 2, 1}}},
|
||||
"21E230" = {{21, 4, 0}, "macOS", {"Monterey", {12, 3, 0}}},
|
||||
"21E258" = {{21, 4, 0}, "macOS", {"Monterey", {12, 3, 1}}},
|
||||
"21F79" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21F2081" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21F2092" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21G72" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
||||
"21G83" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
||||
"21G115" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 0}}},
|
||||
"21G217" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 1}}},
|
||||
"21G320" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 2}}},
|
||||
"21G419" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 3}}},
|
||||
"21G526" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 4}}},
|
||||
"21G531" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 5}}},
|
||||
"21G646" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 6}}},
|
||||
"21G651" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 7}}},
|
||||
"21G725" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 8}}},
|
||||
"21G726" = {{21, 6, 0}, "macOS", {"Monterey", {12, 6, 9}}},
|
||||
"21G816" = {{21, 6, 0}, "macOS", {"Monterey", {12, 7, 0}}},
|
||||
"21G920" = {{21, 6, 0}, "macOS", {"Monterey", {12, 7, 1}}},
|
||||
"21G1974" = {{21, 6, 0}, "macOS", {"Monterey", {12, 7, 2}}},
|
||||
|
||||
// MacOS Ventura
|
||||
"22A380" = {{22, 1, 0}, "macOS", {"Ventura", {13, 0, 0}}},
|
||||
"22A400" = {{22, 1, 0}, "macOS", {"Ventura", {13, 0, 1}}},
|
||||
"22C65" = {{22, 2, 0}, "macOS", {"Ventura", {13, 1, 0}}},
|
||||
"22D49" = {{22, 3, 0}, "macOS", {"Ventura", {13, 2, 0}}},
|
||||
"22D68" = {{22, 3, 0}, "macOS", {"Ventura", {13, 2, 1}}},
|
||||
"22E252" = {{22, 4, 0}, "macOS", {"Ventura", {13, 3, 0}}},
|
||||
"22E261" = {{22, 4, 0}, "macOS", {"Ventura", {13, 3, 1}}},
|
||||
"22F66" = {{22, 5, 0}, "macOS", {"Ventura", {13, 4, 0}}},
|
||||
"22F82" = {{22, 5, 0}, "macOS", {"Ventura", {13, 4, 1}}},
|
||||
"22E772610a" = {{22, 5, 0}, "macOS", {"Ventura", {13, 4, 1}}},
|
||||
"22F770820d" = {{22, 5, 0}, "macOS", {"Ventura", {13, 4, 1}}},
|
||||
"22G74" = {{22, 6, 0}, "macOS", {"Ventura", {13, 5, 0}}},
|
||||
"22G90" = {{22, 6, 0}, "macOS", {"Ventura", {13, 5, 1}}},
|
||||
"22G91" = {{22, 6, 0}, "macOS", {"Ventura", {13, 5, 2}}},
|
||||
"22G120" = {{22, 6, 0}, "macOS", {"Ventura", {13, 6, 0}}},
|
||||
"22G313" = {{22, 6, 0}, "macOS", {"Ventura", {13, 6, 1}}},
|
||||
"22G320" = {{22, 6, 0}, "macOS", {"Ventura", {13, 6, 2}}},
|
||||
|
||||
// MacOS Sonoma
|
||||
"23A344" = {{23, 0, 0}, "macOS", {"Sonoma", {14, 0, 0}}},
|
||||
"23B74" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 0}}},
|
||||
"23B81" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}},
|
||||
"23B2082" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}},
|
||||
"23B92" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}},
|
||||
"23B2091" = {{23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}},
|
||||
"23C64" = {{23, 2, 0}, "macOS", {"Sonoma", {14, 2, 0}}},
|
||||
"23C71" = {{23, 2, 0}, "macOS", {"Sonoma", {14, 2, 1}}},
|
||||
"23D56" = {{23, 3, 0}, "macOS", {"Sonoma", {14, 3, 0}}},
|
||||
"23D60" = {{23, 3, 0}, "macOS", {"Sonoma", {14, 3, 1}}},
|
||||
"23E214" = {{23, 4, 0}, "macOS", {"Sonoma", {14, 4, 0}}},
|
||||
"23E224" = {{23, 4, 0}, "macOS", {"Sonoma", {14, 4, 1}}},
|
||||
"23F79" = {{23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}},
|
||||
"23G80" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
|
||||
"23G93" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
|
||||
"23H124" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
|
||||
|
||||
// MacOS Sequoia
|
||||
"24A335" = {{24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
|
||||
"24A348" = {{24, 0, 0}, "macOS", {"Sequoia", {15, 0, 1}}},
|
||||
}
|
||||
|
||||
@(private)
|
||||
Darwin_Match :: enum {
|
||||
Unknown,
|
||||
Exact,
|
||||
Nearest,
|
||||
}
|
||||
|
||||
@(private)
|
||||
map_darwin_kernel_version_to_macos_release :: proc(build: string, darwin: [3]int) -> (res: Darwin_To_Release, match: Darwin_Match) {
|
||||
// Find exact release match if possible.
|
||||
if v, v_ok := macos_release_map[build]; v_ok {
|
||||
return v, .Exact
|
||||
}
|
||||
|
||||
nearest: Darwin_To_Release
|
||||
for _, v in macos_release_map {
|
||||
// Try an exact match on XNU version first.
|
||||
if darwin == v.darwin {
|
||||
return v, .Exact
|
||||
}
|
||||
|
||||
// Major kernel version needs to match exactly,
|
||||
// otherwise the release is considered .Unknown
|
||||
if darwin.x == v.darwin.x {
|
||||
if nearest == {} {
|
||||
nearest = v
|
||||
}
|
||||
if darwin.y >= v.darwin.y && v.darwin != nearest.darwin {
|
||||
nearest = v
|
||||
if darwin.z >= v.darwin.z && v.darwin != nearest.darwin {
|
||||
nearest = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nearest == {} {
|
||||
return {darwin, "macOS", {"Unknown", {}}}, .Unknown
|
||||
} else {
|
||||
return nearest, .Nearest
|
||||
}
|
||||
os_version.as_string = string(b.buf[:])
|
||||
}
|
||||
|
||||
@@ -519,6 +519,36 @@ Fd_Poll_Events_Bits :: enum {
|
||||
RDHUP = 13,
|
||||
}
|
||||
|
||||
Inotify_Init_Bits :: enum {
|
||||
NONBLOCK = 11,
|
||||
CLOEXEC = 19,
|
||||
}
|
||||
|
||||
Inotify_Event_Bits :: enum u32 {
|
||||
ACCESS = 0,
|
||||
MODIFY = 1,
|
||||
ATTRIB = 2,
|
||||
CLOSE_WRITE = 3,
|
||||
CLOSE_NOWRITE = 4,
|
||||
OPEN = 5,
|
||||
MOVED_FROM = 6,
|
||||
MOVED_TO = 7,
|
||||
CREATE = 8,
|
||||
DELETE = 9,
|
||||
DELETE_SELF = 10,
|
||||
MOVE_SELF = 11,
|
||||
UNMOUNT = 13,
|
||||
Q_OVERFLOW = 14,
|
||||
IGNORED = 15,
|
||||
ONLYDIR = 24,
|
||||
DONT_FOLLOW = 25,
|
||||
EXCL_UNLINK = 26,
|
||||
MASK_CREATE = 28,
|
||||
MASK_ADD = 29,
|
||||
ISDIR = 30,
|
||||
ONESHOT = 31,
|
||||
}
|
||||
|
||||
/*
|
||||
Bits for Mem_Protection bitfield
|
||||
*/
|
||||
|
||||
@@ -135,6 +135,31 @@ STATX_BASIC_STATS :: Statx_Mask {
|
||||
.BLOCKS,
|
||||
}
|
||||
|
||||
IN_ALL_EVENTS :: Inotify_Event_Mask {
|
||||
.ACCESS,
|
||||
.MODIFY,
|
||||
.ATTRIB,
|
||||
.CLOSE_WRITE,
|
||||
.CLOSE_NOWRITE,
|
||||
.OPEN,
|
||||
.MOVED_FROM,
|
||||
.MOVED_TO,
|
||||
.CREATE,
|
||||
.DELETE,
|
||||
.DELETE_SELF,
|
||||
.MOVE_SELF,
|
||||
}
|
||||
|
||||
IN_CLOSE :: Inotify_Event_Mask {
|
||||
.CLOSE_WRITE,
|
||||
.CLOSE_NOWRITE,
|
||||
}
|
||||
|
||||
IN_MOVE :: Inotify_Event_Mask {
|
||||
.MOVED_FROM,
|
||||
.MOVED_TO,
|
||||
}
|
||||
|
||||
/*
|
||||
Tell `shmget` to create a new key
|
||||
*/
|
||||
|
||||
+22
-3
@@ -2536,11 +2536,30 @@ waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, opt
|
||||
|
||||
// TODO(flysand): ioprio_get
|
||||
|
||||
// TODO(flysand): inotify_init
|
||||
inotify_init :: proc "contextless" () -> (Fd, Errno) {
|
||||
when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 {
|
||||
ret := syscall(SYS_inotify_init1, 0)
|
||||
return errno_unwrap(ret, Fd)
|
||||
} else {
|
||||
ret := syscall(SYS_inotify_init)
|
||||
return errno_unwrap(ret, Fd)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(flysand): inotify_add_watch
|
||||
inotify_init1 :: proc "contextless" (flags: Inotify_Init_Flags) -> (Fd, Errno) {
|
||||
ret := syscall(SYS_inotify_init1, transmute(i32)flags)
|
||||
return errno_unwrap(ret, Fd)
|
||||
}
|
||||
|
||||
// TODO(flysand): inotify_rm_watch
|
||||
inotify_add_watch :: proc "contextless" (fd: Fd, pathname: cstring, mask: Inotify_Event_Mask) -> (Wd, Errno) {
|
||||
ret := syscall(SYS_inotify_add_watch, fd, transmute(uintptr) pathname, transmute(u32) mask)
|
||||
return errno_unwrap(ret, Wd)
|
||||
}
|
||||
|
||||
inotify_rm_watch :: proc "contextless" (fd: Fd, wd: Wd) -> (Errno) {
|
||||
ret := syscall(SYS_inotify_rm_watch, fd, wd)
|
||||
return Errno(-ret)
|
||||
}
|
||||
|
||||
// TODO(flysand): migrate_pages
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ Id :: distinct uint
|
||||
*/
|
||||
Fd :: distinct i32
|
||||
|
||||
/*
|
||||
Represents a watch descriptor.
|
||||
*/
|
||||
Wd :: distinct i32
|
||||
|
||||
/*
|
||||
Type for PID file descriptors.
|
||||
*/
|
||||
@@ -343,6 +348,18 @@ Poll_Fd :: struct {
|
||||
revents: Fd_Poll_Events,
|
||||
}
|
||||
|
||||
Inotify_Init_Flags :: bit_set[Inotify_Init_Bits; i32]
|
||||
|
||||
Inotify_Event :: struct {
|
||||
wd: Wd,
|
||||
mask: Inotify_Event_Mask,
|
||||
cookie: u32,
|
||||
len: u32,
|
||||
name: [0]u8,
|
||||
}
|
||||
|
||||
Inotify_Event_Mask :: bit_set[Inotify_Event_Bits; u32]
|
||||
|
||||
/*
|
||||
Specifies protection for memory pages.
|
||||
*/
|
||||
|
||||
@@ -54,15 +54,6 @@ foreign lib {
|
||||
*/
|
||||
closedir :: proc(dirp: DIR) -> result ---
|
||||
|
||||
/*
|
||||
Return a file descriptor referring to the same directory as the dirp argument.
|
||||
|
||||
// TODO: this is a macro on NetBSD?
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]]
|
||||
*/
|
||||
dirfd :: proc(dirp: DIR) -> FD ---
|
||||
|
||||
/*
|
||||
Equivalent to the opendir() function except that the directory is specified by a file descriptor
|
||||
rather than by a name.
|
||||
@@ -161,11 +152,36 @@ when ODIN_OS == .NetBSD {
|
||||
@(private) LSCANDIR :: "__scandir30"
|
||||
@(private) LOPENDIR :: "__opendir30"
|
||||
@(private) LREADDIR :: "__readdir30"
|
||||
|
||||
/*
|
||||
Return a file descriptor referring to the same directory as the dirp argument.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]]
|
||||
*/
|
||||
dirfd :: proc "c" (dirp: DIR) -> FD {
|
||||
_dirdesc :: struct {
|
||||
dd_fd: FD,
|
||||
|
||||
// more stuff...
|
||||
}
|
||||
|
||||
return (^_dirdesc)(dirp).dd_fd
|
||||
}
|
||||
|
||||
} else {
|
||||
@(private) LALPHASORT :: "alphasort" + INODE_SUFFIX
|
||||
@(private) LSCANDIR :: "scandir" + INODE_SUFFIX
|
||||
@(private) LOPENDIR :: "opendir" + INODE_SUFFIX
|
||||
@(private) LREADDIR :: "readdir" + INODE_SUFFIX
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Return a file descriptor referring to the same directory as the dirp argument.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]]
|
||||
*/
|
||||
dirfd :: proc(dirp: DIR) -> FD ---
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
@@ -116,12 +116,14 @@ Prot_Flag_Bits :: enum c.int {
|
||||
Prot_Flags :: bit_set[Prot_Flag_Bits; c.int]
|
||||
|
||||
Map_Flag_Bits :: enum c.int {
|
||||
// Map anonymous memory.
|
||||
ANONYMOUS = log2(MAP_ANONYMOUS),
|
||||
// Interpret addr exactly.
|
||||
FIXED = log2(MAP_FIXED),
|
||||
FIXED = log2(MAP_FIXED),
|
||||
// Changes are private.
|
||||
PRIVATE = log2(MAP_PRIVATE),
|
||||
PRIVATE = log2(MAP_PRIVATE),
|
||||
// Changes are shared.
|
||||
SHARED = log2(MAP_SHARED),
|
||||
SHARED = log2(MAP_SHARED),
|
||||
}
|
||||
Map_Flags :: bit_set[Map_Flag_Bits; c.int]
|
||||
|
||||
@@ -171,9 +173,10 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS
|
||||
PROT_READ :: 0x01
|
||||
PROT_WRITE :: 0x02
|
||||
|
||||
MAP_FIXED :: 0x0010
|
||||
MAP_PRIVATE :: 0x0002
|
||||
MAP_SHARED :: 0x0001
|
||||
MAP_FIXED :: 0x0010
|
||||
MAP_PRIVATE :: 0x0002
|
||||
MAP_SHARED :: 0x0001
|
||||
MAP_ANONYMOUS :: 0x0020 when ODIN_OS == .Linux else 0x1000
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .Linux {
|
||||
MS_INVALIDATE :: 0x0002
|
||||
@@ -207,9 +210,10 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS
|
||||
PROT_READ :: 0x01
|
||||
PROT_WRITE :: 0x02
|
||||
|
||||
MAP_FIXED :: 0x0010
|
||||
MAP_PRIVATE :: 0x0002
|
||||
MAP_SHARED :: 0x0001
|
||||
MAP_FIXED :: 0x0010
|
||||
MAP_PRIVATE :: 0x0002
|
||||
MAP_SHARED :: 0x0001
|
||||
MAP_ANONYMOUS :: 0x1000
|
||||
|
||||
MS_ASYNC :: 0x0001
|
||||
MS_INVALIDATE :: 0x0002
|
||||
|
||||
@@ -48,6 +48,12 @@ foreign libc {
|
||||
addr.sun_family = .UNIX
|
||||
copy(addr.sun_path[:], "/somepath\x00")
|
||||
|
||||
/*
|
||||
unlink the socket before binding in case
|
||||
of previous runs not cleaning up the socket
|
||||
*/
|
||||
posix.unlink("/somepath")
|
||||
|
||||
if posix.bind(sfd, (^posix.sockaddr)(&addr), size_of(addr)) != .OK {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
@@ -186,8 +186,8 @@ Key_Location :: enum u8 {
|
||||
Numpad = 3,
|
||||
}
|
||||
|
||||
KEYBOARD_MAX_KEY_SIZE :: 16
|
||||
KEYBOARD_MAX_CODE_SIZE :: 16
|
||||
KEYBOARD_MAX_KEY_SIZE :: 32
|
||||
KEYBOARD_MAX_CODE_SIZE :: 32
|
||||
|
||||
GAMEPAD_MAX_ID_SIZE :: 64
|
||||
GAMEPAD_MAX_MAPPING_SIZE :: 64
|
||||
|
||||
@@ -1548,8 +1548,8 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
|
||||
|
||||
wmi.storeInt(off(W, W), e.key.length)
|
||||
wmi.storeInt(off(W, W), e.code.length)
|
||||
wmi.storeString(off(16, 1), e.key);
|
||||
wmi.storeString(off(16, 1), e.code);
|
||||
wmi.storeString(off(32, 1), e.key);
|
||||
wmi.storeString(off(32, 1), e.code);
|
||||
} else if (e.type === 'scroll') {
|
||||
wmi.storeF64(off(8, 8), window.scrollX);
|
||||
wmi.storeF64(off(8, 8), window.scrollY);
|
||||
|
||||
@@ -4519,7 +4519,7 @@ DNS_RECORD :: struct { // aka DNS_RECORDA
|
||||
Flags: DWORD,
|
||||
dwTtl: DWORD,
|
||||
_: DWORD,
|
||||
Data: struct #raw_union {
|
||||
Data: struct #raw_union #align(4) {
|
||||
CNAME: DNS_PTR_DATAA,
|
||||
A: u32be, // Ipv4 Address
|
||||
AAAA: u128be, // Ipv6 Address
|
||||
|
||||
@@ -781,3 +781,64 @@ CF_GDIOBJLAST :: 0x03FF
|
||||
CF_OWNERDISPLAY :: 0x0080
|
||||
CF_PRIVATEFIRST :: 0x0200
|
||||
CF_PRIVATELAST :: 0x02FF
|
||||
|
||||
STICKYKEYS :: struct {
|
||||
cbSize: UINT,
|
||||
dwFlags: DWORD,
|
||||
}
|
||||
LPSTICKYKEYS :: ^STICKYKEYS
|
||||
|
||||
SKF_STICKYKEYSON :: 0x1
|
||||
SKF_AVAILABLE :: 0x2
|
||||
SKF_HOTKEYACTIVE :: 0x4
|
||||
SKF_CONFIRMHOTKEY :: 0x8
|
||||
SKF_HOTKEYSOUND :: 0x10
|
||||
SKF_INDICATOR :: 0x20
|
||||
SKF_AUDIBLEFEEDBACK :: 0x40
|
||||
SKF_TRISTATE :: 0x80
|
||||
SKF_TWOKEYSOFF :: 0x100
|
||||
SKF_LSHIFTLOCKED :: 0x10000
|
||||
SKF_RSHIFTLOCKED :: 0x20000
|
||||
SKF_LCTLLOCKED :: 0x40000
|
||||
SKF_RCTLLOCKED :: 0x80000
|
||||
SKF_LALTLOCKED :: 0x100000
|
||||
SKF_RALTLOCKED :: 0x200000
|
||||
SKF_LWINLOCKED :: 0x400000
|
||||
SKF_RWINLOCKED :: 0x800000
|
||||
SKF_LSHIFTLATCHED :: 0x1000000
|
||||
SKF_RSHIFTLATCHED :: 0x2000000
|
||||
SKF_LCTLLATCHED :: 0x4000000
|
||||
SKF_RCTLLATCHED :: 0x8000000
|
||||
SKF_LALTLATCHED :: 0x10000000
|
||||
SKF_RALTLATCHED :: 0x20000000
|
||||
|
||||
TOGGLEKEYS :: struct {
|
||||
cbSize: UINT,
|
||||
dwFlags: DWORD,
|
||||
}
|
||||
LPTOGGLEKEYS :: ^TOGGLEKEYS
|
||||
|
||||
TKF_TOGGLEKEYSON :: 0x1
|
||||
TKF_AVAILABLE :: 0x2
|
||||
TKF_HOTKEYACTIVE :: 0x4
|
||||
TKF_CONFIRMHOTKEY :: 0x8
|
||||
TKF_HOTKEYSOUND :: 0x10
|
||||
TKF_INDICATOR :: 0x20
|
||||
|
||||
FILTERKEYS :: struct {
|
||||
cbSize: UINT,
|
||||
dwFlags: DWORD,
|
||||
iWaitMSec: DWORD,
|
||||
iDelayMSec: DWORD,
|
||||
iRepeatMSec: DWORD,
|
||||
iBounceMSec: DWORD,
|
||||
}
|
||||
LPFILTERKEYS :: ^FILTERKEYS
|
||||
|
||||
FKF_FILTERKEYSON :: 0x1
|
||||
FKF_AVAILABLE :: 0x2
|
||||
FKF_HOTKEYACTIVE :: 0x4
|
||||
FKF_CONFIRMHOTKEY :: 0x8
|
||||
FKF_HOTKEYSOUND :: 0x10
|
||||
FKF_INDICATOR :: 0x20
|
||||
FKF_CLICKON :: 0x40
|
||||
|
||||
@@ -3,7 +3,7 @@ package sys_windows
|
||||
|
||||
foreign import uxtheme "system:UxTheme.lib"
|
||||
|
||||
MARGINS :: distinct [4]int
|
||||
MARGINS :: distinct [4]i32
|
||||
PMARGINS :: ^MARGINS
|
||||
|
||||
@(default_calling_convention="system")
|
||||
|
||||
@@ -381,6 +381,7 @@ match_with_preallocated_capture :: proc(
|
||||
capture.pos[n] = {a, b}
|
||||
n += 1
|
||||
}
|
||||
num_groups = n
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// It takes a string providing the source, which then can be tokenized through
|
||||
// repeated calls to the scan procedure.
|
||||
// For compatibility with existing tooling and languages, the NUL character is not allowed.
|
||||
// If an UTF-8 encoded byte order mark (BOM) is the first character in the first character in the source, it will be discarded.
|
||||
// If an UTF-8 encoded byte order mark (BOM) is the first character in the source, it will be discarded.
|
||||
//
|
||||
// By default, a Scanner skips white space and Odin comments and recognizes all literals defined by the Odin programming language specification.
|
||||
// A Scanner may be customized to recognize only a subset of those literals and to recognize different identifiers and white space characters.
|
||||
|
||||
@@ -9,6 +9,7 @@ package thread
|
||||
import "base:intrinsics"
|
||||
import "core:sync"
|
||||
import "core:mem"
|
||||
import "core:container/queue"
|
||||
|
||||
Task_Proc :: #type proc(task: Task)
|
||||
|
||||
@@ -40,7 +41,7 @@ Pool :: struct {
|
||||
threads: []^Thread,
|
||||
|
||||
|
||||
tasks: [dynamic]Task,
|
||||
tasks: queue.Queue(Task),
|
||||
tasks_done: [dynamic]Task,
|
||||
}
|
||||
|
||||
@@ -69,13 +70,13 @@ pool_thread_runner :: proc(t: ^Thread) {
|
||||
}
|
||||
|
||||
// Once initialized, the pool's memory address is not allowed to change until
|
||||
// it is destroyed.
|
||||
// it is destroyed.
|
||||
//
|
||||
// The thread pool requires an allocator which it either owns, or which is thread safe.
|
||||
pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) {
|
||||
context.allocator = allocator
|
||||
pool.allocator = allocator
|
||||
pool.tasks = make([dynamic]Task)
|
||||
queue.init(&pool.tasks)
|
||||
pool.tasks_done = make([dynamic]Task)
|
||||
pool.threads = make([]^Thread, max(thread_count, 1))
|
||||
|
||||
@@ -92,7 +93,7 @@ pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) {
|
||||
}
|
||||
|
||||
pool_destroy :: proc(pool: ^Pool) {
|
||||
delete(pool.tasks)
|
||||
queue.destroy(&pool.tasks)
|
||||
delete(pool.tasks_done)
|
||||
|
||||
for &t in pool.threads {
|
||||
@@ -140,11 +141,11 @@ pool_join :: proc(pool: ^Pool) {
|
||||
// the thread pool. You can even add tasks from inside other tasks.
|
||||
//
|
||||
// Each task also needs an allocator which it either owns, or which is thread
|
||||
// safe.
|
||||
// safe.
|
||||
pool_add_task :: proc(pool: ^Pool, allocator: mem.Allocator, procedure: Task_Proc, data: rawptr, user_index: int = 0) {
|
||||
sync.guard(&pool.mutex)
|
||||
|
||||
append(&pool.tasks, Task{
|
||||
queue.push_back(&pool.tasks, Task{
|
||||
procedure = procedure,
|
||||
data = data,
|
||||
user_index = user_index,
|
||||
@@ -288,10 +289,10 @@ pool_is_empty :: #force_inline proc(pool: ^Pool) -> bool {
|
||||
pool_pop_waiting :: proc(pool: ^Pool) -> (task: Task, got_task: bool) {
|
||||
sync.guard(&pool.mutex)
|
||||
|
||||
if len(pool.tasks) != 0 {
|
||||
if queue.len(pool.tasks) != 0 {
|
||||
intrinsics.atomic_sub(&pool.num_waiting, 1)
|
||||
intrinsics.atomic_add(&pool.num_in_processing, 1)
|
||||
task = pop_front(&pool.tasks)
|
||||
task = queue.pop_front(&pool.tasks)
|
||||
got_task = true
|
||||
}
|
||||
|
||||
|
||||
@@ -203,6 +203,22 @@ generate_rrule_from_tzi :: proc(tzi: ^REG_TZI_FORMAT, abbrevs: TZ_Abbrev, alloca
|
||||
if err != nil { return }
|
||||
defer if err != nil { delete(std_name, allocator) }
|
||||
|
||||
if (tzi.std_date.month == 0) {
|
||||
return datetime.TZ_RRule{
|
||||
has_dst = false,
|
||||
|
||||
std_name = std_name,
|
||||
std_offset = -(i64(tzi.bias) + i64(tzi.std_bias)) * 60,
|
||||
dst_date = datetime.TZ_Transition_Date{
|
||||
type = .Month_Week_Day,
|
||||
month = u8(tzi.std_date.month),
|
||||
week = u8(tzi.std_date.day),
|
||||
day = tzi.std_date.day_of_week,
|
||||
time = (i64(tzi.std_date.hour) * 60 * 60) + (i64(tzi.std_date.minute) * 60) + i64(tzi.std_date.second),
|
||||
},
|
||||
}, true
|
||||
}
|
||||
|
||||
dst_name: string
|
||||
dst_name, err = strings.clone(abbrevs.dst, allocator)
|
||||
if err != nil { return }
|
||||
|
||||
@@ -93,6 +93,8 @@ trans_date_to_seconds :: proc(year: i64, td: datetime.TZ_Transition_Date) -> (se
|
||||
|
||||
switch td.type {
|
||||
case .Month_Week_Day:
|
||||
if td.month < 1 { return }
|
||||
|
||||
t += month_to_seconds(int(td.month) - 1, is_leap)
|
||||
|
||||
weekday := ((t + (4 * DAY_SEC)) %% (7 * DAY_SEC)) / DAY_SEC
|
||||
|
||||
@@ -536,24 +536,21 @@ parse_tzif :: proc(_buffer: []u8, region_name: string, allocator := context.allo
|
||||
buffer = buffer[(int(real_hdr.leapcnt) * size_of(Leapsecond_Record)):]
|
||||
|
||||
standard_wall_tags := buffer[:int(real_hdr.isstdcnt)]
|
||||
buffer = buffer[int(real_hdr.isstdcnt):]
|
||||
|
||||
ut_tags := buffer[:int(real_hdr.isutcnt)]
|
||||
|
||||
for stdwall_tag, idx in standard_wall_tags {
|
||||
ut_tag := ut_tags[idx]
|
||||
|
||||
for stdwall_tag, _ in standard_wall_tags {
|
||||
if (stdwall_tag != 0 && stdwall_tag != 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
buffer = buffer[int(real_hdr.isstdcnt):]
|
||||
|
||||
ut_tags := buffer[:int(real_hdr.isutcnt)]
|
||||
for ut_tag, _ in ut_tags {
|
||||
if (ut_tag != 0 && ut_tag != 1) {
|
||||
return
|
||||
}
|
||||
|
||||
if ut_tag == 1 && stdwall_tag != 1 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
buffer = buffer[int(real_hdr.isutcnt):]
|
||||
|
||||
// Start of footer
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
The `example` directory contains two packages:
|
||||
|
||||
A [demo](examples/demo) illustrating the basics of Odin.
|
||||
A [demo](demo) illustrating the basics of Odin.
|
||||
|
||||
It further contains [all](examples/all), which imports all [core](core) and [vendor](vendor) packages so we can conveniently run `odin check` on everything at once.
|
||||
It further contains [all](all), which imports all [core](/core) and [vendor](/vendor) packages so we can conveniently run `odin check` on everything at once.
|
||||
|
||||
For additional example code, see the [examples](https://github.com/odin-lang/examples) repository.
|
||||
|
||||
@@ -1,8 +1,2 @@
|
||||
#+build windows
|
||||
package all
|
||||
|
||||
import c_tokenizer "core:c/frontend/tokenizer"
|
||||
import c_preprocessor "core:c/frontend/preprocessor"
|
||||
|
||||
_ :: c_tokenizer
|
||||
_ :: c_preprocessor
|
||||
|
||||
+1
-18
@@ -2052,22 +2052,6 @@ explicit_context_definition :: proc "c" () {
|
||||
dummy_procedure()
|
||||
}
|
||||
|
||||
relative_data_types :: proc() {
|
||||
fmt.println("\n#relative data types")
|
||||
|
||||
x: int = 123
|
||||
ptr: #relative(i16) ^int
|
||||
ptr = &x
|
||||
fmt.println(ptr^)
|
||||
|
||||
arr := [3]int{1, 2, 3}
|
||||
multi_ptr: #relative(i16) [^]int
|
||||
multi_ptr = &arr[0]
|
||||
fmt.println(multi_ptr)
|
||||
fmt.println(multi_ptr[:3])
|
||||
fmt.println(multi_ptr[1])
|
||||
}
|
||||
|
||||
or_else_operator :: proc() {
|
||||
fmt.println("\n#'or_else'")
|
||||
{
|
||||
@@ -2151,7 +2135,7 @@ or_return_operator :: proc() {
|
||||
return .None
|
||||
}
|
||||
foo_2 :: proc() -> (n: int, err: Error) {
|
||||
// It is more common that your procedure turns multiple values
|
||||
// It is more common that your procedure returns multiple values
|
||||
// If 'or_return' is used within a procedure multiple parameters (2+),
|
||||
// then all the parameters must be named so that the remaining parameters
|
||||
// so that a bare 'return' statement can be used
|
||||
@@ -2634,7 +2618,6 @@ main :: proc() {
|
||||
constant_literal_expressions()
|
||||
union_maybe()
|
||||
explicit_context_definition()
|
||||
relative_data_types()
|
||||
or_else_operator()
|
||||
or_return_operator()
|
||||
or_break_and_or_continue_operators()
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
Prints the current date as YYYYMMDD
|
||||
|
||||
e.g. 2024-12-25
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(int arg_count, char const **arg_ptr) {
|
||||
time_t t = time(NULL);
|
||||
struct tm* now = localtime(&t);
|
||||
printf("%04d%02d%02d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday);
|
||||
}
|
||||
+2
-2
@@ -55,12 +55,12 @@ BEGIN
|
||||
BLOCK "0409FDE9"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "https://odin-lang.org/"
|
||||
VALUE "FileDescription", "Odin general-purpose programming language." // note this is shown in the task manager
|
||||
VALUE "FileDescription", "Odin" // note this is shown in the task manager
|
||||
VALUE "FileVersion", QUOTE(VF)
|
||||
VALUE "InternalName", "odin.exe"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2016-2024 Ginger Bill. All rights reserved."
|
||||
VALUE "OriginalFilename", "odin.exe"
|
||||
VALUE "ProductName", "The Odin Programming Language"
|
||||
VALUE "ProductName", "Odin Programming Language"
|
||||
VALUE "ProductVersion", QUOTE(VP)
|
||||
VALUE "Comments", QUOTE(git-sha: GIT_SHA)
|
||||
// custom values
|
||||
|
||||
@@ -3,6 +3,7 @@ pkgs.mkShell {
|
||||
name = "odin";
|
||||
nativeBuildInputs = with pkgs; [
|
||||
git
|
||||
which
|
||||
clang_17
|
||||
llvmPackages_17.llvm
|
||||
llvmPackages_17.bintools
|
||||
|
||||
+43
-461
@@ -2,12 +2,6 @@
|
||||
Gather and print platform and version info to help with reporting Odin bugs.
|
||||
*/
|
||||
|
||||
#if !defined(GB_COMPILER_MSVC)
|
||||
#if defined(GB_CPU_X86)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(GB_SYSTEM_LINUX)
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -154,21 +148,6 @@ gb_internal void report_windows_product_type(DWORD ProductType) {
|
||||
}
|
||||
#endif
|
||||
|
||||
gb_internal void odin_cpuid(int leaf, int result[]) {
|
||||
#if defined(GB_CPU_ARM) || defined(GB_CPU_RISCV)
|
||||
return;
|
||||
|
||||
#elif defined(GB_CPU_X86)
|
||||
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
__cpuid(result, leaf);
|
||||
#else
|
||||
__get_cpuid(leaf, (unsigned int*)&result[0], (unsigned int*)&result[1], (unsigned int*)&result[2], (unsigned int*)&result[3]);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_internal void report_cpu_info() {
|
||||
gb_printf("\tCPU: ");
|
||||
|
||||
@@ -547,387 +526,46 @@ gb_internal void report_os_info() {
|
||||
gb_printf(", %s %s\n", info->sysname, info->release);
|
||||
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
struct Darwin_To_Release {
|
||||
const char* build; // 21G83
|
||||
int darwin[3]; // Darwin kernel triplet
|
||||
const char* os_name; // OS X, MacOS
|
||||
struct {
|
||||
const char* name; // Monterey, Mojave, etc.
|
||||
int version[3]; // 12.4, etc.
|
||||
} release;
|
||||
};
|
||||
|
||||
Darwin_To_Release macos_release_map[] = {
|
||||
{"8A428", { 8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
{"8A432", { 8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
{"8B15", { 8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
{"8B17", { 8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
{"8C46", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
{"8C47", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
{"8E102", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
{"8E45", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
{"8E90", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
{"8F46", { 8, 3, 0}, "macOS", {"Tiger", {10, 4, 3}}},
|
||||
{"8G32", { 8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
{"8G1165", { 8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
{"8H14", { 8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
{"8G1454", { 8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
{"8I127", { 8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
{"8I1119", { 8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
{"8J135", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
{"8J2135a", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
{"8K1079", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
{"8N5107", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
{"8L127", { 8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
{"8L2127", { 8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
{"8P135", { 8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
{"8P2137", { 8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
{"8R218", { 8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
{"8R2218", { 8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
{"8R2232", { 8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
{"8S165", { 8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
{"8S2167", { 8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
{"9A581", { 9, 0, 0}, "macOS", {"Leopard", {10, 5, 0}}},
|
||||
{"9B18", { 9, 1, 0}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
{"9B2117", { 9, 1, 1}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
{"9C31", { 9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
{"9C7010", { 9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
{"9D34", { 9, 3, 0}, "macOS", {"Leopard", {10, 5, 3}}},
|
||||
{"9E17", { 9, 4, 0}, "macOS", {"Leopard", {10, 5, 4}}},
|
||||
{"9F33", { 9, 5, 0}, "macOS", {"Leopard", {10, 5, 5}}},
|
||||
{"9G55", { 9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
{"9G66", { 9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
{"9G71", { 9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
{"9J61", { 9, 7, 0}, "macOS", {"Leopard", {10, 5, 7}}},
|
||||
{"9L30", { 9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
{"9L34", { 9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
{"10A432", {10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
{"10A433", {10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
{"10B504", {10, 1, 0}, "macOS", {"Snow Leopard", {10, 6, 1}}},
|
||||
{"10C540", {10, 2, 0}, "macOS", {"Snow Leopard", {10, 6, 2}}},
|
||||
{"10D573", {10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
{"10D575", {10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
{"10D578", {10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
{"10F569", {10, 4, 0}, "macOS", {"Snow Leopard", {10, 6, 4}}},
|
||||
{"10H574", {10, 5, 0}, "macOS", {"Snow Leopard", {10, 6, 5}}},
|
||||
{"10J567", {10, 6, 0}, "macOS", {"Snow Leopard", {10, 6, 6}}},
|
||||
{"10J869", {10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
{"10J3250", {10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
{"10J4138", {10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
{"10K540", {10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
{"10K549", {10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
{"11A511", {11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
{"11A511s", {11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
{"11A2061", {11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
{"11A2063", {11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
{"11B26", {11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
{"11B2118", {11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
{"11C74", {11, 2, 0}, "macOS", {"Lion", {10, 7, 2}}},
|
||||
{"11D50", {11, 3, 0}, "macOS", {"Lion", {10, 7, 3}}},
|
||||
{"11E53", {11, 4, 0}, "macOS", {"Lion", {10, 7, 4}}},
|
||||
{"11G56", {11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
{"11G63", {11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
{"12A269", {12, 0, 0}, "macOS", {"Mountain Lion", {10, 8, 0}}},
|
||||
{"12B19", {12, 1, 0}, "macOS", {"Mountain Lion", {10, 8, 1}}},
|
||||
{"12C54", {12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
{"12C60", {12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
{"12C2034", {12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
{"12C3104", {12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
{"12D78", {12, 3, 0}, "macOS", {"Mountain Lion", {10, 8, 3}}},
|
||||
{"12E55", {12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
{"12E3067", {12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
{"12E4022", {12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
{"12F37", {12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
{"12F45", {12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
{"12F2501", {12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
{"12F2518", {12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
{"12F2542", {12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
{"12F2560", {12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
{"13A603", {13, 0, 0}, "macOS", {"Mavericks", {10, 9, 0}}},
|
||||
{"13B42", {13, 0, 0}, "macOS", {"Mavericks", {10, 9, 1}}},
|
||||
{"13C64", {13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
{"13C1021", {13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
{"13D65", {13, 2, 0}, "macOS", {"Mavericks", {10, 9, 3}}},
|
||||
{"13E28", {13, 3, 0}, "macOS", {"Mavericks", {10, 9, 4}}},
|
||||
{"13F34", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1066", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1077", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1096", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1112", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1134", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1507", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1603", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1712", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1808", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"13F1911", {13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
{"14A389", {14, 0, 0}, "macOS", {"Yosemite", {10, 10, 0}}},
|
||||
{"14B25", {14, 0, 0}, "macOS", {"Yosemite", {10, 10, 1}}},
|
||||
{"14C109", {14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
{"14C1510", {14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
{"14C2043", {14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
{"14C1514", {14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
{"14C2513", {14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
{"14D131", {14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
{"14D136", {14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
{"14E46", {14, 4, 0}, "macOS", {"Yosemite", {10, 10, 4}}},
|
||||
{"14F27", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1021", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1505", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1509", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1605", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1713", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1808", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1909", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F1912", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F2009", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F2109", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F2315", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F2411", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"14F2511", {14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
{"15A284", {15, 0, 0}, "macOS", {"El Capitan", {10, 11, 0}}},
|
||||
{"15B42", {15, 0, 0}, "macOS", {"El Capitan", {10, 11, 1}}},
|
||||
{"15C50", {15, 2, 0}, "macOS", {"El Capitan", {10, 11, 2}}},
|
||||
{"15D21", {15, 3, 0}, "macOS", {"El Capitan", {10, 11, 3}}},
|
||||
{"15E65", {15, 4, 0}, "macOS", {"El Capitan", {10, 11, 4}}},
|
||||
{"15F34", {15, 5, 0}, "macOS", {"El Capitan", {10, 11, 5}}},
|
||||
{"15G31", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1004", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1011", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1108", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1212", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1217", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1421", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1510", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G1611", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G17023", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G18013", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G19009", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G20015", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G21013", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"15G22010", {15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
{"16A323", {16, 0, 0}, "macOS", {"Sierra", {10, 12, 0}}},
|
||||
{"16B2555", {16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
{"16B2657", {16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
{"16C67", {16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
{"16C68", {16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
{"16D32", {16, 4, 0}, "macOS", {"Sierra", {10, 12, 3}}},
|
||||
{"16E195", {16, 5, 0}, "macOS", {"Sierra", {10, 12, 4}}},
|
||||
{"16F73", {16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
{"16F2073", {16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
{"16G29", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1036", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1114", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1212", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1314", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1408", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1510", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1618", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1710", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1815", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1917", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G1918", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G2016", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G2127", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G2128", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"16G2136", {16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
{"17A365", {17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
{"17A405", {17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
{"17B48", {17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
{"17B1002", {17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
{"17B1003", {17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
{"17C88", {17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
{"17C89", {17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
{"17C205", {17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
{"17C2205", {17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
{"17D47", {17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
{"17D2047", {17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
{"17D102", {17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
{"17D2102", {17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
{"17E199", {17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
{"17E202", {17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
{"17F77", {17, 6, 0}, "macOS", {"High Sierra", {10, 13, 5}}},
|
||||
{"17G65", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G2208", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G2307", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G3025", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G4015", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G5019", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G6029", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G6030", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G7024", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G8029", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G8030", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G8037", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G9016", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G10021", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G11023", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G12034", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G13033", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G13035", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G14019", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G14033", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"17G14042", {17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
{"18A391", {18, 0, 0}, "macOS", {"Mojave", {10, 14, 0}}},
|
||||
{"18B75", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
{"18B2107", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
{"18B3094", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
{"18C54", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 2}}},
|
||||
{"18D42", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
{"18D43", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
{"18D109", {18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
{"18E226", {18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
{"18E227", {18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
{"18F132", {18, 6, 0}, "macOS", {"Mojave", {10, 14, 5}}},
|
||||
{"18G84", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G87", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G95", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G103", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G1012", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G2022", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G3020", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G4032", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G5033", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G6020", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G6032", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G6042", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G7016", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G8012", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G8022", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G9028", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G9216", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"18G9323", {18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
{"19A583", {19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
{"19A602", {19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
{"19A603", {19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
{"19B88", {19, 0, 0}, "macOS", {"Catalina", {10, 15, 1}}},
|
||||
{"19C57", {19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
{"19C58", {19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
{"19D76", {19, 3, 0}, "macOS", {"Catalina", {10, 15, 3}}},
|
||||
{"19E266", {19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
{"19E287", {19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
{"19F96", {19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
{"19F101", {19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
{"19G73", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
{"19G2021", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
{"19H2", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H4", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H15", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H114", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H512", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H524", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1030", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1217", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1323", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1417", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1419", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1519", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1615", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1713", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1715", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1824", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H1922", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"19H2026", {19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
{"20A2411", {20, 1, 0}, "macOS", {"Big Sur", {11, 0, 0}}},
|
||||
{"20B29", {20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
{"20B50", {20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
{"20C69", {20, 2, 0}, "macOS", {"Big Sur", {11, 1, 0}}},
|
||||
{"20D64", {20, 3, 0}, "macOS", {"Big Sur", {11, 2, 0}}},
|
||||
{"20D74", {20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
{"20D75", {20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
{"20D80", {20, 3, 0}, "macOS", {"Big Sur", {11, 2, 2}}},
|
||||
{"20D91", {20, 3, 0}, "macOS", {"Big Sur", {11, 2, 3}}},
|
||||
{"20E232", {20, 4, 0}, "macOS", {"Big Sur", {11, 3, 0}}},
|
||||
{"20E241", {20, 4, 0}, "macOS", {"Big Sur", {11, 3, 1}}},
|
||||
{"20F71", {20, 5, 0}, "macOS", {"Big Sur", {11, 4, 0}}},
|
||||
{"20G71", {20, 6, 0}, "macOS", {"Big Sur", {11, 5, 0}}},
|
||||
{"20G80", {20, 6, 0}, "macOS", {"Big Sur", {11, 5, 1}}},
|
||||
{"20G95", {20, 6, 0}, "macOS", {"Big Sur", {11, 5, 2}}},
|
||||
{"20G165", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 0}}},
|
||||
{"20G224", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 1}}},
|
||||
{"20G314", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 2}}},
|
||||
{"20G415", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 3}}},
|
||||
{"20G417", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 4}}},
|
||||
{"20G527", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 5}}},
|
||||
{"20G624", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 6}}},
|
||||
{"20G630", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 7}}},
|
||||
{"20G730", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 8}}},
|
||||
{"20G817", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 0}}},
|
||||
{"20G918", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 1}}},
|
||||
{"20G1020", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 2}}},
|
||||
{"20G1116", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 3}}},
|
||||
{"20G1120", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 4}}},
|
||||
{"20G1225", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 5}}},
|
||||
{"20G1231", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 6}}},
|
||||
{"20G1345", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 7}}},
|
||||
{"20G1351", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 8}}},
|
||||
{"20G1426", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 9}}},
|
||||
{"20G1427", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 10}}},
|
||||
{"21A344", {21, 0, 1}, "macOS", {"Monterey", {12, 0, 0}}},
|
||||
{"21A559", {21, 1, 0}, "macOS", {"Monterey", {12, 0, 1}}},
|
||||
{"21C52", {21, 2, 0}, "macOS", {"Monterey", {12, 1, 0}}},
|
||||
{"21D49", {21, 3, 0}, "macOS", {"Monterey", {12, 2, 0}}},
|
||||
{"21D62", {21, 3, 0}, "macOS", {"Monterey", {12, 2, 1}}},
|
||||
{"21E230", {21, 4, 0}, "macOS", {"Monterey", {12, 3, 0}}},
|
||||
{"21E258", {21, 4, 0}, "macOS", {"Monterey", {12, 3, 1}}},
|
||||
{"21F79", {21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
{"21F2081", {21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
{"21F2092", {21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
{"21G72", {21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
||||
{"21G83", {21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
||||
{"21G115", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 0}}},
|
||||
{"21G217", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 1}}},
|
||||
{"21G320", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 2}}},
|
||||
{"21G419", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 3}}},
|
||||
{"21G526", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 4}}},
|
||||
{"21G531", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 5}}},
|
||||
{"21G646", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 6}}},
|
||||
{"21G651", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 7}}},
|
||||
{"21G725", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 8}}},
|
||||
{"21G726", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 9}}},
|
||||
{"21G816", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 0}}},
|
||||
{"21G920", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 1}}},
|
||||
{"21G1974", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 2}}},
|
||||
{"22A380", {13, 0, 0}, "macOS", {"Ventura", {22, 1, 0}}},
|
||||
{"22A400", {13, 0, 1}, "macOS", {"Ventura", {22, 1, 0}}},
|
||||
{"22C65", {13, 1, 0}, "macOS", {"Ventura", {22, 2, 0}}},
|
||||
{"22D49", {13, 2, 0}, "macOS", {"Ventura", {22, 3, 0}}},
|
||||
{"22D68", {13, 2, 1}, "macOS", {"Ventura", {22, 3, 0}}},
|
||||
{"22E252", {13, 3, 0}, "macOS", {"Ventura", {22, 4, 0}}},
|
||||
{"22E261", {13, 3, 1}, "macOS", {"Ventura", {22, 4, 0}}},
|
||||
{"22F66", {13, 4, 0}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22F82", {13, 4, 1}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22E772610a", {13, 4, 1}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22F770820d", {13, 4, 1}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22G74", {13, 5, 0}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G90", {13, 5, 1}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G91", {13, 5, 2}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G120", {13, 6, 0}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G313", {13, 6, 1}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G320", {13, 6, 2}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"23A344", {23, 0, 0}, "macOS", {"Sonoma", {14, 0, 0}}},
|
||||
{"23B74", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 0}}},
|
||||
{"23B81", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}},
|
||||
{"23B2082", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}},
|
||||
{"23B92", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}},
|
||||
{"23B2091", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}},
|
||||
{"23C64", {23, 2, 0}, "macOS", {"Sonoma", {14, 2, 0}}},
|
||||
{"23C71", {23, 2, 0}, "macOS", {"Sonoma", {14, 2, 1}}},
|
||||
{"23D56", {23, 3, 0}, "macOS", {"Sonoma", {14, 3, 0}}},
|
||||
{"23D60", {23, 3, 0}, "macOS", {"Sonoma", {14, 3, 1}}},
|
||||
{"23E214", {23, 4, 0}, "macOS", {"Sonoma", {14, 4, 0}}},
|
||||
{"23E224", {23, 4, 0}, "macOS", {"Sonoma", {14, 4, 1}}},
|
||||
{"23F79", {23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}},
|
||||
{"23G80", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
|
||||
{"23G93", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
|
||||
{"23H124", {23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
|
||||
{"24A335", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
|
||||
{"24A348", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 1}}},
|
||||
gbString sw_vers = gb_string_make(heap_allocator(), "");
|
||||
if (!system_exec_command_line_app_output("sw_vers --productVersion", &sw_vers)) {
|
||||
gb_printf("macOS Unknown\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t major, minor, patch;
|
||||
|
||||
if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) != 3) {
|
||||
gb_printf("macOS Unknown\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (major) {
|
||||
case 15: gb_printf("macOS Sequoia"); break;
|
||||
case 14: gb_printf("macOS Sonoma"); break;
|
||||
case 13: gb_printf("macOS Ventura"); break;
|
||||
case 12: gb_printf("macOS Monterey"); break;
|
||||
case 11: gb_printf("macOS Big Sur"); break;
|
||||
case 10:
|
||||
{
|
||||
switch (minor) {
|
||||
case 15: gb_printf("macOS Catalina"); break;
|
||||
case 14: gb_printf("macOS Mojave"); break;
|
||||
case 13: gb_printf("macOS High Sierra"); break;
|
||||
case 12: gb_printf("macOS Sierra"); break;
|
||||
case 11: gb_printf("OS X El Capitan"); break;
|
||||
case 10: gb_printf("OS X Yosemite"); break;
|
||||
default: gb_printf("macOS Unknown");
|
||||
};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gb_printf("macOS Unknown");
|
||||
};
|
||||
|
||||
gb_printf(" %d.%d.%d (build ", major, minor, patch);
|
||||
|
||||
b32 build_found = 1;
|
||||
b32 darwin_found = 1;
|
||||
uint32_t major, minor, patch;
|
||||
|
||||
#define MACOS_VERSION_BUFFER_SIZE 100
|
||||
char build_buffer[MACOS_VERSION_BUFFER_SIZE];
|
||||
@@ -943,81 +581,25 @@ gb_internal void report_os_info() {
|
||||
|
||||
int darwin_mibs[] = { CTL_KERN, KERN_OSRELEASE };
|
||||
if (sysctl(darwin_mibs, 2, darwin_buffer, &darwin_buffer_size, NULL, 0) == -1) {
|
||||
gb_printf("macOS Unknown\n");
|
||||
return;
|
||||
darwin_found = 0;
|
||||
} else {
|
||||
if (sscanf(darwin_buffer, "%u.%u.%u", &major, &minor, &patch) != 3) {
|
||||
darwin_found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan table for match on BUILD
|
||||
int macos_release_count = sizeof(macos_release_map) / sizeof(macos_release_map[0]);
|
||||
Darwin_To_Release build_match = {};
|
||||
Darwin_To_Release kernel_match = {};
|
||||
|
||||
for (int build = 0; build < macos_release_count; build++) {
|
||||
Darwin_To_Release rel = macos_release_map[build];
|
||||
|
||||
// Do we have an exact match on the BUILD?
|
||||
if (gb_strcmp(rel.build, (const char *)build_buffer) == 0) {
|
||||
build_match = rel;
|
||||
break;
|
||||
}
|
||||
|
||||
// Do we have an exact Darwin match?
|
||||
if (rel.darwin[0] == major && rel.darwin[1] == minor && rel.darwin[2] == patch) {
|
||||
kernel_match = rel;
|
||||
}
|
||||
|
||||
// Major kernel version needs to match exactly,
|
||||
if (rel.darwin[0] == major) {
|
||||
// No major version match yet.
|
||||
if (!kernel_match.os_name) {
|
||||
kernel_match = rel;
|
||||
}
|
||||
if (minor >= rel.darwin[1]) {
|
||||
kernel_match = rel;
|
||||
if (patch >= rel.darwin[2]) {
|
||||
kernel_match = rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Darwin_To_Release match = {};
|
||||
if(!build_match.build) {
|
||||
match = kernel_match;
|
||||
if (build_found) {
|
||||
gb_printf("%s, kernel ", build_buffer);
|
||||
} else {
|
||||
match = build_match;
|
||||
gb_printf("Unknown, kernel ");
|
||||
}
|
||||
|
||||
if (match.os_name) {
|
||||
gb_printf("%s %s %d", match.os_name, match.release.name, match.release.version[0]);
|
||||
if (match.release.version[1] > 0 || match.release.version[2] > 0) {
|
||||
gb_printf(".%d", match.release.version[1]);
|
||||
}
|
||||
if (match.release.version[2] > 0) {
|
||||
gb_printf(".%d", match.release.version[2]);
|
||||
}
|
||||
if (build_found) {
|
||||
gb_printf(" (build: %s, kernel: %d.%d.%d)\n", build_buffer, match.darwin[0], match.darwin[1], match.darwin[2]);
|
||||
} else {
|
||||
gb_printf(" (build: %s?, kernel: %d.%d.%d)\n", match.build, match.darwin[0], match.darwin[1], match.darwin[2]);
|
||||
}
|
||||
return;
|
||||
if (darwin_found) {
|
||||
gb_printf("%s)\n", darwin_buffer);
|
||||
} else {
|
||||
gb_printf("Unknown)\n");
|
||||
}
|
||||
|
||||
if (build_found && darwin_found) {
|
||||
gb_printf("macOS Unknown (build: %s, kernel: %d.%d.%d)\n", build_buffer, major, minor, patch);
|
||||
return;
|
||||
} else if (build_found) {
|
||||
gb_printf("macOS Unknown (build: %s)\n", build_buffer);
|
||||
return;
|
||||
} else if (darwin_found) {
|
||||
gb_printf("macOS Unknown (kernel: %d.%d.%d)\n", major, minor, patch);
|
||||
return;
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OPENBSD) || defined(GB_SYSTEM_NETBSD)
|
||||
struct utsname un;
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#if !defined(GB_COMPILER_MSVC)
|
||||
#if defined(GB_CPU_X86)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
gb_internal void odin_cpuid(int leaf, int result[]) {
|
||||
#if defined(GB_CPU_ARM) || defined(GB_CPU_RISCV)
|
||||
return;
|
||||
|
||||
#elif defined(GB_CPU_X86)
|
||||
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
__cpuid(result, leaf);
|
||||
#else
|
||||
__get_cpuid(leaf, (unsigned int*)&result[0], (unsigned int*)&result[1], (unsigned int*)&result[2], (unsigned int*)&result[3]);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
gb_internal bool should_use_march_native() {
|
||||
#if !defined(GB_CPU_X86)
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
||||
int cpu[4];
|
||||
odin_cpuid(0x1, &cpu[0]); // Get feature information in ECX + EDX
|
||||
|
||||
bool have_popcnt = cpu[2] & (1 << 23); // bit 23 in ECX = popcnt
|
||||
return !have_popcnt;
|
||||
|
||||
#endif
|
||||
}
|
||||
+21
-2
@@ -2,6 +2,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include "build_cpuid.cpp"
|
||||
|
||||
// #if defined(GB_SYSTEM_WINDOWS)
|
||||
// #define DEFAULT_TO_THREADED_CHECKER
|
||||
@@ -343,6 +344,22 @@ struct BuildCacheData {
|
||||
bool copy_already_done;
|
||||
};
|
||||
|
||||
|
||||
enum LinkerChoice : i32 {
|
||||
Linker_Invalid = -1,
|
||||
Linker_Default = 0,
|
||||
Linker_lld,
|
||||
Linker_radlink,
|
||||
|
||||
Linker_COUNT,
|
||||
};
|
||||
|
||||
String linker_choices[Linker_COUNT] = {
|
||||
str_lit("default"),
|
||||
str_lit("lld"),
|
||||
str_lit("radlink"),
|
||||
};
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
@@ -418,12 +435,13 @@ struct BuildContext {
|
||||
bool no_rpath;
|
||||
bool no_entry_point;
|
||||
bool no_thread_local;
|
||||
bool use_lld;
|
||||
bool cross_compiling;
|
||||
bool different_os;
|
||||
bool keep_object_files;
|
||||
bool disallow_do;
|
||||
|
||||
LinkerChoice linker_choice;
|
||||
|
||||
StringSet custom_attributes;
|
||||
|
||||
bool strict_style;
|
||||
@@ -449,6 +467,7 @@ struct BuildContext {
|
||||
BuildCacheData build_cache_data;
|
||||
|
||||
bool internal_no_inline;
|
||||
bool internal_by_value;
|
||||
|
||||
bool no_threaded_checker;
|
||||
|
||||
@@ -1870,7 +1889,7 @@ gb_internal bool init_build_paths(String init_filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!build_context.use_lld && find_result.vs_exe_path.len == 0) {
|
||||
if (build_context.linker_choice == Linker_Default && find_result.vs_exe_path.len == 0) {
|
||||
gb_printf_err("link.exe not found.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
+47
-1
@@ -2565,6 +2565,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
case BuiltinProc_swizzle: {
|
||||
// swizzle :: proc(v: [N]T, ..int) -> [M]T
|
||||
if (!operand->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *original_type = operand->type;
|
||||
Type *type = base_type(original_type);
|
||||
i64 max_count = 0;
|
||||
@@ -2922,6 +2926,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
// imag :: proc(x: type) -> float_type
|
||||
|
||||
Operand *x = operand;
|
||||
if (!x->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_type_untyped(x->type)) {
|
||||
if (x->mode == Addressing_Constant) {
|
||||
if (is_type_numeric(x->type)) {
|
||||
@@ -2982,6 +2990,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
// kmag :: proc(x: type) -> float_type
|
||||
|
||||
Operand *x = operand;
|
||||
if (!x->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_type_untyped(x->type)) {
|
||||
if (x->mode == Addressing_Constant) {
|
||||
if (is_type_numeric(x->type)) {
|
||||
@@ -3031,6 +3043,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
case BuiltinProc_conj: {
|
||||
// conj :: proc(x: type) -> type
|
||||
Operand *x = operand;
|
||||
if (!x->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *t = x->type;
|
||||
Type *elem = core_array_type(t);
|
||||
|
||||
@@ -3071,10 +3087,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
case BuiltinProc_expand_values: {
|
||||
if (!operand->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *type = base_type(operand->type);
|
||||
if (!is_type_struct(type) && !is_type_array(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
error(call, "Expected a struct or array type, got '%s'", type_str);
|
||||
error(call, "Expected a struct or array type to 'expand_values', got '%s'", type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
@@ -3110,8 +3130,13 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
check_multi_expr_or_type(c, operand, ce->args[0]);
|
||||
|
||||
if (!operand->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *original_type = operand->type;
|
||||
Type *type = base_type(operand->type);
|
||||
|
||||
if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) {
|
||||
// Okay
|
||||
} else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
||||
@@ -3184,6 +3209,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ce->args.count <= 1) {
|
||||
error(call, "Too few arguments for 'min', two or more are required");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool all_constant = operand->mode == Addressing_Constant;
|
||||
|
||||
@@ -3278,6 +3307,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
check_multi_expr_or_type(c, operand, ce->args[0]);
|
||||
|
||||
if (!operand->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *original_type = operand->type;
|
||||
Type *type = base_type(operand->type);
|
||||
|
||||
@@ -3357,6 +3390,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ce->args.count <= 1) {
|
||||
error(call, "Too few arguments for 'max', two or more are required");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool all_constant = operand->mode == Addressing_Constant;
|
||||
|
||||
@@ -3448,6 +3486,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
case BuiltinProc_abs: {
|
||||
// abs :: proc(n: numeric) -> numeric
|
||||
if (!operand->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(is_type_numeric(operand->type) && !is_type_array(operand->type))) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
error(call, "Expected a numeric type to 'abs', got '%s'", type_str);
|
||||
@@ -3503,6 +3545,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
case BuiltinProc_clamp: {
|
||||
// clamp :: proc(a, min, max: ordered) -> ordered
|
||||
if (!operand->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *type = operand->type;
|
||||
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
|
||||
+20
-68
@@ -897,20 +897,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_relative_pointer(dst)) {
|
||||
i64 score = check_distance_between_types(c, operand, dst->RelativePointer.pointer_type, allow_array_programming);
|
||||
if (score >= 0) {
|
||||
return score+2;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_relative_multi_pointer(dst)) {
|
||||
i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type, allow_array_programming);
|
||||
if (score >= 0) {
|
||||
return score+2;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_proc(dst)) {
|
||||
if (are_types_identical(src, dst)) {
|
||||
return 3;
|
||||
@@ -1052,12 +1038,6 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
|
||||
case Type_DynamicArray:
|
||||
type = type->DynamicArray.elem;
|
||||
continue;
|
||||
case Type_RelativePointer:
|
||||
type = type->RelativePointer.pointer_type;
|
||||
continue;
|
||||
case Type_RelativeMultiPointer:
|
||||
type = type->RelativeMultiPointer.pointer_type;
|
||||
continue;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -3561,6 +3541,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
|
||||
return false;
|
||||
}
|
||||
|
||||
Operand src = *o;
|
||||
|
||||
Type *src_t = o->type;
|
||||
Type *dst_t = t;
|
||||
Type *src_bt = base_type(src_t);
|
||||
@@ -3649,7 +3631,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
|
||||
// identical casts that cannot be foreseen or otherwise
|
||||
// forbidden, so just skip them.
|
||||
if (forbid_identical && check_vet_flags(c) & VetFlag_Cast &&
|
||||
(c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) {
|
||||
(c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig)) &&
|
||||
check_is_castable_to(c, &src, dst_t)) {
|
||||
if (are_types_identical(src_t, dst_t)) {
|
||||
gbString oper_str = expr_to_string(o->expr);
|
||||
gbString to_type = type_to_string(dst_t);
|
||||
@@ -4471,8 +4454,8 @@ gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
|
||||
}
|
||||
|
||||
gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
||||
GB_ASSERT_NOT_NULL(target_type);
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
// GB_ASSERT_NOT_NULL(target_type);
|
||||
if (target_type == nullptr || operand->mode == Addressing_Invalid ||
|
||||
operand->mode == Addressing_Type ||
|
||||
is_type_typed(operand->type) ||
|
||||
target_type == t_invalid) {
|
||||
@@ -4997,8 +4980,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
|
||||
if (success_) *success_ = true;
|
||||
if (finish_) *finish_ = false;
|
||||
return tav.value;
|
||||
} else if (is_type_proc(tav.type)) {
|
||||
if (success_) *success_ = true;
|
||||
if (finish_) *finish_ = false;
|
||||
return tav.value;
|
||||
} else {
|
||||
GB_ASSERT(is_type_untyped_nil(tav.type));
|
||||
GB_ASSERT_MSG(is_type_untyped_nil(tav.type), "%s", type_to_string(tav.type));
|
||||
if (success_) *success_ = true;
|
||||
if (finish_) *finish_ = false;
|
||||
return tav.value;
|
||||
@@ -8232,17 +8219,6 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_RelativeMultiPointer:
|
||||
{
|
||||
Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
|
||||
GB_ASSERT(pointer_type->kind == Type_MultiPointer);
|
||||
o->type = pointer_type->MultiPointer.elem;
|
||||
if (o->mode != Addressing_Constant) {
|
||||
o->mode = Addressing_Variable;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_DynamicArray:
|
||||
o->type = t->DynamicArray.elem;
|
||||
if (o->mode != Addressing_Constant) {
|
||||
@@ -8481,6 +8457,15 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o,
|
||||
error(node, "Undeclared name '%.*s' for type '%s'", LIT(name), typ);
|
||||
|
||||
check_did_you_mean_type(name, bt->Enum.fields);
|
||||
} else if (is_type_bit_set(th) && is_type_enum(th->BitSet.elem)) {
|
||||
ERROR_BLOCK();
|
||||
|
||||
gbString typ = type_to_string(th);
|
||||
gbString str = expr_to_string(node);
|
||||
error(node, "Cannot convert enum value to '%s'", typ);
|
||||
error_line("\tSuggestion: Did you mean '{ %s }'?\n", str);
|
||||
gb_string_free(typ);
|
||||
gb_string_free(str);
|
||||
} else {
|
||||
gbString typ = type_to_string(th);
|
||||
gbString str = expr_to_string(node);
|
||||
@@ -10616,8 +10601,6 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
// Okay
|
||||
} else if (is_type_string(t)) {
|
||||
// Okay
|
||||
} else if (is_type_relative_multi_pointer(t)) {
|
||||
// Okay
|
||||
} else if (is_type_matrix(t)) {
|
||||
// Okay
|
||||
} else {
|
||||
@@ -10772,11 +10755,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_RelativeMultiPointer:
|
||||
valid = true;
|
||||
o->type = type_deref(o->type);
|
||||
break;
|
||||
|
||||
case Type_EnumeratedArray:
|
||||
{
|
||||
gbString str = expr_to_string(o->expr);
|
||||
@@ -10853,16 +10831,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
x[i:n] -> []T
|
||||
*/
|
||||
o->type = alloc_type_slice(t->MultiPointer.elem);
|
||||
} else if (t->kind == Type_RelativeMultiPointer && se->high != nullptr) {
|
||||
/*
|
||||
x[:] -> [^]T
|
||||
x[i:] -> [^]T
|
||||
x[:n] -> []T
|
||||
x[i:n] -> []T
|
||||
*/
|
||||
Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
|
||||
GB_ASSERT(pointer_type->kind == Type_MultiPointer);
|
||||
o->type = alloc_type_slice(pointer_type->MultiPointer.elem);
|
||||
}
|
||||
|
||||
|
||||
@@ -11223,22 +11191,6 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
} else if (t->kind == Type_SoaPointer) {
|
||||
o->mode = Addressing_SoaVariable;
|
||||
o->type = type_deref(t);
|
||||
} else if (t->kind == Type_RelativePointer) {
|
||||
if (o->mode != Addressing_Variable) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
gbString typ = type_to_string(o->type);
|
||||
error(o->expr, "Cannot dereference relative pointer '%s' of type '%s' as it does not have a variable addressing mode", str, typ);
|
||||
gb_string_free(typ);
|
||||
gb_string_free(str);
|
||||
}
|
||||
|
||||
// NOTE(bill): This is required because when dereferencing, the original type has been lost
|
||||
add_type_info_type(c, o->type);
|
||||
|
||||
Type *ptr_type = base_type(t->RelativePointer.pointer_type);
|
||||
GB_ASSERT(ptr_type->kind == Type_Pointer);
|
||||
o->mode = Addressing_Variable;
|
||||
o->type = ptr_type->Pointer.elem;
|
||||
} else {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
gbString typ = type_to_string(o->type);
|
||||
|
||||
@@ -2605,6 +2605,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
if (cond && cond->kind == Ast_BinaryExpr &&
|
||||
cond->BinaryExpr.left && cond->BinaryExpr.right &&
|
||||
cond->BinaryExpr.op.kind == Token_GtEq &&
|
||||
type_of_expr(cond->BinaryExpr.left) != nullptr &&
|
||||
is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) &&
|
||||
cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer &&
|
||||
is_exact_value_zero(cond->BinaryExpr.right->tav.value)) {
|
||||
@@ -2612,6 +2613,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
} else if (cond && cond->kind == Ast_BinaryExpr &&
|
||||
cond->BinaryExpr.left && cond->BinaryExpr.right &&
|
||||
cond->BinaryExpr.op.kind == Token_LtEq &&
|
||||
type_of_expr(cond->BinaryExpr.right) != nullptr &&
|
||||
is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) &&
|
||||
cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer &&
|
||||
is_exact_value_zero(cond->BinaryExpr.left->tav.value)) {
|
||||
|
||||
+3
-37
@@ -2366,8 +2366,7 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res
|
||||
}
|
||||
|
||||
gb_internal void check_procedure_param_polymorphic_type(CheckerContext *ctx, Type *type, Ast *type_expr) {
|
||||
GB_ASSERT_NOT_NULL(type_expr);
|
||||
if (type == nullptr || ctx->in_polymorphic_specialization) { return; }
|
||||
if (type == nullptr || type_expr == nullptr || ctx->in_polymorphic_specialization) { return; }
|
||||
if (!is_type_polymorphic_record_unspecialized(type)) { return; }
|
||||
|
||||
bool invalid_polymorpic_type_use = false;
|
||||
@@ -3517,41 +3516,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
||||
case_end;
|
||||
|
||||
case_ast_node(rt, RelativeType, e);
|
||||
GB_ASSERT(rt->tag->kind == Ast_CallExpr);
|
||||
ast_node(ce, CallExpr, rt->tag);
|
||||
|
||||
Type *base_integer = nullptr;
|
||||
|
||||
if (ce->args.count != 1) {
|
||||
error(rt->type, "#relative expected 1 type argument, got %td", ce->args.count);
|
||||
} else {
|
||||
base_integer = check_type(ctx, ce->args[0]);
|
||||
if (!is_type_integer(base_integer)) {
|
||||
error(rt->type, "#relative base types must be an integer");
|
||||
base_integer = nullptr;
|
||||
} else if (type_size_of(base_integer) > 64) {
|
||||
error(rt->type, "#relative base integer types be less than or equal to 64-bits");
|
||||
base_integer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Type *relative_type = nullptr;
|
||||
Type *base_type = check_type(ctx, rt->type);
|
||||
if (!is_type_pointer(base_type) && !is_type_multi_pointer(base_type)) {
|
||||
error(rt->type, "#relative types can only be a pointer or multi-pointer");
|
||||
relative_type = base_type;
|
||||
} else if (base_integer == nullptr) {
|
||||
relative_type = base_type;
|
||||
} else {
|
||||
if (is_type_pointer(base_type)) {
|
||||
relative_type = alloc_type_relative_pointer(base_type, base_integer);
|
||||
} else if (is_type_multi_pointer(base_type)) {
|
||||
relative_type = alloc_type_relative_multi_pointer(base_type, base_integer);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(relative_type != nullptr);
|
||||
|
||||
*type = relative_type;
|
||||
error(e, "#relative types have been removed from the compiler. Prefer \"core:relative\".");
|
||||
*type = t_invalid;
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
@@ -2186,16 +2186,6 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
|
||||
add_type_info_type_internal(c, bt->SimdVector.elem);
|
||||
break;
|
||||
|
||||
case Type_RelativePointer:
|
||||
add_type_info_type_internal(c, bt->RelativePointer.pointer_type);
|
||||
add_type_info_type_internal(c, bt->RelativePointer.base_integer);
|
||||
break;
|
||||
|
||||
case Type_RelativeMultiPointer:
|
||||
add_type_info_type_internal(c, bt->RelativeMultiPointer.pointer_type);
|
||||
add_type_info_type_internal(c, bt->RelativeMultiPointer.base_integer);
|
||||
break;
|
||||
|
||||
case Type_Matrix:
|
||||
add_type_info_type_internal(c, bt->Matrix.elem);
|
||||
break;
|
||||
@@ -2441,16 +2431,6 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
|
||||
add_min_dep_type_info(c, bt->SimdVector.elem);
|
||||
break;
|
||||
|
||||
case Type_RelativePointer:
|
||||
add_min_dep_type_info(c, bt->RelativePointer.pointer_type);
|
||||
add_min_dep_type_info(c, bt->RelativePointer.base_integer);
|
||||
break;
|
||||
|
||||
case Type_RelativeMultiPointer:
|
||||
add_min_dep_type_info(c, bt->RelativeMultiPointer.pointer_type);
|
||||
add_min_dep_type_info(c, bt->RelativeMultiPointer.base_integer);
|
||||
break;
|
||||
|
||||
case Type_Matrix:
|
||||
add_min_dep_type_info(c, bt->Matrix.elem);
|
||||
break;
|
||||
@@ -3075,8 +3055,6 @@ gb_internal void init_core_type_info(Checker *c) {
|
||||
t_type_info_map = find_core_type(c, str_lit("Type_Info_Map"));
|
||||
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
|
||||
t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
|
||||
t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer"));
|
||||
t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer"));
|
||||
t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix"));
|
||||
t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
|
||||
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
|
||||
@@ -3105,8 +3083,6 @@ gb_internal void init_core_type_info(Checker *c) {
|
||||
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
|
||||
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
|
||||
t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector);
|
||||
t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer);
|
||||
t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer);
|
||||
t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix);
|
||||
t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer);
|
||||
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
|
||||
|
||||
+1
-2
@@ -79,8 +79,7 @@ enum OdinDocTypeKind : u32 {
|
||||
OdinDocType_SOAStructFixed = 17,
|
||||
OdinDocType_SOAStructSlice = 18,
|
||||
OdinDocType_SOAStructDynamic = 19,
|
||||
OdinDocType_RelativePointer = 20,
|
||||
OdinDocType_RelativeMultiPointer = 21,
|
||||
|
||||
OdinDocType_MultiPointer = 22,
|
||||
OdinDocType_Matrix = 23,
|
||||
OdinDocType_SoaPointer = 24,
|
||||
|
||||
@@ -776,24 +776,6 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
doc_type.types = odin_doc_type_as_slice(w, type->SimdVector.elem);
|
||||
// TODO(bill):
|
||||
break;
|
||||
case Type_RelativePointer:
|
||||
doc_type.kind = OdinDocType_RelativePointer;
|
||||
{
|
||||
OdinDocTypeIndex types[2] = {};
|
||||
types[0] = odin_doc_type(w, type->RelativePointer.pointer_type);
|
||||
types[1] = odin_doc_type(w, type->RelativePointer.base_integer);
|
||||
doc_type.types = odin_write_slice(w, types, gb_count_of(types));
|
||||
}
|
||||
break;
|
||||
case Type_RelativeMultiPointer:
|
||||
doc_type.kind = OdinDocType_RelativeMultiPointer;
|
||||
{
|
||||
OdinDocTypeIndex types[2] = {};
|
||||
types[0] = odin_doc_type(w, type->RelativeMultiPointer.pointer_type);
|
||||
types[1] = odin_doc_type(w, type->RelativeMultiPointer.base_integer);
|
||||
doc_type.types = odin_write_slice(w, types, gb_count_of(types));
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Matrix:
|
||||
doc_type.kind = OdinDocType_Matrix;
|
||||
|
||||
+5
-1
@@ -370,7 +370,11 @@ gb_internal ExactValue exact_value_from_basic_literal(TokenKind kind, String con
|
||||
}
|
||||
case Token_Rune: {
|
||||
Rune r = GB_RUNE_INVALID;
|
||||
utf8_decode(string.text, string.len, &r);
|
||||
if (string.len == 1) {
|
||||
r = cast(Rune)string.text[0];
|
||||
} else {
|
||||
utf8_decode(string.text, string.len, &r);
|
||||
}
|
||||
return exact_value_i64(r);
|
||||
}
|
||||
}
|
||||
|
||||
+49
-23
@@ -167,8 +167,10 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
|
||||
if (is_windows) {
|
||||
String section_name = str_lit("msvc-link");
|
||||
if (build_context.use_lld) {
|
||||
section_name = str_lit("lld-link");
|
||||
switch (build_context.linker_choice) {
|
||||
case Linker_Default: break;
|
||||
case Linker_lld: section_name = str_lit("lld-link"); break;
|
||||
case Linker_radlink: section_name = str_lit("rad-link"); break;
|
||||
}
|
||||
timings_start_section(timings, section_name);
|
||||
|
||||
@@ -304,7 +306,48 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
|
||||
defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
|
||||
|
||||
if (!build_context.use_lld) { // msvc
|
||||
switch (build_context.linker_choice) {
|
||||
case Linker_lld:
|
||||
result = system_exec_command_line_app("msvc-lld-link",
|
||||
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%.*s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case Linker_radlink:
|
||||
result = system_exec_command_line_app("msvc-rad-link",
|
||||
"\"%.*s\\bin\\radlink\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%.*s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
default: { // msvc
|
||||
String res_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RES]);
|
||||
String rc_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RC]);
|
||||
defer (gb_free(heap_allocator(), res_path.text));
|
||||
@@ -365,25 +408,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
} else { // lld
|
||||
result = system_exec_command_line_app("msvc-lld-link",
|
||||
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%.*s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
timings_start_section(timings, str_lit("ld-link"));
|
||||
@@ -679,7 +705,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
|
||||
|
||||
if (build_context.use_lld) {
|
||||
if (build_context.linker_choice == Linker_lld) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
|
||||
result = system_exec_command_line_app("lld-link", link_command_line);
|
||||
} else {
|
||||
|
||||
@@ -57,6 +57,10 @@
|
||||
#define LB_USE_NEW_PASS_SYSTEM 0
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
#define LLVMDIBuilderInsertDeclareAtEnd(...) LLVMDIBuilderInsertDeclareRecordAtEnd(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
gb_internal bool lb_use_new_pass_system(void) {
|
||||
return LB_USE_NEW_PASS_SYSTEM;
|
||||
}
|
||||
@@ -75,7 +79,6 @@ enum lbAddrKind {
|
||||
lbAddr_Context,
|
||||
lbAddr_SoaVariable,
|
||||
|
||||
lbAddr_RelativePointer,
|
||||
|
||||
lbAddr_Swizzle,
|
||||
lbAddr_SwizzleLarge,
|
||||
@@ -103,9 +106,6 @@ struct lbAddr {
|
||||
lbValue index;
|
||||
Ast *node;
|
||||
} index_set;
|
||||
struct {
|
||||
bool deref;
|
||||
} relative;
|
||||
struct {
|
||||
Type *type;
|
||||
u8 count; // 2, 3, or 4 components
|
||||
@@ -741,4 +741,4 @@ gb_global char const *llvm_linkage_strings[] = {
|
||||
"linker private weak linkage"
|
||||
};
|
||||
|
||||
#define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
|
||||
#define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
|
||||
|
||||
@@ -920,17 +920,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
elem, subscripts, gb_count_of(subscripts));
|
||||
}
|
||||
|
||||
case Type_RelativePointer: {
|
||||
LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativePointer.base_integer);
|
||||
gbString name = type_to_string(type, temporary_allocator());
|
||||
return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
|
||||
}
|
||||
case Type_RelativeMultiPointer: {
|
||||
LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativeMultiPointer.base_integer);
|
||||
gbString name = type_to_string(type, temporary_allocator());
|
||||
return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
|
||||
}
|
||||
|
||||
case Type_Matrix: {
|
||||
LLVMMetadataRef subscripts[1] = {};
|
||||
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
|
||||
|
||||
+11
-38
@@ -4200,30 +4200,6 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
return lb_addr(v);
|
||||
}
|
||||
|
||||
case Type_RelativeMultiPointer: {
|
||||
lbAddr rel_ptr_addr = {};
|
||||
if (deref) {
|
||||
lbValue rel_ptr_ptr = lb_build_expr(p, ie->expr);
|
||||
rel_ptr_addr = lb_addr(rel_ptr_ptr);
|
||||
} else {
|
||||
rel_ptr_addr = lb_build_addr(p, ie->expr);
|
||||
}
|
||||
lbValue rel_ptr = lb_relative_pointer_to_pointer(p, rel_ptr_addr);
|
||||
|
||||
lbValue index = lb_build_expr(p, ie->index);
|
||||
index = lb_emit_conv(p, index, t_int);
|
||||
lbValue v = {};
|
||||
|
||||
Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
|
||||
GB_ASSERT(pointer_type->kind == Type_MultiPointer);
|
||||
Type *elem = pointer_type->MultiPointer.elem;
|
||||
|
||||
LLVMValueRef indices[1] = {index.value};
|
||||
v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, elem), rel_ptr.value, indices, 1, "");
|
||||
v.type = alloc_type_pointer(elem);
|
||||
return lb_addr(v);
|
||||
}
|
||||
|
||||
case Type_DynamicArray: {
|
||||
lbValue dynamic_array = {};
|
||||
dynamic_array = lb_build_expr(p, ie->expr);
|
||||
@@ -4333,13 +4309,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
|
||||
return slice;
|
||||
}
|
||||
|
||||
case Type_RelativePointer:
|
||||
GB_PANIC("TODO(bill): Type_RelativePointer should be handled above already on the lb_addr_load");
|
||||
break;
|
||||
case Type_RelativeMultiPointer:
|
||||
GB_PANIC("TODO(bill): Type_RelativeMultiPointer should be handled above already on the lb_addr_load");
|
||||
break;
|
||||
|
||||
case Type_DynamicArray: {
|
||||
Type *elem_type = type->DynamicArray.elem;
|
||||
Type *slice_type = alloc_type_slice(elem_type);
|
||||
@@ -4605,7 +4574,11 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
auto const &f = fields[i];
|
||||
|
||||
LLVMValueRef mask = LLVMConstInt(lit, 1, false);
|
||||
mask = LLVMConstShl(mask, LLVMConstInt(lit, f.bit_size, false));
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
mask = LLVMBuildShl(p->builder, mask, LLVMConstInt(lit, f.bit_size, false), "");
|
||||
#else
|
||||
mask = LLVMConstShl(mask, LLVMConstInt(lit, f.bit_size, false));
|
||||
#endif
|
||||
mask = LLVMConstSub(mask, LLVMConstInt(lit, 1, false));
|
||||
|
||||
LLVMValueRef elem = values[i].value;
|
||||
@@ -4653,7 +4626,11 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
bits_to_set -= mask_width;
|
||||
|
||||
LLVMValueRef mask = LLVMConstInt(vt, 1, false);
|
||||
mask = LLVMConstShl(mask, LLVMConstInt(vt, mask_width, false));
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
mask = LLVMBuildShl(p->builder, mask, LLVMConstInt(vt, mask_width, false), "");
|
||||
#else
|
||||
mask = LLVMConstShl(mask, LLVMConstInt(vt, mask_width, false));
|
||||
#endif
|
||||
mask = LLVMConstSub(mask, LLVMConstInt(vt, 1, false));
|
||||
|
||||
LLVMValueRef to_set = LLVMBuildAnd(p->builder, val, mask, "");
|
||||
@@ -5343,11 +5320,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
|
||||
|
||||
case_ast_node(de, DerefExpr, expr);
|
||||
Type *t = type_of_expr(de->expr);
|
||||
if (is_type_relative_pointer(t)) {
|
||||
lbAddr addr = lb_build_addr(p, de->expr);
|
||||
addr.relative.deref = true;
|
||||
return addr;
|
||||
} else if (is_type_soa_pointer(t)) {
|
||||
if (is_type_soa_pointer(t)) {
|
||||
lbValue value = lb_build_expr(p, de->expr);
|
||||
lbValue ptr = lb_emit_struct_ev(p, value, 0);
|
||||
lbValue idx = lb_emit_struct_ev(p, value, 1);
|
||||
|
||||
@@ -409,14 +409,6 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
|
||||
|
||||
gb_internal lbAddr lb_addr(lbValue addr) {
|
||||
lbAddr v = {lbAddr_Default, addr};
|
||||
if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) {
|
||||
GB_ASSERT(is_type_pointer(addr.type));
|
||||
v.kind = lbAddr_RelativePointer;
|
||||
} else if (addr.type != nullptr && is_type_relative_multi_pointer(type_deref(addr.type))) {
|
||||
GB_ASSERT(is_type_pointer(addr.type) ||
|
||||
is_type_multi_pointer(addr.type));
|
||||
v.kind = lbAddr_RelativePointer;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -501,42 +493,6 @@ gb_internal Type *lb_addr_type(lbAddr const &addr) {
|
||||
return type_deref(addr.addr.type);
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbValue lb_relative_pointer_to_pointer(lbProcedure *p, lbAddr const &addr) {
|
||||
GB_ASSERT(addr.kind == lbAddr_RelativePointer);
|
||||
|
||||
Type *t = base_type(lb_addr_type(addr));
|
||||
GB_ASSERT(is_type_relative_pointer(t) || is_type_relative_multi_pointer(t));
|
||||
|
||||
Type *pointer_type = nullptr;
|
||||
Type *base_integer = nullptr;
|
||||
if (t->kind == Type_RelativePointer) {
|
||||
pointer_type = t->RelativePointer.pointer_type;
|
||||
base_integer = t->RelativePointer.base_integer;
|
||||
} else if (t->kind == Type_RelativeMultiPointer) {
|
||||
pointer_type = t->RelativeMultiPointer.pointer_type;
|
||||
base_integer = t->RelativeMultiPointer.base_integer;
|
||||
}
|
||||
|
||||
lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
|
||||
lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer));
|
||||
offset = lb_emit_load(p, offset);
|
||||
|
||||
if (!is_type_unsigned(base_integer)) {
|
||||
offset = lb_emit_conv(p, offset, t_i64);
|
||||
}
|
||||
offset = lb_emit_conv(p, offset, t_uintptr);
|
||||
lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr);
|
||||
absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type);
|
||||
|
||||
lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer));
|
||||
|
||||
// NOTE(bill): nil check
|
||||
lbValue nil_ptr = lb_const_nil(p->module, pointer_type);
|
||||
lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr);
|
||||
return final_ptr;
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
|
||||
lbAddr v = lb_add_local_generated(p, type, false);
|
||||
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
|
||||
@@ -557,9 +513,6 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
||||
case lbAddr_Map:
|
||||
return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||
|
||||
case lbAddr_RelativePointer:
|
||||
return lb_relative_pointer_to_pointer(p, addr);
|
||||
|
||||
case lbAddr_SoaVariable:
|
||||
{
|
||||
Type *soa_ptr_type = alloc_type_soa_pointer(lb_addr_type(addr));
|
||||
@@ -584,9 +537,6 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
||||
|
||||
gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) {
|
||||
lbAddr addr = lb_build_addr(p, expr);
|
||||
if (addr.kind == lbAddr_RelativePointer) {
|
||||
return addr.addr;
|
||||
}
|
||||
return lb_addr_get_ptr(p, addr);
|
||||
}
|
||||
|
||||
@@ -819,10 +769,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
value.value = LLVMConstNull(lb_type(p->module, t));
|
||||
}
|
||||
|
||||
if (addr.kind == lbAddr_RelativePointer && addr.relative.deref) {
|
||||
addr = lb_addr(lb_address_from_load(p, lb_addr_load(p, addr)));
|
||||
}
|
||||
|
||||
if (addr.kind == lbAddr_BitField) {
|
||||
lbValue dst = addr.addr;
|
||||
if (is_type_endian_big(addr.bitfield.type)) {
|
||||
@@ -860,44 +806,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
lb_emit_runtime_call(p, "__write_bits", args);
|
||||
}
|
||||
return;
|
||||
} else if (addr.kind == lbAddr_RelativePointer) {
|
||||
Type *rel_ptr = base_type(lb_addr_type(addr));
|
||||
GB_ASSERT(rel_ptr->kind == Type_RelativePointer ||
|
||||
rel_ptr->kind == Type_RelativeMultiPointer);
|
||||
Type *pointer_type = nullptr;
|
||||
Type *base_integer = nullptr;
|
||||
|
||||
if (rel_ptr->kind == Type_RelativePointer) {
|
||||
pointer_type = rel_ptr->RelativePointer.pointer_type;
|
||||
base_integer = rel_ptr->RelativePointer.base_integer;
|
||||
} else if (rel_ptr->kind == Type_RelativeMultiPointer) {
|
||||
pointer_type = rel_ptr->RelativeMultiPointer.pointer_type;
|
||||
base_integer = rel_ptr->RelativeMultiPointer.base_integer;
|
||||
}
|
||||
|
||||
value = lb_emit_conv(p, value, pointer_type);
|
||||
|
||||
GB_ASSERT(is_type_pointer(addr.addr.type));
|
||||
lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
|
||||
lbValue val_ptr = lb_emit_conv(p, value, t_uintptr);
|
||||
lbValue offset = {};
|
||||
offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, "");
|
||||
offset.type = t_uintptr;
|
||||
|
||||
if (!is_type_unsigned(base_integer)) {
|
||||
offset = lb_emit_conv(p, offset, t_i64);
|
||||
}
|
||||
offset = lb_emit_conv(p, offset, base_integer);
|
||||
|
||||
lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(base_integer));
|
||||
offset = lb_emit_select(p,
|
||||
lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)),
|
||||
lb_const_nil(p->module, base_integer),
|
||||
offset
|
||||
);
|
||||
LLVMBuildStore(p->builder, offset.value, offset_ptr.value);
|
||||
return;
|
||||
|
||||
} else if (addr.kind == lbAddr_Map) {
|
||||
lb_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
||||
return;
|
||||
@@ -1246,46 +1154,6 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
||||
}
|
||||
|
||||
return r;
|
||||
} else if (addr.kind == lbAddr_RelativePointer) {
|
||||
Type *rel_ptr = base_type(lb_addr_type(addr));
|
||||
Type *base_integer = nullptr;
|
||||
Type *pointer_type = nullptr;
|
||||
GB_ASSERT(rel_ptr->kind == Type_RelativePointer ||
|
||||
rel_ptr->kind == Type_RelativeMultiPointer);
|
||||
|
||||
if (rel_ptr->kind == Type_RelativePointer) {
|
||||
base_integer = rel_ptr->RelativePointer.base_integer;
|
||||
pointer_type = rel_ptr->RelativePointer.pointer_type;
|
||||
} else if (rel_ptr->kind == Type_RelativeMultiPointer) {
|
||||
base_integer = rel_ptr->RelativeMultiPointer.base_integer;
|
||||
pointer_type = rel_ptr->RelativeMultiPointer.pointer_type;
|
||||
}
|
||||
|
||||
lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
|
||||
lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer));
|
||||
offset = lb_emit_load(p, offset);
|
||||
|
||||
|
||||
if (!is_type_unsigned(base_integer)) {
|
||||
offset = lb_emit_conv(p, offset, t_i64);
|
||||
}
|
||||
offset = lb_emit_conv(p, offset, t_uintptr);
|
||||
lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr);
|
||||
absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type);
|
||||
|
||||
lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer));
|
||||
|
||||
// NOTE(bill): nil check
|
||||
lbValue nil_ptr = lb_const_nil(p->module, pointer_type);
|
||||
lbValue final_ptr = {};
|
||||
final_ptr.type = absolute_ptr.type;
|
||||
final_ptr.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, "");
|
||||
|
||||
if (rel_ptr->kind == Type_RelativeMultiPointer) {
|
||||
return final_ptr;
|
||||
}
|
||||
return lb_emit_load(p, final_ptr);
|
||||
|
||||
} else if (addr.kind == lbAddr_Map) {
|
||||
Type *map_type = base_type(type_deref(addr.addr.type));
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
@@ -2378,13 +2246,6 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
|
||||
case Type_SimdVector:
|
||||
return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count);
|
||||
|
||||
case Type_RelativePointer:
|
||||
return lb_type_internal(m, type->RelativePointer.base_integer);
|
||||
case Type_RelativeMultiPointer:
|
||||
return lb_type_internal(m, type->RelativeMultiPointer.base_integer);
|
||||
|
||||
|
||||
|
||||
case Type_Matrix:
|
||||
{
|
||||
@@ -2740,7 +2601,7 @@ general_end:;
|
||||
GB_ASSERT(p->decl_block != p->curr_block);
|
||||
|
||||
i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
|
||||
max_align = gb_max(max_align, 4);
|
||||
max_align = gb_max(max_align, 16);
|
||||
|
||||
LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align);
|
||||
|
||||
|
||||
@@ -579,6 +579,8 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
|
||||
p->raw_input_parameters = array_make<LLVMValueRef>(permanent_allocator(), raw_input_parameters_count);
|
||||
LLVMGetParams(p->value, p->raw_input_parameters.data);
|
||||
|
||||
bool is_odin_cc = is_calling_convention_odin(ft->calling_convention);
|
||||
|
||||
unsigned param_index = 0;
|
||||
for_array(i, params->variables) {
|
||||
Entity *e = params->variables[i];
|
||||
@@ -613,9 +615,26 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
|
||||
}
|
||||
} else if (arg_type->kind == lbArg_Indirect) {
|
||||
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
|
||||
i64 sz = type_size_of(e->type);
|
||||
bool do_callee_copy = false;
|
||||
|
||||
if (is_odin_cc) {
|
||||
do_callee_copy = sz <= 16;
|
||||
if (build_context.internal_by_value) {
|
||||
do_callee_copy = true;
|
||||
}
|
||||
}
|
||||
|
||||
lbValue ptr = {};
|
||||
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
|
||||
ptr.type = alloc_type_pointer(e->type);
|
||||
|
||||
if (do_callee_copy) {
|
||||
lbValue new_ptr = lb_add_local_generated(p, e->type, false).addr;
|
||||
lb_mem_copy_non_overlapping(p, new_ptr, ptr, lb_const_int(p->module, t_uint, sz));
|
||||
ptr = new_ptr;
|
||||
}
|
||||
|
||||
lb_add_entity(p->module, e, ptr);
|
||||
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block);
|
||||
}
|
||||
|
||||
@@ -201,6 +201,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) {
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT(s != nullptr);
|
||||
p->curr_scope = s;
|
||||
p->scope_index += 1;
|
||||
array_add(&p->scope_stack, s);
|
||||
|
||||
@@ -221,6 +223,10 @@ gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *b
|
||||
|
||||
}
|
||||
|
||||
if (p->curr_scope) {
|
||||
p->curr_scope = p->curr_scope->parent;
|
||||
}
|
||||
|
||||
p->scope_index -= 1;
|
||||
array_pop(&p->scope_stack);
|
||||
}
|
||||
|
||||
@@ -61,8 +61,6 @@ gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
|
||||
case Type_Proc: kind = Typeid_Procedure; break;
|
||||
case Type_BitSet: kind = Typeid_Bit_Set; break;
|
||||
case Type_SimdVector: kind = Typeid_Simd_Vector; break;
|
||||
case Type_RelativePointer: kind = Typeid_Relative_Pointer; break;
|
||||
case Type_RelativeMultiPointer: kind = Typeid_Relative_Multi_Pointer; break;
|
||||
case Type_SoaPointer: kind = Typeid_SoaPointer; break;
|
||||
case Type_BitField: kind = Typeid_Bit_Field; break;
|
||||
}
|
||||
@@ -950,30 +948,6 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_RelativePointer:
|
||||
{
|
||||
tag_type = t_type_info_relative_pointer;
|
||||
LLVMValueRef vals[2] = {
|
||||
get_type_info_ptr(m, t->RelativePointer.pointer_type),
|
||||
get_type_info_ptr(m, t->RelativePointer.base_integer),
|
||||
};
|
||||
|
||||
variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals));
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_RelativeMultiPointer:
|
||||
{
|
||||
tag_type = t_type_info_relative_multi_pointer;
|
||||
LLVMValueRef vals[2] = {
|
||||
get_type_info_ptr(m, t->RelativeMultiPointer.pointer_type),
|
||||
get_type_info_ptr(m, t->RelativeMultiPointer.base_integer),
|
||||
};
|
||||
|
||||
variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals));
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Matrix:
|
||||
{
|
||||
tag_type = t_type_info_matrix;
|
||||
|
||||
@@ -124,8 +124,16 @@ gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, u
|
||||
switch (kind) {
|
||||
case LLVMStructTypeKind:
|
||||
case LLVMArrayTypeKind:
|
||||
// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
|
||||
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
|
||||
if (is_type_tuple(type)) {
|
||||
// NOTE(bill): even though this should be safe, to keep ASAN happy, do not zero the implicit padding at the end
|
||||
GB_ASSERT(type->kind == Type_Tuple);
|
||||
i64 n = type->Tuple.variables.count-1;
|
||||
i64 end_offset = type->Tuple.offsets[n] + type_size_of(type->Tuple.variables[n]->type);
|
||||
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, end_offset).value, alignment, false);
|
||||
} else {
|
||||
// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
|
||||
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr);
|
||||
@@ -1123,10 +1131,6 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
|
||||
Type *t = base_type(type_deref(s.type));
|
||||
Type *result_type = nullptr;
|
||||
|
||||
if (is_type_relative_pointer(t)) {
|
||||
s = lb_addr_get_ptr(p, lb_addr(s));
|
||||
}
|
||||
|
||||
if (is_type_struct(t)) {
|
||||
result_type = get_struct_field_type(t, index);
|
||||
} else if (is_type_union(t)) {
|
||||
@@ -1432,8 +1436,6 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection
|
||||
e = lb_emit_array_epi(p, e, index);
|
||||
} else if (type->kind == Type_Map) {
|
||||
e = lb_emit_struct_ep(p, e, index);
|
||||
} else if (type->kind == Type_RelativePointer) {
|
||||
e = lb_emit_struct_ep(p, e, index);
|
||||
} else {
|
||||
GB_PANIC("un-gep-able type %s", type_to_string(type));
|
||||
}
|
||||
|
||||
+492
-377
File diff suppressed because it is too large
Load Diff
@@ -2488,6 +2488,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
tag = parse_call_expr(f, tag);
|
||||
}
|
||||
Ast *type = parse_type(f);
|
||||
syntax_error(tag, "#relative types have now been removed in favour of \"core:relative\"");
|
||||
return ast_relative_type(f, tag, type);
|
||||
} else if (name.string == "force_inline" ||
|
||||
name.string == "force_no_inline") {
|
||||
|
||||
+35
-5
@@ -412,6 +412,32 @@ gb_internal String concatenate4_strings(gbAllocator a, String const &x, String c
|
||||
return make_string(data, len);
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
gb_internal String escape_char(gbAllocator a, String s, char cte) {
|
||||
isize buf_len = s.len;
|
||||
isize cte_count = 0;
|
||||
for (isize j = 0; j < s.len; j++) {
|
||||
if (s.text[j] == cte) {
|
||||
cte_count++;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *buf = gb_alloc_array(a, u8, buf_len+cte_count);
|
||||
isize i = 0;
|
||||
for (isize j = 0; j < s.len; j++) {
|
||||
u8 c = s.text[j];
|
||||
|
||||
if (c == cte) {
|
||||
buf[i++] = '\\';
|
||||
buf[i++] = c;
|
||||
} else {
|
||||
buf[i++] = c;
|
||||
}
|
||||
}
|
||||
return make_string(buf, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
gb_internal String string_join_and_quote(gbAllocator a, Array<String> strings) {
|
||||
if (!strings.count) {
|
||||
return make_string(nullptr, 0);
|
||||
@@ -427,7 +453,11 @@ gb_internal String string_join_and_quote(gbAllocator a, Array<String> strings) {
|
||||
if (i > 0) {
|
||||
s = gb_string_append_fmt(s, " ");
|
||||
}
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
s = gb_string_append_fmt(s, "\"%.*s\" ", LIT(escape_char(a, strings[i], '\\')));
|
||||
#else
|
||||
s = gb_string_append_fmt(s, "\"%.*s\" ", LIT(strings[i]));
|
||||
#endif
|
||||
}
|
||||
|
||||
return make_string(cast(u8 *) s, gb_string_length(s));
|
||||
@@ -688,12 +718,12 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt
|
||||
Rune r = -1;
|
||||
isize size = utf8_decode(s.text, s.len, &r);
|
||||
*rune = r;
|
||||
*multiple_bytes = true;
|
||||
*tail_string = make_string(s.text+size, s.len-size);
|
||||
if (multiple_bytes) *multiple_bytes = true;
|
||||
if (tail_string) *tail_string = make_string(s.text+size, s.len-size);
|
||||
return true;
|
||||
} else if (s[0] != '\\') {
|
||||
*rune = s[0];
|
||||
*tail_string = make_string(s.text+1, s.len-1);
|
||||
if (tail_string) *tail_string = make_string(s.text+1, s.len-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -779,10 +809,10 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt
|
||||
return false;
|
||||
}
|
||||
*rune = r;
|
||||
*multiple_bytes = true;
|
||||
if (multiple_bytes) *multiple_bytes = true;
|
||||
} break;
|
||||
}
|
||||
*tail_string = s;
|
||||
if (tail_string) *tail_string = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+7
-101
@@ -272,14 +272,6 @@ struct TypeProc {
|
||||
Type *elem; \
|
||||
Type *generic_count; \
|
||||
}) \
|
||||
TYPE_KIND(RelativePointer, struct { \
|
||||
Type *pointer_type; \
|
||||
Type *base_integer; \
|
||||
}) \
|
||||
TYPE_KIND(RelativeMultiPointer, struct { \
|
||||
Type *pointer_type; \
|
||||
Type *base_integer; \
|
||||
}) \
|
||||
TYPE_KIND(Matrix, struct { \
|
||||
Type *elem; \
|
||||
i64 row_count; \
|
||||
@@ -367,8 +359,6 @@ enum Typeid_Kind : u8 {
|
||||
Typeid_Map,
|
||||
Typeid_Bit_Set,
|
||||
Typeid_Simd_Vector,
|
||||
Typeid_Relative_Pointer,
|
||||
Typeid_Relative_Multi_Pointer,
|
||||
Typeid_Matrix,
|
||||
Typeid_SoaPointer,
|
||||
Typeid_Bit_Field,
|
||||
@@ -678,8 +668,6 @@ gb_global Type *t_type_info_enum = nullptr;
|
||||
gb_global Type *t_type_info_map = nullptr;
|
||||
gb_global Type *t_type_info_bit_set = nullptr;
|
||||
gb_global Type *t_type_info_simd_vector = nullptr;
|
||||
gb_global Type *t_type_info_relative_pointer = nullptr;
|
||||
gb_global Type *t_type_info_relative_multi_pointer = nullptr;
|
||||
gb_global Type *t_type_info_matrix = nullptr;
|
||||
gb_global Type *t_type_info_soa_pointer = nullptr;
|
||||
gb_global Type *t_type_info_bit_field = nullptr;
|
||||
@@ -708,8 +696,6 @@ gb_global Type *t_type_info_enum_ptr = nullptr;
|
||||
gb_global Type *t_type_info_map_ptr = nullptr;
|
||||
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
||||
gb_global Type *t_type_info_simd_vector_ptr = nullptr;
|
||||
gb_global Type *t_type_info_relative_pointer_ptr = nullptr;
|
||||
gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr;
|
||||
gb_global Type *t_type_info_matrix_ptr = nullptr;
|
||||
gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
|
||||
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
||||
@@ -1118,24 +1104,6 @@ gb_internal Type *alloc_type_bit_field() {
|
||||
return t;
|
||||
}
|
||||
|
||||
gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) {
|
||||
GB_ASSERT(is_type_pointer(pointer_type));
|
||||
GB_ASSERT(is_type_integer(base_integer));
|
||||
Type *t = alloc_type(Type_RelativePointer);
|
||||
t->RelativePointer.pointer_type = pointer_type;
|
||||
t->RelativePointer.base_integer = base_integer;
|
||||
return t;
|
||||
}
|
||||
|
||||
gb_internal Type *alloc_type_relative_multi_pointer(Type *pointer_type, Type *base_integer) {
|
||||
GB_ASSERT(is_type_multi_pointer(pointer_type));
|
||||
GB_ASSERT(is_type_integer(base_integer));
|
||||
Type *t = alloc_type(Type_RelativeMultiPointer);
|
||||
t->RelativeMultiPointer.pointer_type = pointer_type;
|
||||
t->RelativeMultiPointer.base_integer = base_integer;
|
||||
return t;
|
||||
}
|
||||
|
||||
gb_internal Type *alloc_type_named(String name, Type *base, Entity *type_name) {
|
||||
Type *t = alloc_type(Type_Named);
|
||||
t->Named.name = name;
|
||||
@@ -1227,8 +1195,6 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) {
|
||||
switch (bt->kind) {
|
||||
case Type_Pointer:
|
||||
return bt->Pointer.elem;
|
||||
case Type_RelativePointer:
|
||||
return type_deref(bt->RelativePointer.pointer_type);
|
||||
case Type_SoaPointer:
|
||||
{
|
||||
Type *elem = base_type(bt->SoaPointer.elem);
|
||||
@@ -1667,15 +1633,6 @@ gb_internal bool is_type_generic(Type *t) {
|
||||
return t->kind == Type_Generic;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_relative_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_RelativePointer;
|
||||
}
|
||||
gb_internal bool is_type_relative_multi_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_RelativeMultiPointer;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_u8_slice(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Slice) {
|
||||
@@ -2118,8 +2075,6 @@ gb_internal bool is_type_indexable(Type *t) {
|
||||
return true;
|
||||
case Type_EnumeratedArray:
|
||||
return true;
|
||||
case Type_RelativeMultiPointer:
|
||||
return true;
|
||||
case Type_Matrix:
|
||||
return true;
|
||||
}
|
||||
@@ -2137,8 +2092,6 @@ gb_internal bool is_type_sliceable(Type *t) {
|
||||
return true;
|
||||
case Type_EnumeratedArray:
|
||||
return false;
|
||||
case Type_RelativeMultiPointer:
|
||||
return true;
|
||||
case Type_Matrix:
|
||||
return false;
|
||||
}
|
||||
@@ -2345,27 +2298,7 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_RelativeMultiPointer:
|
||||
if (is_type_polymorphic(t->RelativeMultiPointer.pointer_type, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
if (t->RelativeMultiPointer.base_integer != nullptr &&
|
||||
is_type_polymorphic(t->RelativeMultiPointer.base_integer, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Type_RelativePointer:
|
||||
if (is_type_polymorphic(t->RelativePointer.pointer_type, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
if (t->RelativePointer.base_integer != nullptr &&
|
||||
is_type_polymorphic(t->RelativePointer.base_integer, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2407,10 +2340,6 @@ gb_internal bool type_has_nil(Type *t) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case Type_RelativePointer:
|
||||
case Type_RelativeMultiPointer:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2579,10 +2508,6 @@ gb_internal bool is_type_load_safe(Type *type) {
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_RelativePointer:
|
||||
case Type_RelativeMultiPointer:
|
||||
return true;
|
||||
|
||||
case Type_Pointer:
|
||||
case Type_MultiPointer:
|
||||
case Type_Slice:
|
||||
@@ -3945,11 +3870,6 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
case Type_Matrix:
|
||||
return matrix_align_of(t, path);
|
||||
|
||||
case Type_RelativePointer:
|
||||
return type_align_of_internal(t->RelativePointer.base_integer, path);
|
||||
case Type_RelativeMultiPointer:
|
||||
return type_align_of_internal(t->RelativeMultiPointer.base_integer, path);
|
||||
|
||||
case Type_SoaPointer:
|
||||
return build_context.int_size;
|
||||
}
|
||||
@@ -3968,6 +3888,10 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
||||
min_field_align = 1;
|
||||
}
|
||||
|
||||
TypePath path{};
|
||||
type_path_init(&path);
|
||||
defer (type_path_free(&path));
|
||||
|
||||
if (is_raw_union) {
|
||||
for_array(i, fields) {
|
||||
offsets[i] = 0;
|
||||
@@ -3977,7 +3901,7 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
||||
if (fields[i]->kind != Entity_Variable) {
|
||||
offsets[i] = -1;
|
||||
} else {
|
||||
i64 size = type_size_of(fields[i]->type);
|
||||
i64 size = type_size_of_internal(fields[i]->type, &path);
|
||||
offsets[i] = curr_offset;
|
||||
curr_offset += size;
|
||||
}
|
||||
@@ -3988,11 +3912,11 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
||||
offsets[i] = -1;
|
||||
} else {
|
||||
Type *t = fields[i]->type;
|
||||
i64 align = gb_max(type_align_of(t), min_field_align);
|
||||
i64 align = gb_max(type_align_of_internal(t, &path), min_field_align);
|
||||
if (max_field_align > min_field_align) {
|
||||
align = gb_min(align, max_field_align);
|
||||
}
|
||||
i64 size = gb_max(type_size_of( t), 0);
|
||||
i64 size = gb_max(type_size_of_internal(t, &path), 0);
|
||||
curr_offset = align_formula(curr_offset, align);
|
||||
offsets[i] = curr_offset;
|
||||
curr_offset += size;
|
||||
@@ -4242,11 +4166,6 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
|
||||
|
||||
case Type_BitField:
|
||||
return type_size_of_internal(t->BitField.backing_type, path);
|
||||
|
||||
case Type_RelativePointer:
|
||||
return type_size_of_internal(t->RelativePointer.base_integer, path);
|
||||
case Type_RelativeMultiPointer:
|
||||
return type_size_of_internal(t->RelativeMultiPointer.base_integer, path);
|
||||
}
|
||||
|
||||
// Catch all
|
||||
@@ -4872,19 +4791,6 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
|
||||
str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count);
|
||||
str = write_type_to_string(str, type->SimdVector.elem);
|
||||
break;
|
||||
|
||||
case Type_RelativePointer:
|
||||
str = gb_string_append_fmt(str, "#relative(");
|
||||
str = write_type_to_string(str, type->RelativePointer.base_integer);
|
||||
str = gb_string_append_fmt(str, ") ");
|
||||
str = write_type_to_string(str, type->RelativePointer.pointer_type);
|
||||
break;
|
||||
case Type_RelativeMultiPointer:
|
||||
str = gb_string_append_fmt(str, "#relative(");
|
||||
str = write_type_to_string(str, type->RelativePointer.base_integer);
|
||||
str = gb_string_append_fmt(str, ") ");
|
||||
str = write_type_to_string(str, type->RelativePointer.pointer_type);
|
||||
break;
|
||||
|
||||
case Type_Matrix:
|
||||
if (type->Matrix.is_row_major) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user