mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00: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
|
name: NetBSD Build, Check, and Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
PKGSRC_BRANCH: 2024Q2
|
PKGSRC_BRANCH: 2024Q3
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Build, Check, and Test
|
- name: Build, Check, and Test
|
||||||
|
|||||||
@@ -171,14 +171,6 @@ Type_Info_Simd_Vector :: struct {
|
|||||||
elem_size: int,
|
elem_size: int,
|
||||||
count: 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 {
|
Type_Info_Matrix :: struct {
|
||||||
elem: ^Type_Info,
|
elem: ^Type_Info,
|
||||||
elem_size: int,
|
elem_size: int,
|
||||||
@@ -241,8 +233,6 @@ Type_Info :: struct {
|
|||||||
Type_Info_Map,
|
Type_Info_Map,
|
||||||
Type_Info_Bit_Set,
|
Type_Info_Bit_Set,
|
||||||
Type_Info_Simd_Vector,
|
Type_Info_Simd_Vector,
|
||||||
Type_Info_Relative_Pointer,
|
|
||||||
Type_Info_Relative_Multi_Pointer,
|
|
||||||
Type_Info_Matrix,
|
Type_Info_Matrix,
|
||||||
Type_Info_Soa_Pointer,
|
Type_Info_Soa_Pointer,
|
||||||
Type_Info_Bit_Field,
|
Type_Info_Bit_Field,
|
||||||
@@ -275,8 +265,6 @@ Typeid_Kind :: enum u8 {
|
|||||||
Map,
|
Map,
|
||||||
Bit_Set,
|
Bit_Set,
|
||||||
Simd_Vector,
|
Simd_Vector,
|
||||||
Relative_Pointer,
|
|
||||||
Relative_Multi_Pointer,
|
|
||||||
Matrix,
|
Matrix,
|
||||||
Soa_Pointer,
|
Soa_Pointer,
|
||||||
Bit_Field,
|
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`.
|
// Note: Prefer using the procedure group `make`.
|
||||||
@(builtin, require_results)
|
@(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
|
m.allocator = allocator
|
||||||
return m
|
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`.
|
// Note: Prefer using the procedure group `make`.
|
||||||
@(builtin, require_results)
|
@(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)
|
make_map_expr_error_loc(loc, capacity)
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ make_soa_slice :: proc($T: typeid/#soa[]$E, #any_int length: int, allocator := c
|
|||||||
@(builtin, require_results)
|
@(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 {
|
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
|
context.allocator = allocator
|
||||||
|
array.allocator = allocator
|
||||||
reserve_soa(&array, 0, loc) or_return
|
reserve_soa(&array, 0, loc) or_return
|
||||||
return array, nil
|
return array, nil
|
||||||
}
|
}
|
||||||
@@ -149,6 +150,7 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.
|
|||||||
@(builtin, require_results)
|
@(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 {
|
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
|
context.allocator = allocator
|
||||||
|
array.allocator = allocator
|
||||||
resize_soa(&array, length, loc) or_return
|
resize_soa(&array, length, loc) or_return
|
||||||
return array, nil
|
return array, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -487,18 +487,6 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
|||||||
print_byte(']')
|
print_byte(']')
|
||||||
print_type(info.elem)
|
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:
|
case Type_Info_Matrix:
|
||||||
print_string("matrix[")
|
print_string("matrix[")
|
||||||
print_u64(u64(info.row_count))
|
print_u64(u64(info.row_count))
|
||||||
|
|||||||
@@ -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_DATE_TIME=%%i
|
||||||
)
|
)
|
||||||
set curr_year=%CURR_DATE_TIME:~0,4%
|
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_full="%V1%.%V2%.%V3%.%V4%"
|
||||||
set odin_version_raw="dev-%V1%-%V2%"
|
set odin_version_raw="dev-%V1%-%V2%"
|
||||||
|
|
||||||
|
|
||||||
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
|
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 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
|
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.
|
# 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 [ -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@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"
|
elif [ -n "$(command -v $(brew --prefix llvm@14)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@14)/bin/llvm-config"
|
||||||
fi
|
fi
|
||||||
@@ -33,13 +34,15 @@ fi
|
|||||||
|
|
||||||
if [ -z "$LLVM_CONFIG" ]; then
|
if [ -z "$LLVM_CONFIG" ]; then
|
||||||
# darwin, linux, openbsd
|
# 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-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-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-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-12)" ]; then LLVM_CONFIG="llvm-config-12"
|
||||||
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
|
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
|
||||||
# freebsd
|
# 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-config18)" ]; then LLVM_CONFIG="llvm-config18"
|
||||||
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config17"
|
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config17"
|
||||||
elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config14"
|
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_MINOR="$(echo $LLVM_VERSION | awk -F. '{print $2}')"
|
||||||
LLVM_VERSION_PATCH="$(echo $LLVM_VERSION | awk -F. '{print $3}')"
|
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
|
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 or 18"
|
error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14, 17, 18 or 19"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$OS_NAME" in
|
case "$OS_NAME" in
|
||||||
Darwin)
|
Darwin)
|
||||||
if [ "$OS_ARCH" = "arm64" ]; then
|
if [ "$OS_ARCH" = "arm64" ]; then
|
||||||
if [ $LLVM_VERSION_MAJOR -lt 13 ]; 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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -152,9 +155,7 @@ build_odin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run_demo() {
|
run_demo() {
|
||||||
if [ $# -eq 0 ] || [ "$1" = "debug" ]; then
|
./odin run examples/demo -vet -strict-style -- Hellope World
|
||||||
./odin run examples/demo -vet -strict-style -- Hellope World
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ $# -eq 0 ]; then
|
if [ $# -eq 0 ]; then
|
||||||
@@ -166,14 +167,20 @@ if [ $# -eq 0 ]; then
|
|||||||
elif [ $# -eq 1 ]; then
|
elif [ $# -eq 1 ]; then
|
||||||
case $1 in
|
case $1 in
|
||||||
report)
|
report)
|
||||||
[ ! -f "./odin" ] && build_odin debug
|
if [ ! -f "./odin" ]; then
|
||||||
|
build_odin debug
|
||||||
|
run_demo
|
||||||
|
fi
|
||||||
./odin report
|
./odin report
|
||||||
;;
|
;;
|
||||||
|
debug)
|
||||||
|
build_odin debug
|
||||||
|
run_demo
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
build_odin $1
|
build_odin $1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
run_demo
|
|
||||||
else
|
else
|
||||||
error "Too many arguments!"
|
error "Too many arguments!"
|
||||||
fi
|
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
|
package main
|
||||||
|
|
||||||
import "core:bytes"
|
import "core:bytes"
|
||||||
|
import "core:compress/zlib"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
@@ -36,7 +37,7 @@ Example:
|
|||||||
buf: bytes.Buffer
|
buf: bytes.Buffer
|
||||||
|
|
||||||
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
|
// 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)
|
defer bytes.buffer_destroy(&buf)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ Symbols :: struct {
|
|||||||
main :: proc() {
|
main :: proc() {
|
||||||
sym: Symbols
|
sym: Symbols
|
||||||
|
|
||||||
|
LIB_PATH :: "lib." + dynlib.LIBRARY_FILE_EXTENSION
|
||||||
|
|
||||||
// Load symbols from `lib.dll` into Symbols struct.
|
// Load symbols from `lib.dll` into Symbols struct.
|
||||||
// Each struct field is prefixed with `foo_` before lookup in the DLL's symbol table.
|
// 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.
|
// 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)
|
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 {
|
if count > 0 {
|
||||||
fmt.println("42 + 42 =", sym.add(42, 42))
|
fmt.println("42 + 42 =", sym.add(42, 42))
|
||||||
@@ -34,8 +36,8 @@ main :: proc() {
|
|||||||
fmt.println("hellope =", sym.hellope^)
|
fmt.println("hellope =", sym.hellope^)
|
||||||
}
|
}
|
||||||
|
|
||||||
count, ok = dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_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.dll (%p).\n", ok, count, sym._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 {
|
if count > 0 {
|
||||||
fmt.println("42 + 42 =", sym.add(42, 42))
|
fmt.println("42 + 42 =", sym.add(42, 42))
|
||||||
|
|||||||
+26
-16
@@ -12,6 +12,11 @@ A handle to a dynamically loaded library.
|
|||||||
*/
|
*/
|
||||||
Library :: distinct rawptr
|
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
|
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.
|
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) {
|
) -> (count: int = -1, ok: bool = false) where intrinsics.type_is_struct(T) {
|
||||||
assert(symbol_table != nil)
|
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.
|
// Buffer to concatenate the prefix + symbol name.
|
||||||
prefixed_symbol_buf: [2048]u8 = ---
|
prefixed_symbol_buf: [2048]u8 = ---
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
for field in reflect.struct_fields_zipped(T) {
|
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
|
// Calculate address of struct member
|
||||||
field_ptr := rawptr(uintptr(symbol_table) + field.offset)
|
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
|
// Let's look up or construct the symbol name to find in the library
|
||||||
prefixed_name: string
|
prefixed_name: string
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ package dynlib
|
|||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
|
||||||
|
_LIBRARY_FILE_EXTENSION :: ""
|
||||||
|
|
||||||
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import "base:runtime"
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:sys/posix"
|
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) {
|
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
||||||
flags := posix.RTLD_Flags{.NOW}
|
flags := posix.RTLD_Flags{.NOW}
|
||||||
if global_symbols {
|
if global_symbols {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import win32 "core:sys/windows"
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:reflect"
|
import "core:reflect"
|
||||||
|
|
||||||
|
_LIBRARY_FILE_EXTENSION :: "dll"
|
||||||
|
|
||||||
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
|
_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
|
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||||
wide_path := win32.utf8_to_wstring(path, allocator)
|
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.name = read_name(r) or_return
|
||||||
layer.components = read_value(r, u8) or_return
|
layer.components = read_value(r, u8) or_return
|
||||||
type := read_value(r, Layer_Data_Type) 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 {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is %d\n",
|
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)))
|
r.filename, u8(type), u8(max(Layer_Data_Type)))
|
||||||
|
|||||||
@@ -193,12 +193,6 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
|||||||
case runtime.Type_Info_Simd_Vector:
|
case runtime.Type_Info_Simd_Vector:
|
||||||
return .Unsupported_Type
|
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:
|
case runtime.Type_Info_Matrix:
|
||||||
return .Unsupported_Type
|
return .Unsupported_Type
|
||||||
|
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
|||||||
skip_digits(t)
|
skip_digits(t)
|
||||||
}
|
}
|
||||||
if t.r == 'e' || t.r == 'E' {
|
if t.r == 'e' || t.r == 'E' {
|
||||||
|
token.kind = .Float
|
||||||
switch r := next_rune(t); r {
|
switch r := next_rune(t); r {
|
||||||
case '+', '-':
|
case '+', '-':
|
||||||
next_rune(t)
|
next_rune(t)
|
||||||
@@ -485,7 +486,7 @@ is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
|
|||||||
case '"':
|
case '"':
|
||||||
// okay
|
// okay
|
||||||
case '\'':
|
case '\'':
|
||||||
if spec != .JSON {
|
if spec == .JSON {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// okay
|
// okay
|
||||||
|
|||||||
@@ -172,20 +172,33 @@ assign_float :: proc(val: any, f: $T) -> bool {
|
|||||||
|
|
||||||
|
|
||||||
@(private)
|
@(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
|
val := val
|
||||||
switch &dst in val {
|
switch &dst in val {
|
||||||
case string:
|
case string:
|
||||||
dst = str
|
dst = str
|
||||||
return true
|
return true, nil
|
||||||
case cstring:
|
case cstring:
|
||||||
if str == "" {
|
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 {
|
} else {
|
||||||
// NOTE: This is valid because 'clone_string' appends a NUL terminator
|
// NOTE: This is valid because 'clone_string' appends a NUL terminator
|
||||||
dst = cstring(raw_data(str))
|
dst = cstring(raw_data(str))
|
||||||
}
|
}
|
||||||
return true
|
ok = true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
#partial switch variant in ti.variant {
|
#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 {
|
for name, i in variant.names {
|
||||||
if name == str {
|
if name == str {
|
||||||
assign_int(val, variant.values[i])
|
assign_int(val, variant.values[i])
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(bill): should this be an error or not?
|
// TODO(bill): should this be an error or not?
|
||||||
return true
|
return true, nil
|
||||||
|
|
||||||
case reflect.Type_Info_Integer:
|
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) {
|
if assign_int(val, i) {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
if assign_float(val, i) {
|
if assign_float(val, i) {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
case reflect.Type_Info_Float:
|
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) {
|
if assign_int(val, f) {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
if assign_float(val, f) {
|
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:
|
case .Ident:
|
||||||
advance_token(p)
|
advance_token(p)
|
||||||
if p.spec == .MJSON {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +333,7 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
|||||||
advance_token(p)
|
advance_token(p)
|
||||||
str := unquote_string(token, p.spec, p.allocator) or_return
|
str := unquote_string(token, p.spec, p.allocator) or_return
|
||||||
dest := any{v.data, ti.id}
|
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)
|
delete(str, p.allocator)
|
||||||
return UNSUPPORTED_TYPE
|
return UNSUPPORTED_TYPE
|
||||||
}
|
}
|
||||||
@@ -399,14 +418,14 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
return UNSUPPORTED_TYPE
|
return UNSUPPORTED_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fields := reflect.struct_fields_zipped(ti.id)
|
||||||
|
|
||||||
struct_loop: for p.curr_token.kind != end_token {
|
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)
|
defer delete(key, p.allocator)
|
||||||
|
|
||||||
unmarshal_expect_token(p, .Colon)
|
unmarshal_expect_token(p, .Colon)
|
||||||
|
|
||||||
fields := reflect.struct_fields_zipped(ti.id)
|
|
||||||
|
|
||||||
field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool {
|
field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool {
|
||||||
prev_set := field_used[offset/8] & byte(offset&7) != 0
|
prev_set := field_used[offset/8] & byte(offset&7) != 0
|
||||||
field_used[offset/8] |= byte(offset&7)
|
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:
|
case runtime.Type_Info_Bit_Set:
|
||||||
fmt_bit_set(fi, v, verb = verb)
|
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:
|
case runtime.Type_Info_Matrix:
|
||||||
fmt_matrix(fi, v, verb, info)
|
fmt_matrix(fi, v, verb, info)
|
||||||
|
|
||||||
|
|||||||
@@ -37,30 +37,30 @@ File_Console_Logger_Data :: struct {
|
|||||||
ident: string,
|
ident: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "") -> Logger {
|
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)
|
data := new(File_Console_Logger_Data, allocator)
|
||||||
data.file_handle = h
|
data.file_handle = h
|
||||||
data.ident = ident
|
data.ident = ident
|
||||||
return Logger{file_console_logger_proc, data, lowest, opt}
|
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
|
data := cast(^File_Console_Logger_Data)log.data
|
||||||
if data.file_handle != os.INVALID_HANDLE {
|
if data.file_handle != os.INVALID_HANDLE {
|
||||||
os.close(data.file_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 {
|
create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
|
||||||
data := new(File_Console_Logger_Data)
|
data := new(File_Console_Logger_Data, allocator)
|
||||||
data.file_handle = os.INVALID_HANDLE
|
data.file_handle = os.INVALID_HANDLE
|
||||||
data.ident = ident
|
data.ident = ident
|
||||||
return Logger{file_console_logger_proc, data, lowest, opt}
|
return Logger{file_console_logger_proc, data, lowest, opt}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_console_logger :: proc(log: Logger) {
|
destroy_console_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||||
free(log.data)
|
free(log.data, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
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,
|
loggers: []Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
create_multi_logger :: proc(logs: ..Logger) -> Logger {
|
create_multi_logger :: proc(logs: ..Logger, allocator := context.allocator) -> Logger {
|
||||||
data := new(Multi_Logger_Data)
|
data := new(Multi_Logger_Data, allocator)
|
||||||
data.loggers = make([]Logger, len(logs))
|
data.loggers = make([]Logger, len(logs), allocator)
|
||||||
copy(data.loggers, logs)
|
copy(data.loggers, logs)
|
||||||
return Logger{multi_logger_proc, data, Level.Debug, nil}
|
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)
|
data := (^Multi_Logger_Data)(log.data)
|
||||||
delete(data.loggers)
|
delete(data.loggers, allocator)
|
||||||
free(data)
|
free(data, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
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)
|
@(require_results)
|
||||||
quaternion64_dot :: proc "contextless" (a, b: $T/quaternion64) -> (c: f16) {
|
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)
|
@(require_results)
|
||||||
quaternion128_dot :: proc "contextless" (a, b: $T/quaternion128) -> (c: f32) {
|
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)
|
@(require_results)
|
||||||
quaternion256_dot :: proc "contextless" (a, b: $T/quaternion256) -> (c: f64) {
|
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}
|
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}
|
length :: proc{vector_length, quaternion_length}
|
||||||
length2 :: proc{vector_length2, quaternion_length2}
|
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)
|
@(require_results)
|
||||||
projection :: proc "contextless" (x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
projection :: proc "contextless" (x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
||||||
return dot(x, normal) / dot(normal, normal) * normal
|
return dot(x, normal) / dot(normal, normal) * normal
|
||||||
|
|||||||
+1
-1
@@ -1271,7 +1271,7 @@ binomial :: proc "contextless" (n, k: int) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b := n
|
b := n
|
||||||
for i in 2..<k {
|
for i in 2..=k {
|
||||||
b = (b * (n+1-i))/i
|
b = (b * (n+1-i))/i
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
|||||||
@@ -189,12 +189,12 @@ sincos_f64 :: proc "contextless" (x: f64) -> (sin, cos: f64) #no_bounds_check {
|
|||||||
// sin coefficients
|
// sin coefficients
|
||||||
@(private="file")
|
@(private="file")
|
||||||
_sin := [?]f64{
|
_sin := [?]f64{
|
||||||
0h3de5d8fd1fd19ccd, // 1.58962301576546568060e-10
|
0h3de5d8fd1fd19ccd, // 1.58962301576546568060e-10
|
||||||
0hbe5ae5e5a9291f5d, // -2.50507477628578072866e-8
|
0hbe5ae5e5a9291f5d, // -2.50507477628578072866e-8
|
||||||
0h3ec71de3567d48a1, // 2.75573136213857245213e-6
|
0h3ec71de3567d48a1, // 2.75573136213857245213e-6
|
||||||
0hbf2a01a019bfdf03, // -1.98412698295895385996e-4
|
0hbf2a01a019bfdf03, // -1.98412698295895385996e-4
|
||||||
0h3f8111111110f7d0, // 8.33333333332211858878e-3
|
0h3f8111111110f7d0, // 8.33333333332211858878e-3
|
||||||
0hbfc5555555555548, // -1.66666666666666307295e-1
|
0hbfc5555555555548, // -1.66666666666666307295e-1
|
||||||
}
|
}
|
||||||
|
|
||||||
// cos coefficients
|
// cos coefficients
|
||||||
|
|||||||
@@ -6,17 +6,13 @@ import "core:sys/posix"
|
|||||||
|
|
||||||
// Define non-posix needed flags:
|
// Define non-posix needed flags:
|
||||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
|
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 {
|
} 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) {
|
_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)
|
result := posix.mmap(nil, size, {}, flags)
|
||||||
if result == posix.MAP_FAILED {
|
if result == posix.MAP_FAILED {
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ Build_Kind :: struct {
|
|||||||
arch: runtime.Odin_Arch_Types,
|
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 {
|
File_Tags :: struct {
|
||||||
build_project_name: [][]string,
|
build_project_name: [][]string,
|
||||||
build: []Build_Kind,
|
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:])
|
append(build_project_names, build_project_name_strings[index_start:])
|
||||||
}
|
}
|
||||||
case "build":
|
case "build":
|
||||||
|
|
||||||
|
if len(build_kinds) > 0 {
|
||||||
|
append(build_kinds, BUILD_KIND_NEWLINE_MARKER)
|
||||||
|
}
|
||||||
|
|
||||||
kinds_loop: for {
|
kinds_loop: for {
|
||||||
os_positive: runtime.Odin_OS_Types
|
os_positive: runtime.Odin_OS_Types
|
||||||
os_negative: 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
|
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 {
|
if len(file_tags.build) > 0 {
|
||||||
os_and_arch_correct ||= target.os in kind.os && target.arch in kind.arch
|
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
|
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)
|
@(require_results)
|
||||||
_read_directory_iterator_create :: proc(f: ^File) -> (Read_Directory_Iterator, Error) {
|
_read_directory_iterator_create :: proc(f: ^File) -> (Read_Directory_Iterator, Error) {
|
||||||
return {}, nil
|
return {}, .Unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
|
_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
|
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.fullpath = path
|
||||||
fi.name = basename(path)
|
fi.name = basename(path)
|
||||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
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.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.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))
|
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)) {
|
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) == size_of(file_id_info.FileId))
|
||||||
#assert(size_of(fi.inode) == 16)
|
#assert(size_of(fi.inode) == 16)
|
||||||
runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16)
|
runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,5 +134,6 @@ _read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_info_delete(it.impl.prev_fi, file_allocator())
|
file_info_delete(it.impl.prev_fi, file_allocator())
|
||||||
|
delete(it.impl.path, file_allocator())
|
||||||
win32.FindClose(it.impl.find_handle)
|
win32.FindClose(it.impl.find_handle)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,22 +200,21 @@ _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: wi
|
|||||||
} else {
|
} else {
|
||||||
mode |= 0o666
|
mode |= 0o666
|
||||||
}
|
}
|
||||||
|
|
||||||
is_sym := false
|
is_sym := false
|
||||||
if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
||||||
is_sym = false
|
is_sym = false
|
||||||
} else {
|
} else {
|
||||||
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
|
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_sym {
|
if is_sym {
|
||||||
type = .Symlink
|
type = .Symlink
|
||||||
} else {
|
} else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
type = .Directory
|
||||||
type = .Directory
|
mode |= 0o111
|
||||||
mode |= 0o111
|
} else if h != nil {
|
||||||
}
|
type = file_type(h)
|
||||||
if h != nil {
|
|
||||||
type = file_type(h)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ get_last_error_string :: proc() -> string {
|
|||||||
|
|
||||||
|
|
||||||
@(require_results)
|
@(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)
|
isDir := is_dir_path(path)
|
||||||
flags := flags
|
flags := flags
|
||||||
if isDir {
|
if isDir {
|
||||||
|
|||||||
+578
-3
@@ -4,15 +4,13 @@ package os
|
|||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
|
import "core:unicode/utf16"
|
||||||
|
|
||||||
Handle :: distinct uintptr
|
Handle :: distinct uintptr
|
||||||
File_Time :: distinct u64
|
File_Time :: distinct u64
|
||||||
|
|
||||||
|
|
||||||
INVALID_HANDLE :: ~Handle(0)
|
INVALID_HANDLE :: ~Handle(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
O_RDONLY :: 0x00000
|
O_RDONLY :: 0x00000
|
||||||
O_WRONLY :: 0x00001
|
O_WRONLY :: 0x00001
|
||||||
O_RDWR :: 0x00002
|
O_RDWR :: 0x00002
|
||||||
@@ -278,3 +276,580 @@ is_windows_11 :: proc "contextless" () -> bool {
|
|||||||
osvi := get_windows_version_w()
|
osvi := get_windows_version_w()
|
||||||
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
|
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_Map :: runtime.Type_Info_Map
|
||||||
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
||||||
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
|
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_Matrix :: runtime.Type_Info_Matrix
|
||||||
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
||||||
Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field
|
Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field
|
||||||
@@ -67,8 +65,6 @@ Type_Kind :: enum {
|
|||||||
Map,
|
Map,
|
||||||
Bit_Set,
|
Bit_Set,
|
||||||
Simd_Vector,
|
Simd_Vector,
|
||||||
Relative_Pointer,
|
|
||||||
Relative_Multi_Pointer,
|
|
||||||
Matrix,
|
Matrix,
|
||||||
Soa_Pointer,
|
Soa_Pointer,
|
||||||
Bit_Field,
|
Bit_Field,
|
||||||
@@ -80,35 +76,33 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
|||||||
ti := type_info_of(T)
|
ti := type_info_of(T)
|
||||||
if ti != nil {
|
if ti != nil {
|
||||||
switch _ in ti.variant {
|
switch _ in ti.variant {
|
||||||
case Type_Info_Named: return .Named
|
case Type_Info_Named: return .Named
|
||||||
case Type_Info_Integer: return .Integer
|
case Type_Info_Integer: return .Integer
|
||||||
case Type_Info_Rune: return .Rune
|
case Type_Info_Rune: return .Rune
|
||||||
case Type_Info_Float: return .Float
|
case Type_Info_Float: return .Float
|
||||||
case Type_Info_Complex: return .Complex
|
case Type_Info_Complex: return .Complex
|
||||||
case Type_Info_Quaternion: return .Quaternion
|
case Type_Info_Quaternion: return .Quaternion
|
||||||
case Type_Info_String: return .String
|
case Type_Info_String: return .String
|
||||||
case Type_Info_Boolean: return .Boolean
|
case Type_Info_Boolean: return .Boolean
|
||||||
case Type_Info_Any: return .Any
|
case Type_Info_Any: return .Any
|
||||||
case Type_Info_Type_Id: return .Type_Id
|
case Type_Info_Type_Id: return .Type_Id
|
||||||
case Type_Info_Pointer: return .Pointer
|
case Type_Info_Pointer: return .Pointer
|
||||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||||
case Type_Info_Procedure: return .Procedure
|
case Type_Info_Procedure: return .Procedure
|
||||||
case Type_Info_Array: return .Array
|
case Type_Info_Array: return .Array
|
||||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||||
case Type_Info_Slice: return .Slice
|
case Type_Info_Slice: return .Slice
|
||||||
case Type_Info_Parameters: return .Tuple
|
case Type_Info_Parameters: return .Tuple
|
||||||
case Type_Info_Struct: return .Struct
|
case Type_Info_Struct: return .Struct
|
||||||
case Type_Info_Union: return .Union
|
case Type_Info_Union: return .Union
|
||||||
case Type_Info_Enum: return .Enum
|
case Type_Info_Enum: return .Enum
|
||||||
case Type_Info_Map: return .Map
|
case Type_Info_Map: return .Map
|
||||||
case Type_Info_Bit_Set: return .Bit_Set
|
case Type_Info_Bit_Set: return .Bit_Set
|
||||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||||
case Type_Info_Relative_Pointer: return .Relative_Pointer
|
case Type_Info_Matrix: return .Matrix
|
||||||
case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer
|
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||||
case Type_Info_Matrix: return .Matrix
|
case Type_Info_Bit_Field: return .Bit_Field
|
||||||
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
|
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
|
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)
|
@(require_results)
|
||||||
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
||||||
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
_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 cstring: value = rawptr(v)
|
||||||
case: valid = false
|
case: valid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type_Info_Relative_Pointer:
|
|
||||||
valid = true
|
|
||||||
value = relative_pointer_to_absolute_raw(a.data, info.base_integer.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -1656,8 +1652,6 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
|||||||
Type_Info_Bit_Set,
|
Type_Info_Bit_Set,
|
||||||
Type_Info_Enum,
|
Type_Info_Enum,
|
||||||
Type_Info_Simd_Vector,
|
Type_Info_Simd_Vector,
|
||||||
Type_Info_Relative_Pointer,
|
|
||||||
Type_Info_Relative_Multi_Pointer,
|
|
||||||
Type_Info_Soa_Pointer,
|
Type_Info_Soa_Pointer,
|
||||||
Type_Info_Matrix:
|
Type_Info_Matrix:
|
||||||
return runtime.memory_compare(a.data, b.data, t.size) == 0
|
return runtime.memory_compare(a.data, b.data, t.size) == 0
|
||||||
|
|||||||
@@ -159,14 +159,6 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
|||||||
y := b.variant.(Type_Info_Simd_Vector) or_return
|
y := b.variant.(Type_Info_Simd_Vector) or_return
|
||||||
return x.count == y.count && x.elem == y.elem
|
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:
|
case Type_Info_Matrix:
|
||||||
y := b.variant.(Type_Info_Matrix) or_return
|
y := b.variant.(Type_Info_Matrix) or_return
|
||||||
if x.row_count != y.row_count { return false }
|
if x.row_count != y.row_count { return false }
|
||||||
@@ -392,18 +384,6 @@ is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
|||||||
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
||||||
return ok
|
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)
|
@(require_results)
|
||||||
@@ -737,18 +717,6 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
|
|||||||
io.write_byte(w, ']', &n) or_return
|
io.write_byte(w, ']', &n) or_return
|
||||||
write_type(w, info.elem, &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:
|
case Type_Info_Matrix:
|
||||||
if info.layout == .Row_Major {
|
if info.layout == .Row_Major {
|
||||||
io.write_string(w, "#row_major ", &n) or_return
|
io.write_string(w, "#row_major ", &n) or_return
|
||||||
|
|||||||
@@ -471,6 +471,12 @@ is_empty :: proc(a: $T/[]$E) -> bool {
|
|||||||
return len(a) == 0
|
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)
|
@(require_results)
|
||||||
|
|||||||
@@ -1872,7 +1872,8 @@ index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) {
|
|||||||
lowest_index := len(s)
|
lowest_index := len(s)
|
||||||
found := false
|
found := false
|
||||||
for substr in substrs {
|
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 {
|
if i < lowest_index {
|
||||||
lowest_index = i
|
lowest_index = i
|
||||||
width = len(substr)
|
width = len(substr)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
|||||||
when !intrinsics.has_target_feature("atomics") {
|
when !intrinsics.has_target_feature("atomics") {
|
||||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||||
} else {
|
} else {
|
||||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
_ = intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||||
return s != 0
|
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")
|
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||||
} else {
|
} else {
|
||||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
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") {
|
when !intrinsics.has_target_feature("atomics") {
|
||||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||||
} else {
|
} else {
|
||||||
loop: for {
|
_ = intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
|
||||||
if s >= 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +38,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
|
|||||||
when !intrinsics.has_target_feature("atomics") {
|
when !intrinsics.has_target_feature("atomics") {
|
||||||
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
|
||||||
} else {
|
} else {
|
||||||
loop: for {
|
_ = intrinsics.wasm_memory_atomic_notify32((^u32)(f), max(u32))
|
||||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
|
||||||
if s >= 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,16 @@ Application_setMainMenu :: proc "c" (self: ^Application, menu: ^Menu) {
|
|||||||
msgSend(nil, self, "setMainMenu:", 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")
|
@(objc_type=Application, objc_name="windows")
|
||||||
Application_windows :: proc "c" (self: ^Application) -> ^Array {
|
Application_windows :: proc "c" (self: ^Application) -> ^Array {
|
||||||
return msgSend(^Array, self, "windows")
|
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
|
YES :: true
|
||||||
NO :: false
|
NO :: false
|
||||||
|
|
||||||
OperatingSystemVersion :: struct #packed {
|
OperatingSystemVersion :: struct #align(8) {
|
||||||
majorVersion: Integer,
|
majorVersion: Integer,
|
||||||
minorVersion: Integer,
|
minorVersion: Integer,
|
||||||
patchVersion: Integer,
|
patchVersion: Integer,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Made available under Odin's BSD-3 license.
|
|||||||
|
|
||||||
List of contributors:
|
List of contributors:
|
||||||
Jeroen van Rijn: Initial implementation.
|
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
|
package sysinfo
|
||||||
|
|
||||||
import sys "core:sys/unix"
|
import "core:strconv"
|
||||||
import "core:strconv"
|
import "core:strings"
|
||||||
import "core:strings"
|
import "core:sys/unix"
|
||||||
import "base:runtime"
|
import NS "core:sys/darwin/Foundation"
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
version_string_buf: [1024]u8
|
version_string_buf: [1024]u8
|
||||||
|
|
||||||
@(init, private)
|
@(init, private)
|
||||||
init_os_version :: proc () {
|
init_platform :: proc() {
|
||||||
os_version.platform = .MacOS
|
ws :: strings.write_string
|
||||||
|
wi :: strings.write_int
|
||||||
|
|
||||||
// Start building display version
|
|
||||||
b := strings.builder_from_bytes(version_string_buf[:])
|
b := strings.builder_from_bytes(version_string_buf[:])
|
||||||
|
|
||||||
mib := []i32{sys.CTL_KERN, sys.KERN_OSVERSION}
|
version: NS.OperatingSystemVersion
|
||||||
build_buf: [12]u8
|
{
|
||||||
|
NS.scoped_autoreleasepool()
|
||||||
|
|
||||||
ok := sys.sysctl(mib, &build_buf)
|
info := NS.ProcessInfo.processInfo()
|
||||||
if !ok {
|
version = info->operatingSystemVersion()
|
||||||
strings.write_string(&b, "macOS Unknown")
|
mem := info->physicalMemory()
|
||||||
os_version.as_string = strings.to_string(b)
|
|
||||||
return
|
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?
|
when ODIN_PLATFORM_SUBTARGET == .iOS {
|
||||||
match: Darwin_Match
|
os_version.platform = .iOS
|
||||||
rel, exact := macos_release_map[build]
|
ws(&b, "iOS")
|
||||||
|
|
||||||
if exact {
|
|
||||||
match = .Exact
|
|
||||||
} else {
|
} 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
|
// Match on XNU kernel version
|
||||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
|
||||||
version_bits: [12]u8 // enough for 999.999.999\x00
|
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)
|
ws(&b, ", kernel ")
|
||||||
if len(triplet) != 3 {
|
ws(&b, kernel)
|
||||||
have_kernel_version = false
|
ws(&b, ")")
|
||||||
} 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
os_version.major = rel.darwin.x
|
os_version.as_string = string(b.buf[:])
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -519,6 +519,36 @@ Fd_Poll_Events_Bits :: enum {
|
|||||||
RDHUP = 13,
|
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
|
Bits for Mem_Protection bitfield
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -135,6 +135,31 @@ STATX_BASIC_STATS :: Statx_Mask {
|
|||||||
.BLOCKS,
|
.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
|
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): 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
|
// TODO(flysand): migrate_pages
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ Id :: distinct uint
|
|||||||
*/
|
*/
|
||||||
Fd :: distinct i32
|
Fd :: distinct i32
|
||||||
|
|
||||||
|
/*
|
||||||
|
Represents a watch descriptor.
|
||||||
|
*/
|
||||||
|
Wd :: distinct i32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Type for PID file descriptors.
|
Type for PID file descriptors.
|
||||||
*/
|
*/
|
||||||
@@ -343,6 +348,18 @@ Poll_Fd :: struct {
|
|||||||
revents: Fd_Poll_Events,
|
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.
|
Specifies protection for memory pages.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -54,15 +54,6 @@ foreign lib {
|
|||||||
*/
|
*/
|
||||||
closedir :: proc(dirp: DIR) -> result ---
|
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
|
Equivalent to the opendir() function except that the directory is specified by a file descriptor
|
||||||
rather than by a name.
|
rather than by a name.
|
||||||
@@ -161,11 +152,36 @@ when ODIN_OS == .NetBSD {
|
|||||||
@(private) LSCANDIR :: "__scandir30"
|
@(private) LSCANDIR :: "__scandir30"
|
||||||
@(private) LOPENDIR :: "__opendir30"
|
@(private) LOPENDIR :: "__opendir30"
|
||||||
@(private) LREADDIR :: "__readdir30"
|
@(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 {
|
} else {
|
||||||
@(private) LALPHASORT :: "alphasort" + INODE_SUFFIX
|
@(private) LALPHASORT :: "alphasort" + INODE_SUFFIX
|
||||||
@(private) LSCANDIR :: "scandir" + INODE_SUFFIX
|
@(private) LSCANDIR :: "scandir" + INODE_SUFFIX
|
||||||
@(private) LOPENDIR :: "opendir" + INODE_SUFFIX
|
@(private) LOPENDIR :: "opendir" + INODE_SUFFIX
|
||||||
@(private) LREADDIR :: "readdir" + 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 {
|
when ODIN_OS == .Darwin {
|
||||||
|
|||||||
@@ -116,12 +116,14 @@ Prot_Flag_Bits :: enum c.int {
|
|||||||
Prot_Flags :: bit_set[Prot_Flag_Bits; c.int]
|
Prot_Flags :: bit_set[Prot_Flag_Bits; c.int]
|
||||||
|
|
||||||
Map_Flag_Bits :: enum c.int {
|
Map_Flag_Bits :: enum c.int {
|
||||||
|
// Map anonymous memory.
|
||||||
|
ANONYMOUS = log2(MAP_ANONYMOUS),
|
||||||
// Interpret addr exactly.
|
// Interpret addr exactly.
|
||||||
FIXED = log2(MAP_FIXED),
|
FIXED = log2(MAP_FIXED),
|
||||||
// Changes are private.
|
// Changes are private.
|
||||||
PRIVATE = log2(MAP_PRIVATE),
|
PRIVATE = log2(MAP_PRIVATE),
|
||||||
// Changes are shared.
|
// Changes are shared.
|
||||||
SHARED = log2(MAP_SHARED),
|
SHARED = log2(MAP_SHARED),
|
||||||
}
|
}
|
||||||
Map_Flags :: bit_set[Map_Flag_Bits; c.int]
|
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_READ :: 0x01
|
||||||
PROT_WRITE :: 0x02
|
PROT_WRITE :: 0x02
|
||||||
|
|
||||||
MAP_FIXED :: 0x0010
|
MAP_FIXED :: 0x0010
|
||||||
MAP_PRIVATE :: 0x0002
|
MAP_PRIVATE :: 0x0002
|
||||||
MAP_SHARED :: 0x0001
|
MAP_SHARED :: 0x0001
|
||||||
|
MAP_ANONYMOUS :: 0x0020 when ODIN_OS == .Linux else 0x1000
|
||||||
|
|
||||||
when ODIN_OS == .Darwin || ODIN_OS == .Linux {
|
when ODIN_OS == .Darwin || ODIN_OS == .Linux {
|
||||||
MS_INVALIDATE :: 0x0002
|
MS_INVALIDATE :: 0x0002
|
||||||
@@ -207,9 +210,10 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS
|
|||||||
PROT_READ :: 0x01
|
PROT_READ :: 0x01
|
||||||
PROT_WRITE :: 0x02
|
PROT_WRITE :: 0x02
|
||||||
|
|
||||||
MAP_FIXED :: 0x0010
|
MAP_FIXED :: 0x0010
|
||||||
MAP_PRIVATE :: 0x0002
|
MAP_PRIVATE :: 0x0002
|
||||||
MAP_SHARED :: 0x0001
|
MAP_SHARED :: 0x0001
|
||||||
|
MAP_ANONYMOUS :: 0x1000
|
||||||
|
|
||||||
MS_ASYNC :: 0x0001
|
MS_ASYNC :: 0x0001
|
||||||
MS_INVALIDATE :: 0x0002
|
MS_INVALIDATE :: 0x0002
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ foreign libc {
|
|||||||
addr.sun_family = .UNIX
|
addr.sun_family = .UNIX
|
||||||
copy(addr.sun_path[:], "/somepath\x00")
|
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 {
|
if posix.bind(sfd, (^posix.sockaddr)(&addr), size_of(addr)) != .OK {
|
||||||
/* Handle error */
|
/* Handle error */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,8 +186,8 @@ Key_Location :: enum u8 {
|
|||||||
Numpad = 3,
|
Numpad = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
KEYBOARD_MAX_KEY_SIZE :: 16
|
KEYBOARD_MAX_KEY_SIZE :: 32
|
||||||
KEYBOARD_MAX_CODE_SIZE :: 16
|
KEYBOARD_MAX_CODE_SIZE :: 32
|
||||||
|
|
||||||
GAMEPAD_MAX_ID_SIZE :: 64
|
GAMEPAD_MAX_ID_SIZE :: 64
|
||||||
GAMEPAD_MAX_MAPPING_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.key.length)
|
||||||
wmi.storeInt(off(W, W), e.code.length)
|
wmi.storeInt(off(W, W), e.code.length)
|
||||||
wmi.storeString(off(16, 1), e.key);
|
wmi.storeString(off(32, 1), e.key);
|
||||||
wmi.storeString(off(16, 1), e.code);
|
wmi.storeString(off(32, 1), e.code);
|
||||||
} else if (e.type === 'scroll') {
|
} else if (e.type === 'scroll') {
|
||||||
wmi.storeF64(off(8, 8), window.scrollX);
|
wmi.storeF64(off(8, 8), window.scrollX);
|
||||||
wmi.storeF64(off(8, 8), window.scrollY);
|
wmi.storeF64(off(8, 8), window.scrollY);
|
||||||
|
|||||||
@@ -4519,7 +4519,7 @@ DNS_RECORD :: struct { // aka DNS_RECORDA
|
|||||||
Flags: DWORD,
|
Flags: DWORD,
|
||||||
dwTtl: DWORD,
|
dwTtl: DWORD,
|
||||||
_: DWORD,
|
_: DWORD,
|
||||||
Data: struct #raw_union {
|
Data: struct #raw_union #align(4) {
|
||||||
CNAME: DNS_PTR_DATAA,
|
CNAME: DNS_PTR_DATAA,
|
||||||
A: u32be, // Ipv4 Address
|
A: u32be, // Ipv4 Address
|
||||||
AAAA: u128be, // Ipv6 Address
|
AAAA: u128be, // Ipv6 Address
|
||||||
|
|||||||
@@ -781,3 +781,64 @@ CF_GDIOBJLAST :: 0x03FF
|
|||||||
CF_OWNERDISPLAY :: 0x0080
|
CF_OWNERDISPLAY :: 0x0080
|
||||||
CF_PRIVATEFIRST :: 0x0200
|
CF_PRIVATEFIRST :: 0x0200
|
||||||
CF_PRIVATELAST :: 0x02FF
|
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"
|
foreign import uxtheme "system:UxTheme.lib"
|
||||||
|
|
||||||
MARGINS :: distinct [4]int
|
MARGINS :: distinct [4]i32
|
||||||
PMARGINS :: ^MARGINS
|
PMARGINS :: ^MARGINS
|
||||||
|
|
||||||
@(default_calling_convention="system")
|
@(default_calling_convention="system")
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ match_with_preallocated_capture :: proc(
|
|||||||
capture.pos[n] = {a, b}
|
capture.pos[n] = {a, b}
|
||||||
n += 1
|
n += 1
|
||||||
}
|
}
|
||||||
|
num_groups = n
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// It takes a string providing the source, which then can be tokenized through
|
// It takes a string providing the source, which then can be tokenized through
|
||||||
// repeated calls to the scan procedure.
|
// repeated calls to the scan procedure.
|
||||||
// For compatibility with existing tooling and languages, the NUL character is not allowed.
|
// 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.
|
// 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.
|
// 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 "base:intrinsics"
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "core:container/queue"
|
||||||
|
|
||||||
Task_Proc :: #type proc(task: Task)
|
Task_Proc :: #type proc(task: Task)
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ Pool :: struct {
|
|||||||
threads: []^Thread,
|
threads: []^Thread,
|
||||||
|
|
||||||
|
|
||||||
tasks: [dynamic]Task,
|
tasks: queue.Queue(Task),
|
||||||
tasks_done: [dynamic]Task,
|
tasks_done: [dynamic]Task,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ pool_thread_runner :: proc(t: ^Thread) {
|
|||||||
pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) {
|
pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
pool.allocator = allocator
|
pool.allocator = allocator
|
||||||
pool.tasks = make([dynamic]Task)
|
queue.init(&pool.tasks)
|
||||||
pool.tasks_done = make([dynamic]Task)
|
pool.tasks_done = make([dynamic]Task)
|
||||||
pool.threads = make([]^Thread, max(thread_count, 1))
|
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) {
|
pool_destroy :: proc(pool: ^Pool) {
|
||||||
delete(pool.tasks)
|
queue.destroy(&pool.tasks)
|
||||||
delete(pool.tasks_done)
|
delete(pool.tasks_done)
|
||||||
|
|
||||||
for &t in pool.threads {
|
for &t in pool.threads {
|
||||||
@@ -144,7 +145,7 @@ pool_join :: proc(pool: ^Pool) {
|
|||||||
pool_add_task :: proc(pool: ^Pool, allocator: mem.Allocator, procedure: Task_Proc, data: rawptr, user_index: int = 0) {
|
pool_add_task :: proc(pool: ^Pool, allocator: mem.Allocator, procedure: Task_Proc, data: rawptr, user_index: int = 0) {
|
||||||
sync.guard(&pool.mutex)
|
sync.guard(&pool.mutex)
|
||||||
|
|
||||||
append(&pool.tasks, Task{
|
queue.push_back(&pool.tasks, Task{
|
||||||
procedure = procedure,
|
procedure = procedure,
|
||||||
data = data,
|
data = data,
|
||||||
user_index = user_index,
|
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) {
|
pool_pop_waiting :: proc(pool: ^Pool) -> (task: Task, got_task: bool) {
|
||||||
sync.guard(&pool.mutex)
|
sync.guard(&pool.mutex)
|
||||||
|
|
||||||
if len(pool.tasks) != 0 {
|
if queue.len(pool.tasks) != 0 {
|
||||||
intrinsics.atomic_sub(&pool.num_waiting, 1)
|
intrinsics.atomic_sub(&pool.num_waiting, 1)
|
||||||
intrinsics.atomic_add(&pool.num_in_processing, 1)
|
intrinsics.atomic_add(&pool.num_in_processing, 1)
|
||||||
task = pop_front(&pool.tasks)
|
task = queue.pop_front(&pool.tasks)
|
||||||
got_task = true
|
got_task = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,22 @@ generate_rrule_from_tzi :: proc(tzi: ^REG_TZI_FORMAT, abbrevs: TZ_Abbrev, alloca
|
|||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
defer if err != nil { delete(std_name, allocator) }
|
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: string
|
||||||
dst_name, err = strings.clone(abbrevs.dst, allocator)
|
dst_name, err = strings.clone(abbrevs.dst, allocator)
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ trans_date_to_seconds :: proc(year: i64, td: datetime.TZ_Transition_Date) -> (se
|
|||||||
|
|
||||||
switch td.type {
|
switch td.type {
|
||||||
case .Month_Week_Day:
|
case .Month_Week_Day:
|
||||||
|
if td.month < 1 { return }
|
||||||
|
|
||||||
t += month_to_seconds(int(td.month) - 1, is_leap)
|
t += month_to_seconds(int(td.month) - 1, is_leap)
|
||||||
|
|
||||||
weekday := ((t + (4 * DAY_SEC)) %% (7 * DAY_SEC)) / DAY_SEC
|
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)):]
|
buffer = buffer[(int(real_hdr.leapcnt) * size_of(Leapsecond_Record)):]
|
||||||
|
|
||||||
standard_wall_tags := buffer[:int(real_hdr.isstdcnt)]
|
standard_wall_tags := buffer[:int(real_hdr.isstdcnt)]
|
||||||
buffer = buffer[int(real_hdr.isstdcnt):]
|
for stdwall_tag, _ in standard_wall_tags {
|
||||||
|
|
||||||
ut_tags := buffer[:int(real_hdr.isutcnt)]
|
|
||||||
|
|
||||||
for stdwall_tag, idx in standard_wall_tags {
|
|
||||||
ut_tag := ut_tags[idx]
|
|
||||||
|
|
||||||
if (stdwall_tag != 0 && stdwall_tag != 1) {
|
if (stdwall_tag != 0 && stdwall_tag != 1) {
|
||||||
return
|
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) {
|
if (ut_tag != 0 && ut_tag != 1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ut_tag == 1 && stdwall_tag != 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = buffer[int(real_hdr.isutcnt):]
|
buffer = buffer[int(real_hdr.isutcnt):]
|
||||||
|
|
||||||
// Start of footer
|
// Start of footer
|
||||||
|
|||||||
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
The `example` directory contains two packages:
|
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.
|
For additional example code, see the [examples](https://github.com/odin-lang/examples) repository.
|
||||||
|
|||||||
@@ -1,8 +1,2 @@
|
|||||||
#+build windows
|
#+build windows
|
||||||
package all
|
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()
|
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() {
|
or_else_operator :: proc() {
|
||||||
fmt.println("\n#'or_else'")
|
fmt.println("\n#'or_else'")
|
||||||
{
|
{
|
||||||
@@ -2151,7 +2135,7 @@ or_return_operator :: proc() {
|
|||||||
return .None
|
return .None
|
||||||
}
|
}
|
||||||
foo_2 :: proc() -> (n: int, err: Error) {
|
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+),
|
// If 'or_return' is used within a procedure multiple parameters (2+),
|
||||||
// then all the parameters must be named so that the remaining parameters
|
// then all the parameters must be named so that the remaining parameters
|
||||||
// so that a bare 'return' statement can be used
|
// so that a bare 'return' statement can be used
|
||||||
@@ -2634,7 +2618,6 @@ main :: proc() {
|
|||||||
constant_literal_expressions()
|
constant_literal_expressions()
|
||||||
union_maybe()
|
union_maybe()
|
||||||
explicit_context_definition()
|
explicit_context_definition()
|
||||||
relative_data_types()
|
|
||||||
or_else_operator()
|
or_else_operator()
|
||||||
or_return_operator()
|
or_return_operator()
|
||||||
or_break_and_or_continue_operators()
|
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"
|
BLOCK "0409FDE9"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "https://odin-lang.org/"
|
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 "FileVersion", QUOTE(VF)
|
||||||
VALUE "InternalName", "odin.exe"
|
VALUE "InternalName", "odin.exe"
|
||||||
VALUE "LegalCopyright", "Copyright (c) 2016-2024 Ginger Bill. All rights reserved."
|
VALUE "LegalCopyright", "Copyright (c) 2016-2024 Ginger Bill. All rights reserved."
|
||||||
VALUE "OriginalFilename", "odin.exe"
|
VALUE "OriginalFilename", "odin.exe"
|
||||||
VALUE "ProductName", "The Odin Programming Language"
|
VALUE "ProductName", "Odin Programming Language"
|
||||||
VALUE "ProductVersion", QUOTE(VP)
|
VALUE "ProductVersion", QUOTE(VP)
|
||||||
VALUE "Comments", QUOTE(git-sha: GIT_SHA)
|
VALUE "Comments", QUOTE(git-sha: GIT_SHA)
|
||||||
// custom values
|
// custom values
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pkgs.mkShell {
|
|||||||
name = "odin";
|
name = "odin";
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
git
|
git
|
||||||
|
which
|
||||||
clang_17
|
clang_17
|
||||||
llvmPackages_17.llvm
|
llvmPackages_17.llvm
|
||||||
llvmPackages_17.bintools
|
llvmPackages_17.bintools
|
||||||
|
|||||||
+42
-460
@@ -2,12 +2,6 @@
|
|||||||
Gather and print platform and version info to help with reporting Odin bugs.
|
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)
|
#if defined(GB_SYSTEM_LINUX)
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
@@ -154,21 +148,6 @@ gb_internal void report_windows_product_type(DWORD ProductType) {
|
|||||||
}
|
}
|
||||||
#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 void report_cpu_info() {
|
gb_internal void report_cpu_info() {
|
||||||
gb_printf("\tCPU: ");
|
gb_printf("\tCPU: ");
|
||||||
|
|
||||||
@@ -547,387 +526,46 @@ gb_internal void report_os_info() {
|
|||||||
gb_printf(", %s %s\n", info->sysname, info->release);
|
gb_printf(", %s %s\n", info->sysname, info->release);
|
||||||
|
|
||||||
#elif defined(GB_SYSTEM_OSX)
|
#elif defined(GB_SYSTEM_OSX)
|
||||||
struct Darwin_To_Release {
|
gbString sw_vers = gb_string_make(heap_allocator(), "");
|
||||||
const char* build; // 21G83
|
if (!system_exec_command_line_app_output("sw_vers --productVersion", &sw_vers)) {
|
||||||
int darwin[3]; // Darwin kernel triplet
|
gb_printf("macOS Unknown\n");
|
||||||
const char* os_name; // OS X, MacOS
|
return;
|
||||||
struct {
|
}
|
||||||
const char* name; // Monterey, Mojave, etc.
|
|
||||||
int version[3]; // 12.4, etc.
|
|
||||||
} release;
|
|
||||||
};
|
|
||||||
|
|
||||||
Darwin_To_Release macos_release_map[] = {
|
uint32_t major, minor, patch;
|
||||||
{"8A428", { 8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
|
||||||
{"8A432", { 8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
if (sscanf(cast(const char *)sw_vers, "%u.%u.%u", &major, &minor, &patch) != 3) {
|
||||||
{"8B15", { 8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
gb_printf("macOS Unknown\n");
|
||||||
{"8B17", { 8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
return;
|
||||||
{"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}}},
|
switch (major) {
|
||||||
{"8E45", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
case 15: gb_printf("macOS Sequoia"); break;
|
||||||
{"8E90", { 8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
case 14: gb_printf("macOS Sonoma"); break;
|
||||||
{"8F46", { 8, 3, 0}, "macOS", {"Tiger", {10, 4, 3}}},
|
case 13: gb_printf("macOS Ventura"); break;
|
||||||
{"8G32", { 8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
case 12: gb_printf("macOS Monterey"); break;
|
||||||
{"8G1165", { 8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
case 11: gb_printf("macOS Big Sur"); break;
|
||||||
{"8H14", { 8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
case 10:
|
||||||
{"8G1454", { 8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
{
|
||||||
{"8I127", { 8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
switch (minor) {
|
||||||
{"8I1119", { 8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
case 15: gb_printf("macOS Catalina"); break;
|
||||||
{"8J135", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
case 14: gb_printf("macOS Mojave"); break;
|
||||||
{"8J2135a", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
case 13: gb_printf("macOS High Sierra"); break;
|
||||||
{"8K1079", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
case 12: gb_printf("macOS Sierra"); break;
|
||||||
{"8N5107", { 8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
case 11: gb_printf("OS X El Capitan"); break;
|
||||||
{"8L127", { 8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
case 10: gb_printf("OS X Yosemite"); break;
|
||||||
{"8L2127", { 8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
default: gb_printf("macOS Unknown");
|
||||||
{"8P135", { 8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
};
|
||||||
{"8P2137", { 8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
break;
|
||||||
{"8R218", { 8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
}
|
||||||
{"8R2218", { 8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
default:
|
||||||
{"8R2232", { 8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
gb_printf("macOS Unknown");
|
||||||
{"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}}},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
gb_printf(" %d.%d.%d (build ", major, minor, patch);
|
||||||
|
|
||||||
b32 build_found = 1;
|
b32 build_found = 1;
|
||||||
b32 darwin_found = 1;
|
b32 darwin_found = 1;
|
||||||
uint32_t major, minor, patch;
|
|
||||||
|
|
||||||
#define MACOS_VERSION_BUFFER_SIZE 100
|
#define MACOS_VERSION_BUFFER_SIZE 100
|
||||||
char build_buffer[MACOS_VERSION_BUFFER_SIZE];
|
char build_buffer[MACOS_VERSION_BUFFER_SIZE];
|
||||||
@@ -943,81 +581,25 @@ gb_internal void report_os_info() {
|
|||||||
|
|
||||||
int darwin_mibs[] = { CTL_KERN, KERN_OSRELEASE };
|
int darwin_mibs[] = { CTL_KERN, KERN_OSRELEASE };
|
||||||
if (sysctl(darwin_mibs, 2, darwin_buffer, &darwin_buffer_size, NULL, 0) == -1) {
|
if (sysctl(darwin_mibs, 2, darwin_buffer, &darwin_buffer_size, NULL, 0) == -1) {
|
||||||
gb_printf("macOS Unknown\n");
|
darwin_found = 0;
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
if (sscanf(darwin_buffer, "%u.%u.%u", &major, &minor, &patch) != 3) {
|
if (sscanf(darwin_buffer, "%u.%u.%u", &major, &minor, &patch) != 3) {
|
||||||
darwin_found = 0;
|
darwin_found = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan table for match on BUILD
|
if (build_found) {
|
||||||
int macos_release_count = sizeof(macos_release_map) / sizeof(macos_release_map[0]);
|
gb_printf("%s, kernel ", build_buffer);
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
match = build_match;
|
gb_printf("Unknown, kernel ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.os_name) {
|
if (darwin_found) {
|
||||||
gb_printf("%s %s %d", match.os_name, match.release.name, match.release.version[0]);
|
gb_printf("%s)\n", darwin_buffer);
|
||||||
if (match.release.version[1] > 0 || match.release.version[2] > 0) {
|
} else {
|
||||||
gb_printf(".%d", match.release.version[1]);
|
gb_printf("Unknown)\n");
|
||||||
}
|
|
||||||
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 (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)
|
#elif defined(GB_SYSTEM_OPENBSD) || defined(GB_SYSTEM_NETBSD)
|
||||||
struct utsname un;
|
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/types.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include "build_cpuid.cpp"
|
||||||
|
|
||||||
// #if defined(GB_SYSTEM_WINDOWS)
|
// #if defined(GB_SYSTEM_WINDOWS)
|
||||||
// #define DEFAULT_TO_THREADED_CHECKER
|
// #define DEFAULT_TO_THREADED_CHECKER
|
||||||
@@ -343,6 +344,22 @@ struct BuildCacheData {
|
|||||||
bool copy_already_done;
|
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
|
// This stores the information for the specify architecture of this build
|
||||||
struct BuildContext {
|
struct BuildContext {
|
||||||
// Constants
|
// Constants
|
||||||
@@ -418,12 +435,13 @@ struct BuildContext {
|
|||||||
bool no_rpath;
|
bool no_rpath;
|
||||||
bool no_entry_point;
|
bool no_entry_point;
|
||||||
bool no_thread_local;
|
bool no_thread_local;
|
||||||
bool use_lld;
|
|
||||||
bool cross_compiling;
|
bool cross_compiling;
|
||||||
bool different_os;
|
bool different_os;
|
||||||
bool keep_object_files;
|
bool keep_object_files;
|
||||||
bool disallow_do;
|
bool disallow_do;
|
||||||
|
|
||||||
|
LinkerChoice linker_choice;
|
||||||
|
|
||||||
StringSet custom_attributes;
|
StringSet custom_attributes;
|
||||||
|
|
||||||
bool strict_style;
|
bool strict_style;
|
||||||
@@ -449,6 +467,7 @@ struct BuildContext {
|
|||||||
BuildCacheData build_cache_data;
|
BuildCacheData build_cache_data;
|
||||||
|
|
||||||
bool internal_no_inline;
|
bool internal_no_inline;
|
||||||
|
bool internal_by_value;
|
||||||
|
|
||||||
bool no_threaded_checker;
|
bool no_threaded_checker;
|
||||||
|
|
||||||
@@ -1870,7 +1889,7 @@ gb_internal bool init_build_paths(String init_filename) {
|
|||||||
return false;
|
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");
|
gb_printf_err("link.exe not found.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-1
@@ -2565,6 +2565,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
|
|
||||||
case BuiltinProc_swizzle: {
|
case BuiltinProc_swizzle: {
|
||||||
// swizzle :: proc(v: [N]T, ..int) -> [M]T
|
// swizzle :: proc(v: [N]T, ..int) -> [M]T
|
||||||
|
if (!operand->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *original_type = operand->type;
|
Type *original_type = operand->type;
|
||||||
Type *type = base_type(original_type);
|
Type *type = base_type(original_type);
|
||||||
i64 max_count = 0;
|
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
|
// imag :: proc(x: type) -> float_type
|
||||||
|
|
||||||
Operand *x = operand;
|
Operand *x = operand;
|
||||||
|
if (!x->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_type_untyped(x->type)) {
|
if (is_type_untyped(x->type)) {
|
||||||
if (x->mode == Addressing_Constant) {
|
if (x->mode == Addressing_Constant) {
|
||||||
if (is_type_numeric(x->type)) {
|
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
|
// kmag :: proc(x: type) -> float_type
|
||||||
|
|
||||||
Operand *x = operand;
|
Operand *x = operand;
|
||||||
|
if (!x->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_type_untyped(x->type)) {
|
if (is_type_untyped(x->type)) {
|
||||||
if (x->mode == Addressing_Constant) {
|
if (x->mode == Addressing_Constant) {
|
||||||
if (is_type_numeric(x->type)) {
|
if (is_type_numeric(x->type)) {
|
||||||
@@ -3031,6 +3043,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
case BuiltinProc_conj: {
|
case BuiltinProc_conj: {
|
||||||
// conj :: proc(x: type) -> type
|
// conj :: proc(x: type) -> type
|
||||||
Operand *x = operand;
|
Operand *x = operand;
|
||||||
|
if (!x->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *t = x->type;
|
Type *t = x->type;
|
||||||
Type *elem = core_array_type(t);
|
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: {
|
case BuiltinProc_expand_values: {
|
||||||
|
if (!operand->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *type = base_type(operand->type);
|
Type *type = base_type(operand->type);
|
||||||
if (!is_type_struct(type) && !is_type_array(type)) {
|
if (!is_type_struct(type) && !is_type_array(type)) {
|
||||||
gbString type_str = type_to_string(operand->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);
|
gb_string_free(type_str);
|
||||||
return false;
|
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]);
|
check_multi_expr_or_type(c, operand, ce->args[0]);
|
||||||
|
|
||||||
|
if (!operand->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *original_type = operand->type;
|
Type *original_type = operand->type;
|
||||||
Type *type = base_type(operand->type);
|
Type *type = base_type(operand->type);
|
||||||
|
|
||||||
if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) {
|
if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) {
|
||||||
// Okay
|
// Okay
|
||||||
} else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
} 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;
|
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;
|
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]);
|
check_multi_expr_or_type(c, operand, ce->args[0]);
|
||||||
|
|
||||||
|
if (!operand->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *original_type = operand->type;
|
Type *original_type = operand->type;
|
||||||
Type *type = base_type(operand->type);
|
Type *type = base_type(operand->type);
|
||||||
|
|
||||||
@@ -3358,6 +3391,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
return false;
|
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;
|
bool all_constant = operand->mode == Addressing_Constant;
|
||||||
|
|
||||||
auto operands = array_make<Operand>(heap_allocator(), 0, ce->args.count);
|
auto operands = array_make<Operand>(heap_allocator(), 0, ce->args.count);
|
||||||
@@ -3448,6 +3486,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
|
|
||||||
case BuiltinProc_abs: {
|
case BuiltinProc_abs: {
|
||||||
// abs :: proc(n: numeric) -> numeric
|
// abs :: proc(n: numeric) -> numeric
|
||||||
|
if (!operand->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(is_type_numeric(operand->type) && !is_type_array(operand->type))) {
|
if (!(is_type_numeric(operand->type) && !is_type_array(operand->type))) {
|
||||||
gbString type_str = type_to_string(operand->type);
|
gbString type_str = type_to_string(operand->type);
|
||||||
error(call, "Expected a numeric type to 'abs', got '%s'", type_str);
|
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: {
|
case BuiltinProc_clamp: {
|
||||||
// clamp :: proc(a, min, max: ordered) -> ordered
|
// clamp :: proc(a, min, max: ordered) -> ordered
|
||||||
|
if (!operand->type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Type *type = operand->type;
|
Type *type = operand->type;
|
||||||
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
||||||
gbString type_str = type_to_string(operand->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 (is_type_proc(dst)) {
|
||||||
if (are_types_identical(src, dst)) {
|
if (are_types_identical(src, dst)) {
|
||||||
return 3;
|
return 3;
|
||||||
@@ -1052,12 +1038,6 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
|
|||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
type = type->DynamicArray.elem;
|
type = type->DynamicArray.elem;
|
||||||
continue;
|
continue;
|
||||||
case Type_RelativePointer:
|
|
||||||
type = type->RelativePointer.pointer_type;
|
|
||||||
continue;
|
|
||||||
case Type_RelativeMultiPointer:
|
|
||||||
type = type->RelativeMultiPointer.pointer_type;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -3561,6 +3541,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operand src = *o;
|
||||||
|
|
||||||
Type *src_t = o->type;
|
Type *src_t = o->type;
|
||||||
Type *dst_t = t;
|
Type *dst_t = t;
|
||||||
Type *src_bt = base_type(src_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
|
// identical casts that cannot be foreseen or otherwise
|
||||||
// forbidden, so just skip them.
|
// forbidden, so just skip them.
|
||||||
if (forbid_identical && check_vet_flags(c) & VetFlag_Cast &&
|
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)) {
|
if (are_types_identical(src_t, dst_t)) {
|
||||||
gbString oper_str = expr_to_string(o->expr);
|
gbString oper_str = expr_to_string(o->expr);
|
||||||
gbString to_type = type_to_string(dst_t);
|
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_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
||||||
GB_ASSERT_NOT_NULL(target_type);
|
// GB_ASSERT_NOT_NULL(target_type);
|
||||||
if (operand->mode == Addressing_Invalid ||
|
if (target_type == nullptr || operand->mode == Addressing_Invalid ||
|
||||||
operand->mode == Addressing_Type ||
|
operand->mode == Addressing_Type ||
|
||||||
is_type_typed(operand->type) ||
|
is_type_typed(operand->type) ||
|
||||||
target_type == t_invalid) {
|
target_type == t_invalid) {
|
||||||
@@ -4997,8 +4980,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
|
|||||||
if (success_) *success_ = true;
|
if (success_) *success_ = true;
|
||||||
if (finish_) *finish_ = false;
|
if (finish_) *finish_ = false;
|
||||||
return tav.value;
|
return tav.value;
|
||||||
|
} else if (is_type_proc(tav.type)) {
|
||||||
|
if (success_) *success_ = true;
|
||||||
|
if (finish_) *finish_ = false;
|
||||||
|
return tav.value;
|
||||||
} else {
|
} 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 (success_) *success_ = true;
|
||||||
if (finish_) *finish_ = false;
|
if (finish_) *finish_ = false;
|
||||||
return tav.value;
|
return tav.value;
|
||||||
@@ -8232,17 +8219,6 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
|
|||||||
}
|
}
|
||||||
return true;
|
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:
|
case Type_DynamicArray:
|
||||||
o->type = t->DynamicArray.elem;
|
o->type = t->DynamicArray.elem;
|
||||||
if (o->mode != Addressing_Constant) {
|
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);
|
error(node, "Undeclared name '%.*s' for type '%s'", LIT(name), typ);
|
||||||
|
|
||||||
check_did_you_mean_type(name, bt->Enum.fields);
|
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 {
|
} else {
|
||||||
gbString typ = type_to_string(th);
|
gbString typ = type_to_string(th);
|
||||||
gbString str = expr_to_string(node);
|
gbString str = expr_to_string(node);
|
||||||
@@ -10616,8 +10601,6 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
|||||||
// Okay
|
// Okay
|
||||||
} else if (is_type_string(t)) {
|
} else if (is_type_string(t)) {
|
||||||
// Okay
|
// Okay
|
||||||
} else if (is_type_relative_multi_pointer(t)) {
|
|
||||||
// Okay
|
|
||||||
} else if (is_type_matrix(t)) {
|
} else if (is_type_matrix(t)) {
|
||||||
// Okay
|
// Okay
|
||||||
} else {
|
} else {
|
||||||
@@ -10772,11 +10755,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Type_RelativeMultiPointer:
|
|
||||||
valid = true;
|
|
||||||
o->type = type_deref(o->type);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Type_EnumeratedArray:
|
case Type_EnumeratedArray:
|
||||||
{
|
{
|
||||||
gbString str = expr_to_string(o->expr);
|
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
|
x[i:n] -> []T
|
||||||
*/
|
*/
|
||||||
o->type = alloc_type_slice(t->MultiPointer.elem);
|
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) {
|
} else if (t->kind == Type_SoaPointer) {
|
||||||
o->mode = Addressing_SoaVariable;
|
o->mode = Addressing_SoaVariable;
|
||||||
o->type = type_deref(t);
|
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 {
|
} else {
|
||||||
gbString str = expr_to_string(o->expr);
|
gbString str = expr_to_string(o->expr);
|
||||||
gbString typ = type_to_string(o->type);
|
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 &&
|
if (cond && cond->kind == Ast_BinaryExpr &&
|
||||||
cond->BinaryExpr.left && cond->BinaryExpr.right &&
|
cond->BinaryExpr.left && cond->BinaryExpr.right &&
|
||||||
cond->BinaryExpr.op.kind == Token_GtEq &&
|
cond->BinaryExpr.op.kind == Token_GtEq &&
|
||||||
|
type_of_expr(cond->BinaryExpr.left) != nullptr &&
|
||||||
is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) &&
|
is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) &&
|
||||||
cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer &&
|
cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer &&
|
||||||
is_exact_value_zero(cond->BinaryExpr.right->tav.value)) {
|
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 &&
|
} else if (cond && cond->kind == Ast_BinaryExpr &&
|
||||||
cond->BinaryExpr.left && cond->BinaryExpr.right &&
|
cond->BinaryExpr.left && cond->BinaryExpr.right &&
|
||||||
cond->BinaryExpr.op.kind == Token_LtEq &&
|
cond->BinaryExpr.op.kind == Token_LtEq &&
|
||||||
|
type_of_expr(cond->BinaryExpr.right) != nullptr &&
|
||||||
is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) &&
|
is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) &&
|
||||||
cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer &&
|
cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer &&
|
||||||
is_exact_value_zero(cond->BinaryExpr.left->tav.value)) {
|
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_internal void check_procedure_param_polymorphic_type(CheckerContext *ctx, Type *type, Ast *type_expr) {
|
||||||
GB_ASSERT_NOT_NULL(type_expr);
|
if (type == nullptr || type_expr == nullptr || ctx->in_polymorphic_specialization) { return; }
|
||||||
if (type == nullptr || ctx->in_polymorphic_specialization) { return; }
|
|
||||||
if (!is_type_polymorphic_record_unspecialized(type)) { return; }
|
if (!is_type_polymorphic_record_unspecialized(type)) { return; }
|
||||||
|
|
||||||
bool invalid_polymorpic_type_use = false;
|
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_end;
|
||||||
|
|
||||||
case_ast_node(rt, RelativeType, e);
|
case_ast_node(rt, RelativeType, e);
|
||||||
GB_ASSERT(rt->tag->kind == Ast_CallExpr);
|
error(e, "#relative types have been removed from the compiler. Prefer \"core:relative\".");
|
||||||
ast_node(ce, CallExpr, rt->tag);
|
*type = t_invalid;
|
||||||
|
|
||||||
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;
|
|
||||||
set_base_type(named_type, *type);
|
set_base_type(named_type, *type);
|
||||||
return true;
|
return true;
|
||||||
case_end;
|
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);
|
add_type_info_type_internal(c, bt->SimdVector.elem);
|
||||||
break;
|
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:
|
case Type_Matrix:
|
||||||
add_type_info_type_internal(c, bt->Matrix.elem);
|
add_type_info_type_internal(c, bt->Matrix.elem);
|
||||||
break;
|
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);
|
add_min_dep_type_info(c, bt->SimdVector.elem);
|
||||||
break;
|
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:
|
case Type_Matrix:
|
||||||
add_min_dep_type_info(c, bt->Matrix.elem);
|
add_min_dep_type_info(c, bt->Matrix.elem);
|
||||||
break;
|
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_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_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_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_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_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"));
|
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_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_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_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_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_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);
|
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_SOAStructFixed = 17,
|
||||||
OdinDocType_SOAStructSlice = 18,
|
OdinDocType_SOAStructSlice = 18,
|
||||||
OdinDocType_SOAStructDynamic = 19,
|
OdinDocType_SOAStructDynamic = 19,
|
||||||
OdinDocType_RelativePointer = 20,
|
|
||||||
OdinDocType_RelativeMultiPointer = 21,
|
|
||||||
OdinDocType_MultiPointer = 22,
|
OdinDocType_MultiPointer = 22,
|
||||||
OdinDocType_Matrix = 23,
|
OdinDocType_Matrix = 23,
|
||||||
OdinDocType_SoaPointer = 24,
|
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);
|
doc_type.types = odin_doc_type_as_slice(w, type->SimdVector.elem);
|
||||||
// TODO(bill):
|
// TODO(bill):
|
||||||
break;
|
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:
|
case Type_Matrix:
|
||||||
doc_type.kind = OdinDocType_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: {
|
case Token_Rune: {
|
||||||
Rune r = GB_RUNE_INVALID;
|
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);
|
return exact_value_i64(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-23
@@ -167,8 +167,10 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
|||||||
|
|
||||||
if (is_windows) {
|
if (is_windows) {
|
||||||
String section_name = str_lit("msvc-link");
|
String section_name = str_lit("msvc-link");
|
||||||
if (build_context.use_lld) {
|
switch (build_context.linker_choice) {
|
||||||
section_name = str_lit("lld-link");
|
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);
|
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]);
|
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));
|
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 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]);
|
String rc_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RC]);
|
||||||
defer (gb_free(heap_allocator(), res_path.text));
|
defer (gb_free(heap_allocator(), res_path.text));
|
||||||
@@ -365,25 +408,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
|||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else { // lld
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
timings_start_section(timings, str_lit("ld-link"));
|
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 ", LIT(build_context.extra_linker_flags));
|
||||||
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
|
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");
|
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
|
||||||
result = system_exec_command_line_app("lld-link", link_command_line);
|
result = system_exec_command_line_app("lld-link", link_command_line);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -57,6 +57,10 @@
|
|||||||
#define LB_USE_NEW_PASS_SYSTEM 0
|
#define LB_USE_NEW_PASS_SYSTEM 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR >= 19
|
||||||
|
#define LLVMDIBuilderInsertDeclareAtEnd(...) LLVMDIBuilderInsertDeclareRecordAtEnd(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
gb_internal bool lb_use_new_pass_system(void) {
|
gb_internal bool lb_use_new_pass_system(void) {
|
||||||
return LB_USE_NEW_PASS_SYSTEM;
|
return LB_USE_NEW_PASS_SYSTEM;
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,6 @@ enum lbAddrKind {
|
|||||||
lbAddr_Context,
|
lbAddr_Context,
|
||||||
lbAddr_SoaVariable,
|
lbAddr_SoaVariable,
|
||||||
|
|
||||||
lbAddr_RelativePointer,
|
|
||||||
|
|
||||||
lbAddr_Swizzle,
|
lbAddr_Swizzle,
|
||||||
lbAddr_SwizzleLarge,
|
lbAddr_SwizzleLarge,
|
||||||
@@ -103,9 +106,6 @@ struct lbAddr {
|
|||||||
lbValue index;
|
lbValue index;
|
||||||
Ast *node;
|
Ast *node;
|
||||||
} index_set;
|
} index_set;
|
||||||
struct {
|
|
||||||
bool deref;
|
|
||||||
} relative;
|
|
||||||
struct {
|
struct {
|
||||||
Type *type;
|
Type *type;
|
||||||
u8 count; // 2, 3, or 4 components
|
u8 count; // 2, 3, or 4 components
|
||||||
|
|||||||
@@ -920,17 +920,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
|||||||
elem, subscripts, gb_count_of(subscripts));
|
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: {
|
case Type_Matrix: {
|
||||||
LLVMMetadataRef subscripts[1] = {};
|
LLVMMetadataRef subscripts[1] = {};
|
||||||
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
|
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);
|
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: {
|
case Type_DynamicArray: {
|
||||||
lbValue dynamic_array = {};
|
lbValue dynamic_array = {};
|
||||||
dynamic_array = lb_build_expr(p, ie->expr);
|
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;
|
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: {
|
case Type_DynamicArray: {
|
||||||
Type *elem_type = type->DynamicArray.elem;
|
Type *elem_type = type->DynamicArray.elem;
|
||||||
Type *slice_type = alloc_type_slice(elem_type);
|
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];
|
auto const &f = fields[i];
|
||||||
|
|
||||||
LLVMValueRef mask = LLVMConstInt(lit, 1, false);
|
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));
|
mask = LLVMConstSub(mask, LLVMConstInt(lit, 1, false));
|
||||||
|
|
||||||
LLVMValueRef elem = values[i].value;
|
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;
|
bits_to_set -= mask_width;
|
||||||
|
|
||||||
LLVMValueRef mask = LLVMConstInt(vt, 1, false);
|
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));
|
mask = LLVMConstSub(mask, LLVMConstInt(vt, 1, false));
|
||||||
|
|
||||||
LLVMValueRef to_set = LLVMBuildAnd(p->builder, val, mask, "");
|
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);
|
case_ast_node(de, DerefExpr, expr);
|
||||||
Type *t = type_of_expr(de->expr);
|
Type *t = type_of_expr(de->expr);
|
||||||
if (is_type_relative_pointer(t)) {
|
if (is_type_soa_pointer(t)) {
|
||||||
lbAddr addr = lb_build_addr(p, de->expr);
|
|
||||||
addr.relative.deref = true;
|
|
||||||
return addr;
|
|
||||||
} else if (is_type_soa_pointer(t)) {
|
|
||||||
lbValue value = lb_build_expr(p, de->expr);
|
lbValue value = lb_build_expr(p, de->expr);
|
||||||
lbValue ptr = lb_emit_struct_ev(p, value, 0);
|
lbValue ptr = lb_emit_struct_ev(p, value, 0);
|
||||||
lbValue idx = lb_emit_struct_ev(p, value, 1);
|
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) {
|
gb_internal lbAddr lb_addr(lbValue addr) {
|
||||||
lbAddr v = {lbAddr_Default, 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;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,42 +493,6 @@ gb_internal Type *lb_addr_type(lbAddr const &addr) {
|
|||||||
return type_deref(addr.addr.type);
|
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) {
|
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);
|
lbAddr v = lb_add_local_generated(p, type, false);
|
||||||
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
|
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:
|
case lbAddr_Map:
|
||||||
return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
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:
|
case lbAddr_SoaVariable:
|
||||||
{
|
{
|
||||||
Type *soa_ptr_type = alloc_type_soa_pointer(lb_addr_type(addr));
|
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) {
|
gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) {
|
||||||
lbAddr addr = lb_build_addr(p, expr);
|
lbAddr addr = lb_build_addr(p, expr);
|
||||||
if (addr.kind == lbAddr_RelativePointer) {
|
|
||||||
return addr.addr;
|
|
||||||
}
|
|
||||||
return lb_addr_get_ptr(p, 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));
|
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) {
|
if (addr.kind == lbAddr_BitField) {
|
||||||
lbValue dst = addr.addr;
|
lbValue dst = addr.addr;
|
||||||
if (is_type_endian_big(addr.bitfield.type)) {
|
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);
|
lb_emit_runtime_call(p, "__write_bits", args);
|
||||||
}
|
}
|
||||||
return;
|
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) {
|
} else if (addr.kind == lbAddr_Map) {
|
||||||
lb_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
lb_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
||||||
return;
|
return;
|
||||||
@@ -1246,46 +1154,6 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
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) {
|
} else if (addr.kind == lbAddr_Map) {
|
||||||
Type *map_type = base_type(type_deref(addr.addr.type));
|
Type *map_type = base_type(type_deref(addr.addr.type));
|
||||||
GB_ASSERT(map_type->kind == Type_Map);
|
GB_ASSERT(map_type->kind == Type_Map);
|
||||||
@@ -2379,13 +2247,6 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
|||||||
case Type_SimdVector:
|
case Type_SimdVector:
|
||||||
return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count);
|
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:
|
case Type_Matrix:
|
||||||
{
|
{
|
||||||
i64 size = type_size_of(type);
|
i64 size = type_size_of(type);
|
||||||
@@ -2740,7 +2601,7 @@ general_end:;
|
|||||||
GB_ASSERT(p->decl_block != p->curr_block);
|
GB_ASSERT(p->decl_block != p->curr_block);
|
||||||
|
|
||||||
i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
|
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);
|
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);
|
p->raw_input_parameters = array_make<LLVMValueRef>(permanent_allocator(), raw_input_parameters_count);
|
||||||
LLVMGetParams(p->value, p->raw_input_parameters.data);
|
LLVMGetParams(p->value, p->raw_input_parameters.data);
|
||||||
|
|
||||||
|
bool is_odin_cc = is_calling_convention_odin(ft->calling_convention);
|
||||||
|
|
||||||
unsigned param_index = 0;
|
unsigned param_index = 0;
|
||||||
for_array(i, params->variables) {
|
for_array(i, params->variables) {
|
||||||
Entity *e = params->variables[i];
|
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) {
|
} else if (arg_type->kind == lbArg_Indirect) {
|
||||||
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
|
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 = {};
|
lbValue ptr = {};
|
||||||
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
|
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
|
||||||
ptr.type = alloc_type_pointer(e->type);
|
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_entity(p->module, e, ptr);
|
||||||
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block);
|
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;
|
p->scope_index += 1;
|
||||||
array_add(&p->scope_stack, s);
|
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;
|
p->scope_index -= 1;
|
||||||
array_pop(&p->scope_stack);
|
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_Proc: kind = Typeid_Procedure; break;
|
||||||
case Type_BitSet: kind = Typeid_Bit_Set; break;
|
case Type_BitSet: kind = Typeid_Bit_Set; break;
|
||||||
case Type_SimdVector: kind = Typeid_Simd_Vector; 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_SoaPointer: kind = Typeid_SoaPointer; break;
|
||||||
case Type_BitField: kind = Typeid_Bit_Field; 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;
|
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:
|
case Type_Matrix:
|
||||||
{
|
{
|
||||||
tag_type = t_type_info_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) {
|
switch (kind) {
|
||||||
case LLVMStructTypeKind:
|
case LLVMStructTypeKind:
|
||||||
case LLVMArrayTypeKind:
|
case LLVMArrayTypeKind:
|
||||||
// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
|
if (is_type_tuple(type)) {
|
||||||
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
|
// 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;
|
break;
|
||||||
default:
|
default:
|
||||||
LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr);
|
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 *t = base_type(type_deref(s.type));
|
||||||
Type *result_type = nullptr;
|
Type *result_type = nullptr;
|
||||||
|
|
||||||
if (is_type_relative_pointer(t)) {
|
|
||||||
s = lb_addr_get_ptr(p, lb_addr(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_type_struct(t)) {
|
if (is_type_struct(t)) {
|
||||||
result_type = get_struct_field_type(t, index);
|
result_type = get_struct_field_type(t, index);
|
||||||
} else if (is_type_union(t)) {
|
} 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);
|
e = lb_emit_array_epi(p, e, index);
|
||||||
} else if (type->kind == Type_Map) {
|
} else if (type->kind == Type_Map) {
|
||||||
e = lb_emit_struct_ep(p, e, index);
|
e = lb_emit_struct_ep(p, e, index);
|
||||||
} else if (type->kind == Type_RelativePointer) {
|
|
||||||
e = lb_emit_struct_ep(p, e, index);
|
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("un-gep-able type %s", type_to_string(type));
|
GB_PANIC("un-gep-able type %s", type_to_string(type));
|
||||||
}
|
}
|
||||||
|
|||||||
+479
-364
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);
|
tag = parse_call_expr(f, tag);
|
||||||
}
|
}
|
||||||
Ast *type = parse_type(f);
|
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);
|
return ast_relative_type(f, tag, type);
|
||||||
} else if (name.string == "force_inline" ||
|
} else if (name.string == "force_inline" ||
|
||||||
name.string == "force_no_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);
|
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) {
|
gb_internal String string_join_and_quote(gbAllocator a, Array<String> strings) {
|
||||||
if (!strings.count) {
|
if (!strings.count) {
|
||||||
return make_string(nullptr, 0);
|
return make_string(nullptr, 0);
|
||||||
@@ -427,7 +453,11 @@ gb_internal String string_join_and_quote(gbAllocator a, Array<String> strings) {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
s = gb_string_append_fmt(s, " ");
|
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]));
|
s = gb_string_append_fmt(s, "\"%.*s\" ", LIT(strings[i]));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return make_string(cast(u8 *) s, gb_string_length(s));
|
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;
|
Rune r = -1;
|
||||||
isize size = utf8_decode(s.text, s.len, &r);
|
isize size = utf8_decode(s.text, s.len, &r);
|
||||||
*rune = r;
|
*rune = r;
|
||||||
*multiple_bytes = true;
|
if (multiple_bytes) *multiple_bytes = true;
|
||||||
*tail_string = make_string(s.text+size, s.len-size);
|
if (tail_string) *tail_string = make_string(s.text+size, s.len-size);
|
||||||
return true;
|
return true;
|
||||||
} else if (s[0] != '\\') {
|
} else if (s[0] != '\\') {
|
||||||
*rune = 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,10 +809,10 @@ gb_internal bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_byt
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*rune = r;
|
*rune = r;
|
||||||
*multiple_bytes = true;
|
if (multiple_bytes) *multiple_bytes = true;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
*tail_string = s;
|
if (tail_string) *tail_string = s;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-101
@@ -272,14 +272,6 @@ struct TypeProc {
|
|||||||
Type *elem; \
|
Type *elem; \
|
||||||
Type *generic_count; \
|
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_KIND(Matrix, struct { \
|
||||||
Type *elem; \
|
Type *elem; \
|
||||||
i64 row_count; \
|
i64 row_count; \
|
||||||
@@ -367,8 +359,6 @@ enum Typeid_Kind : u8 {
|
|||||||
Typeid_Map,
|
Typeid_Map,
|
||||||
Typeid_Bit_Set,
|
Typeid_Bit_Set,
|
||||||
Typeid_Simd_Vector,
|
Typeid_Simd_Vector,
|
||||||
Typeid_Relative_Pointer,
|
|
||||||
Typeid_Relative_Multi_Pointer,
|
|
||||||
Typeid_Matrix,
|
Typeid_Matrix,
|
||||||
Typeid_SoaPointer,
|
Typeid_SoaPointer,
|
||||||
Typeid_Bit_Field,
|
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_map = nullptr;
|
||||||
gb_global Type *t_type_info_bit_set = 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_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_matrix = nullptr;
|
||||||
gb_global Type *t_type_info_soa_pointer = nullptr;
|
gb_global Type *t_type_info_soa_pointer = nullptr;
|
||||||
gb_global Type *t_type_info_bit_field = 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_map_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_bit_set_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_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_matrix_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
|
gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_bit_field_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;
|
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) {
|
gb_internal Type *alloc_type_named(String name, Type *base, Entity *type_name) {
|
||||||
Type *t = alloc_type(Type_Named);
|
Type *t = alloc_type(Type_Named);
|
||||||
t->Named.name = name;
|
t->Named.name = name;
|
||||||
@@ -1227,8 +1195,6 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) {
|
|||||||
switch (bt->kind) {
|
switch (bt->kind) {
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
return bt->Pointer.elem;
|
return bt->Pointer.elem;
|
||||||
case Type_RelativePointer:
|
|
||||||
return type_deref(bt->RelativePointer.pointer_type);
|
|
||||||
case Type_SoaPointer:
|
case Type_SoaPointer:
|
||||||
{
|
{
|
||||||
Type *elem = base_type(bt->SoaPointer.elem);
|
Type *elem = base_type(bt->SoaPointer.elem);
|
||||||
@@ -1667,15 +1633,6 @@ gb_internal bool is_type_generic(Type *t) {
|
|||||||
return t->kind == Type_Generic;
|
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) {
|
gb_internal bool is_type_u8_slice(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
if (t->kind == Type_Slice) {
|
if (t->kind == Type_Slice) {
|
||||||
@@ -2118,8 +2075,6 @@ gb_internal bool is_type_indexable(Type *t) {
|
|||||||
return true;
|
return true;
|
||||||
case Type_EnumeratedArray:
|
case Type_EnumeratedArray:
|
||||||
return true;
|
return true;
|
||||||
case Type_RelativeMultiPointer:
|
|
||||||
return true;
|
|
||||||
case Type_Matrix:
|
case Type_Matrix:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2137,8 +2092,6 @@ gb_internal bool is_type_sliceable(Type *t) {
|
|||||||
return true;
|
return true;
|
||||||
case Type_EnumeratedArray:
|
case Type_EnumeratedArray:
|
||||||
return false;
|
return false;
|
||||||
case Type_RelativeMultiPointer:
|
|
||||||
return true;
|
|
||||||
case Type_Matrix:
|
case Type_Matrix:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2345,27 +2298,7 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2407,10 +2340,6 @@ gb_internal bool type_has_nil(Type *t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case Type_RelativePointer:
|
|
||||||
case Type_RelativeMultiPointer:
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2579,10 +2508,6 @@ gb_internal bool is_type_load_safe(Type *type) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Type_RelativePointer:
|
|
||||||
case Type_RelativeMultiPointer:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
case Type_MultiPointer:
|
case Type_MultiPointer:
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
@@ -3945,11 +3870,6 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
|
|||||||
case Type_Matrix:
|
case Type_Matrix:
|
||||||
return matrix_align_of(t, path);
|
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:
|
case Type_SoaPointer:
|
||||||
return build_context.int_size;
|
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;
|
min_field_align = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePath path{};
|
||||||
|
type_path_init(&path);
|
||||||
|
defer (type_path_free(&path));
|
||||||
|
|
||||||
if (is_raw_union) {
|
if (is_raw_union) {
|
||||||
for_array(i, fields) {
|
for_array(i, fields) {
|
||||||
offsets[i] = 0;
|
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) {
|
if (fields[i]->kind != Entity_Variable) {
|
||||||
offsets[i] = -1;
|
offsets[i] = -1;
|
||||||
} else {
|
} else {
|
||||||
i64 size = type_size_of(fields[i]->type);
|
i64 size = type_size_of_internal(fields[i]->type, &path);
|
||||||
offsets[i] = curr_offset;
|
offsets[i] = curr_offset;
|
||||||
curr_offset += size;
|
curr_offset += size;
|
||||||
}
|
}
|
||||||
@@ -3988,11 +3912,11 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
|||||||
offsets[i] = -1;
|
offsets[i] = -1;
|
||||||
} else {
|
} else {
|
||||||
Type *t = fields[i]->type;
|
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) {
|
if (max_field_align > min_field_align) {
|
||||||
align = gb_min(align, max_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);
|
curr_offset = align_formula(curr_offset, align);
|
||||||
offsets[i] = curr_offset;
|
offsets[i] = curr_offset;
|
||||||
curr_offset += size;
|
curr_offset += size;
|
||||||
@@ -4242,11 +4166,6 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
|
|||||||
|
|
||||||
case Type_BitField:
|
case Type_BitField:
|
||||||
return type_size_of_internal(t->BitField.backing_type, path);
|
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
|
// Catch all
|
||||||
@@ -4873,19 +4792,6 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
|
|||||||
str = write_type_to_string(str, type->SimdVector.elem);
|
str = write_type_to_string(str, type->SimdVector.elem);
|
||||||
break;
|
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:
|
case Type_Matrix:
|
||||||
if (type->Matrix.is_row_major) {
|
if (type->Matrix.is_row_major) {
|
||||||
str = gb_string_appendc(str, "#row_major ");
|
str = gb_string_appendc(str, "#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