mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-18 03:42:23 -07:00
Merge branch 'master' into odin-ast-changes
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: odin-lang
|
||||
patreon: gingerbill
|
||||
|
||||
@@ -38,6 +38,9 @@ jobs:
|
||||
cd tests/vendor
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for OpenBSD amd64
|
||||
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
|
||||
timeout-minutes: 10
|
||||
build_macOS:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@@ -79,7 +82,7 @@ jobs:
|
||||
make
|
||||
timeout-minutes: 10
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: build Odin
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
GIT_SHA=$(shell git rev-parse --short HEAD)
|
||||
DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value
|
||||
LDFLAGS=-pthread -ldl -lm -lstdc++
|
||||
LDFLAGS=-pthread -lm -lstdc++
|
||||
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
|
||||
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
|
||||
CC=clang
|
||||
@@ -8,9 +8,9 @@ CC=clang
|
||||
OS=$(shell uname)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
|
||||
|
||||
ARCH=$(shell uname -m)
|
||||
LLVM_CONFIG=
|
||||
LLVM_CONFIG=llvm-config
|
||||
|
||||
# allow for arm only llvm's with version 13
|
||||
ifeq ($(ARCH), arm64)
|
||||
@@ -27,9 +27,7 @@ ifeq ($(OS), Darwin)
|
||||
LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS))
|
||||
LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))"
|
||||
|
||||
ifneq ($(shell llvm-config --version | grep -E $(LLVM_VERSION_PATTERN)),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),)
|
||||
ifeq ($(ARCH), arm64)
|
||||
$(error "Requirement: llvm-config must be base version 13 for arm64")
|
||||
else
|
||||
@@ -37,7 +35,7 @@ ifeq ($(OS), Darwin)
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -liconv
|
||||
LDFLAGS:=$(LDFLAGS) -liconv -ldl
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
||||
endif
|
||||
@@ -48,13 +46,19 @@ ifeq ($(OS), Linux)
|
||||
else ifneq ($(shell which llvm-config-11-64 2>/dev/null),)
|
||||
LLVM_CONFIG=llvm-config-11-64
|
||||
else
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
ifeq ($(shell $(LLVM_CONFIG) --version | grep '^11\.'),)
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -ldl
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
endif
|
||||
ifeq ($(OS), OpenBSD)
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -liconv
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
endif
|
||||
|
||||
+11
-35
@@ -218,61 +218,37 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) ->
|
||||
|
||||
|
||||
@private
|
||||
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) {
|
||||
s, n := s, n
|
||||
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if sep == nil {
|
||||
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save: int) -> (res: []byte, ok: bool) {
|
||||
if len(sep) == 0 {
|
||||
res = s[:]
|
||||
ok = true
|
||||
s^ = s[len(s):]
|
||||
return
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
n = count(s^, sep) + 1
|
||||
}
|
||||
|
||||
n -= 1
|
||||
|
||||
i := 0
|
||||
for ; i < n; i += 1 {
|
||||
m := index(s^, sep)
|
||||
if m < 0 {
|
||||
break
|
||||
}
|
||||
m := index(s^, sep)
|
||||
if m < 0 {
|
||||
// not found
|
||||
res = s[:]
|
||||
ok = len(res) != 0
|
||||
s^ = s[len(s):]
|
||||
} else {
|
||||
res = s[:m+sep_save]
|
||||
ok = true
|
||||
s^ = s[m+len(sep):]
|
||||
return
|
||||
}
|
||||
res = s[:]
|
||||
ok = res != nil
|
||||
s^ = s[len(s):]
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, 0, -1)
|
||||
}
|
||||
|
||||
split_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, 0, n)
|
||||
return _split_iterator(s, sep, 0)
|
||||
}
|
||||
|
||||
split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, len(sep), -1)
|
||||
return _split_iterator(s, sep, len(sep))
|
||||
}
|
||||
|
||||
split_after_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
||||
return _split_iterator(s, sep, len(sep), n)
|
||||
}
|
||||
|
||||
|
||||
|
||||
index_byte :: proc(s: []byte, c: byte) -> int {
|
||||
for i := 0; i < len(s); i += 1 {
|
||||
|
||||
+4
-4
@@ -7,20 +7,20 @@ char :: builtin.u8 // assuming -funsigned-char
|
||||
schar :: builtin.i8
|
||||
short :: builtin.i16
|
||||
int :: builtin.i32
|
||||
long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||
long :: builtin.i32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||
longlong :: builtin.i64
|
||||
|
||||
uchar :: builtin.u8
|
||||
ushort :: builtin.u16
|
||||
uint :: builtin.u32
|
||||
ulong :: builtin.u32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.u64
|
||||
ulong :: builtin.u32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.u64
|
||||
ulonglong :: builtin.u64
|
||||
|
||||
bool :: builtin.bool
|
||||
|
||||
size_t :: builtin.uint
|
||||
ssize_t :: builtin.int
|
||||
wchar_t :: builtin.u16 when (ODIN_OS == "windows") else builtin.u32
|
||||
wchar_t :: builtin.u16 when (ODIN_OS == .Windows) else builtin.u32
|
||||
|
||||
float :: builtin.f32
|
||||
double :: builtin.f64
|
||||
@@ -48,7 +48,7 @@ int_least64_t :: builtin.i64
|
||||
uint_least64_t :: builtin.u64
|
||||
|
||||
// Same on Windows, Linux, and FreeBSD
|
||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
int_fast8_t :: builtin.i8
|
||||
uint_fast8_t :: builtin.u8
|
||||
int_fast16_t :: builtin.i32
|
||||
|
||||
@@ -2,9 +2,9 @@ package libc
|
||||
|
||||
// 7.3 Complex arithmetic
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package libc
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
|
||||
+18
-5
@@ -2,9 +2,9 @@ package libc
|
||||
|
||||
// 7.5 Errors
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
@@ -14,7 +14,7 @@ when ODIN_OS == "windows" {
|
||||
// EDOM,
|
||||
// EILSEQ
|
||||
// ERANGE
|
||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@@ -27,7 +27,20 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .OpenBSD {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__errno")
|
||||
_get_errno :: proc() -> ^int ---
|
||||
}
|
||||
|
||||
EDOM :: 33
|
||||
EILSEQ :: 84
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@@ -40,7 +53,7 @@ when ODIN_OS == "windows" {
|
||||
ERANGE :: 34
|
||||
}
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
|
||||
@@ -4,9 +4,9 @@ package libc
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
|
||||
@@ -2,14 +2,14 @@ package libc
|
||||
|
||||
// 7.13 Nonlocal jumps
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.13.1 Save calling environment
|
||||
|
||||
@@ -2,9 +2,9 @@ package libc
|
||||
|
||||
// 7.14 Signal handling
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
@@ -21,7 +21,7 @@ foreign libc {
|
||||
raise :: proc(sig: int) -> int ---
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
SIG_ERR :: rawptr(~uintptr(0))
|
||||
SIG_DFL :: rawptr(uintptr(0))
|
||||
SIG_IGN :: rawptr(uintptr(1))
|
||||
@@ -34,7 +34,7 @@ when ODIN_OS == "windows" {
|
||||
SIGTERM :: 15
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||
SIG_ERR :: rawptr(~uintptr(0))
|
||||
SIG_DFL :: rawptr(uintptr(0))
|
||||
SIG_IGN :: rawptr(uintptr(1))
|
||||
@@ -47,7 +47,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
||||
SIGTERM :: 15
|
||||
}
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
SIG_ERR :: rawptr(~uintptr(0))
|
||||
SIG_DFL :: rawptr(uintptr(0))
|
||||
SIG_IGN :: rawptr(uintptr(1))
|
||||
|
||||
+30
-5
@@ -1,8 +1,8 @@
|
||||
package libc
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
@@ -13,7 +13,7 @@ when ODIN_OS == "windows" {
|
||||
FILE :: struct {}
|
||||
|
||||
// MSVCRT compatible.
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
_IOFBF :: 0x0000
|
||||
_IONBF :: 0x0004
|
||||
_IOLBF :: 0x0040
|
||||
@@ -48,7 +48,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
|
||||
// GLIBC and MUSL compatible.
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
||||
|
||||
_IOFBF :: 0
|
||||
@@ -78,7 +78,32 @@ when ODIN_OS == "linux" {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .OpenBSD {
|
||||
fpos_t :: i64
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
_IONBF :: 1
|
||||
|
||||
BUFSIZ :: 1024
|
||||
|
||||
EOF :: int(-1)
|
||||
|
||||
FOPEN_MAX :: 20
|
||||
FILENAME_MAX :: 1024
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
foreign libc {
|
||||
stderr: ^FILE
|
||||
stdin: ^FILE
|
||||
stdout: ^FILE
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
fpos_t :: distinct i64
|
||||
|
||||
_IOFBF :: 0
|
||||
|
||||
@@ -2,15 +2,15 @@ package libc
|
||||
|
||||
// 7.22 General utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
RAND_MAX :: 0x7fff
|
||||
|
||||
@(private="file")
|
||||
@@ -24,7 +24,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
RAND_MAX :: 0x7fffffff
|
||||
|
||||
// GLIBC and MUSL only
|
||||
@@ -40,7 +40,7 @@ when ODIN_OS == "linux" {
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
RAND_MAX :: 0x7fffffff
|
||||
|
||||
// GLIBC and MUSL only
|
||||
|
||||
@@ -4,9 +4,9 @@ import "core:runtime"
|
||||
|
||||
// 7.24 String handling
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
|
||||
@@ -5,7 +5,7 @@ package libc
|
||||
thrd_start_t :: proc "c" (rawptr) -> int
|
||||
tss_dtor_t :: proc "c" (rawptr)
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc {
|
||||
"system:libucrt.lib",
|
||||
"system:msvcprt.lib"
|
||||
@@ -74,7 +74,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
|
||||
// GLIBC and MUSL compatible constants and types.
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
foreign import libc {
|
||||
"system:c",
|
||||
"system:pthread"
|
||||
@@ -138,6 +138,6 @@ when ODIN_OS == "linux" {
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
// TODO: find out what this is meant to be!
|
||||
}
|
||||
|
||||
+10
-5
@@ -2,9 +2,9 @@ package libc
|
||||
|
||||
// 7.27 Date and time
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
@@ -12,7 +12,7 @@ when ODIN_OS == "windows" {
|
||||
|
||||
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
||||
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
// 7.27.2 Time manipulation functions
|
||||
clock :: proc() -> clock_t ---
|
||||
@@ -45,7 +45,7 @@ when ODIN_OS == "windows" {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.27.2 Time manipulation functions
|
||||
@@ -63,7 +63,12 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
||||
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
||||
}
|
||||
|
||||
CLOCKS_PER_SEC :: 1000000
|
||||
when ODIN_OS == .OpenBSD {
|
||||
CLOCKS_PER_SEC :: 100
|
||||
} else {
|
||||
CLOCKS_PER_SEC :: 1000000
|
||||
}
|
||||
|
||||
TIME_UTC :: 1
|
||||
|
||||
time_t :: distinct i64
|
||||
|
||||
@@ -2,9 +2,9 @@ package libc
|
||||
|
||||
// 7.28 Unicode utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
|
||||
@@ -2,9 +2,9 @@ package libc
|
||||
|
||||
// 7.29 Extended multibyte and wide character utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
|
||||
+10
-5
@@ -2,29 +2,34 @@ package libc
|
||||
|
||||
// 7.30 Wide character classification and mapping utilities
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
} else when ODIN_OS == "darwin" {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
wctrans_t :: distinct wchar_t
|
||||
wctype_t :: distinct ushort
|
||||
}
|
||||
|
||||
when ODIN_OS == "linux" {
|
||||
when ODIN_OS == .Linux {
|
||||
wctrans_t :: distinct intptr_t
|
||||
wctype_t :: distinct ulong
|
||||
}
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
wctrans_t :: distinct int
|
||||
wctype_t :: distinct u32
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
wctrans_t :: distinct rawptr
|
||||
wctype_t :: distinct rawptr
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.30.2.1 Wide character classification functions
|
||||
|
||||
@@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
|
||||
|
||||
assert(len(arg1) == 16)
|
||||
|
||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
// While it may be unwise to do deserialization here on our
|
||||
// own when fiat-crypto provides equivalent functionality,
|
||||
// doing it this way provides a little under 3x performance
|
||||
|
||||
@@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Until dedicated assembly can be written leverage the fact that
|
||||
// the callers of this routine ensure that src/dst are valid.
|
||||
|
||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
||||
// systems that also happen to not be strict about aligned
|
||||
// memory access.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package crypto
|
||||
|
||||
when ODIN_OS != "linux" {
|
||||
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows {
|
||||
_rand_bytes :: proc (dst: []byte) {
|
||||
unimplemented("crypto: rand_bytes not supported on this OS")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package crypto
|
||||
|
||||
import "core:c"
|
||||
|
||||
foreign import libc "system:c"
|
||||
foreign libc {
|
||||
arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
|
||||
}
|
||||
|
||||
_rand_bytes :: proc (dst: []byte) {
|
||||
arc4random_buf(raw_data(dst), len(dst))
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package crypto
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:os"
|
||||
import "core:fmt"
|
||||
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
|
||||
if ret != os.ERROR_NONE {
|
||||
switch ret {
|
||||
case os.ERROR_INVALID_HANDLE:
|
||||
// The handle to the first parameter is invalid.
|
||||
// This should not happen here, since we explicitly pass nil to it
|
||||
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
|
||||
case os.ERROR_INVALID_PARAMETER:
|
||||
// One of the parameters was invalid
|
||||
panic("crypto: BCryptGenRandom Invalid parameter")
|
||||
case:
|
||||
// Unknown error
|
||||
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
package siphash
|
||||
|
||||
/*
|
||||
Copyright 2022 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog: Initial implementation.
|
||||
|
||||
Implementation of the SipHash hashing algorithm, as defined at <https://github.com/veorq/SipHash> and <https://www.aumasson.jp/siphash/siphash.pdf>
|
||||
|
||||
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
|
||||
*/
|
||||
|
||||
import "core:crypto"
|
||||
import "core:crypto/util"
|
||||
import "core:mem"
|
||||
|
||||
/*
|
||||
High level API
|
||||
*/
|
||||
|
||||
KEY_SIZE :: 16
|
||||
DIGEST_SIZE :: 8
|
||||
|
||||
// sum_string_1_3 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_string_1_3 :: proc(msg, key: string) -> u64 {
|
||||
return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key))
|
||||
}
|
||||
|
||||
// sum_bytes_1_3 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 {
|
||||
ctx: Context
|
||||
hash: u64
|
||||
init(&ctx, key, 1, 3)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, &hash)
|
||||
return hash
|
||||
}
|
||||
|
||||
// sum_string_to_buffer_1_3 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) {
|
||||
sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||
}
|
||||
|
||||
// sum_bytes_to_buffer_1_3 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) {
|
||||
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||
hash := sum_bytes_1_3(msg, key)
|
||||
_collect_output(dst[:], hash)
|
||||
}
|
||||
|
||||
sum_1_3 :: proc {
|
||||
sum_string_1_3,
|
||||
sum_bytes_1_3,
|
||||
sum_string_to_buffer_1_3,
|
||||
sum_bytes_to_buffer_1_3,
|
||||
}
|
||||
|
||||
// verify_u64_1_3 will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||
return sum_bytes_1_3(msg, key) == tag
|
||||
}
|
||||
|
||||
// verify_bytes will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool {
|
||||
derived_tag: [8]byte
|
||||
sum_bytes_to_buffer_1_3(msg, key, derived_tag[:])
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
verify_1_3 :: proc {
|
||||
verify_bytes_1_3,
|
||||
verify_u64_1_3,
|
||||
}
|
||||
|
||||
// sum_string_2_4 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_string_2_4 :: proc(msg, key: string) -> u64 {
|
||||
return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key))
|
||||
}
|
||||
|
||||
// sum_bytes_2_4 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 {
|
||||
ctx: Context
|
||||
hash: u64
|
||||
init(&ctx, key, 2, 4)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, &hash)
|
||||
return hash
|
||||
}
|
||||
|
||||
// sum_string_to_buffer_2_4 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) {
|
||||
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||
}
|
||||
|
||||
// sum_bytes_to_buffer_2_4 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) {
|
||||
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||
hash := sum_bytes_2_4(msg, key)
|
||||
_collect_output(dst[:], hash)
|
||||
}
|
||||
|
||||
sum_2_4 :: proc {
|
||||
sum_string_2_4,
|
||||
sum_bytes_2_4,
|
||||
sum_string_to_buffer_2_4,
|
||||
sum_bytes_to_buffer_2_4,
|
||||
}
|
||||
|
||||
sum_string :: sum_string_2_4
|
||||
sum_bytes :: sum_bytes_2_4
|
||||
sum_string_to_buffer :: sum_string_to_buffer_2_4
|
||||
sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4
|
||||
sum :: proc {
|
||||
sum_string,
|
||||
sum_bytes,
|
||||
sum_string_to_buffer,
|
||||
sum_bytes_to_buffer,
|
||||
}
|
||||
|
||||
// verify_u64_2_4 will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||
return sum_bytes_2_4(msg, key) == tag
|
||||
}
|
||||
|
||||
// verify_bytes will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool {
|
||||
derived_tag: [8]byte
|
||||
sum_bytes_to_buffer_2_4(msg, key, derived_tag[:])
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
verify_2_4 :: proc {
|
||||
verify_bytes_2_4,
|
||||
verify_u64_2_4,
|
||||
}
|
||||
|
||||
verify_bytes :: verify_bytes_2_4
|
||||
verify_u64 :: verify_u64_2_4
|
||||
verify :: proc {
|
||||
verify_bytes,
|
||||
verify_u64,
|
||||
}
|
||||
|
||||
// sum_string_4_8 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_string_4_8 :: proc(msg, key: string) -> u64 {
|
||||
return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key))
|
||||
}
|
||||
|
||||
// sum_bytes_4_8 will hash the given message with the key and return
|
||||
// the computed hash as a u64
|
||||
sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 {
|
||||
ctx: Context
|
||||
hash: u64
|
||||
init(&ctx, key, 4, 8)
|
||||
update(&ctx, msg)
|
||||
final(&ctx, &hash)
|
||||
return hash
|
||||
}
|
||||
|
||||
// sum_string_to_buffer_4_8 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) {
|
||||
sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||
}
|
||||
|
||||
// sum_bytes_to_buffer_4_8 will hash the given message with the key and write
|
||||
// the computed hash into the provided destination buffer
|
||||
sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) {
|
||||
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||
hash := sum_bytes_4_8(msg, key)
|
||||
_collect_output(dst[:], hash)
|
||||
}
|
||||
|
||||
sum_4_8 :: proc {
|
||||
sum_string_4_8,
|
||||
sum_bytes_4_8,
|
||||
sum_string_to_buffer_4_8,
|
||||
sum_bytes_to_buffer_4_8,
|
||||
}
|
||||
|
||||
// verify_u64_4_8 will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||
return sum_bytes_4_8(msg, key) == tag
|
||||
}
|
||||
|
||||
// verify_bytes will check if the supplied tag matches with the output you
|
||||
// will get from the provided message and key
|
||||
verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool {
|
||||
derived_tag: [8]byte
|
||||
sum_bytes_to_buffer_4_8(msg, key, derived_tag[:])
|
||||
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||
}
|
||||
|
||||
verify_4_8 :: proc {
|
||||
verify_bytes_4_8,
|
||||
verify_u64_4_8,
|
||||
}
|
||||
|
||||
/*
|
||||
Low level API
|
||||
*/
|
||||
|
||||
init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
|
||||
assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16")
|
||||
ctx.c_rounds = c_rounds
|
||||
ctx.d_rounds = d_rounds
|
||||
is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) ||
|
||||
(ctx.c_rounds == 2 && ctx.d_rounds == 4) ||
|
||||
(ctx.c_rounds == 4 && ctx.d_rounds == 8)
|
||||
assert(is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)")
|
||||
ctx.k0 = util.U64_LE(key[:8])
|
||||
ctx.k1 = util.U64_LE(key[8:])
|
||||
ctx.v0 = 0x736f6d6570736575 ~ ctx.k0
|
||||
ctx.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||
ctx.is_initialized = true
|
||||
}
|
||||
|
||||
update :: proc(ctx: ^Context, data: []byte) {
|
||||
assert(ctx.is_initialized, "crypto/siphash: Context is not initalized")
|
||||
ctx.last_block = len(data) / 8 * 8
|
||||
ctx.buf = data
|
||||
i := 0
|
||||
m: u64
|
||||
for i < ctx.last_block {
|
||||
m = u64(ctx.buf[i] & 0xff)
|
||||
i += 1
|
||||
|
||||
for r in u64(1)..<8 {
|
||||
m |= u64(ctx.buf[i] & 0xff) << (r * 8)
|
||||
i += 1
|
||||
}
|
||||
|
||||
ctx.v3 ~= m
|
||||
for _ in 0..<ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
}
|
||||
}
|
||||
|
||||
final :: proc(ctx: ^Context, dst: ^u64) {
|
||||
m: u64
|
||||
for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 {
|
||||
m <<= 8
|
||||
m |= u64(ctx.buf[i] & 0xff)
|
||||
}
|
||||
m |= u64(len(ctx.buf) << 56)
|
||||
|
||||
ctx.v3 ~= m
|
||||
|
||||
for _ in 0..<ctx.c_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
ctx.v0 ~= m
|
||||
ctx.v2 ~= 0xff
|
||||
|
||||
for _ in 0..<ctx.d_rounds {
|
||||
_compress(ctx)
|
||||
}
|
||||
|
||||
dst^ = ctx.v0 ~ ctx.v1 ~ ctx.v2 ~ ctx.v3
|
||||
|
||||
reset(ctx)
|
||||
}
|
||||
|
||||
reset :: proc(ctx: ^Context) {
|
||||
ctx.k0, ctx.k1 = 0, 0
|
||||
ctx.v0, ctx.v1 = 0, 0
|
||||
ctx.v2, ctx.v3 = 0, 0
|
||||
ctx.last_block = 0
|
||||
ctx.c_rounds = 0
|
||||
ctx.d_rounds = 0
|
||||
ctx.is_initialized = false
|
||||
}
|
||||
|
||||
Context :: struct {
|
||||
v0, v1, v2, v3: u64, // State values
|
||||
k0, k1: u64, // Split key
|
||||
c_rounds: int, // Number of message rounds
|
||||
d_rounds: int, // Number of finalization rounds
|
||||
buf: []byte, // Provided data
|
||||
last_block: int, // Offset from the last block
|
||||
is_initialized: bool,
|
||||
}
|
||||
|
||||
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||
}
|
||||
|
||||
_collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) {
|
||||
dst[0] = _get_byte(7, hash)
|
||||
dst[1] = _get_byte(6, hash)
|
||||
dst[2] = _get_byte(5, hash)
|
||||
dst[3] = _get_byte(4, hash)
|
||||
dst[4] = _get_byte(3, hash)
|
||||
dst[5] = _get_byte(2, hash)
|
||||
dst[6] = _get_byte(1, hash)
|
||||
dst[7] = _get_byte(0, hash)
|
||||
}
|
||||
|
||||
_compress :: #force_inline proc "contextless" (ctx: ^Context) {
|
||||
ctx.v0 += ctx.v1
|
||||
ctx.v1 = util.ROTL64(ctx.v1, 13)
|
||||
ctx.v1 ~= ctx.v0
|
||||
ctx.v0 = util.ROTL64(ctx.v0, 32)
|
||||
ctx.v2 += ctx.v3
|
||||
ctx.v3 = util.ROTL64(ctx.v3, 16)
|
||||
ctx.v3 ~= ctx.v2
|
||||
ctx.v0 += ctx.v3
|
||||
ctx.v3 = util.ROTL64(ctx.v3, 21)
|
||||
ctx.v3 ~= ctx.v0
|
||||
ctx.v2 += ctx.v1
|
||||
ctx.v1 = util.ROTL64(ctx.v1, 17)
|
||||
ctx.v1 ~= ctx.v2
|
||||
ctx.v2 = util.ROTL64(ctx.v2, 32)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build linux, darwin, freebsd
|
||||
// +build linux, darwin, freebsd, openbsd
|
||||
package dynlib
|
||||
|
||||
import "core:os"
|
||||
|
||||
+224
-214
File diff suppressed because it is too large
Load Diff
@@ -207,7 +207,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
|
||||
}
|
||||
|
||||
mode: int = 0
|
||||
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
|
||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ when false {
|
||||
}
|
||||
|
||||
mode: int = 0
|
||||
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
|
||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
}
|
||||
|
||||
@@ -0,0 +1,734 @@
|
||||
/*
|
||||
OpenSimplex2 noise implementation.
|
||||
|
||||
Ported from https://github.com/KdotJPG/OpenSimplex2.
|
||||
Copyright 2022 Yuki2 (https://github.com/NoahR02)
|
||||
*/
|
||||
//+private
|
||||
package math_noise
|
||||
|
||||
/*
|
||||
Private implementation details follow.
|
||||
*/
|
||||
|
||||
PRIME_X :: i64(0x5205402B9270C86F)
|
||||
PRIME_Y :: i64(0x598CD327003817B5)
|
||||
PRIME_Z :: i64(0x5BCC226E9FA0BACB)
|
||||
PRIME_W :: i64(0x56CC5227E58F554B)
|
||||
|
||||
HASH_MULTIPLIER :: i64(0x53A3F72DEEC546F5)
|
||||
SEED_FLIP_3D :: i64(-0x52D547B2E96ED629)
|
||||
SEED_OFFSET_4D :: i64(0xE83DC3E0DA7164D)
|
||||
|
||||
ROOT_2_OVER_2 :: f64(0.7071067811865476)
|
||||
SKEW_2D :: f64(0.366025403784439)
|
||||
UNSKEW_2D :: f64(-0.21132486540518713)
|
||||
ROOT_3_OVER_3 :: f64(0.577350269189626)
|
||||
|
||||
FALLBACK_ROTATE_3D :: f64(2.0) / f64(3.0)
|
||||
ROTATE_3D_ORTHOGONALIZER :: f64(UNSKEW_2D)
|
||||
|
||||
SKEW_4D :: f32(0hbe0d8369)
|
||||
UNSKEW_4D :: f32(0.309016994374947)
|
||||
LATTICE_STEP_4D :: f32(0.2)
|
||||
|
||||
N_GRADS_2D_EXPONENT :: 7
|
||||
N_GRADS_3D_EXPONENT :: 8
|
||||
N_GRADS_4D_EXPONENT :: 9
|
||||
N_GRADS_2D :: 1 << N_GRADS_2D_EXPONENT
|
||||
N_GRADS_3D :: 1 << N_GRADS_3D_EXPONENT
|
||||
N_GRADS_4D :: 1 << N_GRADS_4D_EXPONENT
|
||||
|
||||
NORMALIZER_2D :: f64(0.01001634121365712)
|
||||
NORMALIZER_3D :: f64(0.07969837668935331)
|
||||
NORMALIZER_4D :: f64(0.0220065933241897)
|
||||
RSQUARED_2D :: f32(0.5)
|
||||
RSQUARED_3D :: f32(0.6)
|
||||
RSQUARED_4D :: f32(0.6)
|
||||
|
||||
GRADIENTS_2D := [N_GRADS_2D * 2]f32{
|
||||
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||
}
|
||||
|
||||
GRADIENTS_3D := [N_GRADS_3D * 4]f32{
|
||||
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||
}
|
||||
|
||||
GRADIENTS_4D := [N_GRADS_4D * 4]f32{
|
||||
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||
0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85,
|
||||
0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee,
|
||||
0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d,
|
||||
0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564,
|
||||
0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85,
|
||||
0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee,
|
||||
0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d,
|
||||
0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564,
|
||||
0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85,
|
||||
0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee,
|
||||
0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d,
|
||||
0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564,
|
||||
0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a,
|
||||
0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a,
|
||||
0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252,
|
||||
0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c,
|
||||
0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966,
|
||||
0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418,
|
||||
0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c,
|
||||
0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507,
|
||||
0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966,
|
||||
0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418,
|
||||
0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c,
|
||||
0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507,
|
||||
0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d,
|
||||
0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf,
|
||||
0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0,
|
||||
0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00,
|
||||
0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c,
|
||||
0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5,
|
||||
0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966,
|
||||
0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716,
|
||||
0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d,
|
||||
0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf,
|
||||
0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0,
|
||||
0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00,
|
||||
0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c,
|
||||
0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5,
|
||||
0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966,
|
||||
0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716,
|
||||
0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d,
|
||||
0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf,
|
||||
0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0,
|
||||
0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00,
|
||||
0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c,
|
||||
0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5,
|
||||
0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966,
|
||||
0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716,
|
||||
0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252,
|
||||
0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a,
|
||||
0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a,
|
||||
0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18,
|
||||
0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d,
|
||||
0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee,
|
||||
0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee,
|
||||
0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670,
|
||||
0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d,
|
||||
0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee,
|
||||
0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee,
|
||||
0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670,
|
||||
0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d,
|
||||
0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee,
|
||||
0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee,
|
||||
0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670,
|
||||
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||
0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85,
|
||||
0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee,
|
||||
0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d,
|
||||
0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564,
|
||||
0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85,
|
||||
0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee,
|
||||
0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d,
|
||||
0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564,
|
||||
0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85,
|
||||
0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee,
|
||||
0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d,
|
||||
0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564,
|
||||
0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a,
|
||||
0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a,
|
||||
0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252,
|
||||
0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c,
|
||||
0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966,
|
||||
0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418,
|
||||
0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c,
|
||||
0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507,
|
||||
0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966,
|
||||
0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418,
|
||||
0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c,
|
||||
0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507,
|
||||
0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d,
|
||||
0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf,
|
||||
0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0,
|
||||
0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00,
|
||||
0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c,
|
||||
0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5,
|
||||
0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966,
|
||||
0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716,
|
||||
0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d,
|
||||
0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf,
|
||||
0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0,
|
||||
0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00,
|
||||
0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c,
|
||||
0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5,
|
||||
0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966,
|
||||
0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716,
|
||||
0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d,
|
||||
0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf,
|
||||
0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0,
|
||||
0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00,
|
||||
0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c,
|
||||
0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5,
|
||||
0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966,
|
||||
0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716,
|
||||
0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252,
|
||||
0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a,
|
||||
0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a,
|
||||
0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18,
|
||||
0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d,
|
||||
0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee,
|
||||
0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee,
|
||||
0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670,
|
||||
0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d,
|
||||
0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee,
|
||||
0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee,
|
||||
0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670,
|
||||
0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d,
|
||||
0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee,
|
||||
0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee,
|
||||
0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670,
|
||||
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||
0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85,
|
||||
0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee,
|
||||
0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d,
|
||||
0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564,
|
||||
0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85,
|
||||
0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee,
|
||||
0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d,
|
||||
0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564,
|
||||
0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85,
|
||||
0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee,
|
||||
0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d,
|
||||
0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564,
|
||||
0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a,
|
||||
0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a,
|
||||
0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252,
|
||||
0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c,
|
||||
0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966,
|
||||
0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418,
|
||||
0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c,
|
||||
0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507,
|
||||
0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966,
|
||||
0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418,
|
||||
0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c,
|
||||
0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507,
|
||||
0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d,
|
||||
0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf,
|
||||
0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0,
|
||||
0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00,
|
||||
0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c,
|
||||
0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5,
|
||||
0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966,
|
||||
0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716,
|
||||
0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d,
|
||||
0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf,
|
||||
0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0,
|
||||
0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00,
|
||||
0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c,
|
||||
0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5,
|
||||
0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966,
|
||||
0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716,
|
||||
0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d,
|
||||
0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf,
|
||||
0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0,
|
||||
0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00,
|
||||
0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c,
|
||||
0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5,
|
||||
0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966,
|
||||
0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716,
|
||||
0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252,
|
||||
0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a,
|
||||
0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a,
|
||||
0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18,
|
||||
0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d,
|
||||
0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee,
|
||||
0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee,
|
||||
0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670,
|
||||
0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d,
|
||||
0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee,
|
||||
0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee,
|
||||
0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670,
|
||||
0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d,
|
||||
0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee,
|
||||
0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee,
|
||||
0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670,
|
||||
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||
}
|
||||
|
||||
/*
|
||||
2D Simplex noise base.
|
||||
*/
|
||||
_internal_noise_2d_unskewed_base :: proc(seed: i64, coord: Vec2) -> (value: f32) {
|
||||
// Get base points and offsets.
|
||||
base := [2]i64{fast_floor(coord.x), fast_floor(coord.y)}
|
||||
i := [2]f32{f32(coord.x - f64(base.x)), f32(coord.y - f64(base.y))}
|
||||
|
||||
// Prime pre-multiplication for hash.
|
||||
bp := base * [2]i64{PRIME_X, PRIME_Y}
|
||||
|
||||
// Unskew.
|
||||
t := f32(i.x + i.y) * f32(UNSKEW_2D)
|
||||
d0 := i + [2]f32{t, t}
|
||||
|
||||
// First vertex.
|
||||
a0 := RSQUARED_2D - d0.x * d0.x - d0.y * d0.y
|
||||
if a0 > 0 {
|
||||
value = (a0 * a0) * (a0 * a0) * grad(seed, [2]i64{bp.x, bp.y}, d0)
|
||||
}
|
||||
|
||||
// Second vertex.
|
||||
a1 := f32(2 * (1 + 2 * UNSKEW_2D) * (1 / UNSKEW_2D + 2)) * t + f32(-2 * (1 + 2 * UNSKEW_2D) * (1 + 2 * UNSKEW_2D)) + a0
|
||||
if a1 > 0 {
|
||||
d1 := d0 - [2]f32{f32(1 + 2 * UNSKEW_2D), f32(1 + 2 * UNSKEW_2D)}
|
||||
value += (a1 * a1) * (a1 * a1) * grad(seed, [2]i64{bp.x + PRIME_X, bp.y + PRIME_Y}, d1)
|
||||
}
|
||||
|
||||
// Third vertex.
|
||||
if d0.y > d0.x {
|
||||
d2 := d0 - [2]f32{f32(UNSKEW_2D), f32(UNSKEW_2D + 1)}
|
||||
a2 := RSQUARED_2D - d2.x * d2.x - d2.y * d2.y
|
||||
if(a2 > 0) {
|
||||
value += (a2 * a2) * (a2 * a2) * grad(seed, [2]i64{bp.x, bp.y + PRIME_Y}, d2)
|
||||
}
|
||||
} else {
|
||||
d2 := d0 - [2]f32{f32(UNSKEW_2D + 1), f32(UNSKEW_2D)}
|
||||
a2 := RSQUARED_2D - d2.x * d2.x - d2.y * d2.y
|
||||
if(a2 > 0) {
|
||||
value += (a2 * a2) * (a2 * a2) * grad(seed, [2]i64{bp.x + PRIME_X, bp.y}, d2)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Generate overlapping cubic lattices for 3D OpenSimplex2 noise.
|
||||
*/
|
||||
_internal_noise_3d_unrotated_base :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||
seed := seed
|
||||
// Get base points and offsets.
|
||||
// xr, yr, zr := coord.x, coord.y, coord.z
|
||||
|
||||
rb := [3]i64{fast_round(coord.x), fast_round(coord.y), fast_round(coord.z)}
|
||||
ri := [3]f32{f32(coord.x - f64(rb.x)), f32(coord.y - f64(rb.y)), f32(coord.z - f64(rb.z))}
|
||||
|
||||
// -1 if positive, 1 if negative.
|
||||
i_sign := [3]i64{i64(-1.0 - ri.x) | 1, i64(-1.0 - ri.y) | 1, i64(-1.0 - ri.z) | 1}
|
||||
f_sign := [3]f32{f32(i_sign.x), f32(i_sign.y), f32(i_sign.z)}
|
||||
|
||||
// Compute absolute values, using the above as a shortcut. This was faster in my tests for some reason.
|
||||
a0 := f_sign * -ri
|
||||
|
||||
// Prime pre-multiplication for hash.
|
||||
rbp := rb * [3]i64{PRIME_X, PRIME_Y, PRIME_Z}
|
||||
|
||||
// Loop: Pick an edge on each lattice copy.
|
||||
a := (RSQUARED_3D - ri.x * ri.x) - (ri.y * ri.y + ri.z * ri.z)
|
||||
|
||||
l := 0
|
||||
for {
|
||||
defer l += 1
|
||||
|
||||
// Closest point on cube.
|
||||
if a > 0 {
|
||||
a2 := a * a; a4 := a2 * a2
|
||||
value += a4 * grad(seed, rbp, ri)
|
||||
}
|
||||
|
||||
// Second-closest point.
|
||||
if a0.x >= a0.y && a0.x >= a0.z {
|
||||
b := a + a0.x + a0.x
|
||||
if b > 1 {
|
||||
b -= 1
|
||||
b2 := b * b; b4 := b2 * b2
|
||||
value += b4 * grad(seed, [3]i64{rbp.x - i_sign.x * PRIME_X, rbp.y, rbp.z}, [3]f32{ri.x + f_sign.x, ri.y, ri.z})
|
||||
}
|
||||
} else if a0.y > a0.x && a0.y >= a0.z {
|
||||
b := a + a0.y + a0.y
|
||||
if b > 1 {
|
||||
b -= 1
|
||||
b2 := b * b; b4 := b2 * b2
|
||||
value += b4 * grad(seed, [3]i64{rbp.x, rbp.y - i_sign.y * PRIME_Y, rbp.z}, [3]f32{ri.x, ri.y + f_sign.y, ri.z})
|
||||
}
|
||||
} else {
|
||||
b := a + a0.z + a0.z
|
||||
if b > 1 {
|
||||
b -= 1
|
||||
b2 := b * b; b4 := b2 * b2
|
||||
value += b4 * grad(seed, [3]i64{rbp.x, rbp.y, rbp.z - i_sign.z * PRIME_Z}, [3]f32{ri.x, ri.y, ri.z + f_sign.z})
|
||||
}
|
||||
}
|
||||
|
||||
// Break from loop if we're done, skipping updates below.
|
||||
if l == 1 {
|
||||
break
|
||||
}
|
||||
|
||||
// Update absolute value.
|
||||
a0 = 0.5 - a0
|
||||
|
||||
// Update relative coordinate.
|
||||
ri = a0 * f_sign
|
||||
|
||||
// Update falloff.
|
||||
a += (0.75 - a0.x) - (a0.y + a0.z)
|
||||
|
||||
// Update prime for hash.
|
||||
rbp += [3]i64{i_sign.x >> 1, i_sign.y >> 1, i_sign.z >> 1} & {PRIME_X, PRIME_Y, PRIME_Z}
|
||||
|
||||
// Update the reverse sign indicators.
|
||||
i_sign = -i_sign
|
||||
f_sign = -f_sign
|
||||
|
||||
// And finally update the seed for the other lattice copy.
|
||||
seed ~= SEED_FLIP_3D
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/*
|
||||
4D OpenSimplex2 noise base.
|
||||
*/
|
||||
_internal_noise_4d_unskewed_base :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||
seed := seed
|
||||
|
||||
// Get base points and offsets
|
||||
base := [4]i64{fast_floor(coord.x), fast_floor(coord.y), fast_floor(coord.z), fast_floor(coord.w)}
|
||||
si := [4]f32{f32(coord.x - f64(base.x)), f32(coord.y - f64(base.y)), f32(coord.z - f64(base.z)), f32(coord.w - f64(base.w))}
|
||||
|
||||
// Determine which lattice we can be confident has a contributing point its corresponding cell's base simplex.
|
||||
// We only look at the spaces between the diagonal planes. This proved effective in all of my tests.
|
||||
si_sum := (si.x + si.y) + (si.z + si.w)
|
||||
starting_lattice := i64(si_sum * 1.25)
|
||||
|
||||
// Offset for seed based on first lattice copy.
|
||||
seed += starting_lattice * SEED_OFFSET_4D
|
||||
|
||||
// Offset for lattice point relative positions (skewed)
|
||||
starting_lattice_offset := f32(starting_lattice) * -LATTICE_STEP_4D
|
||||
si += starting_lattice_offset
|
||||
|
||||
// Prep for vertex contributions.
|
||||
ssi := (si_sum + starting_lattice_offset * 4) * UNSKEW_4D
|
||||
|
||||
// Prime pre-multiplication for hash.
|
||||
svp := base * [4]i64{PRIME_X, PRIME_Y, PRIME_Z, PRIME_W}
|
||||
|
||||
// Five points to add, total, from five copies of the A4 lattice.
|
||||
for i : i64 = 0; ; i += 1 {
|
||||
|
||||
// Next point is the closest vertex on the 4-simplex whose base vertex is the aforementioned vertex.
|
||||
score := 1.0 + ssi * (-1.0 / UNSKEW_4D) // Seems slightly faster than 1.0-xsi-ysi-zsi-wsi
|
||||
if si.x >= si.x && si.x >= si.z && si.x >= si.w && si.x >= score {
|
||||
svp.x += PRIME_X
|
||||
si.x -= 1
|
||||
ssi -= UNSKEW_4D
|
||||
}
|
||||
else if si.y > si.x && si.y >= si.z && si.y >= si.w && si.y >= score {
|
||||
svp.y += PRIME_Y
|
||||
si.y -= 1
|
||||
ssi -= UNSKEW_4D
|
||||
}
|
||||
else if si.z > si.x && si.z > si.y && si.z >= si.w && si.z >= score {
|
||||
svp.z += PRIME_Z
|
||||
si.z -= 1
|
||||
ssi -= UNSKEW_4D
|
||||
}
|
||||
else if si.w > si.x && si.w > si.y && si.w > si.z && si.w >= score {
|
||||
svp.w += PRIME_W
|
||||
si.w -= 1
|
||||
ssi -= UNSKEW_4D
|
||||
}
|
||||
|
||||
// gradient contribution with falloff.
|
||||
d := si + ssi
|
||||
a := (d.x * d.x + d.y * d.y) + (d.z * d.z + d.w * d.w)
|
||||
|
||||
if a < RSQUARED_4D {
|
||||
a -= RSQUARED_4D
|
||||
a *= a; a4 := a * a
|
||||
value += a4 * grad(seed, svp, d)
|
||||
}
|
||||
|
||||
// Break from loop if we're done, skipping updates below.
|
||||
if i == 4 {
|
||||
break
|
||||
}
|
||||
|
||||
// Update for next lattice copy shifted down by <-0.2, -0.2, -0.2, -0.2>.
|
||||
si += LATTICE_STEP_4D
|
||||
ssi += LATTICE_STEP_4D * 4 * UNSKEW_4D
|
||||
seed -= SEED_OFFSET_4D
|
||||
|
||||
// Because we don't always start on the same lattice copy, there's a special reset case.
|
||||
if i == starting_lattice {
|
||||
svp -= {PRIME_X, PRIME_Y, PRIME_Z, PRIME_W}
|
||||
seed += SEED_OFFSET_4D * 5
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Utility functions
|
||||
*/
|
||||
@(optimization_mode="speed")
|
||||
grad_2d :: proc(seed: i64, svp: [2]i64, delta: [2]f32) -> (value: f32) {
|
||||
hash := seed ~ svp.x ~ svp.y
|
||||
hash *= HASH_MULTIPLIER
|
||||
hash ~= hash >> (64 - N_GRADS_2D_EXPONENT + 1)
|
||||
|
||||
gi := hash & ((N_GRADS_2D - 1) << 1)
|
||||
return GRADIENTS_2D[gi] * delta.x + GRADIENTS_2D[gi | 1] * delta.y
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
grad_3d :: proc(seed: i64, rvp: [3]i64, delta: [3]f32) -> (value: f32) {
|
||||
hash := (seed ~ rvp.x) ~ (rvp.y ~ rvp.z)
|
||||
hash *= HASH_MULTIPLIER
|
||||
hash ~= hash >> (64 - N_GRADS_3D_EXPONENT + 2)
|
||||
|
||||
gi := hash & ((N_GRADS_3D - 1) << 2)
|
||||
return GRADIENTS_3D[gi] * delta.x + GRADIENTS_3D[gi | 1] * delta.y + GRADIENTS_3D[gi | 2] * delta.z
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
grad_4d :: proc(seed: i64, svp: [4]i64, delta: [4]f32) -> (value: f32) {
|
||||
hash := seed ~ (svp.x ~ svp.y) ~ (svp.z ~ svp.w)
|
||||
hash *= HASH_MULTIPLIER
|
||||
hash ~= hash >> (64 - N_GRADS_4D_EXPONENT + 2)
|
||||
|
||||
gi := hash & ((N_GRADS_4D - 1) << 2)
|
||||
return (GRADIENTS_4D[gi] * delta.x + GRADIENTS_4D[gi | 1] * delta.y) + (GRADIENTS_4D[gi | 2] * delta.z + GRADIENTS_4D[gi | 3] * delta.w)
|
||||
}
|
||||
|
||||
grad :: proc {grad_2d, grad_3d, grad_4d}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
fast_floor :: proc(x: f64) -> (floored: i64) {
|
||||
xi := i64(x)
|
||||
return x < f64(xi) ? xi - 1 : xi
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
fast_round :: proc(x: f64) -> (rounded: i64) {
|
||||
return x < 0 ? i64(x - 0.5) : i64(x + 0.5)
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
OpenSimplex2 noise implementation.
|
||||
|
||||
Ported from https://github.com/KdotJPG/OpenSimplex2.
|
||||
Copyright 2022 Yuki2 (https://github.com/NoahR02)
|
||||
*/
|
||||
package math_noise
|
||||
|
||||
/*
|
||||
Input coordinate vectors
|
||||
*/
|
||||
Vec2 :: [2]f64
|
||||
Vec3 :: [3]f64
|
||||
Vec4 :: [4]f64
|
||||
|
||||
/*
|
||||
Noise Evaluators
|
||||
*/
|
||||
|
||||
/*
|
||||
2D Simplex noise, standard lattice orientation.
|
||||
*/
|
||||
noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) {
|
||||
// Get points for A2* lattice
|
||||
skew := SKEW_2D * (coord.x + coord.y)
|
||||
skewed := coord + skew
|
||||
|
||||
return _internal_noise_2d_unskewed_base(seed, skewed)
|
||||
}
|
||||
|
||||
/*
|
||||
2D Simplex noise, with Y pointing down the main diagonal.
|
||||
Might be better for a 2D sandbox style game, where Y is vertical.
|
||||
Probably slightly less optimal for heightmaps or continent maps,
|
||||
unless your map is centered around an equator. It's a subtle
|
||||
difference, but the option is here to make it an easy choice.
|
||||
*/
|
||||
noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) {
|
||||
// Skew transform and rotation baked into one.
|
||||
xx := coord.x * ROOT_2_OVER_2
|
||||
yy := coord.y * (ROOT_2_OVER_2 * (1 + 2 * SKEW_2D))
|
||||
return _internal_noise_2d_unskewed_base(seed, Vec2{yy + xx, yy - xx})
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
3D OpenSimplex2 noise, with better visual isotropy in (X, Y).
|
||||
Recommended for 3D terrain and time-varied animations.
|
||||
The Z coordinate should always be the "different" coordinate in whatever your use case is.
|
||||
If Y is vertical in world coordinates, call `noise_3d_improve_xz(x, z, Y)` or use `noise_3d_xz_before_y`.
|
||||
If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, y, Z)`.
|
||||
For a time varied animation, call `noise_3d_improve_xz(x, y, T)`.
|
||||
*/
|
||||
noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||
/*
|
||||
Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal,
|
||||
and the planes formed by XY are moved far out of alignment with the cube faces.
|
||||
Orthonormal rotation. Not a skew transform.
|
||||
*/
|
||||
xy := coord.x + coord.y
|
||||
s2 := xy * ROTATE_3D_ORTHOGONALIZER
|
||||
zz := coord.z * ROOT_3_OVER_3
|
||||
|
||||
r := Vec3{coord.x + s2 + zz, coord.y + s2 + zz, xy * -ROOT_3_OVER_3 + zz}
|
||||
|
||||
// Evaluate both lattices to form a BCC lattice.
|
||||
return _internal_noise_3d_unrotated_base(seed, r)
|
||||
}
|
||||
|
||||
/*
|
||||
3D OpenSimplex2 noise, with better visual isotropy in (X, Z).
|
||||
Recommended for 3D terrain and time-varied animations.
|
||||
The Y coordinate should always be the "different" coordinate in whatever your use case is.
|
||||
If Y is vertical in world coordinates, call `noise_3d_improve_xz(x, Y, z)`.
|
||||
If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, Z, y)` or use `noise_3d_improve_xy`.
|
||||
For a time varied animation, call `noise_3d_improve_xz(x, T, y)` or use `noise_3d_improve_xy`.
|
||||
*/
|
||||
noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||
/*
|
||||
Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal,
|
||||
and the planes formed by XZ are moved far out of alignment with the cube faces.
|
||||
Orthonormal rotation. Not a skew transform.
|
||||
*/
|
||||
xz := coord.x + coord.z
|
||||
s2 := xz * ROTATE_3D_ORTHOGONALIZER
|
||||
yy := coord.y * ROOT_3_OVER_3
|
||||
|
||||
r := Vec3{coord.x + s2 + yy, xz * -ROOT_3_OVER_3 + yy, coord.z + s2 + yy}
|
||||
|
||||
// Evaluate both lattices to form a BCC lattice.
|
||||
return _internal_noise_3d_unrotated_base(seed, r)
|
||||
}
|
||||
|
||||
/*
|
||||
3D OpenSimplex2 noise, fallback rotation option
|
||||
Use `noise_3d_improve_xy` or `noise_3d_improve_xz` instead, wherever appropriate.
|
||||
They have less diagonal bias. This function's best use is as a fallback.
|
||||
*/
|
||||
noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||
/*
|
||||
Re-orient the cubic lattices via rotation, to produce a familiar look.
|
||||
Orthonormal rotation. Not a skew transform.
|
||||
*/
|
||||
bias := FALLBACK_ROTATE_3D * (coord.x + coord.y + coord.z)
|
||||
biased := bias - coord
|
||||
// Evaluate both lattices to form a BCC lattice.
|
||||
return _internal_noise_3d_unrotated_base(seed, biased)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_improve_xy`
|
||||
and W for an extra degree of freedom. W repeats eventually.
|
||||
Recommended for time-varied animations which texture a 3D object (W=time)
|
||||
in a space where Z is vertical.
|
||||
*/
|
||||
noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||
xy := coord.x + coord.y
|
||||
s2 := xy * -0.21132486540518699998
|
||||
zz := coord.z * 0.28867513459481294226
|
||||
ww := coord.w * 0.2236067977499788
|
||||
|
||||
xr, yr : f64 = coord.x + (zz + ww + s2), coord.y + (zz + ww + s2)
|
||||
zr : f64 = xy * -0.57735026918962599998 + (zz + ww)
|
||||
wr : f64 = coord.z * -0.866025403784439 + ww
|
||||
|
||||
return _internal_noise_4d_unskewed_base(seed, Vec4{xr, yr, zr, wr})
|
||||
}
|
||||
|
||||
/*
|
||||
4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_improve_xz`
|
||||
and W for an extra degree of freedom. W repeats eventually.
|
||||
Recommended for time-varied animations which texture a 3D object (W=time)
|
||||
in a space where Y is vertical.
|
||||
*/
|
||||
noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||
xz := coord.x + coord.z
|
||||
s2 := xz * -0.21132486540518699998
|
||||
yy := coord.y * 0.28867513459481294226
|
||||
ww := coord.w * 0.2236067977499788
|
||||
|
||||
xr, zr : f64 = coord.x + (yy + ww + s2), coord.z + (yy + ww + s2)
|
||||
yr := xz * -0.57735026918962599998 + (yy + ww)
|
||||
wr := coord.y * -0.866025403784439 + ww
|
||||
|
||||
return _internal_noise_4d_unskewed_base(seed, Vec4{xr, yr, zr, wr})
|
||||
}
|
||||
|
||||
/*
|
||||
4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_fallback`
|
||||
and W for an extra degree of freedom. W repeats eventually.
|
||||
Recommended for time-varied animations which texture a 3D object (W=time)
|
||||
where there isn't a clear distinction between horizontal and vertical
|
||||
*/
|
||||
noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||
xyz := coord.x + coord.y + coord.z
|
||||
ww := coord.w * 0.2236067977499788
|
||||
s2 := xyz * -0.16666666666666666 + ww
|
||||
|
||||
skewed := Vec4{coord.x + s2, coord.y + s2, coord.z + s2, -0.5 * xyz + ww}
|
||||
return _internal_noise_4d_unskewed_base(seed, skewed)
|
||||
}
|
||||
|
||||
/*
|
||||
4D OpenSimplex2 noise, fallback lattice orientation.
|
||||
*/
|
||||
noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||
// Get points for A4 lattice
|
||||
skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w)
|
||||
return _internal_noise_4d_unskewed_base(seed, coord + skew)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
package mem implements various types of allocators.
|
||||
|
||||
|
||||
An example of how to use the `Tracking_Allocator` to track subsequent allocations
|
||||
in your program and report leaks and bad frees:
|
||||
|
||||
```odin
|
||||
package foo
|
||||
|
||||
import "core:mem"
|
||||
import "core:fmt"
|
||||
|
||||
_main :: proc() {
|
||||
do stuff
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
track: mem.Tracking_Allocator
|
||||
mem.tracking_allocator_init(&track, context.allocator)
|
||||
context.allocator = mem.tracking_allocator(&track)
|
||||
|
||||
_main()
|
||||
|
||||
for _, leak in track.allocation_map {
|
||||
fmt.printf("%v leaked %v bytes\n", leak.location, leak.size)
|
||||
}
|
||||
for bad_free in track.bad_free_array {
|
||||
fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
package mem
|
||||
@@ -6,25 +6,25 @@ DEFAULT_PAGE_SIZE := uint(4096)
|
||||
|
||||
Allocator_Error :: mem.Allocator_Error
|
||||
|
||||
reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
return _reserve(size)
|
||||
}
|
||||
|
||||
commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
||||
commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
return _commit(data, size)
|
||||
}
|
||||
|
||||
reserve_and_commit :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
data = reserve(size) or_return
|
||||
commit(raw_data(data), size) or_return
|
||||
return
|
||||
}
|
||||
|
||||
decommit :: proc(data: rawptr, size: uint) {
|
||||
decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
_decommit(data, size)
|
||||
}
|
||||
|
||||
release :: proc(data: rawptr, size: uint) {
|
||||
release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
_release(data, size)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ Protect_Flag :: enum u32 {
|
||||
Protect_Flags :: distinct bit_set[Protect_Flag; u32]
|
||||
Protect_No_Access :: Protect_Flags{}
|
||||
|
||||
protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
return _protect(data, size, flags)
|
||||
}
|
||||
|
||||
@@ -82,11 +82,13 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
pmblock := platform_memory_alloc(0, total_size) or_return
|
||||
|
||||
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset)
|
||||
commit(pmblock.block.base, committed) or_return
|
||||
commit_err := platform_memory_commit(pmblock, uint(base_offset) + committed)
|
||||
assert(commit_err == nil)
|
||||
|
||||
// Should be zeroed
|
||||
assert(pmblock.block.used == 0)
|
||||
assert(pmblock.block.prev == nil)
|
||||
if (do_protection) {
|
||||
if do_protection {
|
||||
protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access)
|
||||
}
|
||||
|
||||
@@ -105,7 +107,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
}
|
||||
|
||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
||||
calc_alignment_offset :: proc(block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||
alignment_offset := uint(0)
|
||||
ptr := uintptr(block.base[block.used:])
|
||||
mask := alignment-1
|
||||
@@ -115,23 +117,37 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
|
||||
return alignment_offset
|
||||
|
||||
}
|
||||
|
||||
do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint) -> (err: Allocator_Error) {
|
||||
if block.committed - block.used < size {
|
||||
pmblock := (^Platform_Memory_Block)(block)
|
||||
base_offset := uint(uintptr(block) - uintptr(pmblock))
|
||||
platform_total_commit := base_offset + block.used + size
|
||||
|
||||
assert(pmblock.committed <= pmblock.reserved)
|
||||
assert(pmblock.committed < platform_total_commit)
|
||||
|
||||
platform_memory_commit(pmblock, platform_total_commit) or_return
|
||||
|
||||
pmblock.committed = platform_total_commit
|
||||
block.committed = pmblock.committed - base_offset
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
||||
|
||||
size := uint(min_size) + alignment_offset
|
||||
|
||||
|
||||
if block.used + size > block.reserved {
|
||||
err = .Out_Of_Memory
|
||||
return
|
||||
}
|
||||
|
||||
ptr := block.base[block.used:]
|
||||
ptr = ptr[alignment_offset:]
|
||||
|
||||
assert(block.committed <= block.reserved)
|
||||
do_commit_if_necessary(block, size) or_return
|
||||
|
||||
data = block.base[block.used+alignment_offset:][:min_size]
|
||||
block.used += size
|
||||
assert(block.used <= block.reserved)
|
||||
|
||||
return ptr[:min_size], nil
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.i
|
||||
}
|
||||
|
||||
|
||||
_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
MAP_FAILED := rawptr(~uintptr(0))
|
||||
result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
|
||||
if result == MAP_FAILED {
|
||||
@@ -67,7 +67,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
return ([^]byte)(result)[:size], nil
|
||||
}
|
||||
|
||||
_commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
||||
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
result := mprotect(data, size, PROT_READ|PROT_WRITE)
|
||||
if result != 0 {
|
||||
// TODO(bill): Handle error value correctly
|
||||
@@ -75,14 +75,14 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
_decommit :: proc(data: rawptr, size: uint) {
|
||||
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
mprotect(data, size, PROT_NONE)
|
||||
madvise(data, size, MADV_FREE)
|
||||
}
|
||||
_release :: proc(data: rawptr, size: uint) {
|
||||
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
munmap(data, size)
|
||||
}
|
||||
_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
pflags: c.int
|
||||
pflags = PROT_NONE
|
||||
if .Read in flags { pflags |= PROT_READ }
|
||||
|
||||
@@ -4,12 +4,13 @@ package mem_virtual
|
||||
import sync "core:sync/sync2"
|
||||
|
||||
Platform_Memory_Block :: struct {
|
||||
block: Memory_Block,
|
||||
reserved: uint,
|
||||
block: Memory_Block,
|
||||
committed: uint,
|
||||
reserved: uint,
|
||||
prev, next: ^Platform_Memory_Block,
|
||||
}
|
||||
|
||||
platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
||||
platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
||||
to_commit, to_reserve := to_commit, to_reserve
|
||||
to_reserve = max(to_commit, to_reserve)
|
||||
|
||||
@@ -20,12 +21,13 @@ platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_
|
||||
commit(raw_data(data), to_commit)
|
||||
|
||||
block = (^Platform_Memory_Block)(raw_data(data))
|
||||
block.reserved = to_reserve
|
||||
block.committed = to_commit
|
||||
block.reserved = to_reserve
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
platform_memory_free :: proc(block: ^Platform_Memory_Block) {
|
||||
platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) {
|
||||
if block != nil {
|
||||
release(block, block.reserved)
|
||||
}
|
||||
@@ -52,3 +54,17 @@ platform_memory_init :: proc() {
|
||||
global_platform_memory_block_sentinel_set = true
|
||||
}
|
||||
}
|
||||
|
||||
platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
|
||||
if to_commit < block.committed {
|
||||
return nil
|
||||
}
|
||||
if to_commit > block.reserved {
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
|
||||
|
||||
commit(block, to_commit) or_return
|
||||
block.committed = to_commit
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ foreign Kernel32 {
|
||||
}
|
||||
|
||||
|
||||
_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
|
||||
if result == nil {
|
||||
err = .Out_Of_Memory
|
||||
@@ -72,7 +72,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
return
|
||||
}
|
||||
|
||||
_commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
||||
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
|
||||
if result == nil {
|
||||
switch err := GetLastError(); err {
|
||||
@@ -85,13 +85,13 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
_decommit :: proc(data: rawptr, size: uint) {
|
||||
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
VirtualFree(data, size, MEM_DECOMMIT)
|
||||
}
|
||||
_release :: proc(data: rawptr, size: uint) {
|
||||
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
VirtualFree(data, 0, MEM_RELEASE)
|
||||
}
|
||||
_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
pflags: u32
|
||||
pflags = PAGE_NOACCESS
|
||||
switch flags {
|
||||
|
||||
@@ -428,9 +428,21 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token {
|
||||
str := tokenizer.token_to_string(token)
|
||||
error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str)
|
||||
}
|
||||
return expect_token(p, .Close_Brace)
|
||||
expect_brace := expect_token(p, .Close_Brace)
|
||||
|
||||
if expect_brace.kind != .Close_Brace {
|
||||
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) {
|
||||
advance_token(p)
|
||||
}
|
||||
return p.curr_tok
|
||||
}
|
||||
|
||||
return expect_brace
|
||||
}
|
||||
|
||||
is_non_inserted_semicolon :: proc(tok: tokenizer.Token) -> bool {
|
||||
return tok.kind == .Semicolon && tok.text != "\n"
|
||||
}
|
||||
|
||||
is_blank_ident :: proc{
|
||||
is_blank_ident_string,
|
||||
@@ -1312,7 +1324,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
}
|
||||
|
||||
results: [dynamic]^ast.Expr
|
||||
for p.curr_tok.kind != .Semicolon {
|
||||
for p.curr_tok.kind != .Semicolon && p.curr_tok.kind != .Close_Brace {
|
||||
result := parse_expr(p, false)
|
||||
append(&results, result)
|
||||
if p.curr_tok.kind != .Comma ||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package os
|
||||
|
||||
import "core:strings"
|
||||
import "core:mem"
|
||||
|
||||
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||
dirp: Dir
|
||||
dirp, err = _fdopendir(fd)
|
||||
if err != ERROR_NONE {
|
||||
return
|
||||
}
|
||||
|
||||
defer _closedir(dirp)
|
||||
|
||||
// XXX OpenBSD
|
||||
dirpath: string
|
||||
dirpath, err = absolute_path_from_handle(fd)
|
||||
|
||||
if err != ERROR_NONE {
|
||||
return
|
||||
}
|
||||
|
||||
defer delete(dirpath)
|
||||
|
||||
n := n
|
||||
size := n
|
||||
if n <= 0 {
|
||||
n = -1
|
||||
size = 100
|
||||
}
|
||||
|
||||
dfi := make([dynamic]File_Info, 0, size, allocator)
|
||||
|
||||
for {
|
||||
entry: Dirent
|
||||
end_of_stream: bool
|
||||
entry, err, end_of_stream = _readdir(dirp)
|
||||
if err != ERROR_NONE {
|
||||
for fi_ in dfi {
|
||||
file_info_delete(fi_, allocator)
|
||||
}
|
||||
delete(dfi)
|
||||
return
|
||||
} else if end_of_stream {
|
||||
break
|
||||
}
|
||||
|
||||
fi_: File_Info
|
||||
filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] })
|
||||
|
||||
if filename == "." || filename == ".." {
|
||||
continue
|
||||
}
|
||||
|
||||
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
|
||||
defer delete(fullpath, context.temp_allocator)
|
||||
|
||||
fi_, err = stat(fullpath, allocator)
|
||||
if err != ERROR_NONE {
|
||||
for fi__ in dfi {
|
||||
file_info_delete(fi__, allocator)
|
||||
}
|
||||
delete(dfi)
|
||||
return
|
||||
}
|
||||
|
||||
append(&dfi, fi_)
|
||||
}
|
||||
|
||||
return dfi[:], ERROR_NONE
|
||||
}
|
||||
@@ -106,19 +106,23 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
|
||||
BUF_SIZE :: 386
|
||||
buf16: [BUF_SIZE]u16
|
||||
buf8: [4*BUF_SIZE]u8
|
||||
|
||||
|
||||
for n < len(b) && err == 0 {
|
||||
max_read := u32(min(BUF_SIZE, len(b)/4))
|
||||
|
||||
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 = Errno(win32.GetLastError())
|
||||
}
|
||||
|
||||
|
||||
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+i < len(b); i += 1 {
|
||||
x := src[i]
|
||||
@@ -129,9 +133,16 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
|
||||
b[n] = x
|
||||
n += 1
|
||||
}
|
||||
if ctrl_z || single_read_length < len(buf16) {
|
||||
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
|
||||
@@ -399,7 +410,7 @@ is_abs :: proc(path: string) -> bool {
|
||||
if len(path) > 0 && path[0] == '/' {
|
||||
return true
|
||||
}
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
if len(path) > 2 {
|
||||
switch path[0] {
|
||||
case 'A'..='Z', 'a'..='z':
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ
|
||||
}
|
||||
|
||||
mode: int = 0
|
||||
when OS == "linux" || OS == "darwin" {
|
||||
when OS == .Linux || OS == .Darwin {
|
||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ package os2
|
||||
import "core:strings"
|
||||
|
||||
user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
|
||||
switch ODIN_OS {
|
||||
case "windows":
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
dir = get_env("LocalAppData")
|
||||
if dir != "" {
|
||||
dir = strings.clone(dir, allocator)
|
||||
}
|
||||
case "darwin":
|
||||
case .Darwin:
|
||||
dir = get_env("HOME")
|
||||
if dir != "" {
|
||||
dir = strings.concatenate({dir, "/Library/Caches"}, allocator)
|
||||
@@ -29,13 +29,13 @@ user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defin
|
||||
}
|
||||
|
||||
user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
|
||||
switch ODIN_OS {
|
||||
case "windows":
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
dir = get_env("AppData")
|
||||
if dir != "" {
|
||||
dir = strings.clone(dir, allocator)
|
||||
}
|
||||
case "darwin":
|
||||
case .Darwin:
|
||||
dir = get_env("HOME")
|
||||
if dir != "" {
|
||||
dir = strings.concatenate({dir, "/Library/Application Support"}, allocator)
|
||||
@@ -56,8 +56,8 @@ user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defi
|
||||
|
||||
user_home_dir :: proc() -> (dir: string, is_defined: bool) {
|
||||
env := "HOME"
|
||||
switch ODIN_OS {
|
||||
case "windows":
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
env = "USERPROFILE"
|
||||
}
|
||||
if v := get_env(env); v != "" {
|
||||
|
||||
+13
-4
@@ -313,6 +313,7 @@ foreign libc {
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u32) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||
@@ -320,7 +321,7 @@ foreign libc {
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
_unix_fdopendir :: proc {_unix_fdopendir_amd64}
|
||||
_unix_readdir_r :: proc {_unix_readdir_r_amd64}
|
||||
} else {
|
||||
@@ -344,14 +345,13 @@ get_last_error_string :: proc() -> string {
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||
delete(cstr)
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, 1
|
||||
}
|
||||
|
||||
when ODIN_OS == "darwin" && ODIN_ARCH == "arm64" {
|
||||
when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
|
||||
if mode != 0 {
|
||||
err := fchmod(handle, cast(u16)mode)
|
||||
if err != 0 {
|
||||
@@ -670,6 +670,15 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
exit :: proc "contextless" (code: int) -> ! {
|
||||
_unix_exit(i32(code))
|
||||
}
|
||||
|
||||
+272
-279
@@ -7,149 +7,149 @@ import "core:runtime"
|
||||
import "core:strings"
|
||||
import "core:c"
|
||||
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
Errno :: distinct i32;
|
||||
Syscall :: distinct i32;
|
||||
Handle :: distinct i32
|
||||
File_Time :: distinct u64
|
||||
Errno :: distinct i32
|
||||
Syscall :: distinct i32
|
||||
|
||||
INVALID_HANDLE :: ~Handle(0);
|
||||
INVALID_HANDLE :: ~Handle(0)
|
||||
|
||||
ERROR_NONE: Errno : 0;
|
||||
EPERM: Errno : 1;
|
||||
ENOENT: Errno : 2;
|
||||
ESRCH: Errno : 3;
|
||||
EINTR: Errno : 4;
|
||||
EIO: Errno : 5;
|
||||
ENXIO: Errno : 6;
|
||||
E2BIG: Errno : 7;
|
||||
ENOEXEC: Errno : 8;
|
||||
EBADF: Errno : 9;
|
||||
ECHILD: Errno : 10;
|
||||
EBEADLK: Errno : 11;
|
||||
ENOMEM: Errno : 12;
|
||||
EACCESS: Errno : 13;
|
||||
EFAULT: Errno : 14;
|
||||
ENOTBLK: Errno : 15;
|
||||
EBUSY: Errno : 16;
|
||||
EEXIST: Errno : 17;
|
||||
EXDEV: Errno : 18;
|
||||
ENODEV: Errno : 19;
|
||||
ENOTDIR: Errno : 20;
|
||||
EISDIR: Errno : 21;
|
||||
EINVAL: Errno : 22;
|
||||
ENFILE: Errno : 23;
|
||||
EMFILE: Errno : 24;
|
||||
ENOTTY: Errno : 25;
|
||||
ETXTBSY: Errno : 26;
|
||||
EFBIG: Errno : 27;
|
||||
ENOSPC: Errno : 28;
|
||||
ESPIPE: Errno : 29;
|
||||
EROFS: Errno : 30;
|
||||
EMLINK: Errno : 31;
|
||||
EPIPE: Errno : 32;
|
||||
EDOM: Errno : 33;
|
||||
ERANGE: Errno : 34; /* Result too large */
|
||||
EAGAIN: Errno : 35;
|
||||
EINPROGRESS: Errno : 36;
|
||||
EALREADY: Errno : 37;
|
||||
ENOTSOCK: Errno : 38;
|
||||
EDESTADDRREQ: Errno : 39;
|
||||
EMSGSIZE: Errno : 40;
|
||||
EPROTOTYPE: Errno : 41;
|
||||
ENOPROTOOPT: Errno : 42;
|
||||
EPROTONOSUPPORT: Errno : 43;
|
||||
ESOCKTNOSUPPORT: Errno : 44;
|
||||
EOPNOTSUPP: Errno : 45;
|
||||
EPFNOSUPPORT: Errno : 46;
|
||||
EAFNOSUPPORT: Errno : 47;
|
||||
EADDRINUSE: Errno : 48;
|
||||
EADDRNOTAVAIL: Errno : 49;
|
||||
ENETDOWN: Errno : 50;
|
||||
ENETUNREACH: Errno : 51;
|
||||
ENETRESET: Errno : 52;
|
||||
ECONNABORTED: Errno : 53;
|
||||
ECONNRESET: Errno : 54;
|
||||
ENOBUFS: Errno : 55;
|
||||
EISCONN: Errno : 56;
|
||||
ENOTCONN: Errno : 57;
|
||||
ESHUTDOWN: Errno : 58;
|
||||
ETIMEDOUT: Errno : 60;
|
||||
ECONNREFUSED: Errno : 61;
|
||||
ELOOP: Errno : 62;
|
||||
ENAMETOOLING: Errno : 63;
|
||||
EHOSTDOWN: Errno : 64;
|
||||
EHOSTUNREACH: Errno : 65;
|
||||
ENOTEMPTY: Errno : 66;
|
||||
EPROCLIM: Errno : 67;
|
||||
EUSERS: Errno : 68;
|
||||
EDQUOT: Errno : 69;
|
||||
ESTALE: Errno : 70;
|
||||
EBADRPC: Errno : 72;
|
||||
ERPCMISMATCH: Errno : 73;
|
||||
EPROGUNAVAIL: Errno : 74;
|
||||
EPROGMISMATCH: Errno : 75;
|
||||
EPROCUNAVAIL: Errno : 76;
|
||||
ENOLCK: Errno : 77;
|
||||
ENOSYS: Errno : 78;
|
||||
EFTYPE: Errno : 79;
|
||||
EAUTH: Errno : 80;
|
||||
ENEEDAUTH: Errno : 81;
|
||||
EIDRM: Errno : 82;
|
||||
ENOMSG: Errno : 83;
|
||||
EOVERFLOW: Errno : 84;
|
||||
ECANCELED: Errno : 85;
|
||||
EILSEQ: Errno : 86;
|
||||
ENOATTR: Errno : 87;
|
||||
EDOOFUS: Errno : 88;
|
||||
EBADMSG: Errno : 89;
|
||||
EMULTIHOP: Errno : 90;
|
||||
ENOLINK: Errno : 91;
|
||||
EPROTO: Errno : 92;
|
||||
ENOTCAPABLE: Errno : 93;
|
||||
ECAPMODE: Errno : 94;
|
||||
ENOTRECOVERABLE: Errno : 95;
|
||||
EOWNERDEAD: Errno : 96;
|
||||
ERROR_NONE: Errno : 0
|
||||
EPERM: Errno : 1
|
||||
ENOENT: Errno : 2
|
||||
ESRCH: Errno : 3
|
||||
EINTR: Errno : 4
|
||||
EIO: Errno : 5
|
||||
ENXIO: Errno : 6
|
||||
E2BIG: Errno : 7
|
||||
ENOEXEC: Errno : 8
|
||||
EBADF: Errno : 9
|
||||
ECHILD: Errno : 10
|
||||
EBEADLK: Errno : 11
|
||||
ENOMEM: Errno : 12
|
||||
EACCESS: Errno : 13
|
||||
EFAULT: Errno : 14
|
||||
ENOTBLK: Errno : 15
|
||||
EBUSY: Errno : 16
|
||||
EEXIST: Errno : 17
|
||||
EXDEV: Errno : 18
|
||||
ENODEV: Errno : 19
|
||||
ENOTDIR: Errno : 20
|
||||
EISDIR: Errno : 21
|
||||
EINVAL: Errno : 22
|
||||
ENFILE: Errno : 23
|
||||
EMFILE: Errno : 24
|
||||
ENOTTY: Errno : 25
|
||||
ETXTBSY: Errno : 26
|
||||
EFBIG: Errno : 27
|
||||
ENOSPC: Errno : 28
|
||||
ESPIPE: Errno : 29
|
||||
EROFS: Errno : 30
|
||||
EMLINK: Errno : 31
|
||||
EPIPE: Errno : 32
|
||||
EDOM: Errno : 33
|
||||
ERANGE: Errno : 34 /* Result too large */
|
||||
EAGAIN: Errno : 35
|
||||
EINPROGRESS: Errno : 36
|
||||
EALREADY: Errno : 37
|
||||
ENOTSOCK: Errno : 38
|
||||
EDESTADDRREQ: Errno : 39
|
||||
EMSGSIZE: Errno : 40
|
||||
EPROTOTYPE: Errno : 41
|
||||
ENOPROTOOPT: Errno : 42
|
||||
EPROTONOSUPPORT: Errno : 43
|
||||
ESOCKTNOSUPPORT: Errno : 44
|
||||
EOPNOTSUPP: Errno : 45
|
||||
EPFNOSUPPORT: Errno : 46
|
||||
EAFNOSUPPORT: Errno : 47
|
||||
EADDRINUSE: Errno : 48
|
||||
EADDRNOTAVAIL: Errno : 49
|
||||
ENETDOWN: Errno : 50
|
||||
ENETUNREACH: Errno : 51
|
||||
ENETRESET: Errno : 52
|
||||
ECONNABORTED: Errno : 53
|
||||
ECONNRESET: Errno : 54
|
||||
ENOBUFS: Errno : 55
|
||||
EISCONN: Errno : 56
|
||||
ENOTCONN: Errno : 57
|
||||
ESHUTDOWN: Errno : 58
|
||||
ETIMEDOUT: Errno : 60
|
||||
ECONNREFUSED: Errno : 61
|
||||
ELOOP: Errno : 62
|
||||
ENAMETOOLING: Errno : 63
|
||||
EHOSTDOWN: Errno : 64
|
||||
EHOSTUNREACH: Errno : 65
|
||||
ENOTEMPTY: Errno : 66
|
||||
EPROCLIM: Errno : 67
|
||||
EUSERS: Errno : 68
|
||||
EDQUOT: Errno : 69
|
||||
ESTALE: Errno : 70
|
||||
EBADRPC: Errno : 72
|
||||
ERPCMISMATCH: Errno : 73
|
||||
EPROGUNAVAIL: Errno : 74
|
||||
EPROGMISMATCH: Errno : 75
|
||||
EPROCUNAVAIL: Errno : 76
|
||||
ENOLCK: Errno : 77
|
||||
ENOSYS: Errno : 78
|
||||
EFTYPE: Errno : 79
|
||||
EAUTH: Errno : 80
|
||||
ENEEDAUTH: Errno : 81
|
||||
EIDRM: Errno : 82
|
||||
ENOMSG: Errno : 83
|
||||
EOVERFLOW: Errno : 84
|
||||
ECANCELED: Errno : 85
|
||||
EILSEQ: Errno : 86
|
||||
ENOATTR: Errno : 87
|
||||
EDOOFUS: Errno : 88
|
||||
EBADMSG: Errno : 89
|
||||
EMULTIHOP: Errno : 90
|
||||
ENOLINK: Errno : 91
|
||||
EPROTO: Errno : 92
|
||||
ENOTCAPABLE: Errno : 93
|
||||
ECAPMODE: Errno : 94
|
||||
ENOTRECOVERABLE: Errno : 95
|
||||
EOWNERDEAD: Errno : 96
|
||||
|
||||
O_RDONLY :: 0x00000;
|
||||
O_WRONLY :: 0x00001;
|
||||
O_RDWR :: 0x00002;
|
||||
O_CREATE :: 0x00040;
|
||||
O_EXCL :: 0x00080;
|
||||
O_NOCTTY :: 0x00100;
|
||||
O_TRUNC :: 0x00200;
|
||||
O_NONBLOCK :: 0x00800;
|
||||
O_APPEND :: 0x00400;
|
||||
O_SYNC :: 0x01000;
|
||||
O_ASYNC :: 0x02000;
|
||||
O_CLOEXEC :: 0x80000;
|
||||
O_RDONLY :: 0x00000
|
||||
O_WRONLY :: 0x00001
|
||||
O_RDWR :: 0x00002
|
||||
O_CREATE :: 0x00040
|
||||
O_EXCL :: 0x00080
|
||||
O_NOCTTY :: 0x00100
|
||||
O_TRUNC :: 0x00200
|
||||
O_NONBLOCK :: 0x00800
|
||||
O_APPEND :: 0x00400
|
||||
O_SYNC :: 0x01000
|
||||
O_ASYNC :: 0x02000
|
||||
O_CLOEXEC :: 0x80000
|
||||
|
||||
|
||||
SEEK_SET :: 0;
|
||||
SEEK_CUR :: 1;
|
||||
SEEK_END :: 2;
|
||||
SEEK_DATA :: 3;
|
||||
SEEK_HOLE :: 4;
|
||||
SEEK_MAX :: SEEK_HOLE;
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
SEEK_DATA :: 3
|
||||
SEEK_HOLE :: 4
|
||||
SEEK_MAX :: SEEK_HOLE
|
||||
|
||||
// NOTE: These are OS specific!
|
||||
// Do not mix these up!
|
||||
RTLD_LAZY :: 0x001;
|
||||
RTLD_NOW :: 0x002;
|
||||
//RTLD_BINDING_MASK :: 0x3; // Called MODEMASK in dlfcn.h
|
||||
RTLD_GLOBAL :: 0x100;
|
||||
RTLD_LOCAL :: 0x000;
|
||||
RTLD_TRACE :: 0x200;
|
||||
RTLD_NODELETE :: 0x01000;
|
||||
RTLD_NOLOAD :: 0x02000;
|
||||
RTLD_LAZY :: 0x001
|
||||
RTLD_NOW :: 0x002
|
||||
//RTLD_BINDING_MASK :: 0x3 // Called MODEMASK in dlfcn.h
|
||||
RTLD_GLOBAL :: 0x100
|
||||
RTLD_LOCAL :: 0x000
|
||||
RTLD_TRACE :: 0x200
|
||||
RTLD_NODELETE :: 0x01000
|
||||
RTLD_NOLOAD :: 0x02000
|
||||
|
||||
args := _alloc_command_line_arguments();
|
||||
args := _alloc_command_line_arguments()
|
||||
|
||||
Unix_File_Time :: struct {
|
||||
seconds: i64,
|
||||
nanoseconds: c.long,
|
||||
}
|
||||
|
||||
pid_t :: u32;
|
||||
pid_t :: u32
|
||||
|
||||
OS_Stat :: struct {
|
||||
device_id: u64,
|
||||
@@ -177,297 +177,290 @@ OS_Stat :: struct {
|
||||
}
|
||||
|
||||
// File type
|
||||
S_IFMT :: 0o170000; // Type of file mask
|
||||
S_IFIFO :: 0o010000; // Named pipe (fifo)
|
||||
S_IFCHR :: 0o020000; // Character special
|
||||
S_IFDIR :: 0o040000; // Directory
|
||||
S_IFBLK :: 0o060000; // Block special
|
||||
S_IFREG :: 0o100000; // Regular
|
||||
S_IFLNK :: 0o120000; // Symbolic link
|
||||
S_IFSOCK :: 0o140000; // Socket
|
||||
//S_ISVTX :: 0o001000; // Save swapped text even after use
|
||||
S_IFMT :: 0o170000 // Type of file mask
|
||||
S_IFIFO :: 0o010000 // Named pipe (fifo)
|
||||
S_IFCHR :: 0o020000 // Character special
|
||||
S_IFDIR :: 0o040000 // Directory
|
||||
S_IFBLK :: 0o060000 // Block special
|
||||
S_IFREG :: 0o100000 // Regular
|
||||
S_IFLNK :: 0o120000 // Symbolic link
|
||||
S_IFSOCK :: 0o140000 // Socket
|
||||
//S_ISVTX :: 0o001000 // Save swapped text even after use
|
||||
|
||||
// File mode
|
||||
// Read, write, execute/search by owner
|
||||
S_IRWXU :: 0o0700; // RWX mask for owner
|
||||
S_IRUSR :: 0o0400; // R for owner
|
||||
S_IWUSR :: 0o0200; // W for owner
|
||||
S_IXUSR :: 0o0100; // X for owner
|
||||
S_IRWXU :: 0o0700 // RWX mask for owner
|
||||
S_IRUSR :: 0o0400 // R for owner
|
||||
S_IWUSR :: 0o0200 // W for owner
|
||||
S_IXUSR :: 0o0100 // X for owner
|
||||
|
||||
// Read, write, execute/search by group
|
||||
S_IRWXG :: 0o0070; // RWX mask for group
|
||||
S_IRGRP :: 0o0040; // R for group
|
||||
S_IWGRP :: 0o0020; // W for group
|
||||
S_IXGRP :: 0o0010; // X for group
|
||||
S_IRWXG :: 0o0070 // RWX mask for group
|
||||
S_IRGRP :: 0o0040 // R for group
|
||||
S_IWGRP :: 0o0020 // W for group
|
||||
S_IXGRP :: 0o0010 // X for group
|
||||
|
||||
// Read, write, execute/search by others
|
||||
S_IRWXO :: 0o0007; // RWX mask for other
|
||||
S_IROTH :: 0o0004; // R for other
|
||||
S_IWOTH :: 0o0002; // W for other
|
||||
S_IXOTH :: 0o0001; // X for other
|
||||
S_IRWXO :: 0o0007 // RWX mask for other
|
||||
S_IROTH :: 0o0004 // R for other
|
||||
S_IWOTH :: 0o0002 // W for other
|
||||
S_IXOTH :: 0o0001 // X for other
|
||||
|
||||
S_ISUID :: 0o4000; // Set user id on execution
|
||||
S_ISGID :: 0o2000; // Set group id on execution
|
||||
S_ISVTX :: 0o1000; // Directory restrcted delete
|
||||
S_ISUID :: 0o4000 // Set user id on execution
|
||||
S_ISGID :: 0o2000 // Set group id on execution
|
||||
S_ISVTX :: 0o1000 // Directory restrcted delete
|
||||
|
||||
|
||||
S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
|
||||
S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
|
||||
S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
|
||||
S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
|
||||
S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
|
||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
|
||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
|
||||
S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK
|
||||
S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG
|
||||
S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR
|
||||
S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR
|
||||
S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK
|
||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO
|
||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK
|
||||
|
||||
F_OK :: 0; // Test for file existance
|
||||
X_OK :: 1; // Test for execute permission
|
||||
W_OK :: 2; // Test for write permission
|
||||
R_OK :: 4; // Test for read permission
|
||||
F_OK :: 0 // Test for file existance
|
||||
X_OK :: 1 // Test for execute permission
|
||||
W_OK :: 2 // Test for write permission
|
||||
R_OK :: 4 // Test for read permission
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__error") __errno_location :: proc() -> ^int ---;
|
||||
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
|
||||
@(link_name="__error") __errno_location :: proc() -> ^int ---
|
||||
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---
|
||||
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---;
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---;
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
|
||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---;
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---;
|
||||
@(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---;
|
||||
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---;
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---;
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---;
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---;
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---;
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---;
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---;
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
foreign dl {
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||
|
||||
@(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int ---;
|
||||
@(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int ---
|
||||
}
|
||||
|
||||
is_path_separator :: proc(r: rune) -> bool {
|
||||
return r == '/';
|
||||
return r == '/'
|
||||
}
|
||||
|
||||
get_last_error :: proc() -> int {
|
||||
return __errno_location()^;
|
||||
return __errno_location()^
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.clone_to_cstring(path);
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode));
|
||||
delete(cstr);
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, Errno(get_last_error());
|
||||
return INVALID_HANDLE, Errno(get_last_error())
|
||||
}
|
||||
return handle, ERROR_NONE;
|
||||
return handle, ERROR_NONE
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) -> Errno {
|
||||
result := _unix_close(fd);
|
||||
result := _unix_close(fd)
|
||||
if result == -1 {
|
||||
return Errno(get_last_error());
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE;
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)));
|
||||
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
|
||||
if bytes_read == -1 {
|
||||
return -1, Errno(get_last_error());
|
||||
return -1, Errno(get_last_error())
|
||||
}
|
||||
return int(bytes_read), ERROR_NONE;
|
||||
return int(bytes_read), ERROR_NONE
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE;
|
||||
return 0, ERROR_NONE
|
||||
}
|
||||
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)));
|
||||
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
|
||||
if bytes_written == -1 {
|
||||
return -1, Errno(get_last_error());
|
||||
return -1, Errno(get_last_error())
|
||||
}
|
||||
return int(bytes_written), ERROR_NONE;
|
||||
return int(bytes_written), ERROR_NONE
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
res := _unix_seek(fd, offset, c.int(whence));
|
||||
res := _unix_seek(fd, offset, c.int(whence))
|
||||
if res == -1 {
|
||||
return -1, Errno(get_last_error());
|
||||
return -1, Errno(get_last_error())
|
||||
}
|
||||
return res, ERROR_NONE;
|
||||
return res, ERROR_NONE
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
s, err := fstat(fd);
|
||||
s, err := fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return -1, err;
|
||||
return -1, err
|
||||
}
|
||||
return s.size, ERROR_NONE;
|
||||
return s.size, ERROR_NONE
|
||||
}
|
||||
|
||||
stdin: Handle = 0;
|
||||
stdout: Handle = 1;
|
||||
stderr: Handle = 2;
|
||||
stdin: Handle = 0
|
||||
stdout: Handle = 1
|
||||
stderr: Handle = 2
|
||||
|
||||
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||
s, err := fstat(fd);
|
||||
s, err := fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err;
|
||||
return 0, err
|
||||
}
|
||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds;
|
||||
return File_Time(modified), ERROR_NONE;
|
||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||
return File_Time(modified), ERROR_NONE
|
||||
}
|
||||
|
||||
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
s, err := stat(name);
|
||||
s, err := stat(name)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err;
|
||||
return 0, err
|
||||
}
|
||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds;
|
||||
return File_Time(modified), ERROR_NONE;
|
||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||
return File_Time(modified), ERROR_NONE
|
||||
}
|
||||
|
||||
stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path);
|
||||
defer delete(cstr);
|
||||
|
||||
s: OS_Stat;
|
||||
result := _unix_stat(cstr, &s);
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
s: OS_Stat
|
||||
result := _unix_stat(cstr, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error());
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE;
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
s: OS_Stat;
|
||||
result := _unix_fstat(fd, &s);
|
||||
s: OS_Stat
|
||||
result := _unix_fstat(fd, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error());
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE;
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||
cstr := strings.clone_to_cstring(path);
|
||||
defer delete(cstr);
|
||||
result := _unix_access(cstr, c.int(mask));
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
result := _unix_access(cstr, c.int(mask))
|
||||
if result == -1 {
|
||||
return false, Errno(get_last_error());
|
||||
return false, Errno(get_last_error())
|
||||
}
|
||||
return true, ERROR_NONE;
|
||||
return true, ERROR_NONE
|
||||
}
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
assert(size >= 0);
|
||||
return _unix_calloc(1, c.size_t(size));
|
||||
assert(size >= 0)
|
||||
return _unix_calloc(1, c.size_t(size))
|
||||
}
|
||||
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||
// POSIX platforms. Ensure your caller takes this into account.
|
||||
return _unix_realloc(ptr, c.size_t(new_size));
|
||||
return _unix_realloc(ptr, c.size_t(new_size))
|
||||
}
|
||||
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
_unix_free(ptr);
|
||||
_unix_free(ptr)
|
||||
}
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.clone_to_cstring(name);
|
||||
defer delete(path_str);
|
||||
cstr := _unix_getenv(path_str);
|
||||
path_str := strings.clone_to_cstring(name, context.temp_allocator)
|
||||
cstr := _unix_getenv(path_str)
|
||||
if cstr == nil {
|
||||
return "", false;
|
||||
return "", false
|
||||
}
|
||||
return string(cstr), true;
|
||||
return string(cstr), true
|
||||
}
|
||||
|
||||
get_current_directory :: proc() -> string {
|
||||
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
|
||||
// an authoritative value for it across all systems.
|
||||
// The largest value I could find was 4096, so might as well use the page size.
|
||||
page_size := get_page_size();
|
||||
buf := make([dynamic]u8, page_size);
|
||||
page_size := get_page_size()
|
||||
buf := make([dynamic]u8, page_size)
|
||||
#no_bounds_check for {
|
||||
cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf)));
|
||||
cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf)))
|
||||
if cwd != nil {
|
||||
return string(cwd);
|
||||
return string(cwd)
|
||||
}
|
||||
if Errno(get_last_error()) != ERANGE {
|
||||
return "";
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf)+page_size);
|
||||
resize(&buf, len(buf)+page_size)
|
||||
}
|
||||
unreachable();
|
||||
unreachable()
|
||||
}
|
||||
|
||||
set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator);
|
||||
res := _unix_chdir(cstr);
|
||||
if res == -1 do return Errno(get_last_error());
|
||||
return ERROR_NONE;
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_chdir(cstr)
|
||||
if res == -1 do return Errno(get_last_error())
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
exit :: proc "contextless" (code: int) -> ! {
|
||||
_unix_exit(c.int(code));
|
||||
_unix_exit(c.int(code))
|
||||
}
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return cast(int) pthread_getthreadid_np();
|
||||
return cast(int) pthread_getthreadid_np()
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.clone_to_cstring(filename);
|
||||
defer delete(cstr);
|
||||
handle := _unix_dlopen(cstr, c.int(flags));
|
||||
return handle;
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil);
|
||||
cstr := strings.clone_to_cstring(symbol);
|
||||
defer delete(cstr);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
return proc_handle;
|
||||
assert(handle != nil)
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
}
|
||||
dlclose :: proc(handle: rawptr) -> bool {
|
||||
assert(handle != nil);
|
||||
return _unix_dlclose(handle) == 0;
|
||||
assert(handle != nil)
|
||||
return _unix_dlclose(handle) == 0
|
||||
}
|
||||
dlerror :: proc() -> string {
|
||||
return string(_unix_dlerror());
|
||||
return string(_unix_dlerror())
|
||||
}
|
||||
|
||||
get_page_size :: proc() -> int {
|
||||
// NOTE(tetra): The page size never changes, so why do anything complicated
|
||||
// if we don't have to.
|
||||
@static page_size := -1;
|
||||
if page_size != -1 do return page_size;
|
||||
@static page_size := -1
|
||||
if page_size != -1 do return page_size
|
||||
|
||||
page_size = int(_unix_getpagesize());
|
||||
return page_size;
|
||||
page_size = int(_unix_getpagesize())
|
||||
return page_size
|
||||
}
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
res := make([]string, len(runtime.args__));
|
||||
res := make([]string, len(runtime.args__))
|
||||
for arg, i in runtime.args__ {
|
||||
res[i] = string(arg);
|
||||
res[i] = string(arg)
|
||||
}
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
+63
-39
@@ -11,6 +11,7 @@ import "core:intrinsics"
|
||||
import "core:sys/unix"
|
||||
|
||||
Handle :: distinct i32
|
||||
Pid :: distinct i32
|
||||
File_Time :: distinct u64
|
||||
Errno :: distinct i32
|
||||
|
||||
@@ -150,6 +151,8 @@ ERFKILL: Errno : 132 /* Operation not possible due to RF-kill */
|
||||
|
||||
EHWPOISON: Errno : 133 /* Memory page has hardware error */
|
||||
|
||||
ADDR_NO_RANDOMIZE :: 0x40000
|
||||
|
||||
O_RDONLY :: 0x00000
|
||||
O_WRONLY :: 0x00001
|
||||
O_RDWR :: 0x00002
|
||||
@@ -270,8 +273,17 @@ AT_FDCWD :: -100
|
||||
AT_REMOVEDIR :: uintptr(0x200)
|
||||
AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
|
||||
|
||||
_unix_personality :: proc(persona: u64) -> int {
|
||||
return int(intrinsics.syscall(unix.SYS_personality, uintptr(persona)))
|
||||
}
|
||||
|
||||
_unix_fork :: proc() -> Pid {
|
||||
res := int(intrinsics.syscall(unix.SYS_fork))
|
||||
return -1 if res < 0 else Pid(res)
|
||||
}
|
||||
|
||||
_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
||||
} else { // NOTE: arm64 does not have open
|
||||
res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode))))
|
||||
@@ -292,7 +304,7 @@ _unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int {
|
||||
}
|
||||
|
||||
_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
||||
when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
|
||||
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
|
||||
return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence)))
|
||||
} else {
|
||||
low := uintptr(offset & 0xFFFFFFFF)
|
||||
@@ -304,9 +316,9 @@ _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
||||
}
|
||||
|
||||
_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
when ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .amd64 {
|
||||
return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else when ODIN_ARCH != "arm64" {
|
||||
} else when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else { // NOTE: arm64 does not have stat
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0))
|
||||
@@ -314,7 +326,7 @@ _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
}
|
||||
|
||||
_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int {
|
||||
when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
|
||||
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat)))
|
||||
} else {
|
||||
return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat)))
|
||||
@@ -322,9 +334,9 @@ _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int {
|
||||
}
|
||||
|
||||
_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
when ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .amd64 {
|
||||
return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else when ODIN_ARCH != "arm64" {
|
||||
} else when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else { // NOTE: arm64 does not have any lstat
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
|
||||
@@ -332,7 +344,7 @@ _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
}
|
||||
|
||||
_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
} else { // NOTE: arm64 does not have readlink
|
||||
return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
@@ -340,7 +352,7 @@ _unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
|
||||
}
|
||||
|
||||
_unix_access :: proc(path: cstring, mask: int) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask)))
|
||||
} else { // NOTE: arm64 does not have access
|
||||
return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask)))
|
||||
@@ -356,7 +368,7 @@ _unix_chdir :: proc(path: cstring) -> int {
|
||||
}
|
||||
|
||||
_unix_rename :: proc(old, new: cstring) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
} else { // NOTE: arm64 does not have rename
|
||||
return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
@@ -364,7 +376,7 @@ _unix_rename :: proc(old, new: cstring) -> int {
|
||||
}
|
||||
|
||||
_unix_unlink :: proc(path: cstring) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path))))
|
||||
} else { // NOTE: arm64 does not have unlink
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0)))
|
||||
@@ -372,7 +384,7 @@ _unix_unlink :: proc(path: cstring) -> int {
|
||||
}
|
||||
|
||||
_unix_rmdir :: proc(path: cstring) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path))))
|
||||
} else { // NOTE: arm64 does not have rmdir
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR))
|
||||
@@ -380,7 +392,7 @@ _unix_rmdir :: proc(path: cstring) -> int {
|
||||
}
|
||||
|
||||
_unix_mkdir :: proc(path: cstring, mode: u32) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
|
||||
} else { // NOTE: arm64 does not have mkdir
|
||||
return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode)))
|
||||
@@ -431,10 +443,25 @@ get_last_error :: proc() -> int {
|
||||
return __errno_location()^
|
||||
}
|
||||
|
||||
personality :: proc(persona: u64) -> (Errno) {
|
||||
res := _unix_personality(persona)
|
||||
if res == -1 {
|
||||
return _get_errno(res)
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
fork :: proc() -> (Pid, Errno) {
|
||||
pid := _unix_fork()
|
||||
if pid == -1 {
|
||||
return -1, _get_errno(int(pid))
|
||||
}
|
||||
return pid, ERROR_NONE
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, flags, mode)
|
||||
defer delete(cstr)
|
||||
if handle < 0 {
|
||||
return INVALID_HANDLE, _get_errno(int(handle))
|
||||
}
|
||||
@@ -473,11 +500,13 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err
|
||||
}
|
||||
return max(s.size, 0), ERROR_NONE
|
||||
// deliberately uninitialized; the syscall fills this buffer for us
|
||||
s: OS_Stat = ---
|
||||
result := _unix_fstat(fd, &s)
|
||||
if result < 0 {
|
||||
return 0, _get_errno(result)
|
||||
}
|
||||
return max(s.size, 0), ERROR_NONE
|
||||
}
|
||||
|
||||
rename :: proc(old_path, new_path: string) -> Errno {
|
||||
@@ -580,10 +609,10 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
defer delete(cstr)
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
s: OS_Stat
|
||||
// deliberately uninitialized; the syscall fills this buffer for us
|
||||
s: OS_Stat = ---
|
||||
result := _unix_stat(cstr, &s)
|
||||
if result < 0 {
|
||||
return s, _get_errno(result)
|
||||
@@ -593,10 +622,10 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
defer delete(cstr)
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
s: OS_Stat
|
||||
// deliberately uninitialized; the syscall fills this buffer for us
|
||||
s: OS_Stat = ---
|
||||
result := _unix_lstat(cstr, &s)
|
||||
if result < 0 {
|
||||
return s, _get_errno(result)
|
||||
@@ -606,7 +635,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
@private
|
||||
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
s: OS_Stat
|
||||
// deliberately uninitialized; the syscall fills this buffer for us
|
||||
s: OS_Stat = ---
|
||||
result := _unix_fstat(fd, &s)
|
||||
if result < 0 {
|
||||
return s, _get_errno(result)
|
||||
@@ -659,8 +689,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
path_cstr := strings.clone_to_cstring(path)
|
||||
defer delete(path_cstr)
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = 256
|
||||
buf := make([]byte, bufsz)
|
||||
@@ -696,8 +725,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
rel = "."
|
||||
}
|
||||
|
||||
rel_cstr := strings.clone_to_cstring(rel)
|
||||
defer delete(rel_cstr)
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||
if path_ptr == nil {
|
||||
@@ -712,8 +740,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
}
|
||||
|
||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
defer delete(cstr)
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
result := _unix_access(cstr, mask)
|
||||
if result < 0 {
|
||||
return false, _get_errno(result)
|
||||
@@ -737,8 +764,7 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.clone_to_cstring(name)
|
||||
defer delete(path_str)
|
||||
path_str := strings.clone_to_cstring(name, context.temp_allocator)
|
||||
cstr := _unix_getenv(path_str)
|
||||
if cstr == nil {
|
||||
return "", false
|
||||
@@ -784,15 +810,13 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.clone_to_cstring(filename)
|
||||
defer delete(cstr)
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil)
|
||||
cstr := strings.clone_to_cstring(symbol)
|
||||
defer delete(cstr)
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
}
|
||||
|
||||
@@ -0,0 +1,706 @@
|
||||
package os
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
import "core:c"
|
||||
|
||||
Handle :: distinct i32
|
||||
Pid :: distinct i32
|
||||
File_Time :: distinct u64
|
||||
Errno :: distinct i32
|
||||
|
||||
INVALID_HANDLE :: ~Handle(0)
|
||||
|
||||
ERROR_NONE: Errno: 0
|
||||
|
||||
EPERM: Errno: 1
|
||||
ENOENT: Errno: 2
|
||||
ESRCH: Errno: 3
|
||||
EINTR: Errno: 4
|
||||
EIO: Errno: 5
|
||||
ENXIO: Errno: 6
|
||||
E2BIG: Errno: 7
|
||||
ENOEXEC: Errno: 8
|
||||
EBADF: Errno: 9
|
||||
ECHILD: Errno: 10
|
||||
EDEADLK: Errno: 11
|
||||
ENOMEM: Errno: 12
|
||||
EACCES: Errno: 13
|
||||
EFAULT: Errno: 14
|
||||
ENOTBLK: Errno: 15
|
||||
EBUSY: Errno: 16
|
||||
EEXIST: Errno: 17
|
||||
EXDEV: Errno: 18
|
||||
ENODEV: Errno: 19
|
||||
ENOTDIR: Errno: 20
|
||||
EISDIR: Errno: 21
|
||||
EINVAL: Errno: 22
|
||||
ENFILE: Errno: 23
|
||||
EMFILE: Errno: 24
|
||||
ENOTTY: Errno: 25
|
||||
ETXTBSY: Errno: 26
|
||||
EFBIG: Errno: 27
|
||||
ENOSPC: Errno: 28
|
||||
ESPIPE: Errno: 29
|
||||
EROFS: Errno: 30
|
||||
EMLINK: Errno: 31
|
||||
EPIPE: Errno: 32
|
||||
EDOM: Errno: 33
|
||||
ERANGE: Errno: 34
|
||||
EAGAIN: Errno: 35
|
||||
EWOULDBLOCK: Errno: EAGAIN
|
||||
EINPROGRESS: Errno: 36
|
||||
EALREADY: Errno: 37
|
||||
ENOTSOCK: Errno: 38
|
||||
EDESTADDRREQ: Errno: 39
|
||||
EMSGSIZE: Errno: 40
|
||||
EPROTOTYPE: Errno: 41
|
||||
ENOPROTOOPT: Errno: 42
|
||||
EPROTONOSUPPORT: Errno: 43
|
||||
ESOCKTNOSUPPORT: Errno: 44
|
||||
EOPNOTSUPP: Errno: 45
|
||||
EPFNOSUPPORT: Errno: 46
|
||||
EAFNOSUPPORT: Errno: 47
|
||||
EADDRINUSE: Errno: 48
|
||||
EADDRNOTAVAIL: Errno: 49
|
||||
ENETDOWN: Errno: 50
|
||||
ENETUNREACH: Errno: 51
|
||||
ENETRESET: Errno: 52
|
||||
ECONNABORTED: Errno: 53
|
||||
ECONNRESET: Errno: 54
|
||||
ENOBUFS: Errno: 55
|
||||
EISCONN: Errno: 56
|
||||
ENOTCONN: Errno: 57
|
||||
ESHUTDOWN: Errno: 58
|
||||
ETOOMANYREFS: Errno: 59
|
||||
ETIMEDOUT: Errno: 60
|
||||
ECONNREFUSED: Errno: 61
|
||||
ELOOP: Errno: 62
|
||||
ENAMETOOLONG: Errno: 63
|
||||
EHOSTDOWN: Errno: 64
|
||||
EHOSTUNREACH: Errno: 65
|
||||
ENOTEMPTY: Errno: 66
|
||||
EPROCLIM: Errno: 67
|
||||
EUSERS: Errno: 68
|
||||
EDQUOT: Errno: 69
|
||||
ESTALE: Errno: 70
|
||||
EREMOTE: Errno: 71
|
||||
EBADRPC: Errno: 72
|
||||
ERPCMISMATCH: Errno: 73
|
||||
EPROGUNAVAIL: Errno: 74
|
||||
EPROGMISMATCH: Errno: 75
|
||||
EPROCUNAVAIL: Errno: 76
|
||||
ENOLCK: Errno: 77
|
||||
ENOSYS: Errno: 78
|
||||
EFTYPE: Errno: 79
|
||||
EAUTH: Errno: 80
|
||||
ENEEDAUTH: Errno: 81
|
||||
EIPSEC: Errno: 82
|
||||
ENOATTR: Errno: 83
|
||||
EILSEQ: Errno: 84
|
||||
ENOMEDIUM: Errno: 85
|
||||
EMEDIUMTYPE: Errno: 86
|
||||
EOVERFLOW: Errno: 87
|
||||
ECANCELED: Errno: 88
|
||||
EIDRM: Errno: 89
|
||||
ENOMSG: Errno: 90
|
||||
ENOTSUP: Errno: 91
|
||||
EBADMSG: Errno: 92
|
||||
ENOTRECOVERABLE: Errno: 93
|
||||
EOWNERDEAD: Errno: 94
|
||||
EPROTO: Errno: 95
|
||||
|
||||
O_RDONLY :: 0x00000
|
||||
O_WRONLY :: 0x00001
|
||||
O_RDWR :: 0x00002
|
||||
O_NONBLOCK :: 0x00004
|
||||
O_APPEND :: 0x00008
|
||||
O_ASYNC :: 0x00040
|
||||
O_SYNC :: 0x00080
|
||||
O_CREATE :: 0x00200
|
||||
O_TRUNC :: 0x00400
|
||||
O_EXCL :: 0x00800
|
||||
O_NOCTTY :: 0x08000
|
||||
O_CLOEXEC :: 0x10000
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
RTLD_LAZY :: 0x001
|
||||
RTLD_NOW :: 0x002
|
||||
RTLD_LOCAL :: 0x000
|
||||
RTLD_GLOBAL :: 0x100
|
||||
RTLD_TRACE :: 0x200
|
||||
RTLD_NODELETE :: 0x400
|
||||
|
||||
MAX_PATH :: 1024
|
||||
|
||||
// "Argv" arguments converted to Odin strings
|
||||
args := _alloc_command_line_arguments()
|
||||
|
||||
pid_t :: i32
|
||||
time_t :: i64
|
||||
mode_t :: u32
|
||||
dev_t :: i32
|
||||
ino_t :: u64
|
||||
nlink_t :: u32
|
||||
uid_t :: u32
|
||||
gid_t :: u32
|
||||
off_t :: i64
|
||||
blkcnt_t :: u64
|
||||
blksize_t :: i32
|
||||
|
||||
Unix_File_Time :: struct {
|
||||
seconds: time_t,
|
||||
nanoseconds: c.long,
|
||||
}
|
||||
|
||||
OS_Stat :: struct {
|
||||
mode: mode_t, // inode protection mode
|
||||
device_id: dev_t, // inode's device
|
||||
serial: ino_t, // inode's number
|
||||
nlink: nlink_t, // number of hard links
|
||||
uid: uid_t, // user ID of the file's owner
|
||||
gid: gid_t, // group ID of the file's group
|
||||
rdev: dev_t, // device type
|
||||
|
||||
last_access: Unix_File_Time, // time of last access
|
||||
modified: Unix_File_Time, // time of last data modification
|
||||
status_change: Unix_File_Time, // time of last file status change
|
||||
|
||||
size: off_t, // file size, in bytes
|
||||
blocks: blkcnt_t, // blocks allocated for file
|
||||
block_size: blksize_t, // optimal blocksize for I/O
|
||||
|
||||
flags: u32, // user defined flags for file
|
||||
gen: u32, // file generation number
|
||||
birthtime: Unix_File_Time, // time of file creation
|
||||
}
|
||||
|
||||
MAXNAMLEN :: 255
|
||||
|
||||
// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
|
||||
Dirent :: struct {
|
||||
ino: ino_t, // file number of entry
|
||||
off: off_t, // offset after this entry
|
||||
reclen: u16, // length of this record
|
||||
type: u8, // file type
|
||||
namlen: u8, // length of string in name
|
||||
_padding: [4]u8,
|
||||
name: [MAXNAMLEN + 1]byte, // name
|
||||
}
|
||||
|
||||
Dir :: distinct rawptr // DIR*
|
||||
|
||||
// File type
|
||||
S_IFMT :: 0o170000 // Type of file mask
|
||||
S_IFIFO :: 0o010000 // Named pipe (fifo)
|
||||
S_IFCHR :: 0o020000 // Character special
|
||||
S_IFDIR :: 0o040000 // Directory
|
||||
S_IFBLK :: 0o060000 // Block special
|
||||
S_IFREG :: 0o100000 // Regular
|
||||
S_IFLNK :: 0o120000 // Symbolic link
|
||||
S_IFSOCK :: 0o140000 // Socket
|
||||
S_ISVTX :: 0o001000 // Save swapped text even after use
|
||||
|
||||
// File mode
|
||||
// Read, write, execute/search by owner
|
||||
S_IRWXU :: 0o0700 // RWX mask for owner
|
||||
S_IRUSR :: 0o0400 // R for owner
|
||||
S_IWUSR :: 0o0200 // W for owner
|
||||
S_IXUSR :: 0o0100 // X for owner
|
||||
|
||||
// Read, write, execute/search by group
|
||||
S_IRWXG :: 0o0070 // RWX mask for group
|
||||
S_IRGRP :: 0o0040 // R for group
|
||||
S_IWGRP :: 0o0020 // W for group
|
||||
S_IXGRP :: 0o0010 // X for group
|
||||
|
||||
// Read, write, execute/search by others
|
||||
S_IRWXO :: 0o0007 // RWX mask for other
|
||||
S_IROTH :: 0o0004 // R for other
|
||||
S_IWOTH :: 0o0002 // W for other
|
||||
S_IXOTH :: 0o0001 // X for other
|
||||
|
||||
S_ISUID :: 0o4000 // Set user id on execution
|
||||
S_ISGID :: 0o2000 // Set group id on execution
|
||||
S_ISTXT :: 0o1000 // Sticky bit
|
||||
|
||||
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
|
||||
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
|
||||
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
|
||||
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
|
||||
S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
|
||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
|
||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
||||
|
||||
F_OK :: 0x00 // Test for file existance
|
||||
X_OK :: 0x01 // Test for execute permission
|
||||
W_OK :: 0x02 // Test for write permission
|
||||
R_OK :: 0x04 // Test for read permission
|
||||
|
||||
AT_FDCWD :: -100
|
||||
AT_EACCESS :: 0x01
|
||||
AT_SYMLINK_NOFOLLOW :: 0x02
|
||||
AT_SYMLINK_FOLLOW :: 0x04
|
||||
AT_REMOVEDIR :: 0x08
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__errno") __errno :: proc() -> ^int ---
|
||||
|
||||
@(link_name="fork") _unix_fork :: proc() -> pid_t ---
|
||||
@(link_name="getthrid") _unix_getthrid :: proc() -> int ---
|
||||
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
|
||||
@(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
|
||||
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
|
||||
@(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
|
||||
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
|
||||
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||
}
|
||||
|
||||
is_path_separator :: proc(r: rune) -> bool {
|
||||
return r == '/'
|
||||
}
|
||||
|
||||
get_last_error :: proc() -> int {
|
||||
return __errno()^
|
||||
}
|
||||
|
||||
fork :: proc() -> (Pid, Errno) {
|
||||
pid := _unix_fork()
|
||||
if pid == -1 {
|
||||
return Pid(-1), Errno(get_last_error())
|
||||
}
|
||||
return Pid(pid), ERROR_NONE
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, Errno(get_last_error())
|
||||
}
|
||||
return handle, ERROR_NONE
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) -> Errno {
|
||||
result := _unix_close(fd)
|
||||
if result == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
|
||||
if bytes_read == -1 {
|
||||
return -1, Errno(get_last_error())
|
||||
}
|
||||
return int(bytes_read), ERROR_NONE
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE
|
||||
}
|
||||
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
|
||||
if bytes_written == -1 {
|
||||
return -1, Errno(get_last_error())
|
||||
}
|
||||
return int(bytes_written), ERROR_NONE
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
res := _unix_seek(fd, offset, c.int(whence))
|
||||
if res == -1 {
|
||||
return -1, Errno(get_last_error())
|
||||
}
|
||||
return res, ERROR_NONE
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return -1, err
|
||||
}
|
||||
return s.size, ERROR_NONE
|
||||
}
|
||||
|
||||
rename :: proc(old_path, new_path: string) -> Errno {
|
||||
old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
|
||||
new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
res := _unix_rename(old_path_cstr, new_path_cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
remove :: proc(path: string) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_unlink(path_cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
remove_directory :: proc(path: string) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_rmdir(path_cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
is_file_handle :: proc(fd: Handle) -> bool {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
s: OS_Stat
|
||||
err: Errno
|
||||
if follow_links {
|
||||
s, err = _stat(path)
|
||||
} else {
|
||||
s, err = _lstat(path)
|
||||
}
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
is_dir_handle :: proc(fd: Handle) -> bool {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
s: OS_Stat
|
||||
err: Errno
|
||||
if follow_links {
|
||||
s, err = _stat(path)
|
||||
} else {
|
||||
s, err = _lstat(path)
|
||||
}
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_file :: proc {is_file_path, is_file_handle}
|
||||
is_dir :: proc {is_dir_path, is_dir_handle}
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
|
||||
stdin: Handle = 0
|
||||
stdout: Handle = 1
|
||||
stderr: Handle = 2
|
||||
|
||||
/* TODO(zangent): Implement these!
|
||||
last_write_time :: proc(fd: Handle) -> File_Time {}
|
||||
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||
*/
|
||||
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err
|
||||
}
|
||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||
return File_Time(modified), ERROR_NONE
|
||||
}
|
||||
|
||||
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
s, err := _stat(name)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err
|
||||
}
|
||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||
return File_Time(modified), ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized
|
||||
s: OS_Stat = ---
|
||||
res := _unix_stat(cstr, &s)
|
||||
if res == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized
|
||||
s: OS_Stat = ---
|
||||
res := _unix_lstat(cstr, &s)
|
||||
if res == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
// deliberately uninitialized
|
||||
s: OS_Stat = ---
|
||||
res := _unix_fstat(fd, &s)
|
||||
if res == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
|
||||
dirp := _unix_fdopendir(fd)
|
||||
if dirp == cast(Dir)nil {
|
||||
return nil, Errno(get_last_error())
|
||||
}
|
||||
return dirp, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_closedir :: proc(dirp: Dir) -> Errno {
|
||||
rc := _unix_closedir(dirp)
|
||||
if rc != 0 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_rewinddir :: proc(dirp: Dir) {
|
||||
_unix_rewinddir(dirp)
|
||||
}
|
||||
|
||||
@private
|
||||
_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
|
||||
result: ^Dirent
|
||||
rc := _unix_readdir_r(dirp, &entry, &result)
|
||||
|
||||
if rc != 0 {
|
||||
err = Errno(get_last_error())
|
||||
return
|
||||
}
|
||||
err = ERROR_NONE
|
||||
|
||||
if result == nil {
|
||||
end_of_stream = true
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = MAX_PATH
|
||||
buf := make([]byte, MAX_PATH)
|
||||
for {
|
||||
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
|
||||
if rc == -1 {
|
||||
delete(buf)
|
||||
return "", Errno(get_last_error())
|
||||
} else if rc == int(bufsz) {
|
||||
bufsz += MAX_PATH
|
||||
delete(buf)
|
||||
buf = make([]byte, bufsz)
|
||||
} else {
|
||||
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
|
||||
}
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
// XXX OpenBSD
|
||||
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||
return "", Errno(ENOSYS)
|
||||
}
|
||||
|
||||
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
rel := rel
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||
if path_ptr == nil {
|
||||
return "", Errno(get_last_error())
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
|
||||
path_cstr := transmute(cstring)path_ptr
|
||||
path = strings.clone( string(path_cstr) )
|
||||
|
||||
return path, ERROR_NONE
|
||||
}
|
||||
|
||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_access(cstr, c.int(mask))
|
||||
if res == -1 {
|
||||
return false, Errno(get_last_error())
|
||||
}
|
||||
return true, ERROR_NONE
|
||||
}
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
assert(size >= 0)
|
||||
return _unix_calloc(1, c.size_t(size))
|
||||
}
|
||||
|
||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||
// POSIX platforms. Ensure your caller takes this into account.
|
||||
return _unix_realloc(ptr, c.size_t(new_size))
|
||||
}
|
||||
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
_unix_free(ptr)
|
||||
}
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.clone_to_cstring(name, context.temp_allocator)
|
||||
cstr := _unix_getenv(path_str)
|
||||
if cstr == nil {
|
||||
return "", false
|
||||
}
|
||||
return string(cstr), true
|
||||
}
|
||||
|
||||
get_current_directory :: proc() -> string {
|
||||
buf := make([dynamic]u8, MAX_PATH)
|
||||
for {
|
||||
cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf)))
|
||||
if cwd != nil {
|
||||
return string(cwd)
|
||||
}
|
||||
if Errno(get_last_error()) != ERANGE {
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf) + MAX_PATH)
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_chdir(cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
exit :: proc "contextless" (code: int) -> ! {
|
||||
_unix_exit(c.int(code))
|
||||
}
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return _unix_getthrid()
|
||||
}
|
||||
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil)
|
||||
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||
proc_handle := _unix_dlsym(handle, cstr)
|
||||
return proc_handle
|
||||
}
|
||||
dlclose :: proc(handle: rawptr) -> bool {
|
||||
assert(handle != nil)
|
||||
return _unix_dlclose(handle) == 0
|
||||
}
|
||||
dlerror :: proc() -> string {
|
||||
return string(_unix_dlerror())
|
||||
}
|
||||
|
||||
get_page_size :: proc() -> int {
|
||||
// NOTE(tetra): The page size never changes, so why do anything complicated
|
||||
// if we don't have to.
|
||||
@static page_size := -1
|
||||
if page_size != -1 {
|
||||
return page_size
|
||||
}
|
||||
|
||||
page_size = int(_unix_getpagesize())
|
||||
return page_size
|
||||
}
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
res := make([]string, len(runtime.args__))
|
||||
for arg, i in runtime.args__ {
|
||||
res[i] = string(arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build linux, darwin, freebsd
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
package os
|
||||
|
||||
import "core:time"
|
||||
|
||||
+3
-3
@@ -19,7 +19,7 @@ _file_stream_vtable := &io.Stream_VTable{
|
||||
return
|
||||
},
|
||||
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||
when ODIN_OS == "windows" || ODIN_OS == "wasi" {
|
||||
when ODIN_OS == .Windows || ODIN_OS == .WASI {
|
||||
fd := Handle(uintptr(s.stream_data))
|
||||
os_err: Errno
|
||||
n, os_err = read_at(fd, p, offset)
|
||||
@@ -33,7 +33,7 @@ _file_stream_vtable := &io.Stream_VTable{
|
||||
return
|
||||
},
|
||||
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||
when ODIN_OS == "windows" || ODIN_OS == "wasi" {
|
||||
when ODIN_OS == .Windows || ODIN_OS == .WASI {
|
||||
fd := Handle(uintptr(s.stream_data))
|
||||
os_err: Errno
|
||||
n, os_err = write_at(fd, p, offset)
|
||||
@@ -53,7 +53,7 @@ _file_stream_vtable := &io.Stream_VTable{
|
||||
return sz
|
||||
},
|
||||
impl_flush = proc(s: io.Stream) -> io.Error {
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
fd := Handle(uintptr(s.stream_data))
|
||||
flush(fd)
|
||||
} else {
|
||||
|
||||
@@ -89,7 +89,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
|
||||
scan_loop: for i = 0; i < len(pattern); i += 1 {
|
||||
switch pattern[i] {
|
||||
case '\\':
|
||||
when ODIN_OS != "windows" {
|
||||
when ODIN_OS != .Windows {
|
||||
if i+1 < len(pattern) {
|
||||
i += 1
|
||||
}
|
||||
@@ -161,7 +161,7 @@ match_chunk :: proc(chunk, s: string) -> (rest: string, ok: bool, err: Match_Err
|
||||
chunk = chunk[1:]
|
||||
|
||||
case '\\':
|
||||
when ODIN_OS != "windows" {
|
||||
when ODIN_OS != .Windows {
|
||||
chunk = chunk[1:]
|
||||
if len(chunk) == 0 {
|
||||
err = .Syntax_Error
|
||||
@@ -188,7 +188,7 @@ get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Er
|
||||
return
|
||||
}
|
||||
chunk := chunk
|
||||
if chunk[0] == '\\' && ODIN_OS != "windows" {
|
||||
if chunk[0] == '\\' && ODIN_OS != .Windows {
|
||||
chunk = chunk[1:]
|
||||
if len(chunk) == 0 {
|
||||
err = .Syntax_Error
|
||||
@@ -227,11 +227,10 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str
|
||||
return m[:], .None
|
||||
}
|
||||
|
||||
temp_buf: [8]byte
|
||||
|
||||
dir, file := split(pattern)
|
||||
volume_len := 0
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
temp_buf: [8]byte
|
||||
volume_len, dir = clean_glob_path_windows(dir, temp_buf[:])
|
||||
} else {
|
||||
dir = clean_glob_path(dir)
|
||||
@@ -308,7 +307,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
|
||||
|
||||
@(private)
|
||||
has_meta :: proc(path: string) -> bool {
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
CHARS :: `*?[`
|
||||
} else {
|
||||
CHARS :: `*?[\`
|
||||
|
||||
@@ -8,7 +8,7 @@ import "core:strings"
|
||||
is_separator :: proc(c: byte) -> bool {
|
||||
switch c {
|
||||
case '/': return true
|
||||
case '\\': return ODIN_OS == "windows"
|
||||
case '\\': return ODIN_OS == .Windows
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -32,7 +32,7 @@ volume_name :: proc(path: string) -> string {
|
||||
}
|
||||
|
||||
volume_name_len :: proc(path: string) -> int {
|
||||
if ODIN_OS == "windows" {
|
||||
if ODIN_OS == .Windows {
|
||||
if len(path) < 2 {
|
||||
return 0
|
||||
}
|
||||
@@ -284,13 +284,14 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
|
||||
}
|
||||
|
||||
dir :: proc(path: string, allocator := context.allocator) -> string {
|
||||
context.allocator = allocator
|
||||
vol := volume_name(path)
|
||||
i := len(path) - 1
|
||||
for i >= len(vol) && !is_separator(path[i]) {
|
||||
i -= 1
|
||||
}
|
||||
dir := clean(path[len(vol) : i+1], allocator)
|
||||
defer delete(dir, allocator)
|
||||
dir := clean(path[len(vol) : i+1])
|
||||
defer delete(dir)
|
||||
if dir == "." && len(vol) > 2 {
|
||||
return strings.clone(vol)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//+build linux, darwin, freebsd
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
package filepath
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
@@ -54,11 +54,16 @@ foreign libc {
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
|
||||
}
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
@(private)
|
||||
foreign libc {
|
||||
@(link_name="__error") __error :: proc() -> ^i32 ---
|
||||
}
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
@(private)
|
||||
foreign libc {
|
||||
@(link_name="__errno") __error :: proc() -> ^i32 ---
|
||||
}
|
||||
} else {
|
||||
@(private)
|
||||
foreign libc {
|
||||
|
||||
@@ -334,11 +334,11 @@ is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
||||
|
||||
|
||||
|
||||
write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid) {
|
||||
write_type(buf, type_info_of(id))
|
||||
write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) {
|
||||
return write_type_writer(strings.to_writer(buf), type_info_of(id))
|
||||
}
|
||||
write_typeid_writer :: proc(writer: io.Writer, id: typeid) {
|
||||
write_type(writer, type_info_of(id))
|
||||
write_typeid_writer :: proc(writer: io.Writer, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) {
|
||||
return write_type_writer(writer, type_info_of(id), n_written)
|
||||
}
|
||||
|
||||
write_typeid :: proc{
|
||||
|
||||
+35
-2
@@ -33,6 +33,11 @@ Calling_Convention :: enum u8 {
|
||||
|
||||
None = 6,
|
||||
Naked = 7,
|
||||
|
||||
_ = 8, // reserved
|
||||
|
||||
Win64 = 9,
|
||||
SysV = 10,
|
||||
}
|
||||
|
||||
Type_Info_Enum_Value :: distinct i64
|
||||
@@ -346,7 +351,6 @@ Context :: struct {
|
||||
assertion_failure_proc: Assertion_Failure_Proc,
|
||||
logger: Logger,
|
||||
|
||||
user_data: any,
|
||||
user_ptr: rawptr,
|
||||
user_index: int,
|
||||
|
||||
@@ -387,6 +391,35 @@ Raw_Cstring :: struct {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_OS_Type :: enum int {
|
||||
Unknown,
|
||||
Windows,
|
||||
Darwin,
|
||||
Linux,
|
||||
Essence,
|
||||
FreeBSD,
|
||||
WASI,
|
||||
JS,
|
||||
Freestanding,
|
||||
}
|
||||
*/
|
||||
Odin_OS_Type :: type_of(ODIN_OS)
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Arch_Type :: enum int {
|
||||
Unknown,
|
||||
amd64,
|
||||
i386,
|
||||
arm64,
|
||||
wasm32,
|
||||
wasm64,
|
||||
}
|
||||
*/
|
||||
Odin_Arch_Type :: type_of(ODIN_ARCH)
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Build_Mode_Type :: enum int {
|
||||
@@ -540,7 +573,7 @@ __init_context :: proc "contextless" (c: ^Context) {
|
||||
}
|
||||
|
||||
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
|
||||
when ODIN_OS == "freestanding" {
|
||||
when ODIN_OS == .Freestanding {
|
||||
// Do nothing
|
||||
} else {
|
||||
print_caller_location(loc)
|
||||
|
||||
@@ -32,7 +32,7 @@ nil_allocator :: proc() -> Allocator {
|
||||
|
||||
|
||||
|
||||
when ODIN_OS == "freestanding" {
|
||||
when ODIN_OS == .Freestanding {
|
||||
default_allocator_proc :: nil_allocator_proc
|
||||
default_allocator :: nil_allocator
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package runtime
|
||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
|
||||
|
||||
|
||||
when ODIN_OS == "freestanding" || ODIN_OS == "js" || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||
Default_Temp_Allocator :: struct {}
|
||||
|
||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//+private
|
||||
//+build linux, darwin, freebsd
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -22,7 +22,7 @@ when ODIN_BUILD_MODE == .Dynamic {
|
||||
return true
|
||||
}
|
||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
when ODIN_ARCH == "i386" || ODIN_NO_CRT {
|
||||
when ODIN_ARCH == .i386 || ODIN_NO_CRT {
|
||||
@(link_name="mainCRTStartup", linkage="strong", require)
|
||||
mainCRTStartup :: proc "stdcall" () -> i32 {
|
||||
context = default_context()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package runtime
|
||||
|
||||
bounds_trap :: proc "contextless" () -> ! {
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
windows_trap_array_bounds()
|
||||
} else {
|
||||
trap()
|
||||
@@ -9,7 +9,7 @@ bounds_trap :: proc "contextless" () -> ! {
|
||||
}
|
||||
|
||||
type_assertion_trap :: proc "contextless" () -> ! {
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
windows_trap_type_assertion()
|
||||
} else {
|
||||
trap()
|
||||
@@ -25,7 +25,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Index ")
|
||||
print_i64(i64(index))
|
||||
print_string(" is out of bounds range 0:")
|
||||
print_string(" is out of range 0..<")
|
||||
print_i64(i64(count))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
@@ -35,11 +35,11 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
||||
|
||||
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid slice indices: ")
|
||||
print_string(" Invalid slice indices ")
|
||||
print_i64(i64(lo))
|
||||
print_string(":")
|
||||
print_i64(i64(hi))
|
||||
print_string(":")
|
||||
print_string(" is out of range 0..<")
|
||||
print_i64(i64(len))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
@@ -47,7 +47,7 @@ slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, h
|
||||
|
||||
multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid slice indices: ")
|
||||
print_string(" Invalid slice indices ")
|
||||
print_i64(i64(lo))
|
||||
print_string(":")
|
||||
print_i64(i64(hi))
|
||||
@@ -83,11 +83,11 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
||||
}
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid dynamic array values: ")
|
||||
print_string(" Invalid dynamic array indices ")
|
||||
print_i64(i64(low))
|
||||
print_string(":")
|
||||
print_i64(i64(high))
|
||||
print_string(":")
|
||||
print_string(" is out of range 0..<")
|
||||
print_i64(i64(max))
|
||||
print_byte('\n')
|
||||
bounds_trap()
|
||||
@@ -107,7 +107,7 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
|
||||
print_i64(i64(row_index))
|
||||
print_string(", ")
|
||||
print_i64(i64(column_index))
|
||||
print_string(" is out of bounds range [0..<")
|
||||
print_string(" is out of range [0..<")
|
||||
print_i64(i64(row_count))
|
||||
print_string(", 0..<")
|
||||
print_i64(i64(column_count))
|
||||
|
||||
@@ -3,7 +3,7 @@ package runtime
|
||||
import "core:intrinsics"
|
||||
|
||||
@(private="file")
|
||||
IS_WASM :: ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64"
|
||||
IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64
|
||||
|
||||
@(private)
|
||||
RUNTIME_LINKAGE :: "strong" when (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package runtime
|
||||
|
||||
when ODIN_NO_CRT && ODIN_OS == "windows" {
|
||||
when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
foreign import lib "system:NtDll.lib"
|
||||
|
||||
@(private="file")
|
||||
@@ -25,7 +25,7 @@ when ODIN_NO_CRT && ODIN_OS == "windows" {
|
||||
RtlMoveMemory(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
} else when ODIN_NO_CRT || (ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64") {
|
||||
} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64) {
|
||||
@(link_name="memset", linkage="strong", require)
|
||||
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
|
||||
if ptr != nil && len != 0 {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//+private
|
||||
package runtime
|
||||
|
||||
foreign import "system:Foundation.framework"
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
objc_id :: ^intrinsics.objc_object
|
||||
objc_Class :: ^intrinsics.objc_class
|
||||
objc_SEL :: ^intrinsics.objc_selector
|
||||
|
||||
foreign Foundation {
|
||||
objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class ---
|
||||
sel_registerName :: proc "c" (name: cstring) -> objc_SEL ---
|
||||
objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) ---
|
||||
|
||||
objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) ---
|
||||
objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 ---
|
||||
objc_msgSend_fp2ret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> complex128 ---
|
||||
objc_msgSend_stret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) ---
|
||||
}
|
||||
@@ -895,6 +895,7 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str
|
||||
if s == `""` {
|
||||
return "", false, true
|
||||
}
|
||||
s = s[1:len(s)-1]
|
||||
|
||||
if contains_rune(s, '\n') >= 0 {
|
||||
return s, false, false
|
||||
|
||||
+31
-47
@@ -280,10 +280,29 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
|
||||
return res[:i+1]
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into parts, based on a separator.
|
||||
Returned strings are substrings of 's'.
|
||||
```
|
||||
s := "aaa.bbb.ccc.ddd.eee" // 5 parts
|
||||
ss := split(s, ".")
|
||||
fmt.println(ss) // [aaa, bbb, ccc, ddd, eee]
|
||||
```
|
||||
*/
|
||||
split :: proc(s, sep: string, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, 0, -1, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into a total of 'n' parts, based on a separator.
|
||||
Returns fewer parts if there wasn't enough occurrences of the separator.
|
||||
Returned strings are substrings of 's'.
|
||||
```
|
||||
s := "aaa.bbb.ccc.ddd.eee" // 5 parts present
|
||||
ss := split_n(s, ".", 3) // total of 3 wanted
|
||||
fmt.println(ss) // [aaa, bbb, ccc.ddd.eee]
|
||||
```
|
||||
*/
|
||||
split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, 0, n, allocator)
|
||||
}
|
||||
@@ -298,13 +317,7 @@ split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) ->
|
||||
|
||||
|
||||
@private
|
||||
_split_iterator :: proc(s: ^string, sep: string, sep_save, n: int) -> (res: string, ok: bool) {
|
||||
s, n := s, n
|
||||
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, ok: bool) {
|
||||
if sep == "" {
|
||||
res = s[:]
|
||||
ok = true
|
||||
@@ -312,44 +325,27 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save, n: int) -> (res: stri
|
||||
return
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
n = count(s^, sep) + 1
|
||||
}
|
||||
|
||||
n -= 1
|
||||
|
||||
i := 0
|
||||
for ; i < n; i += 1 {
|
||||
m := index(s^, sep)
|
||||
if m < 0 {
|
||||
break
|
||||
}
|
||||
m := index(s^, sep)
|
||||
if m < 0 {
|
||||
// not found
|
||||
res = s[:]
|
||||
ok = res != ""
|
||||
s^ = s[len(s):]
|
||||
} else {
|
||||
res = s[:m+sep_save]
|
||||
ok = true
|
||||
s^ = s[m+len(sep):]
|
||||
return
|
||||
}
|
||||
res = s[:]
|
||||
ok = res != ""
|
||||
s^ = s[len(s):]
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
split_iterator :: proc(s: ^string, sep: string) -> (string, bool) {
|
||||
return _split_iterator(s, sep, 0, -1)
|
||||
}
|
||||
|
||||
split_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool) {
|
||||
return _split_iterator(s, sep, 0, n)
|
||||
return _split_iterator(s, sep, 0)
|
||||
}
|
||||
|
||||
split_after_iterator :: proc(s: ^string, sep: string) -> (string, bool) {
|
||||
return _split_iterator(s, sep, len(sep), -1)
|
||||
}
|
||||
|
||||
split_after_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool) {
|
||||
return _split_iterator(s, sep, len(sep), n)
|
||||
return _split_iterator(s, sep, len(sep))
|
||||
}
|
||||
|
||||
|
||||
@@ -402,25 +398,13 @@ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -
|
||||
|
||||
split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, 0, -1) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
split_lines_n_iterator :: proc(s: ^string, n: int) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, 0, n) or_return
|
||||
line = _split_iterator(s, sep, 0) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, len(sep), -1) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
split_lines_after_n_iterator :: proc(s: ^string, n: int) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, len(sep), n) or_return
|
||||
line = _split_iterator(s, sep, len(sep)) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build linux, darwin, freebsd
|
||||
// +build linux, darwin, freebsd, openbsd
|
||||
package sync
|
||||
|
||||
import "core:time"
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//+private
|
||||
//+build openbsd
|
||||
package sync2
|
||||
|
||||
import "core:c"
|
||||
import "core:os"
|
||||
import "core:time"
|
||||
|
||||
FUTEX_WAIT :: 1
|
||||
FUTEX_WAKE :: 2
|
||||
|
||||
FUTEX_PRIVATE_FLAG :: 128
|
||||
|
||||
FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
|
||||
FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
foreign libc {
|
||||
@(link_name="futex")
|
||||
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
|
||||
}
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
|
||||
|
||||
if res != -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
|
||||
return false
|
||||
}
|
||||
|
||||
panic("futex_wait failure")
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
timespec_t :: struct {
|
||||
tv_sec: c.long,
|
||||
tv_nsec: c.long,
|
||||
}
|
||||
|
||||
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, ×pec_t{
|
||||
tv_sec = (c.long)(duration/1e9),
|
||||
tv_nsec = (c.long)(duration%1e9),
|
||||
})
|
||||
|
||||
if res != -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
|
||||
return false
|
||||
}
|
||||
|
||||
panic("futex_wait_with_timeout failure")
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("_futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
//
|
||||
// A Mutex must not be copied after first use
|
||||
Mutex :: struct {
|
||||
impl: _Mutex,
|
||||
impl: _Mutex `This is a tag`,
|
||||
}
|
||||
|
||||
// mutex_lock locks m
|
||||
|
||||
@@ -93,7 +93,7 @@ when #config(ODIN_SYNC_RECURSIVE_MUTEX_USE_FUTEX, true) {
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS != "windows" {
|
||||
when ODIN_OS != .Windows {
|
||||
RW_Mutex_State :: distinct uint
|
||||
RW_Mutex_State_Half_Width :: size_of(RW_Mutex_State)*8/2
|
||||
RW_Mutex_State_Is_Writing :: RW_Mutex_State(1)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//+build openbsd
|
||||
//+private
|
||||
package sync2
|
||||
|
||||
import "core:os"
|
||||
|
||||
_current_thread_id :: proc "contextless" () -> int {
|
||||
return os.current_thread_id()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build linux, freebsd
|
||||
//+build linux, freebsd, openbsd
|
||||
//+private
|
||||
package sync2
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package sync
|
||||
|
||||
import "core:sys/unix"
|
||||
import "core:os"
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return os.current_thread_id()
|
||||
}
|
||||
|
||||
// The Darwin docs say it best:
|
||||
// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously.
|
||||
// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens,
|
||||
// but when there are none left, a thread must wait until another thread returns one.
|
||||
Semaphore :: struct #align 16 {
|
||||
handle: unix.sem_t,
|
||||
}
|
||||
|
||||
semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
|
||||
assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0)
|
||||
}
|
||||
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
assert(unix.sem_destroy(&s.handle) == 0)
|
||||
s.handle = {}
|
||||
}
|
||||
|
||||
semaphore_post :: proc(s: ^Semaphore, count := 1) {
|
||||
// NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop.
|
||||
for in 0..<count {
|
||||
assert(unix.sem_post(&s.handle) == 0)
|
||||
}
|
||||
}
|
||||
|
||||
semaphore_wait_for :: proc(s: ^Semaphore) {
|
||||
assert(unix.sem_wait(&s.handle) == 0)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build linux, darwin, freebsd
|
||||
// +build linux, darwin, freebsd, openbsd
|
||||
package sync
|
||||
|
||||
import "core:sys/unix"
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
package darwin
|
||||
|
||||
import "core:strings"
|
||||
import "core:c"
|
||||
|
||||
// this package uses the sys prefix for the proc names to indicate that these aren't native syscalls but directly call such
|
||||
sys_write_string :: proc (fd: c.int, message: string) -> bool {
|
||||
return syscall_write(fd, strings.ptr_from_string(message), cast(u64)len(message))
|
||||
}
|
||||
|
||||
Offset_From :: enum c.int {
|
||||
SEEK_SET = 0, // the offset is set to offset bytes.
|
||||
SEEK_CUR = 1, // the offset is set to its current location plus offset bytes.
|
||||
SEEK_END = 2, // the offset is set to the size of the file plus offset bytes.
|
||||
SEEK_HOLE = 3, // the offset is set to the start of the next hole greater than or equal to the supplied offset.
|
||||
SEEK_DATA = 4, // the offset is set to the start of the next non-hole file region greater than or equal to the supplied offset.
|
||||
}
|
||||
|
||||
Open_Flags_Enum :: enum u8 {
|
||||
RDONLY, /* open for reading only */
|
||||
WRONLY, /* open for writing only */
|
||||
RDWR, /* open for reading and writing */
|
||||
|
||||
NONBLOCK, /* no delay */
|
||||
APPEND, /* set append mode */
|
||||
CREAT, /* create if nonexistant */
|
||||
TRUNC, /* truncate to zero length */
|
||||
EXCL, /* error if already exists */
|
||||
SHLOCK, /* open with shared file lock */
|
||||
EXLOCK, /* open with exclusive file lock */
|
||||
DIRECTORY, /* restrict open to only directories */
|
||||
NOFOLLOW, /* don't follow symlinks */
|
||||
SYMLINK, /* allow open of a symlink */
|
||||
EVTONLY, /* descriptor requested for event notifications only */
|
||||
CLOEXEC, /* causes the descriptor to be closed if you use any of the exec like functions */
|
||||
NOFOLLOW_ANY, /* no symlinks allowed in path */
|
||||
}
|
||||
Open_Flags :: bit_set[Open_Flags_Enum; u16]
|
||||
|
||||
Permission_Enum :: enum u8 {
|
||||
/* For owner */
|
||||
PERMISSION_OWNER_READ, /* R for owner */
|
||||
PERMISSION_OWNER_WRITE, /* W for owner */
|
||||
PERMISSION_OWNER_EXECUTE, /* X for owner */
|
||||
//IRWXU, /* RWX mask for owner */
|
||||
|
||||
/* For group */
|
||||
PERMISSION_GROUP_READ, /* R for group */
|
||||
PERMISSION_GROUP_WRITE, /* W for group */
|
||||
PERMISSION_GROUP_EXECUTE, /* X for group */
|
||||
//IRWXG, /* RWX mask for group */
|
||||
|
||||
/* For other */
|
||||
PERMISSION_OTHER_READ, /* R for other */
|
||||
PERMISSION_OTHER_WRITE, /* W for other */
|
||||
PERMISSION_OTHER_EXECUTE, /* X for other */
|
||||
//IRWXO, /* RWX mask for other */
|
||||
|
||||
/* Special */
|
||||
PERMISSION_SET_USER_ON_EXECUTION, /* set user id on execution */
|
||||
PERMISSION_SET_GROUP_ON_EXECUTION, /* set group id on execution */
|
||||
|
||||
/* ?? */
|
||||
PERMISSION_ISVTX, /* save swapped text even after use */
|
||||
}
|
||||
Permission :: bit_set[Permission_Enum; u16]
|
||||
|
||||
PERMISSION_NONE_NONE :: Permission{}
|
||||
PERMISSION_OWNER_ALL :: Permission{.PERMISSION_OWNER_READ, .PERMISSION_OWNER_WRITE, .PERMISSION_OWNER_EXECUTE}
|
||||
PERMISSION_GROUP_ALL :: Permission{.PERMISSION_GROUP_READ, .PERMISSION_GROUP_WRITE, .PERMISSION_GROUP_EXECUTE}
|
||||
PERMISSION_OTHER_ALL :: Permission{.PERMISSION_OTHER_READ, .PERMISSION_OTHER_WRITE, .PERMISSION_OTHER_EXECUTE}
|
||||
PERMISSION_ALL_ALL :: PERMISSION_OWNER_ALL | PERMISSION_GROUP_ALL | PERMISSION_OTHER_ALL
|
||||
|
||||
_sys_permission_mode :: #force_inline proc (mode: Permission) -> u32 {
|
||||
cflags: u32 = 0
|
||||
|
||||
cflags |= PERMISSION_MASK_IRUSR * u32(Permission.PERMISSION_OWNER_READ in mode)
|
||||
cflags |= PERMISSION_MASK_IWUSR * u32(Permission.PERMISSION_OWNER_WRITE in mode)
|
||||
cflags |= PERMISSION_MASK_IXUSR * u32(Permission.PERMISSION_OWNER_WRITE in mode)
|
||||
cflags |= PERMISSION_MASK_IRGRP * u32(Permission.PERMISSION_GROUP_READ in mode)
|
||||
cflags |= PERMISSION_MASK_IWGRP * u32(Permission.PERMISSION_GROUP_WRITE in mode)
|
||||
cflags |= PERMISSION_MASK_IXGRP * u32(Permission.PERMISSION_GROUP_WRITE in mode)
|
||||
cflags |= PERMISSION_MASK_IROTH * u32(Permission.PERMISSION_OTHER_READ in mode)
|
||||
cflags |= PERMISSION_MASK_IWOTH * u32(Permission.PERMISSION_OTHER_WRITE in mode)
|
||||
cflags |= PERMISSION_MASK_IXOTH * u32(Permission.PERMISSION_OTHER_WRITE in mode)
|
||||
|
||||
return cflags
|
||||
}
|
||||
|
||||
sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) {
|
||||
|
||||
cmode: u32 = 0
|
||||
cflags: u32 = 0
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
cflags = _sys_permission_mode(mode)
|
||||
|
||||
cmode |= OPEN_FLAG_RDONLY * u32(Open_Flags.RDONLY in oflag)
|
||||
cmode |= OPEN_FLAG_WRONLY * u32(Open_Flags.WRONLY in oflag)
|
||||
cmode |= OPEN_FLAG_RDWR * u32(Open_Flags.RDWR in oflag)
|
||||
cmode |= OPEN_FLAG_NONBLOCK * u32(Open_Flags.NONBLOCK in oflag)
|
||||
cmode |= OPEN_FLAG_CREAT * u32(Open_Flags.CREAT in oflag)
|
||||
cmode |= OPEN_FLAG_APPEND * u32(Open_Flags.APPEND in oflag)
|
||||
cmode |= OPEN_FLAG_TRUNC * u32(Open_Flags.TRUNC in oflag)
|
||||
cmode |= OPEN_FLAG_EXCL * u32(Open_Flags.EXCL in oflag)
|
||||
cmode |= OPEN_FLAG_SHLOCK * u32(Open_Flags.SHLOCK in oflag)
|
||||
cmode |= OPEN_FLAG_EXLOCK * u32(Open_Flags.EXLOCK in oflag)
|
||||
cmode |= OPEN_FLAG_DIRECTORY * u32(Open_Flags.DIRECTORY in oflag)
|
||||
cmode |= OPEN_FLAG_NOFOLLOW * u32(Open_Flags.NOFOLLOW in oflag)
|
||||
cmode |= OPEN_FLAG_SYMLINK * u32(Open_Flags.SYMLINK in oflag)
|
||||
cmode |= OPEN_FLAG_EVTONLY * u32(Open_Flags.EVTONLY in oflag)
|
||||
cmode |= OPEN_FLAG_CLOEXEC * u32(Open_Flags.CLOEXEC in oflag)
|
||||
cmode |= OPEN_FLAG_NOFOLLOW_ANY * u32(Open_Flags.NOFOLLOW_ANY in oflag)
|
||||
|
||||
result := syscall_open(cpath, cmode, cflags)
|
||||
state := result != -1
|
||||
|
||||
if state && cflags != 0 {
|
||||
state = (syscall_fchmod(result, cflags) != -1)
|
||||
}
|
||||
|
||||
return result * cast(c.int)state, state
|
||||
}
|
||||
|
||||
sys_mkdir :: proc(path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_mkdir(cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_mkdir_at(fd, cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_rmdir :: proc(path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_rmdir(cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_rename :: proc(path: string, new_path: string) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
return syscall_rename(cpath, cnpath) != -1
|
||||
}
|
||||
|
||||
sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1
|
||||
}
|
||||
|
||||
sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 {
|
||||
return syscall_lseek(fd, offset, cast(c.int)whence)
|
||||
}
|
||||
|
||||
sys_chmod :: proc(path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cmode := _sys_permission_mode(mode)
|
||||
return syscall_chmod(cpath, cmode) != -1
|
||||
}
|
||||
|
||||
sys_lstat :: proc(path: string, status: ^stat) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
return syscall_lstat(cpath, status) != -1
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
package darwin
|
||||
|
||||
unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr {
|
||||
return uintptr(number) + uintptr(0x2000000)
|
||||
}
|
||||
|
||||
System_Call_Number :: enum uintptr {
|
||||
/* 0 syscall */
|
||||
exit = 1,
|
||||
fork = 2,
|
||||
read = 3,
|
||||
write = 4,
|
||||
open = 5,
|
||||
close = 6,
|
||||
wait4 = 7,
|
||||
/* 8 old creat */
|
||||
link = 9,
|
||||
unlink = 10,
|
||||
/* 11 old execv */
|
||||
chdir = 12,
|
||||
fchdir = 13,
|
||||
mknod = 14,
|
||||
chmod = 15,
|
||||
chown = 16,
|
||||
/* 17 old break */
|
||||
getfsstat = 18,
|
||||
/* 19 old lseek */
|
||||
getpid = 20,
|
||||
/* 21 old mount */
|
||||
/* 22 old umount */
|
||||
setuid = 23,
|
||||
getuid = 24,
|
||||
geteuid = 25,
|
||||
ptrace = 26,
|
||||
recvmsg = 27,
|
||||
sendmsg = 28,
|
||||
recvfrom = 29,
|
||||
accept = 30,
|
||||
getpeername = 31,
|
||||
getsockname = 32,
|
||||
access = 33,
|
||||
chflags = 34,
|
||||
fchflags = 35,
|
||||
sync = 36,
|
||||
kill = 37,
|
||||
/* 38 old stat */
|
||||
getppid = 39,
|
||||
/* 40 old lstat */
|
||||
dup = 41,
|
||||
pipe = 42,
|
||||
getegid = 43,
|
||||
/* 44 old profil */
|
||||
/* 45 old ktrace */
|
||||
sigaction = 46,
|
||||
getgid = 47,
|
||||
sigprocmask = 48,
|
||||
getlogin = 49,
|
||||
setlogin = 50,
|
||||
acct = 51,
|
||||
sigpending = 52,
|
||||
sigaltstack = 53,
|
||||
ioctl = 54,
|
||||
reboot = 55,
|
||||
revoke = 56,
|
||||
symlink = 57,
|
||||
readlink = 58,
|
||||
execve = 59,
|
||||
umask = 60,
|
||||
chroot = 61,
|
||||
/* 62 old fstat */
|
||||
/* 63 used internally and reserved */
|
||||
/* getpagesize = 64, invalid */
|
||||
msync = 65,
|
||||
vfork = 66,
|
||||
/* 67 old vread */
|
||||
/* 68 old vwrite */
|
||||
/* 69 old sbrk */
|
||||
/* 70 old sstk */
|
||||
/* 71 old mmap */
|
||||
/* 72 old vadvise */
|
||||
munmap = 73,
|
||||
mprotect = 74,
|
||||
madvise = 75,
|
||||
/* 76 old vhangup */
|
||||
/* 77 old vlimit */
|
||||
mincore = 78,
|
||||
getgroups = 79,
|
||||
setgroups = 80,
|
||||
getpgrp = 81,
|
||||
setpgid = 82,
|
||||
setitimer = 83,
|
||||
/* 84 old wait */
|
||||
swapon = 85,
|
||||
getitimer = 86,
|
||||
/* 87 old gethostname */
|
||||
/* 88 old sethostname */
|
||||
getdtablesize = 89,
|
||||
dup2 = 90,
|
||||
/* 91 old getdopt */
|
||||
fcntl = 92,
|
||||
select = 93,
|
||||
/* 94 old setdopt */
|
||||
fsync = 95,
|
||||
setpriority = 96,
|
||||
socket = 97,
|
||||
connect = 98,
|
||||
/* 99 old accept */
|
||||
getpriority = 100,
|
||||
/* 101 old send */
|
||||
/* 102 old recv */
|
||||
/* 103 old sigreturn */
|
||||
bind = 104,
|
||||
setsockopt = 105,
|
||||
listen = 106,
|
||||
/* 107 old vtimes */
|
||||
/* 108 old sigvec */
|
||||
/* 109 old sigblock */
|
||||
/* 110 old sigsetmask */
|
||||
sigsuspend = 111,
|
||||
/* 112 old sigstack */
|
||||
/* 113 old recvmsg */
|
||||
/* 114 old sendmsg */
|
||||
/* 115 old vtrace */
|
||||
gettimeofday = 116,
|
||||
getrusage = 117,
|
||||
getsockopt = 118,
|
||||
/* 119 old resuba */
|
||||
readv = 120,
|
||||
writev = 121,
|
||||
settimeofday = 122,
|
||||
fchown = 123,
|
||||
fchmod = 124,
|
||||
/* 125 old recvfrom */
|
||||
setreuid = 126,
|
||||
setregid = 127,
|
||||
rename = 128,
|
||||
/* 129 old truncate */
|
||||
/* 130 old ftruncate */
|
||||
flock = 131,
|
||||
mkfifo = 132,
|
||||
sendto = 133,
|
||||
shutdown = 134,
|
||||
socketpair = 135,
|
||||
mkdir = 136,
|
||||
rmdir = 137,
|
||||
utimes = 138,
|
||||
futimes = 139,
|
||||
adjtime = 140,
|
||||
/* 141 old getpeername */
|
||||
gethostuuid = 142,
|
||||
/* 143 old sethostid */
|
||||
/* 144 old getrlimit */
|
||||
/* 145 old setrlimit */
|
||||
/* 146 old killpg */
|
||||
setsid = 147,
|
||||
/* 148 old setquota */
|
||||
/* 149 old qquota */
|
||||
/* 150 old getsockname */
|
||||
getpgid = 151,
|
||||
setprivexec = 152,
|
||||
pread = 153,
|
||||
pwrite = 154,
|
||||
nfssvc = 155,
|
||||
/* 156 old getdirentries */
|
||||
statfs = 157,
|
||||
fstatfs = 158,
|
||||
unmount = 159,
|
||||
/* 160 old async_daemon */
|
||||
getfh = 161,
|
||||
/* 162 old getdomainname */
|
||||
/* 163 old setdomainname */
|
||||
/* 164 */
|
||||
quotactl = 165,
|
||||
/* 166 old exportfs */
|
||||
mount = 167,
|
||||
/* 168 old ustat */
|
||||
csops = 169,
|
||||
csops_audittoken = 170,
|
||||
/* 171 old wait3 */
|
||||
/* 172 old rpause */
|
||||
waitid = 173,
|
||||
/* 174 old getdents */
|
||||
/* 175 old gc_control */
|
||||
/* 176 old add_profil */
|
||||
kdebug_typefilter = 177,
|
||||
kdebug_trace_string = 178,
|
||||
kdebug_trace64 = 179,
|
||||
kdebug_trace = 180,
|
||||
setgid = 181,
|
||||
setegid = 182,
|
||||
seteuid = 183,
|
||||
sigreturn = 184,
|
||||
/* 185 old chud */
|
||||
thread_selfcounts = 186,
|
||||
fdatasync = 187,
|
||||
stat = 188,
|
||||
fstat = 189,
|
||||
lstat = 190,
|
||||
pathconf = 191,
|
||||
fpathconf = 192,
|
||||
/* 193 old getfsstat */
|
||||
getrlimit = 194,
|
||||
setrlimit = 195,
|
||||
getdirentries = 196,
|
||||
mmap = 197,
|
||||
/* 198 old __syscall */
|
||||
lseek = 199,
|
||||
truncate = 200,
|
||||
ftruncate = 201,
|
||||
sysctl = 202,
|
||||
mlock = 203,
|
||||
munlock = 204,
|
||||
undelete = 205,
|
||||
/* 206 old ATsocket */
|
||||
/* 207 old ATgetmsg */
|
||||
/* 208 old ATputmsg */
|
||||
/* 209 old ATsndreq */
|
||||
/* 210 old ATsndrsp */
|
||||
/* 211 old ATgetreq */
|
||||
/* 212 old ATgetrsp */
|
||||
/* 213 Reserved for AppleTalk */
|
||||
/* 214 */
|
||||
/* 215 */
|
||||
open_dprotected_np = 216,
|
||||
fsgetpath_ext = 217,
|
||||
/* 218 old lstatv */
|
||||
/* 219 old fstatv */
|
||||
getattrlist = 220,
|
||||
setattrlist = 221,
|
||||
getdirentriesattr = 222,
|
||||
exchangedata = 223,
|
||||
/* 224 old checkuseraccess or fsgetpath */
|
||||
searchfs = 225,
|
||||
delete = 226,
|
||||
copyfile = 227,
|
||||
fgetattrlist = 228,
|
||||
fsetattrlist = 229,
|
||||
poll = 230,
|
||||
/* 231 old watchevent */
|
||||
/* 232 old waitevent */
|
||||
/* 233 old modwatch */
|
||||
getxattr = 234,
|
||||
fgetxattr = 235,
|
||||
setxattr = 236,
|
||||
fsetxattr = 237,
|
||||
removexattr = 238,
|
||||
fremovexattr = 239,
|
||||
listxattr = 240,
|
||||
flistxattr = 241,
|
||||
fsctl = 242,
|
||||
initgroups = 243,
|
||||
posix_spawn = 244,
|
||||
ffsctl = 245,
|
||||
/* 246 */
|
||||
nfsclnt = 247,
|
||||
fhopen = 248,
|
||||
/* 249 */
|
||||
minherit = 250,
|
||||
semsys = 251,
|
||||
msgsys = 252,
|
||||
shmsys = 253,
|
||||
semctl = 254,
|
||||
semget = 255,
|
||||
semop = 256,
|
||||
/* 257 old semconfig */
|
||||
msgctl = 258,
|
||||
msgget = 259,
|
||||
msgsnd = 260,
|
||||
msgrcv = 261,
|
||||
shmat = 262,
|
||||
shmctl = 263,
|
||||
shmdt = 264,
|
||||
shmget = 265,
|
||||
shm_open = 266,
|
||||
shm_unlink = 267,
|
||||
sem_open = 268,
|
||||
sem_close = 269,
|
||||
sem_unlink = 270,
|
||||
sem_wait = 271,
|
||||
sem_trywait = 272,
|
||||
sem_post = 273,
|
||||
sysctlbyname = 274,
|
||||
/* 275 old sem_init */
|
||||
/* 276 old sem_destroy */
|
||||
open_extended = 277,
|
||||
umask_extended = 278,
|
||||
stat_extended = 279,
|
||||
lstat_extended = 280,
|
||||
fstat_extended = 281,
|
||||
chmod_extended = 282,
|
||||
fchmod_extended = 283,
|
||||
access_extended = 284,
|
||||
settid = 285,
|
||||
gettid = 286,
|
||||
setsgroups = 287,
|
||||
getsgroups = 288,
|
||||
setwgroups = 289,
|
||||
getwgroups = 290,
|
||||
mkfifo_extended = 291,
|
||||
mkdir_extended = 292,
|
||||
identitysvc = 293,
|
||||
shared_region_check_np = 294,
|
||||
/* 295 old shared_region_map_np */
|
||||
vm_pressure_monitor = 296,
|
||||
psynch_rw_longrdlock = 297,
|
||||
psynch_rw_yieldwrlock = 298,
|
||||
psynch_rw_downgrade = 299,
|
||||
psynch_rw_upgrade = 300,
|
||||
psynch_mutexwait = 301,
|
||||
psynch_mutexdrop = 302,
|
||||
psynch_cvbroad = 303,
|
||||
psynch_cvsignal = 304,
|
||||
psynch_cvwait = 305,
|
||||
psynch_rw_rdlock = 306,
|
||||
psynch_rw_wrlock = 307,
|
||||
psynch_rw_unlock = 308,
|
||||
psynch_rw_unlock2 = 309,
|
||||
getsid = 310,
|
||||
settid_with_pid = 311,
|
||||
psynch_cvclrprepost = 312,
|
||||
aio_fsync = 313,
|
||||
aio_return = 314,
|
||||
aio_suspend = 315,
|
||||
aio_cancel = 316,
|
||||
aio_error = 317,
|
||||
aio_read = 318,
|
||||
aio_write = 319,
|
||||
lio_listio = 320,
|
||||
/* 321 old __pthread_cond_wait */
|
||||
iopolicysys = 322,
|
||||
process_policy = 323,
|
||||
mlockall = 324,
|
||||
munlockall = 325,
|
||||
/* 326 */
|
||||
issetugid = 327,
|
||||
__pthread_kill = 328,
|
||||
__pthread_sigmask = 329,
|
||||
__sigwait = 330,
|
||||
__disable_threadsignal = 331,
|
||||
__pthread_markcancel = 332,
|
||||
__pthread_canceled = 333,
|
||||
__semwait_signal = 334,
|
||||
/* 335 old utrace */
|
||||
proc_info = 336,
|
||||
sendfile = 337,
|
||||
stat64 = 338,
|
||||
fstat64 = 339,
|
||||
lstat64 = 340,
|
||||
stat64_extended = 341,
|
||||
lstat64_extended = 342,
|
||||
fstat64_extended = 343,
|
||||
getdirentries64 = 344,
|
||||
statfs64 = 345,
|
||||
fstatfs64 = 346,
|
||||
getfsstat64 = 347,
|
||||
__pthread_chdir = 348,
|
||||
__pthread_fchdir = 349,
|
||||
audit = 350,
|
||||
auditon = 351,
|
||||
/* 352 */
|
||||
getauid = 353,
|
||||
setauid = 354,
|
||||
/* 355 old getaudit */
|
||||
/* 356 old setaudit */
|
||||
getaudit_addr = 357,
|
||||
setaudit_addr = 358,
|
||||
auditctl = 359,
|
||||
bsdthread_create = 360,
|
||||
bsdthread_terminate = 361,
|
||||
kqueue = 362,
|
||||
kevent = 363,
|
||||
lchown = 364,
|
||||
/* 365 old stack_snapshot */
|
||||
bsdthread_register = 366,
|
||||
workq_open = 367,
|
||||
workq_kernreturn = 368,
|
||||
kevent64 = 369,
|
||||
__old_semwait_signal = 370,
|
||||
__old_semwait_signal_nocancel = 371,
|
||||
thread_selfid = 372,
|
||||
ledger = 373,
|
||||
kevent_qos = 374,
|
||||
kevent_id = 375,
|
||||
/* 376 */
|
||||
/* 377 */
|
||||
/* 378 */
|
||||
/* 379 */
|
||||
__mac_execve = 380,
|
||||
__mac_syscall = 381,
|
||||
__mac_get_file = 382,
|
||||
__mac_set_file = 383,
|
||||
__mac_get_link = 384,
|
||||
__mac_set_link = 385,
|
||||
__mac_get_proc = 386,
|
||||
__mac_set_proc = 387,
|
||||
__mac_get_fd = 388,
|
||||
__mac_set_fd = 389,
|
||||
__mac_get_pid = 390,
|
||||
/* 391 */
|
||||
/* 392 */
|
||||
/* 393 */
|
||||
pselect = 394,
|
||||
pselect_nocancel = 395,
|
||||
read_nocancel = 396,
|
||||
write_nocancel = 397,
|
||||
open_nocancel = 398,
|
||||
close_nocancel = 399,
|
||||
wait4_nocancel = 400,
|
||||
recvmsg_nocancel = 401,
|
||||
sendmsg_nocancel = 402,
|
||||
recvfrom_nocancel = 403,
|
||||
accept_nocancel = 404,
|
||||
msync_nocancel = 405,
|
||||
fcntl_nocancel = 406,
|
||||
select_nocancel = 407,
|
||||
fsync_nocancel = 408,
|
||||
connect_nocancel = 409,
|
||||
sigsuspend_nocancel = 410,
|
||||
readv_nocancel = 411,
|
||||
writev_nocancel = 412,
|
||||
sendto_nocancel = 413,
|
||||
pread_nocancel = 414,
|
||||
pwrite_nocancel = 415,
|
||||
waitid_nocancel = 416,
|
||||
poll_nocancel = 417,
|
||||
msgsnd_nocancel = 418,
|
||||
msgrcv_nocancel = 419,
|
||||
sem_wait_nocancel = 420,
|
||||
aio_suspend_nocancel = 421,
|
||||
__sigwait_nocancel = 422,
|
||||
__semwait_signal_nocancel = 423,
|
||||
__mac_mount = 424,
|
||||
__mac_get_mount = 425,
|
||||
__mac_getfsstat = 426,
|
||||
fsgetpath = 427,
|
||||
audit_session_self = 428,
|
||||
audit_session_join = 429,
|
||||
fileport_makeport = 430,
|
||||
fileport_makefd = 431,
|
||||
audit_session_port = 432,
|
||||
pid_suspend = 433,
|
||||
pid_resume = 434,
|
||||
pid_hibernate = 435,
|
||||
pid_shutdown_sockets = 436,
|
||||
/* 437 old shared_region_slide_np */
|
||||
shared_region_map_and_slide_np = 438,
|
||||
kas_info = 439,
|
||||
memorystatus_control = 440,
|
||||
guarded_open_np = 441,
|
||||
guarded_close_np = 442,
|
||||
guarded_kqueue_np = 443,
|
||||
change_fdguard_np = 444,
|
||||
usrctl = 445,
|
||||
proc_rlimit_control = 446,
|
||||
connectx = 447,
|
||||
disconnectx = 448,
|
||||
peeloff = 449,
|
||||
socket_delegate = 450,
|
||||
telemetry = 451,
|
||||
proc_uuid_policy = 452,
|
||||
memorystatus_get_level = 453,
|
||||
system_override = 454,
|
||||
vfs_purge = 455,
|
||||
sfi_ctl = 456,
|
||||
sfi_pidctl = 457,
|
||||
coalition = 458,
|
||||
coalition_info = 459,
|
||||
necp_match_policy = 460,
|
||||
getattrlistbulk = 461,
|
||||
clonefileat = 462,
|
||||
openat = 463,
|
||||
openat_nocancel = 464,
|
||||
renameat = 465,
|
||||
faccessat = 466,
|
||||
fchmodat = 467,
|
||||
fchownat = 468,
|
||||
fstatat = 469,
|
||||
fstatat64 = 470,
|
||||
linkat = 471,
|
||||
unlinkat = 472,
|
||||
readlinkat = 473,
|
||||
symlinkat = 474,
|
||||
mkdirat = 475,
|
||||
getattrlistat = 476,
|
||||
proc_trace_log = 477,
|
||||
bsdthread_ctl = 478,
|
||||
openbyid_np = 479,
|
||||
recvmsg_x = 480,
|
||||
sendmsg_x = 481,
|
||||
thread_selfusage = 482,
|
||||
csrctl = 483,
|
||||
guarded_open_dprotected_np = 484,
|
||||
guarded_write_np = 485,
|
||||
guarded_pwrite_np = 486,
|
||||
guarded_writev_np = 487,
|
||||
renameatx_np = 488,
|
||||
mremap_encrypted = 489,
|
||||
netagent_trigger = 490,
|
||||
stack_snapshot_with_config = 491,
|
||||
microstackshot = 492,
|
||||
grab_pgo_data = 493,
|
||||
persona = 494,
|
||||
/* 495 */
|
||||
mach_eventlink_signal = 496,
|
||||
mach_eventlink_wait_until = 497,
|
||||
mach_eventlink_signal_wait_until = 498,
|
||||
work_interval_ctl = 499,
|
||||
getentropy = 500,
|
||||
necp_open = 501,
|
||||
necp_client_action = 502,
|
||||
nexus_open = 503, // for those who are intressted http://newosxbook.com/bonus/vol1ch16.html
|
||||
nexus_register = 504,
|
||||
nexus_deregister = 505,
|
||||
nexus_create = 506,
|
||||
nexus_destroy = 507,
|
||||
nexus_get_opt = 508,
|
||||
nexus_set_opt = 509,
|
||||
channel_open = 510,
|
||||
channel_get_info = 511,
|
||||
channel_sync = 512,
|
||||
channel_get_opt = 513,
|
||||
channel_set_opt = 514,
|
||||
ulock_wait = 515,
|
||||
ulock_wake = 516,
|
||||
fclonefileat = 517,
|
||||
fs_snapshot = 518,
|
||||
register_uexc_handler = 519,
|
||||
terminate_with_payload = 520,
|
||||
abort_with_payload = 521,
|
||||
necp_session_open = 522,
|
||||
necp_session_action = 523,
|
||||
setattrlistat = 524,
|
||||
net_qos_guideline = 525,
|
||||
fmount = 526,
|
||||
ntp_adjtime = 527,
|
||||
ntp_gettime = 528,
|
||||
os_fault_with_payload = 529,
|
||||
kqueue_workloop_ctl = 530,
|
||||
mach_bridge_remote_time = 531,
|
||||
coalition_ledger = 532,
|
||||
log_data = 533,
|
||||
memorystatus_available_memory = 534,
|
||||
objc_bp_assist_cfg_np = 535,
|
||||
shared_region_map_and_slide_2_np = 536,
|
||||
pivot_root = 537,
|
||||
task_inspect_for_pid = 538,
|
||||
task_read_for_pid = 539,
|
||||
preadv = 540,
|
||||
pwritev = 541,
|
||||
preadv_nocancel = 542,
|
||||
pwritev_nocancel = 543,
|
||||
ulock_wait2 = 544,
|
||||
proc_info_extended_id = 545,
|
||||
tracker_action = 546,
|
||||
debug_syscall_reject = 547,
|
||||
MAXSYSCALL = 548,
|
||||
/* invalid = 63, */
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
package darwin
|
||||
|
||||
import "core:c"
|
||||
import "core:intrinsics"
|
||||
|
||||
/* flock */
|
||||
LOCK_SH :: 1 /* shared lock */
|
||||
LOCK_EX :: 2 /* exclusive lock */
|
||||
LOCK_NB :: 4 /* don't block when locking */
|
||||
LOCK_UN :: 8 /* unlock */
|
||||
|
||||
/* sys/unistd.h for access */
|
||||
F_OK :: c.int(0) /* test for existence of file */
|
||||
X_OK :: c.int((1 << 0)) /* test for execute or search permission */
|
||||
W_OK :: c.int((1 << 1)) /* test for write permission */
|
||||
R_OK :: c.int((1 << 2)) /* test for read permission */
|
||||
|
||||
/* copyfile flags */
|
||||
COPYFILE_ACL :: (1 << 0)
|
||||
COPYFILE_STAT :: (1 << 1)
|
||||
COPYFILE_XATTR :: (1 << 2)
|
||||
COPYFILE_DATA :: (1 << 3)
|
||||
|
||||
COPYFILE_SECURITY :: (COPYFILE_STAT | COPYFILE_ACL)
|
||||
COPYFILE_METADATA :: (COPYFILE_SECURITY | COPYFILE_XATTR)
|
||||
COPYFILE_ALL :: (COPYFILE_METADATA | COPYFILE_DATA)
|
||||
|
||||
/* syslimits.h */
|
||||
PATH_MAX :: 1024 /* max bytes in pathname */
|
||||
|
||||
/* param.h */
|
||||
MAXPATHLEN :: PATH_MAX
|
||||
|
||||
/* proc_info.h */
|
||||
DARWIN_PROC_PIDPATHINFO_SIZE :: MAXPATHLEN
|
||||
DARWIN_PROC_PIDPATHINFO :: 11
|
||||
|
||||
DARWIN_PROC_ALL_PIDS :: c.int(1)
|
||||
DARWIN_PROC_PGRP_ONLY :: c.int(2)
|
||||
DARWIN_PROC_TTY_ONLY :: c.int(3)
|
||||
DARWIN_PROC_UID_ONLY :: c.int(4)
|
||||
DARWIN_PROC_RUID_ONLY :: c.int(5)
|
||||
DARWIN_PROC_PPID_ONLY :: c.int(6)
|
||||
DARWIN_PROC_KDBG_ONLY :: c.int(7)
|
||||
|
||||
DARWIN_PROC_INFO_CALL_LISTPIDS :: c.int(0x1)
|
||||
DARWIN_PROC_INFO_CALL_PIDINFO :: c.int(0x2)
|
||||
DARWIN_PROC_INFO_CALL_PIDFDINFO :: c.int(0x3)
|
||||
DARWIN_PROC_INFO_CALL_KERNMSGBUF :: c.int(0x4)
|
||||
DARWIN_PROC_INFO_CALL_SETCONTROL :: c.int(0x5)
|
||||
DARWIN_PROC_INFO_CALL_PIDFILEPORTINFO :: c.int(0x6)
|
||||
DARWIN_PROC_INFO_CALL_TERMINATE :: c.int(0x7)
|
||||
DARWIN_PROC_INFO_CALL_DIRTYCONTROL :: c.int(0x8)
|
||||
DARWIN_PROC_INFO_CALL_PIDRUSAGE :: c.int(0x9)
|
||||
DARWIN_PROC_INFO_CALL_PIDORIGINATORINFO :: c.int(0xa)
|
||||
DARWIN_PROC_INFO_CALL_LISTCOALITIONS :: c.int(0xb)
|
||||
DARWIN_PROC_INFO_CALL_CANUSEFGHW :: c.int(0xc)
|
||||
DARWIN_PROC_INFO_CALL_PIDDYNKQUEUEINFO :: c.int(0xd)
|
||||
DARWIN_PROC_INFO_CALL_UDATA_INFO :: c.int(0xe)
|
||||
|
||||
/* mmap flags */
|
||||
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
|
||||
MAP_FILE :: 0x0000 /* map from file (default) */
|
||||
MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */
|
||||
MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */
|
||||
MAP_PRIVATE :: 0x0002 /* [MF|SHM] changes are private */
|
||||
MAP_SHARED :: 0x0001 /* [MF|SHM] share changes */
|
||||
MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */
|
||||
MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */
|
||||
MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */
|
||||
|
||||
/* mmap prot flags */
|
||||
PROT_NONE :: 0x00 /* [MC2] no permissions */
|
||||
PROT_READ :: 0x01 /* [MC2] pages can be read */
|
||||
PROT_WRITE :: 0x02 /* [MC2] pages can be written */
|
||||
PROT_EXEC :: 0x04 /* [MC2] pages can be executed */
|
||||
|
||||
/* For owner Mode/Permission Flags for Open etc. */
|
||||
PERMISSION_MASK_IRWXU :: 0o000700 /* RWX mask for owner */
|
||||
PERMISSION_MASK_IRUSR :: 0o000400 /* R for owner */
|
||||
PERMISSION_MASK_IWUSR :: 0o000200 /* W for owner */
|
||||
PERMISSION_MASK_IXUSR :: 0o000100 /* X for owner */
|
||||
|
||||
/* For group Mode/Permission Flags for Open etc. */
|
||||
PERMISSION_MASK_IRWXG :: 0o000070 /* RWX mask for group */
|
||||
PERMISSION_MASK_IRGRP :: 0o000040 /* R for group */
|
||||
PERMISSION_MASK_IWGRP :: 0o000020 /* W for group */
|
||||
PERMISSION_MASK_IXGRP :: 0o000010 /* X for group */
|
||||
|
||||
/* For other Mode/Permission Flags for Open etc. */
|
||||
PERMISSION_MASK_IRWXO :: 0o000007 /* RWX mask for other */
|
||||
PERMISSION_MASK_IROTH :: 0o000004 /* R for other */
|
||||
PERMISSION_MASK_IWOTH :: 0o000002 /* W for other */
|
||||
PERMISSION_MASK_IXOTH :: 0o000001 /* X for other */
|
||||
|
||||
/* Special Mode/Permission Flags for Open etc. */
|
||||
PERMISSION_MASK_ISUID :: 0o004000 /* set user id on execution */
|
||||
PERMISSION_MASK_ISGID :: 0o002000 /* set group id on execution */
|
||||
PERMISSION_MASK_ISVTX :: 0o001000 /* save swapped text even after use */
|
||||
|
||||
OPEN_FLAG_RDONLY :: 0x0000 /* open for reading only */
|
||||
OPEN_FLAG_WRONLY :: 0x0001 /* open for writing only */
|
||||
OPEN_FLAG_RDWR :: 0x0002 /* open for reading and writing */
|
||||
|
||||
/* mask for above rd/wr/rdwr flags */
|
||||
MASK_ACCMODE :: 0x0003
|
||||
|
||||
OPEN_FLAG_NONBLOCK :: 0x00000004 /* no delay */
|
||||
OPEN_FLAG_APPEND :: 0x00000008 /* set append mode */
|
||||
OPEN_FLAG_CREAT :: 0x00000200 /* create if nonexistant */
|
||||
OPEN_FLAG_TRUNC :: 0x00000400 /* truncate to zero length */
|
||||
OPEN_FLAG_EXCL :: 0x00000800 /* error if already exists */
|
||||
OPEN_FLAG_SHLOCK :: 0x00000010 /* open with shared file lock */
|
||||
OPEN_FLAG_EXLOCK :: 0x00000020 /* open with exclusive file lock */
|
||||
OPEN_FLAG_DIRECTORY :: 0x00100000 /* restrict open to only directories */
|
||||
OPEN_FLAG_NOFOLLOW :: 0x00000100 /* don't follow symlinks */
|
||||
OPEN_FLAG_SYMLINK :: 0x00200000 /* allow open of a symlink */
|
||||
OPEN_FLAG_EVTONLY :: 0x00008000 /* descriptor requested for event notifications only */
|
||||
OPEN_FLAG_CLOEXEC :: 0x01000000 /* causes the descriptor to be closed if you use any of the exec like functions */
|
||||
OPEN_FLAG_NOFOLLOW_ANY :: 0x20000000 /* no symlinks allowed in path */
|
||||
|
||||
/* bsd/sys/param.h */
|
||||
DARWIN_MAXCOMLEN :: 16
|
||||
|
||||
/*--==========================================================================--*/
|
||||
|
||||
__darwin_ino64_t :: u64
|
||||
__darwin_time_t :: u32
|
||||
__darwin_dev_t :: i32
|
||||
__darwin_mode_t :: u16
|
||||
__darwin_off_t :: i64
|
||||
__darwin_blkcnt_t :: i64
|
||||
__darwin_blksize_t :: i32
|
||||
__darwin_pid_t :: i32
|
||||
__darwin_suseconds_t :: i32
|
||||
|
||||
time_t :: __darwin_time_t
|
||||
dev_t :: __darwin_dev_t
|
||||
mode_t :: u16
|
||||
nlink_t :: u16
|
||||
uid_t :: u16
|
||||
gid_t :: u16
|
||||
off_t :: __darwin_off_t
|
||||
blkcnt_t :: __darwin_blkcnt_t
|
||||
blksize_t :: __darwin_blksize_t
|
||||
pid_t :: __darwin_pid_t
|
||||
|
||||
stat :: __DARWIN_STRUCT_STAT64
|
||||
timeval :: _STRUCT_TIMEVAL
|
||||
|
||||
/*--==========================================================================--*/
|
||||
|
||||
/* sys/stat.h */
|
||||
__DARWIN_STRUCT_STAT64 :: struct {
|
||||
st_dev: dev_t, /* [XSI] ID of device containing file */
|
||||
st_mode: mode_t, /* [XSI] Mode of file (see below) */
|
||||
st_nlink: nlink_t, /* [XSI] Number of hard links */
|
||||
st_ino: __darwin_ino64_t, /* [XSI] File serial number */
|
||||
st_uid_t: uid_t, /* [XSI] User ID of the file */
|
||||
st_gid_t: gid_t, /* [XSI] Group ID of the file */
|
||||
st_rdev: dev_t, /* [XSI] Device ID */
|
||||
|
||||
// __DARWIN_STRUCT_STAT64_TIMES
|
||||
st_atime: time_t, /* [XSI] Time of last access */
|
||||
st_atimensec: i32, /* nsec of last access */
|
||||
st_mtime: time_t, /* [XSI] Last data modification time */
|
||||
st_mtimensec: i32, /* last data modification nsec */
|
||||
st_ctime: time_t, /* [XSI] Time of last status change */
|
||||
st_ctimensec: u32, /* nsec of last status change */
|
||||
st_birthtime: time_t, /* File creation time(birth) */
|
||||
st_birthtimensec: i32, /* nsec of File creation time */
|
||||
// end __DARWIN_STRUCT_STAT64_TIMES
|
||||
|
||||
st_size: off_t, /* [XSI] file size, in bytes */
|
||||
st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */
|
||||
st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */
|
||||
st_flags: u32, /* user defined flags for file */
|
||||
st_gen: u32, /* file generation number */
|
||||
st_lspare: i32, /* RESERVED: DO NOT USE! */
|
||||
st_qspare: [2]i64, /* RESERVED: DO NOT USE! */
|
||||
}
|
||||
|
||||
/* sys/_types/_timeval.h */
|
||||
_STRUCT_TIMEVAL :: struct {
|
||||
tv_sec: __darwin_time_t, /* seconds */
|
||||
tv_usec: __darwin_suseconds_t, /* microseconds */
|
||||
}
|
||||
|
||||
/* pwd.h */
|
||||
_Password_Entry :: struct {
|
||||
pw_name: cstring, /* username */
|
||||
pw_passwd: cstring, /* user password */
|
||||
pw_uid: i32, /* user ID */
|
||||
pw_gid: i32, /* group ID */
|
||||
pw_change: u64, /* password change time */
|
||||
pw_class: cstring, /* user access class */
|
||||
pw_gecos: cstring, /* full user name */
|
||||
pw_dir: cstring, /* home directory */
|
||||
pw_shell: cstring, /* shell program */
|
||||
pw_expire: u64, /* account expiration */
|
||||
pw_fields: i32, /* filled fields */
|
||||
}
|
||||
|
||||
/* processinfo.h */
|
||||
_Proc_Bsdinfo :: struct {
|
||||
pbi_flags: u32, /* if is 64bit; emulated etc */
|
||||
pbi_status: u32,
|
||||
pbi_xstatus: u32,
|
||||
pbi_pid: u32,
|
||||
pbi_ppid: u32,
|
||||
pbi_uid: u32,
|
||||
pbi_gid: u32,
|
||||
pbi_ruid: u32,
|
||||
pbi_rgid: u32,
|
||||
pbi_svuid: u32,
|
||||
pbi_svgid: u32,
|
||||
res: u32,
|
||||
pbi_comm: [DARWIN_MAXCOMLEN]u8,
|
||||
pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */
|
||||
pbi_nfiles: u32,
|
||||
pbi_pgid: u32,
|
||||
pbi_pjobc: u32,
|
||||
e_tdev: u32, /* controlling tty dev */
|
||||
e_tpgid: u32, /* tty process group id */
|
||||
pbi_nice: i32,
|
||||
pbi_start_tvsec: u64,
|
||||
pbi_start_tvusec: u64,
|
||||
}
|
||||
|
||||
/*--==========================================================================--*/
|
||||
|
||||
syscall_fsync :: #force_inline proc(fildes: c.int) -> bool {
|
||||
return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes)))
|
||||
}
|
||||
|
||||
syscall_write :: #force_inline proc (fildes: c.int, buf: ^byte, nbyte: u64) -> bool {
|
||||
return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.write), uintptr(fildes), uintptr(buf), uintptr(nbyte)))
|
||||
}
|
||||
|
||||
syscall_read :: #force_inline proc(fildes: c.int, buf: ^byte, nbyte: u64) -> i64 {
|
||||
return cast(i64)intrinsics.syscall(unix_offset_syscall(.read), uintptr(fildes), uintptr(buf), uintptr(nbyte))
|
||||
}
|
||||
|
||||
syscall_open :: #force_inline proc(path: cstring, oflag: u32, mode: u32) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.open), transmute(uintptr)path, uintptr(oflag), uintptr(mode))
|
||||
}
|
||||
|
||||
syscall_close :: #force_inline proc(fd: c.int) -> bool {
|
||||
return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.close), uintptr(fd)))
|
||||
}
|
||||
|
||||
syscall_fchmod :: #force_inline proc(fildes: c.int, mode: u32) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.fchmod), uintptr(fildes), uintptr(mode)))
|
||||
}
|
||||
|
||||
syscall_chmod :: #force_inline proc(path: cstring, mode: u32) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.chmod), transmute(uintptr)path, uintptr(mode)))
|
||||
}
|
||||
|
||||
syscall_mkdir :: #force_inline proc(path: cstring, mode: u32) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), transmute(uintptr)path, uintptr(mode)))
|
||||
}
|
||||
|
||||
syscall_mkdir_at :: #force_inline proc(fd: c.int, path: cstring, mode: u32) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), uintptr(fd), transmute(uintptr)path, uintptr(mode)))
|
||||
}
|
||||
|
||||
syscall_rmdir :: #force_inline proc(path: cstring, mode: u32) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rmdir), transmute(uintptr)path, uintptr(mode)))
|
||||
}
|
||||
|
||||
syscall_rename :: #force_inline proc(path_old: cstring, path_new: cstring) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rename), transmute(uintptr)path_old, transmute(uintptr)path_new))
|
||||
}
|
||||
|
||||
syscall_rename_at :: #force_inline proc(from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int {
|
||||
return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.renameat), uintptr(from_fd), transmute(uintptr)from, uintptr(to_fd), transmute(uintptr)to))
|
||||
}
|
||||
|
||||
syscall_lseek :: #force_inline proc(fd: c.int, offset: i64, whence: c.int) -> i64 {
|
||||
return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence))
|
||||
}
|
||||
|
||||
syscall_gettid :: #force_inline proc() -> u64 {
|
||||
return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid))
|
||||
}
|
||||
|
||||
syscall_fstat :: #force_inline proc(fd: c.int, status: ^stat) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstat), uintptr(fd), uintptr(status))
|
||||
}
|
||||
|
||||
syscall_lstat :: #force_inline proc(path: cstring, status: ^stat) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.lstat), transmute(uintptr)path, uintptr(status))
|
||||
}
|
||||
|
||||
syscall_stat :: #force_inline proc(path: cstring, status: ^stat) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.stat), transmute(uintptr)path, uintptr(status))
|
||||
}
|
||||
|
||||
syscall_fstatat :: #force_inline proc(fd: c.int, path: cstring, status: ^stat) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstatat), uintptr(fd), transmute(uintptr)path, uintptr(status))
|
||||
}
|
||||
|
||||
syscall_link :: #force_inline proc(path: cstring, to_link: cstring) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.link), transmute(uintptr)path, transmute(uintptr)to_link)
|
||||
}
|
||||
|
||||
syscall_linkat :: #force_inline proc(fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.linkat), uintptr(fd), transmute(uintptr)path, uintptr(fd2), transmute(uintptr)to_link)
|
||||
}
|
||||
|
||||
syscall_readlink :: #force_inline proc(path: cstring, buf: ^u8, buf_size: u64) -> i64 {
|
||||
return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlink), transmute(uintptr)path, uintptr(buf), uintptr(buf_size))
|
||||
}
|
||||
|
||||
syscall_readlinkat :: #force_inline proc(fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 {
|
||||
return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlinkat), uintptr(fd), transmute(uintptr)path, uintptr(buf), uintptr(buf_size))
|
||||
}
|
||||
|
||||
syscall_access :: #force_inline proc(path: cstring, mode: c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.access), transmute(uintptr)path, uintptr(mode))
|
||||
}
|
||||
|
||||
syscall_faccessat :: #force_inline proc(fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.faccessat), uintptr(fd), transmute(uintptr)path, uintptr(mode), uintptr(flag))
|
||||
}
|
||||
|
||||
syscall_getdirentries :: #force_inline proc(fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getdirentries), uintptr(fd), uintptr(buf), uintptr(nbytes), uintptr(base_pointer))
|
||||
}
|
||||
|
||||
syscall_truncate :: #force_inline proc (path: cstring, length: off_t) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.truncate), transmute(uintptr)path, uintptr(length))
|
||||
}
|
||||
|
||||
syscall_ftruncate :: #force_inline proc (fd: c.int, length: off_t) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length))
|
||||
}
|
||||
|
||||
syscall_sysctl :: #force_inline proc (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen))
|
||||
}
|
||||
|
||||
syscall_copyfile :: #force_inline proc(from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.copyfile), transmute(uintptr)from, transmute(uintptr)to, uintptr(state), uintptr(flags))
|
||||
}
|
||||
|
||||
// think about this? last arg should be more than one
|
||||
syscall_fcntl :: #force_inline proc(fd: c.int, cmd: c.int, other: rawptr) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fsctl), uintptr(fd), uintptr(cmd), uintptr(other))
|
||||
}
|
||||
|
||||
syscall_exit :: #force_inline proc(code: c.int) {
|
||||
intrinsics.syscall(unix_offset_syscall(.exit), uintptr(code))
|
||||
}
|
||||
|
||||
syscall_kill :: #force_inline proc(pid: pid_t, sig: c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.kill), uintptr(pid), uintptr(sig))
|
||||
}
|
||||
|
||||
syscall_dup :: #force_inline proc(fd: c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.dup), uintptr(fd))
|
||||
}
|
||||
|
||||
syscall_execve :: #force_inline proc(path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.execve), transmute(uintptr)path, transmute(uintptr)argv, transmute(uintptr)env)
|
||||
}
|
||||
|
||||
syscall_munmap :: #force_inline proc(addr: rawptr, len: u64) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len))
|
||||
}
|
||||
|
||||
syscall_mmap :: #force_inline proc(addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 {
|
||||
return cast(^u8)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len), uintptr(port), uintptr(flags), uintptr(fd), uintptr(offset))
|
||||
}
|
||||
|
||||
syscall_flock :: #force_inline proc(fd: c.int, operation: c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.flock), uintptr(fd), uintptr(operation))
|
||||
}
|
||||
|
||||
syscall_utimes :: #force_inline proc(path: cstring, times: ^timeval) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.utimes), transmute(uintptr)path, uintptr(times))
|
||||
}
|
||||
|
||||
syscall_futimes :: #force_inline proc(fd: c.int, times: ^timeval) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.futimes), uintptr(fd), uintptr(times))
|
||||
}
|
||||
|
||||
syscall_adjtime :: #force_inline proc(delta: ^timeval, old_delta: ^timeval) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta))
|
||||
}
|
||||
|
||||
syscall_sysctlbyname :: #force_inline proc(name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), transmute(uintptr)name, uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen))
|
||||
}
|
||||
|
||||
syscall_proc_info :: #force_inline proc(num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.proc_info), uintptr(num), uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(buffer), uintptr(buffer_size))
|
||||
}
|
||||
|
||||
syscall_openat :: #force_inline proc(fd: int, path: cstring, oflag: u32, mode: u32) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.openat), uintptr(fd), transmute(uintptr)path, uintptr(oflag), uintptr(mode))
|
||||
}
|
||||
|
||||
syscall_getentropy :: #force_inline proc(buf: ^u8, buflen: u64) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(buf), uintptr(buflen))
|
||||
}
|
||||
|
||||
syscall_pipe :: #force_inline proc(fds: [^]c.int) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(&fds[0]), uintptr(&fds[1]))
|
||||
}
|
||||
|
||||
syscall_chdir :: #force_inline proc(path: cstring) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), transmute(uintptr)path)
|
||||
}
|
||||
|
||||
syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int {
|
||||
return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path)
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//+build openbsd
|
||||
package unix
|
||||
|
||||
import "core:c"
|
||||
|
||||
pthread_t :: distinct rawptr
|
||||
pthread_attr_t :: distinct rawptr
|
||||
pthread_mutex_t :: distinct rawptr
|
||||
pthread_mutexattr_t :: distinct rawptr
|
||||
pthread_cond_t :: distinct rawptr
|
||||
pthread_condattr_t :: distinct rawptr
|
||||
pthread_rwlock_t :: distinct rawptr
|
||||
pthread_rwlockattr_t :: distinct rawptr
|
||||
pthread_barrier_t :: distinct rawptr
|
||||
pthread_barrierattr_t :: distinct rawptr
|
||||
pthread_spinlock_t :: distinct rawptr
|
||||
|
||||
pthread_key_t :: distinct c.int
|
||||
pthread_once_t :: struct {
|
||||
state: c.int,
|
||||
mutex: pthread_mutex_t,
|
||||
}
|
||||
|
||||
PTHREAD_MUTEX_ERRORCHECK :: 1
|
||||
PTHREAD_MUTEX_RECURSIVE :: 2
|
||||
PTHREAD_MUTEX_NORMAL :: 3
|
||||
PTHREAD_MUTEX_STRICT_NP :: 4
|
||||
|
||||
PTHREAD_DETACHED :: 0x1
|
||||
PTHREAD_SCOPE_SYSTEM :: 0x2
|
||||
PTHREAD_INHERIT_SCHED :: 0x4
|
||||
PTHREAD_NOFLOAT :: 0x8
|
||||
|
||||
PTHREAD_CREATE_DETACHED :: PTHREAD_DETACHED
|
||||
PTHREAD_CREATE_JOINABLE :: 0
|
||||
PTHREAD_SCOPE_PROCESS :: 0
|
||||
PTHREAD_EXPLICIT_SCHED :: 0
|
||||
|
||||
SCHED_FIFO :: 1
|
||||
SCHED_OTHER :: 2
|
||||
SCHED_RR :: 3
|
||||
|
||||
sched_param :: struct {
|
||||
sched_priority: c.int,
|
||||
}
|
||||
|
||||
sem_t :: distinct rawptr
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
|
||||
|
||||
sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
|
||||
sem_destroy :: proc(sem: ^sem_t) -> c.int ---
|
||||
sem_post :: proc(sem: ^sem_t) -> c.int ---
|
||||
sem_wait :: proc(sem: ^sem_t) -> c.int ---
|
||||
sem_trywait :: proc(sem: ^sem_t) -> c.int ---
|
||||
//sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---
|
||||
|
||||
// NOTE: unclear whether pthread_yield is well-supported on Linux systems,
|
||||
// see https://linux.die.net/man/3/pthread_yield
|
||||
pthread_yield :: proc() ---
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build linux, darwin, freebsd
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
package unix
|
||||
|
||||
foreign import "system:pthread"
|
||||
|
||||
@@ -15,7 +15,7 @@ import "core:intrinsics"
|
||||
// 386: arch/x86/entry/syscalls/sycall_32.tbl
|
||||
// arm: arch/arm/tools/syscall.tbl
|
||||
|
||||
when ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == .amd64 {
|
||||
SYS_read : uintptr : 0
|
||||
SYS_write : uintptr : 1
|
||||
SYS_open : uintptr : 2
|
||||
@@ -374,7 +374,7 @@ when ODIN_ARCH == "amd64" {
|
||||
SYS_landlock_add_rule : uintptr : 445
|
||||
SYS_landlock_restrict_self : uintptr : 446
|
||||
SYS_memfd_secret : uintptr : 447
|
||||
} else when ODIN_ARCH == "arm64" {
|
||||
} else when ODIN_ARCH == .arm64 {
|
||||
SYS_io_setup : uintptr : 0
|
||||
SYS_io_destroy : uintptr : 1
|
||||
SYS_io_submit : uintptr : 2
|
||||
@@ -675,7 +675,7 @@ when ODIN_ARCH == "amd64" {
|
||||
SYS_landlock_create_ruleset : uintptr : 444
|
||||
SYS_landlock_add_rule : uintptr : 445
|
||||
SYS_landlock_restrict_self : uintptr : 446
|
||||
} else when ODIN_ARCH == "i386" {
|
||||
} else when ODIN_ARCH == .i386 {
|
||||
SYS_restart_syscall : uintptr : 0
|
||||
SYS_exit : uintptr : 1
|
||||
SYS_fork : uintptr : 2
|
||||
@@ -1112,7 +1112,7 @@ when ODIN_ARCH == "amd64" {
|
||||
SYS_landlock_add_rule : uintptr : 445
|
||||
SYS_landlock_restrict_self : uintptr : 446
|
||||
SYS_memfd_secret : uintptr : 447
|
||||
} else when ODIN_ARCH == "arm" {
|
||||
} else when false /*ODIN_ARCH == .arm*/ { // TODO
|
||||
SYS_restart_syscall : uintptr : 0
|
||||
SYS_exit : uintptr : 1
|
||||
SYS_fork : uintptr : 2
|
||||
|
||||
@@ -101,6 +101,9 @@ foreign user32 {
|
||||
}
|
||||
@(link_name="GetCursorPos") get_cursor_pos :: proc(p: ^Point) -> Bool ---
|
||||
@(link_name="SetCursorPos") set_cursor_pos :: proc(x, y: i32) -> Bool ---
|
||||
@(link_name="GetCapure") get_capture :: proc(hwnd: Hwnd) -> Hwnd ---
|
||||
@(link_name="SetCapture") set_capture :: proc(hwnd: Hwnd) -> Hwnd ---
|
||||
@(link_name="ReleaseCapture") release_capture :: proc() -> Bool ---
|
||||
@(link_name="ScreenToClient") screen_to_client :: proc(h: Hwnd, p: ^Point) -> Bool ---
|
||||
@(link_name="ClientToScreen") client_to_screen :: proc(h: Hwnd, p: ^Point) -> Bool ---
|
||||
@(link_name="PostQuitMessage") post_quit_message :: proc(exit_code: i32) ---
|
||||
|
||||
@@ -376,6 +376,9 @@ FILE_TYPE_DISK :: 0x0001
|
||||
FILE_TYPE_CHAR :: 0x0002
|
||||
FILE_TYPE_PIPE :: 0x0003
|
||||
|
||||
RECT :: struct {left, top, right, bottom: LONG}
|
||||
POINT :: struct {x, y: LONG}
|
||||
|
||||
|
||||
when size_of(uintptr) == 4 {
|
||||
WSADATA :: struct {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build linux, darwin, freebsd
|
||||
// +build linux, darwin, freebsd, openbsd
|
||||
// +private
|
||||
package thread
|
||||
|
||||
|
||||
+24
-12
@@ -1,9 +1,9 @@
|
||||
//+build linux, darwin, freebsd
|
||||
//+build linux, darwin, freebsd, openbsd
|
||||
package time
|
||||
|
||||
IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC.
|
||||
|
||||
when ODIN_OS == "darwin" {
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
@@ -22,16 +22,28 @@ TimeSpec :: struct {
|
||||
tv_nsec : i64, /* nanoseconds */
|
||||
}
|
||||
|
||||
CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
|
||||
CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 2
|
||||
CLOCK_THREAD_CPUTIME_ID :: 3
|
||||
CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
|
||||
CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
|
||||
CLOCK_MONOTONIC_COARSE :: 6
|
||||
CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
|
||||
CLOCK_REALTIME_ALARM :: 8
|
||||
CLOCK_BOOTTIME_ALARM :: 9
|
||||
when ODIN_OS == .OpenBSD {
|
||||
CLOCK_REALTIME :: 0
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 2
|
||||
CLOCK_MONOTONIC :: 3
|
||||
CLOCK_THREAD_CPUTIME_ID :: 4
|
||||
CLOCK_UPTIME :: 5
|
||||
CLOCK_BOOTTIME :: 6
|
||||
|
||||
// CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC
|
||||
CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC
|
||||
} else {
|
||||
CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
|
||||
CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 2
|
||||
CLOCK_THREAD_CPUTIME_ID :: 3
|
||||
CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
|
||||
CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
|
||||
CLOCK_MONOTONIC_COARSE :: 6
|
||||
CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
|
||||
CLOCK_REALTIME_ALARM :: 8
|
||||
CLOCK_BOOTTIME_ALARM :: 9
|
||||
}
|
||||
|
||||
// TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants.
|
||||
// I do not know if Darwin programmers are used to the existance of these constants or not, so
|
||||
|
||||
@@ -119,6 +119,7 @@ _ :: bit_array
|
||||
_ :: priority_queue
|
||||
_ :: queue
|
||||
_ :: small_array
|
||||
_ :: lru
|
||||
_ :: crypto
|
||||
_ :: blake
|
||||
_ :: blake2b
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
//+build windows
|
||||
package all
|
||||
|
||||
|
||||
import botan "vendor:botan"
|
||||
import ENet "vendor:ENet"
|
||||
import gl "vendor:OpenGL"
|
||||
@@ -17,14 +15,11 @@ import IMG "vendor:sdl2/image"
|
||||
import MIX "vendor:sdl2/mixer"
|
||||
import TTF "vendor:sdl2/ttf"
|
||||
|
||||
import stb_easy_font "vendor:stb/easy_font"
|
||||
import stbi "vendor:stb/image"
|
||||
import stbrp "vendor:stb/rect_pack"
|
||||
import stbtt "vendor:stb/truetype"
|
||||
import stb_vorbis "vendor:stb/vorbis"
|
||||
|
||||
import vk "vendor:vulkan"
|
||||
|
||||
import NS "vendor:darwin/Foundation"
|
||||
import MTL "vendor:darwin/Metal"
|
||||
import CA "vendor:darwin/QuartzCore"
|
||||
|
||||
_ :: botan
|
||||
_ :: ENet
|
||||
@@ -39,9 +34,7 @@ _ :: SDLNet
|
||||
_ :: IMG
|
||||
_ :: MIX
|
||||
_ :: TTF
|
||||
_ :: stb_easy_font
|
||||
_ :: stbi
|
||||
_ :: stbrp
|
||||
_ :: stbtt
|
||||
_ :: stb_vorbis
|
||||
_ :: vk
|
||||
_ :: vk
|
||||
_ :: NS
|
||||
_ :: MTL
|
||||
_ :: CA
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//+build windows
|
||||
package all
|
||||
|
||||
import D3D11 "vendor:directx/d3d11"
|
||||
import D3D12 "vendor:directx/d3d12"
|
||||
import DXGI "vendor:directx/dxgi"
|
||||
|
||||
_ :: D3D11
|
||||
_ :: D3D12
|
||||
_ :: DXGI
|
||||
@@ -0,0 +1,15 @@
|
||||
//+build windows, linux
|
||||
package all
|
||||
|
||||
import stb_easy_font "vendor:stb/easy_font"
|
||||
import stbi "vendor:stb/image"
|
||||
import stbrp "vendor:stb/rect_pack"
|
||||
import stbtt "vendor:stb/truetype"
|
||||
import stb_vorbis "vendor:stb/vorbis"
|
||||
|
||||
_ :: stb_easy_font
|
||||
_ :: stbi
|
||||
_ :: stbrp
|
||||
_ :: stbtt
|
||||
_ :: stb_vorbis
|
||||
|
||||
+22
-16
@@ -11,22 +11,28 @@ import "core:intrinsics"
|
||||
import "core:math/big"
|
||||
|
||||
/*
|
||||
The Odin programming language is fast, concise, readable, pragmatic and open sourced.
|
||||
It is designed with the intent of replacing C with the following goals:
|
||||
* simplicity
|
||||
* high performance
|
||||
* built for modern systems
|
||||
* joy of programming
|
||||
Odin is a general-purpose programming language with distinct typing built
|
||||
for high performance, modern systems and data-oriented programming.
|
||||
|
||||
Odin is the C alternative for the Joy of Programming.
|
||||
|
||||
# Installing Odin
|
||||
Getting Started - https://odin-lang.org/docs/install/
|
||||
Instructions for downloading and install the Odin compiler and libraries.
|
||||
|
||||
# Learning Odin
|
||||
Getting Started - https://odin-lang.org/docs/install/
|
||||
Getting Started with Odin. Downloading, installing, and getting your
|
||||
first program to compile and run.
|
||||
Overview of Odin - https://odin-lang.org/docs/overview/
|
||||
An overview of the Odin programming language.
|
||||
An overview of the Odin programming language and its features.
|
||||
Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/
|
||||
Answers to common questions about Odin.
|
||||
Packages - https://pkg.odin-lang.org/
|
||||
Documentation for all the official packages part of the
|
||||
core and vendor library collections.
|
||||
Nightly Builds - https://odin-lang.org/docs/nightly/
|
||||
Get the latest nightly builds of Odin.
|
||||
*/
|
||||
|
||||
the_basics :: proc() {
|
||||
@@ -244,10 +250,10 @@ control_flow :: proc() {
|
||||
// A switch statement is another way to write a sequence of if-else statements.
|
||||
// In Odin, the default case is denoted as a case without any expression.
|
||||
|
||||
switch arch := ODIN_ARCH; arch {
|
||||
case "386":
|
||||
#partial switch arch := ODIN_ARCH; arch {
|
||||
case .i386:
|
||||
fmt.println("32-bit")
|
||||
case "amd64":
|
||||
case .amd64:
|
||||
fmt.println("64-bit")
|
||||
case: // default
|
||||
fmt.println("Unsupported architecture")
|
||||
@@ -363,12 +369,12 @@ control_flow :: proc() {
|
||||
*/
|
||||
|
||||
// Example
|
||||
when ODIN_ARCH == "386" {
|
||||
when ODIN_ARCH == .i386 {
|
||||
fmt.println("32 bit")
|
||||
} else when ODIN_ARCH == "amd64" {
|
||||
} else when ODIN_ARCH == .amd64 {
|
||||
fmt.println("64 bit")
|
||||
} else {
|
||||
fmt.println("Unsupported architecture")
|
||||
fmt.println("Unknown architecture")
|
||||
}
|
||||
// The when statement is very useful for writing platform specific code.
|
||||
// This is akin to the #if construct in C’s preprocessor however, in Odin,
|
||||
@@ -1100,7 +1106,7 @@ prefix_table := [?]string{
|
||||
}
|
||||
|
||||
threading_example :: proc() {
|
||||
if ODIN_OS == "darwin" {
|
||||
if ODIN_OS == .Darwin {
|
||||
// TODO: Fix threads on darwin/macOS
|
||||
return
|
||||
}
|
||||
@@ -1606,13 +1612,13 @@ where_clauses :: proc() {
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import kernel32 "system:kernel32.lib"
|
||||
}
|
||||
|
||||
foreign_system :: proc() {
|
||||
fmt.println("\n#foreign system")
|
||||
when ODIN_OS == "windows" {
|
||||
when ODIN_OS == .Windows {
|
||||
// It is sometimes necessarily to interface with foreign code,
|
||||
// such as a C library. In Odin, this is achieved through the
|
||||
// foreign system. You can “import” a library into the code
|
||||
|
||||
+3
-1
@@ -89,7 +89,9 @@ template <typename T>
|
||||
void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
|
||||
GB_ASSERT(count >= 0);
|
||||
s->data = gb_alloc_array(allocator, T, count);
|
||||
GB_ASSERT(s->data != nullptr);
|
||||
if (count > 0) {
|
||||
GB_ASSERT(s->data != nullptr);
|
||||
}
|
||||
s->count = count;
|
||||
}
|
||||
|
||||
|
||||
+24
-3
@@ -17,6 +17,11 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(GB_SYSTEM_OPENBSD)
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
|
||||
*/
|
||||
@@ -242,6 +247,14 @@ void report_ram_info() {
|
||||
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
|
||||
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OPENBSD)
|
||||
uint64_t ram_amount;
|
||||
size_t val_size = sizeof(ram_amount);
|
||||
|
||||
int sysctls[] = { CTL_HW, HW_PHYSMEM64 };
|
||||
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
|
||||
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
|
||||
}
|
||||
#else
|
||||
gb_printf("Unknown.\n");
|
||||
#endif
|
||||
@@ -473,11 +486,11 @@ void print_bug_report_help() {
|
||||
|
||||
#elif defined(GB_SYSTEM_LINUX)
|
||||
/*
|
||||
Try to parse `/usr/lib/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
|
||||
Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
|
||||
*/
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
gbFileContents release = gb_file_read_contents(a, 1, "/usr/lib/os-release");
|
||||
gbFileContents release = gb_file_read_contents(a, 1, "/etc/os-release");
|
||||
defer (gb_file_free_contents(&release));
|
||||
|
||||
b32 found = 0;
|
||||
@@ -643,6 +656,14 @@ void print_bug_report_help() {
|
||||
} else {
|
||||
gb_printf("macOS: Unknown\n");
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OPENBSD)
|
||||
struct utsname un;
|
||||
|
||||
if (uname(&un) != -1) {
|
||||
gb_printf("%s %s %s %s\n", un.sysname, un.release, un.version, un.machine);
|
||||
} else {
|
||||
gb_printf("OpenBSD: Unknown\n");
|
||||
}
|
||||
#else
|
||||
gb_printf("Unknown\n");
|
||||
|
||||
@@ -657,4 +678,4 @@ void print_bug_report_help() {
|
||||
And RAM info.
|
||||
*/
|
||||
report_ram_info();
|
||||
}
|
||||
}
|
||||
|
||||
+48
-3
@@ -1,4 +1,4 @@
|
||||
#if defined(GB_SYSTEM_FREEBSD)
|
||||
#if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
@@ -16,6 +16,7 @@ enum TargetOsKind {
|
||||
TargetOs_linux,
|
||||
TargetOs_essence,
|
||||
TargetOs_freebsd,
|
||||
TargetOs_openbsd,
|
||||
|
||||
TargetOs_wasi,
|
||||
TargetOs_js,
|
||||
@@ -53,6 +54,7 @@ String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit("linux"),
|
||||
str_lit("essence"),
|
||||
str_lit("freebsd"),
|
||||
str_lit("openbsd"),
|
||||
|
||||
str_lit("wasi"),
|
||||
str_lit("js"),
|
||||
@@ -354,6 +356,15 @@ gb_global TargetMetrics target_freebsd_amd64 = {
|
||||
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_openbsd_amd64 = {
|
||||
TargetOs_openbsd,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
str_lit("x86_64-unknown-openbsd-elf"),
|
||||
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_essence_amd64 = {
|
||||
TargetOs_essence,
|
||||
TargetArch_amd64,
|
||||
@@ -417,6 +428,7 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("windows_amd64"), &target_windows_amd64 },
|
||||
{ str_lit("freebsd_386"), &target_freebsd_386 },
|
||||
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 },
|
||||
{ str_lit("openbsd_amd64"), &target_openbsd_amd64 },
|
||||
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
|
||||
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
|
||||
{ str_lit("js_wasm32"), &target_js_wasm32 },
|
||||
@@ -722,10 +734,38 @@ String internal_odin_root_dir(void) {
|
||||
len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count);
|
||||
#elif defined(GB_SYSTEM_DRAGONFLYBSD)
|
||||
len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count);
|
||||
#else
|
||||
#elif defined(GB_SYSTEM_LINUX)
|
||||
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
|
||||
#elif defined(GB_SYSTEM_OPENBSD)
|
||||
int error;
|
||||
int mib[] = {
|
||||
CTL_KERN,
|
||||
KERN_PROC_ARGS,
|
||||
getpid(),
|
||||
KERN_PROC_ARGV,
|
||||
};
|
||||
// get argv size
|
||||
error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0);
|
||||
if (error == -1) {
|
||||
// sysctl error
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
// get argv
|
||||
char **argv = (char **)gb_malloc(len);
|
||||
error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0);
|
||||
if (error == -1) {
|
||||
// sysctl error
|
||||
gb_mfree(argv);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
// copy argv[0] to path_buf
|
||||
len = gb_strlen(argv[0]);
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], argv[0], len);
|
||||
}
|
||||
gb_mfree(argv);
|
||||
#endif
|
||||
if(len == 0) {
|
||||
if(len == 0 || len == -1) {
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
if (len < path_buf.count) {
|
||||
@@ -922,6 +962,8 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
#endif
|
||||
#elif defined(GB_SYSTEM_FREEBSD)
|
||||
metrics = &target_freebsd_amd64;
|
||||
#elif defined(GB_SYSTEM_OPENBSD)
|
||||
metrics = &target_openbsd_amd64;
|
||||
#elif defined(GB_CPU_ARM)
|
||||
metrics = &target_linux_arm64;
|
||||
#else
|
||||
@@ -980,6 +1022,9 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
case TargetOs_freebsd:
|
||||
bc->link_flags = str_lit("-arch x86-64 ");
|
||||
break;
|
||||
case TargetOs_openbsd:
|
||||
bc->link_flags = str_lit("-arch x86-64 ");
|
||||
break;
|
||||
}
|
||||
} else if (bc->metrics.arch == TargetArch_i386) {
|
||||
switch (bc->metrics.os) {
|
||||
|
||||
+296
-7
@@ -143,6 +143,241 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na
|
||||
}
|
||||
|
||||
|
||||
bool does_require_msgSend_stret(Type *return_type) {
|
||||
if (return_type == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) {
|
||||
i64 struct_limit = type_size_of(t_uintptr) << 1;
|
||||
return type_size_of(return_type) > struct_limit;
|
||||
}
|
||||
if (build_context.metrics.arch == TargetArch_arm64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if (build_context.metrics.arch == TargetArch_arm32) {
|
||||
// i64 struct_limit = type_size_of(t_uintptr);
|
||||
// // NOTE(bill): This is technically wrong
|
||||
// return is_type_struct(return_type) && !is_type_raw_union(return_type) && type_size_of(return_type) > struct_limit;
|
||||
// }
|
||||
GB_PANIC("unsupported architecture");
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
||||
if (return_type == nullptr) {
|
||||
return ObjcMsg_normal;
|
||||
}
|
||||
|
||||
if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) {
|
||||
if (is_type_float(return_type)) {
|
||||
return ObjcMsg_fpret;
|
||||
}
|
||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||
if (is_type_complex(return_type)) {
|
||||
// URL: https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/message.h#L143-L159
|
||||
return ObjcMsg_fpret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (build_context.metrics.arch != TargetArch_arm64) {
|
||||
if (does_require_msgSend_stret(return_type)) {
|
||||
return ObjcMsg_stret;
|
||||
}
|
||||
}
|
||||
return ObjcMsg_normal;
|
||||
}
|
||||
|
||||
void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) {
|
||||
ObjcMsgKind kind = get_objc_proc_kind(return_type);
|
||||
|
||||
Scope *scope = create_scope(c->info, nullptr);
|
||||
|
||||
// NOTE(bill, 2022-02-08): the backend's ABI handling should handle this correctly, I hope
|
||||
Type *params = alloc_type_tuple();
|
||||
{
|
||||
auto variables = array_make<Entity *>(permanent_allocator(), 0, param_types.count);
|
||||
|
||||
for_array(i, param_types) {
|
||||
Type *type = param_types[i];
|
||||
Entity *param = alloc_entity_param(scope, blank_token, type, false, true);
|
||||
array_add(&variables, param);
|
||||
}
|
||||
params->Tuple.variables = slice_from_array(variables);
|
||||
}
|
||||
|
||||
Type *results = alloc_type_tuple();
|
||||
if (return_type) {
|
||||
auto variables = array_make<Entity *>(permanent_allocator(), 1);
|
||||
results->Tuple.variables = slice_from_array(variables);
|
||||
Entity *param = alloc_entity_param(scope, blank_token, return_type, false, true);
|
||||
results->Tuple.variables[0] = param;
|
||||
}
|
||||
|
||||
|
||||
ObjcMsgData data = {};
|
||||
data.kind = kind;
|
||||
data.proc_type = alloc_type_proc(scope, params, param_types.count, results, results->Tuple.variables.count, false, ProcCC_CDecl);
|
||||
|
||||
mutex_lock(&c->info->objc_types_mutex);
|
||||
map_set(&c->info->objc_msgSend_types, call, data);
|
||||
mutex_unlock(&c->info->objc_types_mutex);
|
||||
|
||||
try_to_add_package_dependency(c, "runtime", "objc_msgSend");
|
||||
try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret");
|
||||
try_to_add_package_dependency(c, "runtime", "objc_msgSend_fp2ret");
|
||||
try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret");
|
||||
}
|
||||
|
||||
bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
|
||||
Operand op = {};
|
||||
check_expr(c, &op, expr);
|
||||
if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
|
||||
if (name_) *name_ = op.value.value_string;
|
||||
return true;
|
||||
}
|
||||
gbString e = expr_to_string(op.expr);
|
||||
gbString t = type_to_string(op.type);
|
||||
error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
String builtin_name = builtin_procs[id].name;
|
||||
|
||||
if (build_context.metrics.os != TargetOs_darwin) {
|
||||
// allow on doc generation (e.g. Metal stuff)
|
||||
if (build_context.command_kind != Command_doc && build_context.command_kind != Command_check) {
|
||||
error(call, "'%.*s' only works on darwin", LIT(builtin_name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ast_node(ce, CallExpr, call);
|
||||
switch (id) {
|
||||
default:
|
||||
GB_PANIC("Implement objective built-in procedure: %.*s", LIT(builtin_name));
|
||||
return false;
|
||||
|
||||
case BuiltinProc_objc_send: {
|
||||
Type *return_type = nullptr;
|
||||
|
||||
Operand rt = {};
|
||||
check_expr_or_type(c, &rt, ce->args[0]);
|
||||
if (rt.mode == Addressing_Type) {
|
||||
return_type = rt.type;
|
||||
} else if (is_operand_nil(rt)) {
|
||||
return_type = nullptr;
|
||||
} else {
|
||||
gbString e = expr_to_string(rt.expr);
|
||||
error(rt.expr, "'%.*s' expected a type or nil to define the return type of the Objective-C call, got %s", LIT(builtin_name), e);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->type = return_type;
|
||||
operand->mode = return_type ? Addressing_Value : Addressing_NoValue;
|
||||
|
||||
String class_name = {};
|
||||
String sel_name = {};
|
||||
|
||||
Type *sel_type = t_objc_SEL;
|
||||
Operand self = {};
|
||||
check_expr_or_type(c, &self, ce->args[1]);
|
||||
if (self.mode == Addressing_Type) {
|
||||
if (!is_type_objc_object(self.type)) {
|
||||
gbString t = type_to_string(self.type);
|
||||
error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got type %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
if (!has_type_got_objc_class_attribute(self.type)) {
|
||||
gbString t = type_to_string(self.type);
|
||||
error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=<string>) , got type %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_type = t_objc_Class;
|
||||
} else if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) {
|
||||
gbString e = expr_to_string(self.expr);
|
||||
gbString t = type_to_string(self.type);
|
||||
error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
} else if (!is_type_pointer(self.type)) {
|
||||
gbString e = expr_to_string(self.expr);
|
||||
gbString t = type_to_string(self.type);
|
||||
error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
} else {
|
||||
Type *type = type_deref(self.type);
|
||||
if (!(type->kind == Type_Named &&
|
||||
type->Named.type_name != nullptr &&
|
||||
type->Named.type_name->TypeName.objc_class_name != "")) {
|
||||
gbString t = type_to_string(type);
|
||||
error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=<string>) , got type %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!is_constant_string(c, builtin_name, ce->args[2], &sel_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isize const arg_offset = 1;
|
||||
auto param_types = slice_make<Type *>(permanent_allocator(), ce->args.count-arg_offset);
|
||||
param_types[0] = t_objc_id;
|
||||
param_types[1] = sel_type;
|
||||
|
||||
for (isize i = 2+arg_offset; i < ce->args.count; i++) {
|
||||
Operand x = {};
|
||||
check_expr(c, &x, ce->args[i]);
|
||||
param_types[i-arg_offset] = x.type;
|
||||
}
|
||||
|
||||
add_objc_proc_type(c, call, return_type, param_types);
|
||||
|
||||
return true;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_objc_find_selector:
|
||||
case BuiltinProc_objc_find_class:
|
||||
case BuiltinProc_objc_register_selector:
|
||||
case BuiltinProc_objc_register_class:
|
||||
{
|
||||
String sel_name = {};
|
||||
if (!is_constant_string(c, builtin_name, ce->args[0], &sel_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case BuiltinProc_objc_find_selector:
|
||||
case BuiltinProc_objc_register_selector:
|
||||
operand->type = t_objc_SEL;
|
||||
break;
|
||||
case BuiltinProc_objc_find_class:
|
||||
case BuiltinProc_objc_register_class:
|
||||
operand->type = t_objc_Class;
|
||||
break;
|
||||
|
||||
}
|
||||
operand->mode = Addressing_Value;
|
||||
|
||||
try_to_add_package_dependency(c, "runtime", "objc_lookUpClass");
|
||||
try_to_add_package_dependency(c, "runtime", "sel_registerName");
|
||||
try_to_add_package_dependency(c, "runtime", "objc_allocateClassPair");
|
||||
return true;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
@@ -179,6 +414,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case BuiltinProc_len:
|
||||
case BuiltinProc_min:
|
||||
case BuiltinProc_max:
|
||||
case BuiltinProc_type_is_subtype_of:
|
||||
case BuiltinProc_objc_send:
|
||||
case BuiltinProc_objc_find_selector:
|
||||
case BuiltinProc_objc_find_class:
|
||||
case BuiltinProc_objc_register_selector:
|
||||
case BuiltinProc_objc_register_class:
|
||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||
break;
|
||||
|
||||
@@ -202,7 +443,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
break;
|
||||
}
|
||||
|
||||
String builtin_name = builtin_procs[id].name;;
|
||||
String builtin_name = builtin_procs[id].name;
|
||||
|
||||
|
||||
if (ce->args.count > 0) {
|
||||
@@ -219,6 +460,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name));
|
||||
break;
|
||||
|
||||
case BuiltinProc_objc_send:
|
||||
case BuiltinProc_objc_find_selector:
|
||||
case BuiltinProc_objc_find_class:
|
||||
case BuiltinProc_objc_register_selector:
|
||||
case BuiltinProc_objc_register_class:
|
||||
return check_builtin_objc_procedure(c, operand, call, id, type_hint);
|
||||
|
||||
case BuiltinProc___entry_point:
|
||||
operand->mode = Addressing_NoValue;
|
||||
operand->type = nullptr;
|
||||
@@ -858,7 +1106,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
Selection sel = lookup_field(type, field_name, false);
|
||||
if (sel.entity == nullptr) {
|
||||
gbString type_str = type_to_string(type);
|
||||
gbString type_str = type_to_string_shorthand(type);
|
||||
error(ce->args[0],
|
||||
"'%s' has no field named '%.*s'", type_str, LIT(field_name));
|
||||
gb_string_free(type_str);
|
||||
@@ -870,7 +1118,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
return false;
|
||||
}
|
||||
if (sel.indirect) {
|
||||
gbString type_str = type_to_string(type);
|
||||
gbString type_str = type_to_string_shorthand(type);
|
||||
error(ce->args[0],
|
||||
"Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str);
|
||||
gb_string_free(type_str);
|
||||
@@ -931,7 +1179,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
Selection sel = lookup_field(type, field_name, false);
|
||||
if (sel.entity == nullptr) {
|
||||
gbString type_str = type_to_string(type);
|
||||
gbString type_str = type_to_string_shorthand(type);
|
||||
error(ce->args[0],
|
||||
"'%s' has no field named '%.*s'", type_str, LIT(field_name));
|
||||
gb_string_free(type_str);
|
||||
@@ -943,7 +1191,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
return false;
|
||||
}
|
||||
if (sel.indirect) {
|
||||
gbString type_str = type_to_string(type);
|
||||
gbString type_str = type_to_string_shorthand(type);
|
||||
error(ce->args[0],
|
||||
"Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str);
|
||||
gb_string_free(type_str);
|
||||
@@ -3258,6 +3506,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case TargetOs_linux:
|
||||
case TargetOs_essence:
|
||||
case TargetOs_freebsd:
|
||||
case TargetOs_openbsd:
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_i386:
|
||||
case TargetArch_amd64:
|
||||
@@ -3344,9 +3593,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case BuiltinProc_type_is_simple_compare:
|
||||
case BuiltinProc_type_is_dereferenceable:
|
||||
case BuiltinProc_type_is_valid_map_key:
|
||||
case BuiltinProc_type_is_valid_matrix_elements:
|
||||
case BuiltinProc_type_is_named:
|
||||
case BuiltinProc_type_is_pointer:
|
||||
case BuiltinProc_type_is_array:
|
||||
case BuiltinProc_type_is_enumerated_array:
|
||||
case BuiltinProc_type_is_slice:
|
||||
case BuiltinProc_type_is_dynamic_array:
|
||||
case BuiltinProc_type_is_map:
|
||||
@@ -3354,10 +3605,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case BuiltinProc_type_is_union:
|
||||
case BuiltinProc_type_is_enum:
|
||||
case BuiltinProc_type_is_proc:
|
||||
case BuiltinProc_type_is_bit_field:
|
||||
case BuiltinProc_type_is_bit_field_value:
|
||||
case BuiltinProc_type_is_bit_set:
|
||||
case BuiltinProc_type_is_simd_vector:
|
||||
case BuiltinProc_type_is_matrix:
|
||||
case BuiltinProc_type_is_specialized_polymorphic_record:
|
||||
case BuiltinProc_type_is_unspecialized_polymorphic_record:
|
||||
case BuiltinProc_type_has_nil:
|
||||
@@ -3725,6 +3975,31 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
break;
|
||||
|
||||
case BuiltinProc_type_is_subtype_of:
|
||||
{
|
||||
Operand op_src = {};
|
||||
Operand op_dst = {};
|
||||
|
||||
check_expr_or_type(c, &op_src, ce->args[0]);
|
||||
if (op_src.mode != Addressing_Type) {
|
||||
gbString e = expr_to_string(op_src.expr);
|
||||
error(op_src.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
check_expr_or_type(c, &op_dst, ce->args[1]);
|
||||
if (op_dst.mode != Addressing_Type) {
|
||||
gbString e = expr_to_string(op_dst.expr);
|
||||
error(op_dst.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->value = exact_value_bool(is_type_subtype_of(op_src.type, op_dst.type));
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->type = t_untyped_bool;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_type_field_index_of:
|
||||
{
|
||||
Operand op = {};
|
||||
@@ -3814,6 +4089,20 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
operand->type = t_hasher_proc;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_constant_utf16_cstring:
|
||||
{
|
||||
String value = {};
|
||||
if (!is_constant_string(c, builtin_name, ce->args[0], &value)) {
|
||||
return false;
|
||||
}
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = alloc_type_multi_pointer(t_u16);
|
||||
operand->value = {};
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -174,6 +174,10 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_proc(e->type)) {
|
||||
error(e->token, "Illegal declaration of a constant procedure value");
|
||||
}
|
||||
|
||||
e->parent_proc_decl = ctx->curr_proc_decl;
|
||||
|
||||
e->Constant.value = operand->value;
|
||||
@@ -338,6 +342,13 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
|
||||
if (decl != nullptr) {
|
||||
AttributeContext ac = {};
|
||||
check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac);
|
||||
if (e->kind == Entity_TypeName && ac.objc_class != "") {
|
||||
e->TypeName.objc_class_name = ac.objc_class;
|
||||
|
||||
if (type_size_of(e->type) > 0) {
|
||||
error(e->token, "@(objc_class) marked type must be of zero size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -819,6 +830,63 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode;
|
||||
|
||||
if (ac.objc_name.len || ac.objc_is_class_method || ac.objc_type) {
|
||||
if (ac.objc_name.len == 0 && ac.objc_is_class_method) {
|
||||
error(e->token, "@(objc_name) is required with @(objc_is_class_method)");
|
||||
} else if (ac.objc_type == nullptr) {
|
||||
error(e->token, "@(objc_name) requires that @(objc_type) to be set");
|
||||
} else if (ac.objc_name.len == 0 && ac.objc_type) {
|
||||
error(e->token, "@(objc_name) is required with @(objc_type)");
|
||||
} else {
|
||||
Type *t = ac.objc_type;
|
||||
if (t->kind == Type_Named) {
|
||||
Entity *tn = t->Named.type_name;
|
||||
|
||||
GB_ASSERT(tn->kind == Entity_TypeName);
|
||||
|
||||
if (tn->scope != e->scope) {
|
||||
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
|
||||
} else {
|
||||
mutex_lock(&global_type_name_objc_metadata_mutex);
|
||||
defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
|
||||
|
||||
if (!tn->TypeName.objc_metadata) {
|
||||
tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
|
||||
}
|
||||
auto *md = tn->TypeName.objc_metadata;
|
||||
mutex_lock(md->mutex);
|
||||
defer (mutex_unlock(md->mutex));
|
||||
|
||||
if (!ac.objc_is_class_method) {
|
||||
bool ok = true;
|
||||
for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
|
||||
if (entry.name == ac.objc_name) {
|
||||
error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
|
||||
}
|
||||
} else {
|
||||
bool ok = true;
|
||||
for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
|
||||
if (entry.name == ac.objc_name) {
|
||||
error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (e->Procedure.optimization_mode) {
|
||||
case ProcedureOptimizationMode_None:
|
||||
|
||||
+73
-44
@@ -132,6 +132,62 @@ void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
|
||||
}
|
||||
}
|
||||
|
||||
void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_type) {
|
||||
if (e->kind != Entity_TypeName) {
|
||||
return;
|
||||
}
|
||||
if (e->TypeName.objc_metadata == nullptr) {
|
||||
return;
|
||||
}
|
||||
TypeNameObjCMetadata *objc_metadata = e->TypeName.objc_metadata;
|
||||
Type *t = base_type(e->type);
|
||||
GB_ASSERT(t->kind == Type_Struct);
|
||||
|
||||
if (is_type) {
|
||||
for_array(i, objc_metadata->type_entries) {
|
||||
String name = objc_metadata->type_entries[i].name;
|
||||
string_set_add(set, name);
|
||||
}
|
||||
} else {
|
||||
for_array(i, objc_metadata->value_entries) {
|
||||
String name = objc_metadata->value_entries[i].name;
|
||||
string_set_add(set, name);
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
if (f->flags & EntityFlag_Using && f->type != nullptr) {
|
||||
if (f->type->kind == Type_Named && f->type->Named.type_name) {
|
||||
populate_check_did_you_mean_objc_entity(set, f->type->Named.type_name, is_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
|
||||
ERROR_BLOCK();
|
||||
GB_ASSERT(e->kind == Entity_TypeName);
|
||||
GB_ASSERT(e->TypeName.objc_metadata != nullptr);
|
||||
auto *objc_metadata = e->TypeName.objc_metadata;
|
||||
mutex_lock(objc_metadata->mutex);
|
||||
defer (mutex_unlock(objc_metadata->mutex));
|
||||
|
||||
StringSet set = {};
|
||||
string_set_init(&set, heap_allocator());
|
||||
defer (string_set_destroy(&set));
|
||||
populate_check_did_you_mean_objc_entity(&set, e, is_type);
|
||||
|
||||
|
||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), set.entries.count, name);
|
||||
defer (did_you_mean_destroy(&d));
|
||||
for_array(i, set.entries) {
|
||||
did_you_mean_append(&d, set.entries[i].value);
|
||||
}
|
||||
check_did_you_mean_print(&d, prefix);
|
||||
}
|
||||
|
||||
void check_did_you_mean_type(String const &name, Array<Entity *> const &fields, char const *prefix = "") {
|
||||
ERROR_BLOCK();
|
||||
|
||||
@@ -144,6 +200,7 @@ void check_did_you_mean_type(String const &name, Array<Entity *> const &fields,
|
||||
check_did_you_mean_print(&d, prefix);
|
||||
}
|
||||
|
||||
|
||||
void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields, char const *prefix = "") {
|
||||
ERROR_BLOCK();
|
||||
|
||||
@@ -228,42 +285,6 @@ void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes, isize reser
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) {
|
||||
Type *prev_src = src;
|
||||
src = type_deref(src);
|
||||
if (!src_is_ptr) {
|
||||
src_is_ptr = src != prev_src;
|
||||
}
|
||||
src = base_type(src);
|
||||
|
||||
if (!is_type_struct(src)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for_array(i, src->Struct.fields) {
|
||||
Entity *f = src->Struct.fields[i];
|
||||
if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (are_types_identical(f->type, dst)) {
|
||||
return level+1;
|
||||
}
|
||||
if (src_is_ptr && is_type_pointer(dst)) {
|
||||
if (are_types_identical(f->type, type_deref(dst))) {
|
||||
return level+1;
|
||||
}
|
||||
}
|
||||
isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr);
|
||||
if (nested_level > 0) {
|
||||
return nested_level;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_entity, Type *type,
|
||||
Array<Operand> *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -4449,14 +4470,19 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
|
||||
if (entity == nullptr) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gbString type_str = type_to_string_shorthand(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
|
||||
|
||||
if (operand->type != nullptr && selector->kind == Ast_Ident) {
|
||||
String const &name = selector->Ident.token.string;
|
||||
Type *bt = base_type(operand->type);
|
||||
if (bt->kind == Type_Struct) {
|
||||
if (operand->type->kind == Type_Named &&
|
||||
operand->type->Named.type_name &&
|
||||
operand->type->Named.type_name->kind == Entity_TypeName &&
|
||||
operand->type->Named.type_name->TypeName.objc_metadata) {
|
||||
check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type);
|
||||
} else if (bt->kind == Type_Struct) {
|
||||
check_did_you_mean_type(name, bt->Struct.fields);
|
||||
} else if (bt->kind == Type_Enum) {
|
||||
check_did_you_mean_type(name, bt->Enum.fields);
|
||||
@@ -4485,7 +4511,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
}
|
||||
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gbString type_str = type_to_string_shorthand(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
|
||||
gb_string_free(sel_str);
|
||||
@@ -4510,7 +4536,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
}
|
||||
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gbString type_str = type_to_string_shorthand(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
|
||||
gb_string_free(sel_str);
|
||||
@@ -4523,7 +4549,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
|
||||
if (expr_entity != nullptr && is_type_polymorphic(expr_entity->type)) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gbString type_str = type_to_string_shorthand(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(op_expr, "Cannot access field '%s' from non-specialized polymorphic type '%s'", sel_str, op_str);
|
||||
gb_string_free(sel_str);
|
||||
@@ -6432,10 +6458,10 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr
|
||||
return builtin_procs[id].kind;
|
||||
}
|
||||
|
||||
Entity *e = entity_of_node(operand->expr);
|
||||
Entity *initial_entity = entity_of_node(operand->expr);
|
||||
|
||||
if (e != nullptr && e->kind == Entity_Procedure) {
|
||||
if (e->Procedure.deferred_procedure.entity != nullptr) {
|
||||
if (initial_entity != nullptr && initial_entity->kind == Entity_Procedure) {
|
||||
if (initial_entity->Procedure.deferred_procedure.entity != nullptr) {
|
||||
call->viral_state_flags |= ViralStateFlag_ContainsDeferredProcedure;
|
||||
}
|
||||
}
|
||||
@@ -9810,6 +9836,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
|
||||
if (f->flags&FieldFlag_const) {
|
||||
str = gb_string_appendc(str, "#const ");
|
||||
}
|
||||
if (f->flags&FieldFlag_subtype) {
|
||||
str = gb_string_appendc(str, "#subtype ");
|
||||
}
|
||||
|
||||
for_array(i, f->names) {
|
||||
Ast *name = f->names[i];
|
||||
|
||||
@@ -144,6 +144,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
|
||||
}
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
bool is_subtype = (p->flags&FieldFlag_subtype) != 0;
|
||||
|
||||
for_array(j, p->names) {
|
||||
Ast *name = p->names[j];
|
||||
@@ -158,6 +159,9 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
|
||||
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
|
||||
add_entity(ctx, ctx->scope, name, field);
|
||||
field->Variable.field_group_index = field_group_index;
|
||||
if (is_subtype) {
|
||||
field->flags |= EntityFlag_Subtype;
|
||||
}
|
||||
|
||||
if (j == 0) {
|
||||
field->Variable.docs = docs;
|
||||
@@ -194,6 +198,20 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
|
||||
|
||||
populate_using_entity_scope(ctx, node, p, type);
|
||||
}
|
||||
|
||||
if (is_subtype && p->names.count > 0) {
|
||||
Type *first_type = fields_array[fields_array.count-1]->type;
|
||||
Type *t = base_type(type_deref(first_type));
|
||||
|
||||
if (!does_field_type_allow_using(t) &&
|
||||
p->names.count >= 1 &&
|
||||
p->names[0]->kind == Ast_Ident) {
|
||||
Token name_token = p->names[0]->Ident.token;
|
||||
gbString type_str = type_to_string(first_type);
|
||||
error(name_token, "'subtype' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
|
||||
gb_string_free(type_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fields = slice_from_array(fields_array);
|
||||
@@ -323,6 +341,10 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
|
||||
}
|
||||
|
||||
named_type->Named.type_name = e;
|
||||
GB_ASSERT(original_type->kind == Type_Named);
|
||||
e->TypeName.objc_class_name = original_type->Named.type_name->TypeName.objc_class_name;
|
||||
// TODO(bill): Is this even correct? Or should the metadata be copied?
|
||||
e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata;
|
||||
|
||||
mutex_lock(&ctx->info->gen_types_mutex);
|
||||
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
|
||||
@@ -1906,6 +1928,25 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
||||
c->scope->flags &= ~ScopeFlag_ContextDefined;
|
||||
}
|
||||
|
||||
TargetArchKind arch = build_context.metrics.arch;
|
||||
switch (cc) {
|
||||
case ProcCC_StdCall:
|
||||
case ProcCC_FastCall:
|
||||
if (arch != TargetArch_i386 && arch != TargetArch_amd64) {
|
||||
error(proc_type_node, "Invalid procedure calling convention \"%s\" for target architecture, expected either i386 or amd64, got %.*s",
|
||||
proc_calling_convention_strings[cc], LIT(target_arch_names[arch]));
|
||||
}
|
||||
break;
|
||||
case ProcCC_Win64:
|
||||
case ProcCC_SysV:
|
||||
if (arch != TargetArch_amd64) {
|
||||
error(proc_type_node, "Invalid procedure calling convention \"%s\" for target architecture, expected amd64, got %.*s",
|
||||
proc_calling_convention_strings[cc], LIT(target_arch_names[arch]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
bool variadic = false;
|
||||
isize variadic_index = -1;
|
||||
bool success = true;
|
||||
|
||||
+136
-11
@@ -4,7 +4,7 @@
|
||||
void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
|
||||
void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
|
||||
void add_comparison_procedures_for_fields(CheckerContext *c, Type *t);
|
||||
|
||||
Type *check_type(CheckerContext *ctx, Ast *e);
|
||||
|
||||
bool is_operand_value(Operand o) {
|
||||
switch (o.mode) {
|
||||
@@ -225,8 +225,8 @@ bool decl_info_has_init(DeclInfo *d) {
|
||||
Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) {
|
||||
Scope *s = gb_alloc_item(permanent_allocator(), Scope);
|
||||
s->parent = parent;
|
||||
string_map_init(&s->elements, permanent_allocator(), init_elements_capacity);
|
||||
ptr_set_init(&s->imported, permanent_allocator(), 0);
|
||||
string_map_init(&s->elements, heap_allocator(), init_elements_capacity);
|
||||
ptr_set_init(&s->imported, heap_allocator(), 0);
|
||||
mutex_init(&s->mutex);
|
||||
|
||||
if (parent != nullptr && parent != builtin_pkg->scope) {
|
||||
@@ -733,12 +733,25 @@ void add_package_dependency(CheckerContext *c, char const *package_name, char co
|
||||
String n = make_string_c(name);
|
||||
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
|
||||
Entity *e = scope_lookup(p->scope, n);
|
||||
e->flags |= EntityFlag_Used;
|
||||
GB_ASSERT_MSG(e != nullptr, "%s", name);
|
||||
GB_ASSERT(c->decl != nullptr);
|
||||
e->flags |= EntityFlag_Used;
|
||||
add_dependency(c->info, c->decl, e);
|
||||
}
|
||||
|
||||
void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) {
|
||||
String n = make_string_c(name);
|
||||
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
|
||||
Entity *e = scope_lookup(p->scope, n);
|
||||
if (e == nullptr) {
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(c->decl != nullptr);
|
||||
e->flags |= EntityFlag_Used;
|
||||
add_dependency(c->info, c->decl, e);
|
||||
}
|
||||
|
||||
|
||||
void add_declaration_dependency(CheckerContext *c, Entity *e) {
|
||||
if (e == nullptr) {
|
||||
return;
|
||||
@@ -841,6 +854,17 @@ void add_global_enum_constant(Slice<Entity *> const &fields, char const *name, i
|
||||
GB_PANIC("Unfound enum value for global constant: %s %lld", name, cast(long long)value);
|
||||
}
|
||||
|
||||
Type *add_global_type_name(Scope *scope, String const &type_name, Type *backing_type) {
|
||||
Entity *e = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved);
|
||||
Type *named_type = alloc_type_named(type_name, backing_type, e);
|
||||
e->type = named_type;
|
||||
set_base_type(named_type, backing_type);
|
||||
if (scope_insert(scope, e)) {
|
||||
compiler_error("double declaration of %.*s", LIT(e->token.string));
|
||||
}
|
||||
return named_type;
|
||||
}
|
||||
|
||||
|
||||
void init_universal(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
@@ -870,11 +894,43 @@ void init_universal(void) {
|
||||
add_global_bool_constant("false", false);
|
||||
|
||||
// TODO(bill): Set through flags in the compiler
|
||||
add_global_string_constant("ODIN_OS", bc->ODIN_OS);
|
||||
add_global_string_constant("ODIN_ARCH", bc->ODIN_ARCH);
|
||||
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
|
||||
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
|
||||
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
|
||||
|
||||
{
|
||||
GlobalEnumValue values[TargetOs_COUNT] = {
|
||||
{"Unknown", TargetOs_Invalid},
|
||||
{"Windows", TargetOs_windows},
|
||||
{"Darwin", TargetOs_darwin},
|
||||
{"Linux", TargetOs_linux},
|
||||
{"Essence", TargetOs_essence},
|
||||
{"FreeBSD", TargetOs_freebsd},
|
||||
{"OpenBSD", TargetOs_openbsd},
|
||||
{"WASI", TargetOs_wasi},
|
||||
{"JS", TargetOs_js},
|
||||
{"Freestanding", TargetOs_freestanding},
|
||||
};
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Odin_OS_Type"), values, gb_count_of(values));
|
||||
add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os);
|
||||
add_global_string_constant("ODIN_OS_STRING", target_os_names[bc->metrics.os]);
|
||||
}
|
||||
|
||||
{
|
||||
GlobalEnumValue values[TargetArch_COUNT] = {
|
||||
{"Unknown", TargetArch_Invalid},
|
||||
{"amd64", TargetArch_amd64},
|
||||
{"i386", TargetArch_i386},
|
||||
{"arm64", TargetArch_arm64},
|
||||
{"wasm32", TargetArch_wasm32},
|
||||
{"wasm64", TargetArch_wasm64},
|
||||
};
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Odin_Arch_Type"), values, gb_count_of(values));
|
||||
add_global_enum_constant(fields, "ODIN_ARCH", bc->metrics.arch);
|
||||
add_global_string_constant("ODIN_ARCH_STRING", target_arch_names[bc->metrics.arch]);
|
||||
}
|
||||
|
||||
{
|
||||
GlobalEnumValue values[BuildMode_COUNT] = {
|
||||
@@ -889,7 +945,6 @@ void init_universal(void) {
|
||||
add_global_enum_constant(fields, "ODIN_BUILD_MODE", bc->build_mode);
|
||||
}
|
||||
|
||||
add_global_string_constant("ODIN_ENDIAN_STRING", target_endian_names[target_endians[bc->metrics.arch]]);
|
||||
{
|
||||
GlobalEnumValue values[TargetEndian_COUNT] = {
|
||||
{"Unknown", TargetEndian_Invalid},
|
||||
@@ -900,6 +955,7 @@ void init_universal(void) {
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Odin_Endian_Type"), values, gb_count_of(values));
|
||||
add_global_enum_constant(fields, "ODIN_ENDIAN", target_endians[bc->metrics.arch]);
|
||||
add_global_string_constant("ODIN_ENDIAN_STRING", target_endian_names[target_endians[bc->metrics.arch]]);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -985,6 +1041,17 @@ void init_universal(void) {
|
||||
t_f64_ptr = alloc_type_pointer(t_f64);
|
||||
t_u8_slice = alloc_type_slice(t_u8);
|
||||
t_string_slice = alloc_type_slice(t_string);
|
||||
|
||||
// intrinsics types for objective-c stuff
|
||||
{
|
||||
t_objc_object = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_object"), alloc_type_struct());
|
||||
t_objc_selector = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_selector"), alloc_type_struct());
|
||||
t_objc_class = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_class"), alloc_type_struct());
|
||||
|
||||
t_objc_id = alloc_type_pointer(t_objc_object);
|
||||
t_objc_SEL = alloc_type_pointer(t_objc_selector);
|
||||
t_objc_Class = alloc_type_pointer(t_objc_class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1041,6 +1108,9 @@ void init_checker_info(CheckerInfo *i) {
|
||||
semaphore_init(&i->collect_semaphore);
|
||||
|
||||
mpmc_init(&i->intrinsics_entry_point_usage, a, 1<<10); // just waste some memory here, even if it probably never used
|
||||
|
||||
mutex_init(&i->objc_types_mutex);
|
||||
map_init(&i->objc_msgSend_types, a);
|
||||
}
|
||||
|
||||
void destroy_checker_info(CheckerInfo *i) {
|
||||
@@ -1073,6 +1143,9 @@ void destroy_checker_info(CheckerInfo *i) {
|
||||
mutex_destroy(&i->type_and_value_mutex);
|
||||
mutex_destroy(&i->identifier_uses_mutex);
|
||||
mutex_destroy(&i->foreign_mutex);
|
||||
|
||||
mutex_destroy(&i->objc_types_mutex);
|
||||
map_destroy(&i->objc_msgSend_types);
|
||||
}
|
||||
|
||||
CheckerContext make_checker_context(Checker *c) {
|
||||
@@ -2712,6 +2785,14 @@ ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) {
|
||||
return ev;
|
||||
}
|
||||
|
||||
Type *check_decl_attribute_type(CheckerContext *c, Ast *value) {
|
||||
if (value != nullptr) {
|
||||
return check_type(c, value);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
#define ATTRIBUTE_USER_TAG_NAME "tag"
|
||||
|
||||
|
||||
@@ -3011,6 +3092,42 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
error(elem, "Expected a string for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "objc_name") {
|
||||
ExactValue ev = check_decl_attribute_value(c, value);
|
||||
if (ev.kind == ExactValue_String) {
|
||||
if (string_is_valid_identifier(ev.value_string)) {
|
||||
ac->objc_name = ev.value_string;
|
||||
} else {
|
||||
error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string));
|
||||
}
|
||||
} else {
|
||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "objc_is_class_method") {
|
||||
ExactValue ev = check_decl_attribute_value(c, value);
|
||||
if (ev.kind == ExactValue_Bool) {
|
||||
ac->objc_is_class_method = ev.value_bool;
|
||||
} else {
|
||||
error(elem, "Expected a boolean value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "objc_type") {
|
||||
if (value == nullptr) {
|
||||
error(elem, "Expected a type for '%.*s'", LIT(name));
|
||||
} else {
|
||||
Type *objc_type = check_type(c, value);
|
||||
if (objc_type != nullptr) {
|
||||
if (!has_type_got_objc_class_attribute(objc_type)) {
|
||||
gbString t = type_to_string(objc_type);
|
||||
error(value, "'%.*s' expected a named type with the attribute @(obj_class=<string>), got type %s", LIT(name), t);
|
||||
gb_string_free(t);
|
||||
} else {
|
||||
ac->objc_type = objc_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -3161,6 +3278,14 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) {
|
||||
} else if (name == "private") {
|
||||
// NOTE(bill): Handled elsewhere `check_collect_value_decl`
|
||||
return true;
|
||||
} else if (name == "objc_class") {
|
||||
ExactValue ev = check_decl_attribute_value(c, value);
|
||||
if (ev.kind != ExactValue_String || ev.value_string == "") {
|
||||
error(elem, "Expected a non-empty string value for '%.*s'", LIT(name));
|
||||
} else {
|
||||
ac->objc_class = ev.value_string;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -3477,11 +3602,11 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
if (entity_visibility_kind == EntityVisiblity_Public &&
|
||||
(c->scope->flags&ScopeFlag_File) &&
|
||||
c->scope->file) {
|
||||
if (c->scope->file->flags & AstFile_IsPrivatePkg) {
|
||||
entity_visibility_kind = EntityVisiblity_PrivateToPackage;
|
||||
} else if (c->scope->file->flags & AstFile_IsPrivateFile) {
|
||||
if (c->scope->file->flags & AstFile_IsPrivateFile) {
|
||||
entity_visibility_kind = EntityVisiblity_PrivateToFile;
|
||||
}
|
||||
} else if (c->scope->file->flags & AstFile_IsPrivatePkg) {
|
||||
entity_visibility_kind = EntityVisiblity_PrivateToPackage;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity_visibility_kind != EntityVisiblity_Public && !(c->scope->flags&ScopeFlag_File)) {
|
||||
|
||||
+18
-1
@@ -118,6 +118,11 @@ struct AttributeContext {
|
||||
bool init : 1;
|
||||
bool set_cold : 1;
|
||||
u32 optimization_mode; // ProcedureOptimizationMode
|
||||
|
||||
String objc_class;
|
||||
String objc_name;
|
||||
bool objc_is_class_method;
|
||||
Type * objc_type;
|
||||
};
|
||||
|
||||
AttributeContext make_attribute_context(String link_prefix) {
|
||||
@@ -267,6 +272,17 @@ struct UntypedExprInfo {
|
||||
typedef PtrMap<Ast *, ExprInfo *> UntypedExprInfoMap;
|
||||
typedef MPMCQueue<ProcInfo *> ProcBodyQueue;
|
||||
|
||||
enum ObjcMsgKind : u32 {
|
||||
ObjcMsg_normal,
|
||||
ObjcMsg_fpret,
|
||||
ObjcMsg_fp2ret,
|
||||
ObjcMsg_stret,
|
||||
};
|
||||
struct ObjcMsgData {
|
||||
ObjcMsgKind kind;
|
||||
Type *proc_type;
|
||||
};
|
||||
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
struct CheckerInfo {
|
||||
Checker *checker;
|
||||
@@ -340,7 +356,8 @@ struct CheckerInfo {
|
||||
|
||||
MPMCQueue<Ast *> intrinsics_entry_point_usage;
|
||||
|
||||
|
||||
BlockingMutex objc_types_mutex;
|
||||
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
|
||||
@@ -213,8 +213,6 @@ BuiltinProc__type_simple_boolean_begin,
|
||||
BuiltinProc_type_is_union,
|
||||
BuiltinProc_type_is_enum,
|
||||
BuiltinProc_type_is_proc,
|
||||
BuiltinProc_type_is_bit_field,
|
||||
BuiltinProc_type_is_bit_field_value,
|
||||
BuiltinProc_type_is_bit_set,
|
||||
BuiltinProc_type_is_simd_vector,
|
||||
BuiltinProc_type_is_matrix,
|
||||
@@ -243,6 +241,8 @@ BuiltinProc__type_simple_boolean_end,
|
||||
BuiltinProc_type_polymorphic_record_parameter_count,
|
||||
BuiltinProc_type_polymorphic_record_parameter_value,
|
||||
|
||||
BuiltinProc_type_is_subtype_of,
|
||||
|
||||
BuiltinProc_type_field_index_of,
|
||||
|
||||
BuiltinProc_type_equal_proc,
|
||||
@@ -252,6 +252,15 @@ BuiltinProc__type_end,
|
||||
|
||||
BuiltinProc___entry_point,
|
||||
|
||||
BuiltinProc_objc_send,
|
||||
BuiltinProc_objc_find_selector,
|
||||
BuiltinProc_objc_find_class,
|
||||
BuiltinProc_objc_register_selector,
|
||||
BuiltinProc_objc_register_class,
|
||||
|
||||
BuiltinProc_constant_utf16_cstring,
|
||||
|
||||
|
||||
BuiltinProc_COUNT,
|
||||
};
|
||||
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
@@ -466,8 +475,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_is_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_field_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
@@ -495,6 +502,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_polymorphic_record_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_is_subtype_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
@@ -504,4 +513,14 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("objc_find_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
};
|
||||
|
||||
+2
-2
@@ -848,7 +848,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
|
||||
return ReadDirectory_None;
|
||||
}
|
||||
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD)
|
||||
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
@@ -1021,7 +1021,7 @@ LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_fil
|
||||
#endif
|
||||
}
|
||||
|
||||
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, fullpath);
|
||||
gbFileContents fc = gb_file_read_contents(permanent_allocator(), true, fullpath);
|
||||
|
||||
if (fc.size > I32_MAX) {
|
||||
err = LoadedFile_FileTooLarge;
|
||||
|
||||
+17
-2
@@ -139,6 +139,7 @@ struct PlatformMemoryBlock {
|
||||
};
|
||||
|
||||
|
||||
gb_global std::atomic<isize> global_platform_memory_total_usage;
|
||||
gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
|
||||
|
||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
|
||||
@@ -158,10 +159,17 @@ void platform_virtual_memory_protect(void *memory, isize size);
|
||||
|
||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
|
||||
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
|
||||
if (pmblock == nullptr) {
|
||||
gb_printf_err("Out of Virtual memory, oh no...\n");
|
||||
gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size);
|
||||
gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
|
||||
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
|
||||
}
|
||||
global_platform_memory_total_usage += total_size;
|
||||
return pmblock;
|
||||
}
|
||||
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||
global_platform_memory_total_usage -= block->total_size;
|
||||
GB_ASSERT(VirtualFree(block, 0, MEM_RELEASE));
|
||||
}
|
||||
void platform_virtual_memory_protect(void *memory, isize size) {
|
||||
@@ -180,11 +188,18 @@ void platform_virtual_memory_protect(void *memory, isize size);
|
||||
|
||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
|
||||
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
|
||||
if (pmblock == nullptr) {
|
||||
gb_printf_err("Out of Virtual memory, oh no...\n");
|
||||
gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size);
|
||||
gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
|
||||
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
|
||||
}
|
||||
global_platform_memory_total_usage += total_size;
|
||||
return pmblock;
|
||||
}
|
||||
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||
isize size = block->total_size;
|
||||
global_platform_memory_total_usage -= size;
|
||||
munmap(block, size);
|
||||
}
|
||||
void platform_virtual_memory_protect(void *memory, isize size) {
|
||||
|
||||
+1
-34
@@ -683,40 +683,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
types[1] = odin_doc_type(w, type->Proc.results);
|
||||
doc_type.types = odin_write_slice(w, types, gb_count_of(types));
|
||||
|
||||
String calling_convention = {};
|
||||
switch (type->Proc.calling_convention) {
|
||||
case ProcCC_Invalid:
|
||||
// no need
|
||||
break;
|
||||
case ProcCC_Odin:
|
||||
if (default_calling_convention() != ProcCC_Odin) {
|
||||
calling_convention = str_lit("odin");
|
||||
}
|
||||
break;
|
||||
case ProcCC_Contextless:
|
||||
if (default_calling_convention() != ProcCC_Contextless) {
|
||||
calling_convention = str_lit("contextless");
|
||||
}
|
||||
break;
|
||||
case ProcCC_CDecl:
|
||||
calling_convention = str_lit("cdecl");
|
||||
break;
|
||||
case ProcCC_StdCall:
|
||||
calling_convention = str_lit("stdcall");
|
||||
break;
|
||||
case ProcCC_FastCall:
|
||||
calling_convention = str_lit("fastcall");
|
||||
break;
|
||||
case ProcCC_None:
|
||||
calling_convention = str_lit("none");
|
||||
break;
|
||||
case ProcCC_Naked:
|
||||
calling_convention = str_lit("naked");
|
||||
break;
|
||||
case ProcCC_InlineAsm:
|
||||
calling_convention = str_lit("inline-assembly");
|
||||
break;
|
||||
}
|
||||
String calling_convention = make_string_c(proc_calling_convention_strings[type->Proc.calling_convention]);
|
||||
doc_type.calling_convention = odin_doc_write_string(w, calling_convention);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -74,6 +74,7 @@ enum EntityFlag : u64 {
|
||||
|
||||
EntityFlag_Test = 1ull<<30,
|
||||
EntityFlag_Init = 1ull<<31,
|
||||
EntityFlag_Subtype = 1ull<<32,
|
||||
|
||||
EntityFlag_CustomLinkName = 1ull<<40,
|
||||
EntityFlag_CustomLinkage_Internal = 1ull<<41,
|
||||
@@ -86,6 +87,10 @@ enum EntityFlag : u64 {
|
||||
EntityFlag_Overridden = 1ull<<63,
|
||||
};
|
||||
|
||||
enum : u64 {
|
||||
EntityFlags_IsSubtype = EntityFlag_Using|EntityFlag_Subtype,
|
||||
};
|
||||
|
||||
enum EntityState : u32 {
|
||||
EntityState_Unresolved = 0,
|
||||
EntityState_InProgress = 1,
|
||||
@@ -122,6 +127,28 @@ enum ProcedureOptimizationMode : u32 {
|
||||
ProcedureOptimizationMode_Speed,
|
||||
};
|
||||
|
||||
|
||||
BlockingMutex global_type_name_objc_metadata_mutex;
|
||||
|
||||
struct TypeNameObjCMetadataEntry {
|
||||
String name;
|
||||
Entity *entity;
|
||||
};
|
||||
struct TypeNameObjCMetadata {
|
||||
BlockingMutex *mutex;
|
||||
Array<TypeNameObjCMetadataEntry> type_entries;
|
||||
Array<TypeNameObjCMetadataEntry> value_entries;
|
||||
};
|
||||
|
||||
TypeNameObjCMetadata *create_type_name_obj_c_metadata() {
|
||||
TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata);
|
||||
md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex);
|
||||
mutex_init(md->mutex);
|
||||
array_init(&md->type_entries, heap_allocator());
|
||||
array_init(&md->value_entries, heap_allocator());
|
||||
return md;
|
||||
}
|
||||
|
||||
// An Entity is a named "thing" in the language
|
||||
struct Entity {
|
||||
EntityKind kind;
|
||||
@@ -186,6 +213,8 @@ struct Entity {
|
||||
Type * type_parameter_specialization;
|
||||
String ir_mangled_name;
|
||||
bool is_type_alias;
|
||||
String objc_class_name;
|
||||
TypeNameObjCMetadata *objc_metadata;
|
||||
} TypeName;
|
||||
struct {
|
||||
u64 tags;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user