Merge branch 'master' into bill/sdl3

This commit is contained in:
gingerBill
2025-01-30 10:37:21 +00:00
68 changed files with 580 additions and 132 deletions

View File

@@ -210,10 +210,24 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case size == 0:
err = .Mode_Not_Implemented
return
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
// shrink data in-place
data = old_data[:size]
return
case uintptr(old_data) & uintptr(alignment-1) == 0:
if size < old_size {
// shrink data in-place
data = old_data[:size]
return
}
if block := arena.curr_block; block != nil {
start := uint(uintptr(old_memory)) - uint(uintptr(block.base))
old_end := start + old_size
new_end := start + size
if start < old_end && old_end == block.used && new_end <= block.capacity {
// grow data in-place, adjusting next allocation
block.used = uint(new_end)
data = block.base[start:new_end]
return
}
}
}
new_memory := arena_alloc(arena, size, alignment, location) or_return

View File

@@ -9,7 +9,7 @@ set -eu
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
CXXFLAGS="$CXXFLAGS -std=c++14"
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
LDFLAGS="$LDFLAGS -pthread -lm"
OS_ARCH="$(uname -m)"
OS_NAME="$(uname -s)"
@@ -95,15 +95,15 @@ Darwin)
;;
FreeBSD)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
LDFLAGS="$LDFLAGS -lstdc++ $($LLVM_CONFIG --libs core native --system-libs)"
;;
NetBSD)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
LDFLAGS="$LDFLAGS -lstdc++ $($LLVM_CONFIG --libs core native --system-libs)"
;;
Linux)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)"
LDFLAGS="$LDFLAGS -lstdc++ -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)"
# Copy libLLVM*.so into current directory for linking
# NOTE: This is needed by the Linux release pipeline!
# cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./
@@ -111,12 +111,12 @@ Linux)
;;
OpenBSD)
CXXFLAGS="$CXXFLAGS -I/usr/local/include $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -L/usr/local/lib -liconv"
LDFLAGS="$LDFLAGS -lstdc++ -L/usr/local/lib -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;;
Haiku)
CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE $($LLVM_CONFIG --cxxflags --ldflags) -I/system/develop/headers/private/shared -I/system/develop/headers/private/kernel"
LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS -lstdc++ -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;;
*)

View File

@@ -114,3 +114,5 @@ CHAR_BIT :: 8
va_list :: struct #align(16) {
_: [4096]u8,
}
FILE :: struct {}

View File

@@ -1,5 +1,6 @@
package libc
import "core:c"
import "core:io"
when ODIN_OS == .Windows {
@@ -15,7 +16,7 @@ when ODIN_OS == .Windows {
// 7.21 Input/output
FILE :: struct {}
FILE :: c.FILE
Whence :: enum int {
SET = SEEK_SET,

View File

@@ -1379,9 +1379,9 @@ _pad :: proc(fi: ^Info, s: string) {
if fi.minus { // right pad
io.write_string(fi.writer, s, &fi.n)
fmt_write_padding(fi, width)
} else if !fi.space && s != "" && s[0] == '-' {
} else if !fi.space && s != "" && (s[0] == '-' || s[0] == '+') {
// left pad accounting for zero pad of negative number
io.write_byte(fi.writer, '-', &fi.n)
io.write_byte(fi.writer, s[0], &fi.n)
fmt_write_padding(fi, width)
io.write_string(fi.writer, s[1:], &fi.n)
} else { // left pad

View File

@@ -1207,8 +1207,8 @@ matrix2_inverse_f16 :: proc "contextless" (m: Matrix2f16) -> (c: Matrix2f16) #no
d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0]
id := 1.0/d
c[0, 0] = +m[1, 1] * id
c[0, 1] = -m[1, 0] * id
c[1, 0] = -m[0, 1] * id
c[0, 1] = -m[0, 1] * id
c[1, 0] = -m[1, 0] * id
c[1, 1] = +m[0, 0] * id
return c
}
@@ -1217,8 +1217,8 @@ matrix2_inverse_f32 :: proc "contextless" (m: Matrix2f32) -> (c: Matrix2f32) #no
d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0]
id := 1.0/d
c[0, 0] = +m[1, 1] * id
c[0, 1] = -m[1, 0] * id
c[1, 0] = -m[0, 1] * id
c[0, 1] = -m[0, 1] * id
c[1, 0] = -m[1, 0] * id
c[1, 1] = +m[0, 0] * id
return c
}
@@ -1227,8 +1227,8 @@ matrix2_inverse_f64 :: proc "contextless" (m: Matrix2f64) -> (c: Matrix2f64) #no
d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0]
id := 1.0/d
c[0, 0] = +m[1, 1] * id
c[0, 1] = -m[1, 0] * id
c[1, 0] = -m[0, 1] * id
c[0, 1] = -m[0, 1] * id
c[1, 0] = -m[1, 0] * id
c[1, 1] = +m[0, 0] * id
return c
}

View File

@@ -328,10 +328,24 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
case size == 0:
err = .Mode_Not_Implemented
return
case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
// shrink data in-place
data = old_data[:size]
return
case uintptr(old_data) & uintptr(alignment-1) == 0:
if size < old_size {
// shrink data in-place
data = old_data[:size]
return
}
if block := arena.curr_block; block != nil {
start := uint(uintptr(old_memory)) - uint(uintptr(block.base))
old_end := start + old_size
new_end := start + size
if start < old_end && old_end == block.used && new_end <= block.reserved {
// grow data in-place, adjusting next allocation
_ = alloc_from_memory_block(block, new_end - old_end, 1, default_commit_size=arena.default_commit_size) or_return
data = block.base[start:new_end]
return
}
}
}
new_memory := arena_alloc(arena, size, alignment, location) or_return

View File

@@ -95,6 +95,7 @@ Resolve_Error :: enum u32 {
}
DNS_Error :: enum u32 {
None = 0,
Invalid_Hostname_Error = 1,
Invalid_Hosts_Config_Error,
Invalid_Resolv_Config_Error,
@@ -147,6 +148,9 @@ IP6_Loopback :: IP6_Address{0, 0, 0, 0, 0, 0, 0, 1}
IP4_Any := IP4_Address{}
IP6_Any := IP6_Address{}
IP4_mDNS_Broadcast := Endpoint{address=IP4_Address{224, 0, 0, 251}, port=5353}
IP6_mDNS_Broadcast := Endpoint{address=IP6_Address{65282, 0, 0, 0, 0, 0, 0, 251}, port = 5353}
Endpoint :: struct {
address: Address,
port: int,

View File

@@ -132,7 +132,14 @@ resolve_ip4 :: proc(hostname_and_maybe_port: string) -> (ep4: Endpoint, err: Net
return
}
case Host:
recs, _ := get_dns_records_from_os(t.hostname, .IP4, context.temp_allocator)
recs: []DNS_Record
if ODIN_OS != .Windows && strings.has_suffix(t.hostname, ".local") {
recs, _ = get_dns_records_from_nameservers(t.hostname, .IP4, {IP4_mDNS_Broadcast}, nil, context.temp_allocator)
} else {
recs, _ = get_dns_records_from_os(t.hostname, .IP4, context.temp_allocator)
}
if len(recs) == 0 {
err = .Unable_To_Resolve
return
@@ -159,7 +166,14 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net
return t, nil
}
case Host:
recs, _ := get_dns_records_from_os(t.hostname, .IP6, context.temp_allocator)
recs: []DNS_Record
if ODIN_OS != .Windows && strings.has_suffix(t.hostname, ".local") {
recs, _ = get_dns_records_from_nameservers(t.hostname, .IP6, {IP6_mDNS_Broadcast}, nil, context.temp_allocator)
} else {
recs, _ = get_dns_records_from_os(t.hostname, .IP6, context.temp_allocator)
}
if len(recs) == 0 {
err = .Unable_To_Resolve
return
@@ -255,12 +269,6 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type
return nil, .Connection_Error
}
// recv_sz, _, recv_err := recv_udp(conn, dns_response_buf[:])
// if recv_err == UDP_Recv_Error.Timeout {
// continue
// } else if recv_err != nil {
// continue
// }
recv_sz, _ := recv_udp(conn, dns_response_buf[:]) or_continue
if recv_sz == 0 {
continue

View File

@@ -29,9 +29,14 @@ import win "core:sys/windows"
_get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
context.allocator = allocator
options := win.DNS_QUERY_OPTIONS{}
if strings.has_suffix(hostname, ".local") {
options = {.MULTICAST_ONLY, .MULTICAST_WAIT} // 0x00020500
}
host_cstr := strings.clone_to_cstring(hostname, context.temp_allocator)
rec: ^win.DNS_RECORD
res := win.DnsQuery_UTF8(host_cstr, u16(type), 0, nil, &rec, nil)
res := win.DnsQuery_UTF8(host_cstr, u16(type), options, nil, &rec, nil)
switch u32(res) {
case 0:

View File

@@ -35,6 +35,7 @@ Socket_Option :: enum c.int {
Send_Buffer_Size = c.int(linux.Socket_Option.SNDBUF),
Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO),
Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO),
Broadcast = c.int(linux.Socket_Option.BROADCAST),
}
// Wrappers and unwrappers for system-native types
@@ -337,7 +338,8 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc :=
.Reuse_Address,
.Keep_Alive,
.Out_Of_Bounds_Data_Inline,
.TCP_Nodelay:
.TCP_Nodelay,
.Broadcast:
// TODO: verify whether these are options or not on Linux
// .Broadcast, <-- yes
// .Conditional_Accept,

View File

@@ -10,8 +10,12 @@ _error_string :: proc(errno: i32) -> string {
return string(posix.strerror(posix.Errno(errno)))
}
_get_platform_error :: proc() -> Error {
#partial switch errno := posix.errno(); errno {
_get_platform_error_from_errno :: proc() -> Error {
return _get_platform_error_existing(posix.errno())
}
_get_platform_error_existing :: proc(errno: posix.Errno) -> Error {
#partial switch errno {
case .EPERM:
return .Permission_Denied
case .EEXIST:
@@ -32,3 +36,8 @@ _get_platform_error :: proc() -> Error {
return Platform_Error(errno)
}
}
_get_platform_error :: proc{
_get_platform_error_existing,
_get_platform_error_from_errno,
}

View File

@@ -7,6 +7,13 @@ import "core:time"
import "core:sync"
import "core:sys/linux"
// Most implementations will EINVAL at some point when doing big writes.
// In practice a read/write call would probably never read/write these big buffers all at once,
// which is why the number of bytes is returned and why there are procs that will call this in a
// loop for you.
// We set a max of 1GB to keep alignment and to be safe.
MAX_RW :: 1 << 30
File_Impl :: struct {
file: File,
name: string,
@@ -179,10 +186,11 @@ _seek :: proc(f: ^File_Impl, offset: i64, whence: io.Seek_From) -> (ret: i64, er
}
_read :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
if len(p) == 0 {
if len(p) <= 0 {
return 0, nil
}
n, errno := linux.read(f.fd, p[:])
n, errno := linux.read(f.fd, p[:min(len(p), MAX_RW)])
if errno != .NONE {
return -1, _get_platform_error(errno)
}
@@ -190,13 +198,13 @@ _read :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
}
_read_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (i64, Error) {
if len(p) == 0 {
if len(p) <= 0 {
return 0, nil
}
if offset < 0 {
return 0, .Invalid_Offset
}
n, errno := linux.pread(f.fd, p[:], offset)
n, errno := linux.pread(f.fd, p[:min(len(p), MAX_RW)], offset)
if errno != .NONE {
return -1, _get_platform_error(errno)
}
@@ -206,29 +214,42 @@ _read_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (i64, Error) {
return i64(n), nil
}
_write :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
if len(p) == 0 {
return 0, nil
_write :: proc(f: ^File_Impl, p: []byte) -> (nt: i64, err: Error) {
p := p
for len(p) > 0 {
n, errno := linux.write(f.fd, p[:min(len(p), MAX_RW)])
if errno != .NONE {
err = _get_platform_error(errno)
return
}
p = p[n:]
nt += i64(n)
}
n, errno := linux.write(f.fd, p[:])
if errno != .NONE {
return -1, _get_platform_error(errno)
}
return i64(n), nil
return
}
_write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (i64, Error) {
if len(p) == 0 {
return 0, nil
}
_write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (nt: i64, err: Error) {
if offset < 0 {
return 0, .Invalid_Offset
}
n, errno := linux.pwrite(f.fd, p[:], offset)
if errno != .NONE {
return -1, _get_platform_error(errno)
p := p
offset := offset
for len(p) > 0 {
n, errno := linux.pwrite(f.fd, p[:min(len(p), MAX_RW)], offset)
if errno != .NONE {
err = _get_platform_error(errno)
return
}
p = p[n:]
nt += i64(n)
offset += i64(n)
}
return i64(n), nil
return
}
_file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) {

View File

@@ -2,6 +2,8 @@ package os2
import "base:runtime"
import "core:path/filepath"
Path_Separator :: _Path_Separator // OS-Specific
Path_Separator_String :: _Path_Separator_String // OS-Specific
Path_List_Separator :: _Path_List_Separator // OS-Specific
@@ -39,3 +41,13 @@ setwd :: set_working_directory
set_working_directory :: proc(dir: string) -> (err: Error) {
return _set_working_directory(dir)
}
get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
return _get_executable_path(allocator)
}
get_executable_directory :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
path = _get_executable_path(allocator) or_return
path, _ = filepath.split(path)
return
}

View File

@@ -0,0 +1,17 @@
package os2
import "base:runtime"
import "core:sys/darwin"
import "core:sys/posix"
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
buffer: [darwin.PIDPATHINFO_MAXSIZE]byte = ---
ret := darwin.proc_pidpath(posix.getpid(), raw_data(buffer[:]), len(buffer))
if ret > 0 {
return clone_string(string(buffer[:ret]), allocator)
}
err = _get_platform_error()
return
}

View File

@@ -0,0 +1,29 @@
package os2
import "base:runtime"
import "core:sys/freebsd"
import "core:sys/posix"
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
req := []freebsd.MIB_Identifier{.CTL_KERN, .KERN_PROC, .KERN_PROC_PATHNAME, freebsd.MIB_Identifier(-1)}
size: uint
if ret := freebsd.sysctl(req, nil, &size, nil, 0); ret != .NONE {
err = _get_platform_error(posix.Errno(ret))
return
}
assert(size > 0)
buf := make([]byte, size, allocator) or_return
defer if err != nil { delete(buf, allocator) }
assert(uint(len(buf)) == size)
if ret := freebsd.sysctl(req, raw_data(buf), &size, nil, 0); ret != .NONE {
err = _get_platform_error(posix.Errno(ret))
return
}
return string(buf[:size]), nil
}

View File

@@ -1,9 +1,10 @@
#+private
package os2
import "base:runtime"
import "core:strings"
import "core:strconv"
import "base:runtime"
import "core:sys/linux"
_Path_Separator :: '/'
@@ -171,6 +172,25 @@ _set_working_directory :: proc(dir: string) -> Error {
return _get_platform_error(linux.chdir(dir_cstr))
}
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
TEMP_ALLOCATOR_GUARD()
buf := make([dynamic]byte, 1024, temp_allocator()) or_return
for {
n, errno := linux.readlink("/proc/self/exe", buf[:])
if errno != .NONE {
err = _get_platform_error(errno)
return
}
if n < len(buf) {
return clone_string(string(buf[:n]), allocator)
}
resize(&buf, len(buf)*2) or_return
}
}
_get_full_path :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fullpath: string, err: Error) {
PROC_FD_PATH :: "/proc/self/fd/"

View File

@@ -0,0 +1,24 @@
package os2
import "base:runtime"
import "core:sys/posix"
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
TEMP_ALLOCATOR_GUARD()
buf := make([dynamic]byte, 1024, temp_allocator()) or_return
for {
n := posix.readlink("/proc/curproc/exe", raw_data(buf), len(buf))
if n < 0 {
err = _get_platform_error()
return
}
if n < len(buf) {
return clone_string(string(buf[:n]), allocator)
}
resize(&buf, len(buf)*2) or_return
}
}

View File

@@ -0,0 +1,57 @@
package os2
import "base:runtime"
import "core:strings"
import "core:sys/posix"
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
// OpenBSD does not have an API for this, we do our best below.
if len(runtime.args__) <= 0 {
err = .Invalid_Path
return
}
real :: proc(path: cstring, allocator: runtime.Allocator) -> (out: string, err: Error) {
real := posix.realpath(path)
if real == nil {
err = _get_platform_error()
return
}
defer posix.free(real)
return clone_string(string(real), allocator)
}
arg := runtime.args__[0]
sarg := string(arg)
if len(sarg) == 0 {
err = .Invalid_Path
return
}
if sarg[0] == '.' || sarg[0] == '/' {
return real(arg, allocator)
}
TEMP_ALLOCATOR_GUARD()
buf := strings.builder_make(temp_allocator())
paths := get_env("PATH", temp_allocator())
for dir in strings.split_iterator(&paths, ":") {
strings.builder_reset(&buf)
strings.write_string(&buf, dir)
strings.write_string(&buf, "/")
strings.write_string(&buf, sarg)
cpath := strings.to_cstring(&buf)
if posix.access(cpath, {.X_OK}) == .OK {
return real(cpath, allocator)
}
}
err = .Invalid_Path
return
}

View File

@@ -4,6 +4,7 @@ package os2
import "base:runtime"
import "core:path/filepath"
import "core:sync"
import "core:sys/wasm/wasi"
_Path_Separator :: '/'
@@ -74,11 +75,39 @@ _remove_all :: proc(path: string) -> (err: Error) {
return remove(path)
}
g_wd: string
g_wd_mutex: sync.Mutex
_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return ".", .Unsupported
sync.guard(&g_wd_mutex)
return clone_string(g_wd if g_wd != "" else "/", allocator)
}
_set_working_directory :: proc(dir: string) -> (err: Error) {
err = .Unsupported
sync.guard(&g_wd_mutex)
if dir == g_wd {
return
}
if g_wd != "" {
delete(g_wd, file_allocator())
}
g_wd = clone_string(dir, file_allocator()) or_return
return
}
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
if len(args) <= 0 {
return clone_string("/", allocator)
}
arg := args[0]
if len(arg) > 0 && (arg[0] == '.' || arg[0] == '/') {
return clone_string(arg, allocator)
}
return concatenate({"/", arg}, allocator)
}

View File

@@ -136,6 +136,26 @@ _set_working_directory :: proc(dir: string) -> (err: Error) {
return
}
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
TEMP_ALLOCATOR_GUARD()
buf := make([dynamic]u16, 512, temp_allocator()) or_return
for {
ret := win32.GetModuleFileNameW(nil, raw_data(buf), win32.DWORD(len(buf)))
if ret == 0 {
err = _get_platform_error()
return
}
if ret == win32.DWORD(len(buf)) && win32.GetLastError() == win32.ERROR_INSUFFICIENT_BUFFER {
resize(&buf, len(buf)*2) or_return
continue
}
return win32_utf16_to_utf8(buf[:ret], allocator)
}
}
can_use_long_paths: bool
@(init)

View File

@@ -1287,7 +1287,7 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc
}
send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) {
result := _unix_send(c.int(sd), raw_data(data), len(data), 0)
result := _unix_send(c.int(sd), raw_data(data), len(data), i32(flags))
if result < 0 {
return 0, get_last_error()
}

View File

@@ -1155,7 +1155,7 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc
}
send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) {
result := unix.sys_sendto(int(sd), raw_data(data), len(data), 0, nil, 0)
result := unix.sys_sendto(int(sd), raw_data(data), len(data), flags, nil, 0)
if result < 0 {
return 0, _get_errno(int(result))
}

View File

@@ -7,3 +7,13 @@ SavePanel :: struct{ using _: Panel }
SavePanel_runModal :: proc "c" (self: ^SavePanel) -> ModalResponse {
return msgSend(ModalResponse, self, "runModal")
}
@(objc_type=SavePanel, objc_name="savePanel", objc_is_class_method=true)
SavePanel_savePanel :: proc "c" () -> ^SavePanel {
return msgSend(^SavePanel, SavePanel, "savePanel")
}
@(objc_type=SavePanel, objc_name="URL")
SavePanel_URL :: proc "c" (self: ^SavePanel) -> ^Array {
return msgSend(^Array, self, "URL")
}

View File

@@ -5,6 +5,6 @@ foreign import "system:Dnsapi.lib"
@(default_calling_convention="system")
foreign Dnsapi {
DnsQuery_UTF8 :: proc(name: cstring, type: u16, options: DWORD, extra: PVOID, results: ^^DNS_RECORD, reserved: PVOID) -> DNS_STATUS ---
DnsQuery_UTF8 :: proc(name: cstring, type: u16, options: DNS_QUERY_OPTIONS, extra: PVOID, results: ^^DNS_RECORD, reserved: PVOID) -> DNS_STATUS ---
DnsRecordListFree :: proc(list: ^DNS_RECORD, options: DWORD) ---
}

View File

@@ -4576,6 +4576,31 @@ DNS_SRV_DATAA :: struct {
_: WORD, // padding
}
// See https://learn.microsoft.com/en-us/windows/win32/dns/dns-constants
DNS_QUERY_OPTION :: enum DWORD {
ACCEPT_TRUNCATED_RESPONSE = 0,
DNS_QUERY_USE_TCP_ONLY = 1,
NO_RECURSION = 2,
BYPASS_CACHE = 3,
NO_WIRE_QUERY = 4,
NO_LOCAL_NAME = 5,
NO_HOSTS_FILE = 6,
NO_NETBT = 7,
WIRE_ONLY = 8,
RETURN_MESSAGE = 9,
MULTICAST_ONLY = 10,
NO_MULTICAST = 11,
TREAT_AS_FQDN = 12,
ADDRCONFIG = 13,
DUAL_ADDR = 14,
MULTICAST_WAIT = 17,
MULTICAST_VERIFY = 18,
DONT_RESET_TTL_VALUES = 20,
DISABLE_IDN_ENCODING = 21,
APPEND_MULTILABEL = 23,
}
DNS_QUERY_OPTIONS :: bit_set[DNS_QUERY_OPTION; DWORD]
SOCKADDR :: struct {
sa_family: ADDRESS_FAMILY,
sa_data: [14]CHAR,

View File

@@ -251,7 +251,10 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success
exp *= 10;
exp += v;
}
big_int_exp_u64(dst, &b, exp, success);
BigInt tmp = {};
mp_init(&tmp);
big_int_exp_u64(&tmp, &b, exp, success);
big_int_mul_eq(dst, &tmp);
}
if (is_negative) {

View File

@@ -5040,6 +5040,12 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
ac->extra_linker_flags = ev.value_string;
}
return true;
} else if (name == "ignore_duplicates") {
if (value != nullptr) {
error(elem, "Expected no parameter for '%.*s'", LIT(name));
}
ac->ignore_duplicates = true;
return true;
}
return false;
}
@@ -5190,6 +5196,9 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
if (ac.foreign_import_priority_index != 0) {
e->LibraryName.priority_index = ac.foreign_import_priority_index;
}
if (ac.ignore_duplicates) {
e->LibraryName.ignore_duplicates = true;
}
String extra_linker_flags = string_trim_whitespace(ac.extra_linker_flags);
if (extra_linker_flags.len != 0) {
e->LibraryName.extra_linker_flags = extra_linker_flags;

View File

@@ -140,6 +140,7 @@ struct AttributeContext {
bool instrumentation_enter : 1;
bool instrumentation_exit : 1;
bool rodata : 1;
bool ignore_duplicates : 1;
u32 optimization_mode; // ProcedureOptimizationMode
i64 foreign_import_priority_index;
String extra_linker_flags;

View File

@@ -274,6 +274,7 @@ struct Entity {
Slice<String> paths;
String name;
i64 priority_index;
bool ignore_duplicates;
String extra_linker_flags;
} LibraryName;
i32 Nil;

View File

@@ -449,6 +449,26 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (extra_linker_flags.len != 0) {
lib_str = gb_string_append_fmt(lib_str, " %.*s", LIT(extra_linker_flags));
}
if (build_context.metrics.os == TargetOs_darwin) {
// Print frameworks first
for (String lib : e->LibraryName.paths) {
lib = string_trim_whitespace(lib);
if (lib.len == 0) {
continue;
}
if (string_ends_with(lib, str_lit(".framework"))) {
if (string_set_update(&min_libs_set, lib)) {
continue;
}
String lib_name = lib;
lib_name = remove_extension_from_path(lib_name);
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
}
}
}
for (String lib : e->LibraryName.paths) {
lib = string_trim_whitespace(lib);
if (lib.len == 0) {
@@ -541,7 +561,9 @@ gb_internal i32 linker_stage(LinkerData *gen) {
short_circuit = true;
} else if (string_ends_with(lib, str_lit(".dylib"))) {
short_circuit = true;
} else if (string_ends_with(lib, str_lit(".so"))) {
} else if (string_ends_with(lib, str_lit(".so"))) {
short_circuit = true;
} else if (e->LibraryName.ignore_duplicates) {
short_circuit = true;
}

View File

@@ -1147,14 +1147,14 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) {
String name = entry.key;
args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args);
lb_addr_store(p, entry.value, ptr);
lb_addr_store(p, entry.value.local_module_addr, ptr);
}
for (auto const &entry : m->objc_selectors) {
String name = entry.key;
args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args);
lb_addr_store(p, entry.value, ptr);
lb_addr_store(p, entry.value.local_module_addr, ptr);
}
lb_end_procedure_body(p);

View File

@@ -143,6 +143,11 @@ struct lbPadType {
LLVMTypeRef type;
};
struct lbObjcRef {
Entity * entity;
lbAddr local_module_addr;
};
struct lbModule {
LLVMModuleRef mod;
LLVMContextRef ctx;
@@ -196,8 +201,8 @@ struct lbModule {
RecursiveMutex debug_values_mutex;
PtrMap<void *, LLVMMetadataRef> debug_values;
StringMap<lbAddr> objc_classes;
StringMap<lbAddr> objc_selectors;
StringMap<lbObjcRef> objc_classes;
StringMap<lbObjcRef> objc_selectors;
PtrMap<Type *, lbAddr> map_cell_info_map; // address of runtime.Map_Info
PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info

View File

@@ -4294,6 +4294,17 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
ast_node(se, SliceExpr, expr);
lbAddr addr = lb_build_addr(p, se->expr);
lbValue base = lb_addr_load(p, addr);
Type *type = base_type(base.type);
if (is_type_pointer(type)) {
type = base_type(type_deref(type));
addr = lb_addr(base);
base = lb_addr_load(p, addr);
}
lbValue low = lb_const_int(p->module, t_int, 0);
lbValue high = {};
@@ -4306,16 +4317,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
bool no_indices = se->low == nullptr && se->high == nullptr;
lbAddr addr = lb_build_addr(p, se->expr);
lbValue base = lb_addr_load(p, addr);
Type *type = base_type(base.type);
if (is_type_pointer(type)) {
type = base_type(type_deref(type));
addr = lb_addr(base);
base = lb_addr_load(p, addr);
}
switch (type->kind) {
case Type_Slice: {
Type *slice_type = type;

View File

@@ -2093,23 +2093,34 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export
gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
lbAddr *found = string_map_get(&p->module->objc_selectors, name);
lbObjcRef *found = string_map_get(&p->module->objc_selectors, name);
if (found) {
return *found;
} else {
lbModule *default_module = &p->module->gen->default_module;
Entity *e = nullptr;
lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e);
lbValue ptr = lb_find_value_from_entity(p->module, e);
lbAddr local_addr = lb_addr(ptr);
string_map_set(&default_module->objc_selectors, name, default_addr);
if (default_module != p->module) {
string_map_set(&p->module->objc_selectors, name, local_addr);
}
return local_addr;
return found->local_module_addr;
}
lbModule *default_module = &p->module->gen->default_module;
Entity *entity = {};
if (default_module != p->module) {
found = string_map_get(&default_module->objc_selectors, name);
if (found) {
entity = found->entity;
}
}
if (!entity) {
lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &entity);
string_map_set(&default_module->objc_selectors, name, lbObjcRef{entity, default_addr});
}
lbValue ptr = lb_find_value_from_entity(p->module, entity);
lbAddr local_addr = lb_addr(ptr);
if (default_module != p->module) {
string_map_set(&p->module->objc_selectors, name, lbObjcRef{entity, local_addr});
}
return local_addr;
}
gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
@@ -2139,23 +2150,34 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr)
}
gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
lbAddr *found = string_map_get(&p->module->objc_classes, name);
lbObjcRef *found = string_map_get(&p->module->objc_classes, name);
if (found) {
return *found;
} else {
lbModule *default_module = &p->module->gen->default_module;
Entity *e = nullptr;
lbAddr default_addr = lb_add_global_generated(default_module, t_objc_SEL, {}, &e);
lbValue ptr = lb_find_value_from_entity(p->module, e);
lbAddr local_addr = lb_addr(ptr);
string_map_set(&default_module->objc_classes, name, default_addr);
if (default_module != p->module) {
string_map_set(&p->module->objc_classes, name, local_addr);
}
return local_addr;
return found->local_module_addr;
}
lbModule *default_module = &p->module->gen->default_module;
Entity *entity = {};
if (default_module != p->module) {
found = string_map_get(&default_module->objc_classes, name);
if (found) {
entity = found->entity;
}
}
if (!entity) {
lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &entity);
string_map_set(&default_module->objc_classes, name, lbObjcRef{entity, default_addr});
}
lbValue ptr = lb_find_value_from_entity(p->module, entity);
lbAddr local_addr = lb_addr(ptr);
if (default_module != p->module) {
string_map_set(&p->module->objc_classes, name, lbObjcRef{entity, local_addr});
}
return local_addr;
}
gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
@@ -2196,23 +2218,7 @@ gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
GB_ASSERT(e->kind == Entity_TypeName);
String name = e->TypeName.objc_class_name;
lbAddr *found = string_map_get(&p->module->objc_classes, name);
if (found) {
return lb_addr_load(p, *found);
} else {
lbModule *default_module = &p->module->gen->default_module;
Entity *e = nullptr;
lbAddr default_addr = lb_add_global_generated(default_module, t_objc_Class, {}, &e);
lbValue ptr = lb_find_value_from_entity(p->module, e);
lbAddr local_addr = lb_addr(ptr);
string_map_set(&default_module->objc_classes, name, default_addr);
if (default_module != p->module) {
string_map_set(&p->module->objc_classes, name, local_addr);
}
return lb_addr_load(p, local_addr);
}
return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name));
}
return lb_build_expr(p, expr);

View File

@@ -0,0 +1,22 @@
package tests_core_os_os2
import os "core:os/os2"
import "core:log"
import "core:path/filepath"
import "core:testing"
import "core:strings"
@(test)
test_executable :: proc(t: ^testing.T) {
path, err := os.get_executable_path(context.allocator)
defer delete(path)
log.infof("executable path: %q", path)
// NOTE: some sanity checks that should always be the case, at least in the CI.
testing.expect_value(t, err, nil)
testing.expect(t, len(path) > 0)
testing.expect(t, filepath.is_abs(path))
testing.expectf(t, strings.contains(path, filepath.base(os.args[0])), "expected the executable path to contain the base of os.args[0] which is %q", filepath.base(os.args[0]))
}

View File

@@ -7,7 +7,6 @@
package vendor_commonmark
import "core:c"
import "core:c/libc"
import "base:runtime"
COMMONMARK_SHARED :: #config(COMMONMARK_SHARED, false)
@@ -450,7 +449,7 @@ foreign lib {
// Called `parse_from_libc_file` so as not to confuse with Odin's file handling.
@(link_name = "parse_from_file")
parse_from_libc_file :: proc(file: ^libc.FILE, options: Options) -> (root: ^Node) ---
parse_from_libc_file :: proc(file: ^c.FILE, options: Options) -> (root: ^Node) ---
}
parser_feed_from_string :: proc "c" (parser: ^Parser, s: string) {

View File

@@ -150,9 +150,9 @@ sound_inlined :: struct {
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
@(deprecated="Will be removed in 0.12. Use sound_config_init2() instead.")
@(deprecated="Will be removed in 0.12. Use sound_config_init_2() instead.")
sound_config_init :: proc() -> sound_config ---
sound_config_init2 :: proc(pEngine: ^engine) -> sound_config --- /* Will be renamed to sound_config_init() in version 0.12. */
sound_config_init_2 :: proc(pEngine: ^engine) -> sound_config --- /* Will be renamed to sound_config_init() in version 0.12. */
sound_init_from_file :: proc(pEngine: ^engine, pFilePath: cstring, flags: sound_flags, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result ---
sound_init_from_file_w :: proc(pEngine: ^engine, pFilePath: [^]c.wchar_t, flags: sound_flags, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result ---
@@ -241,9 +241,9 @@ sound_group :: distinct sound
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
@(deprecated="Will be removed in 0.12. Use sound_config_init2() instead.")
@(deprecated="Will be removed in 0.12. Use sound_config_init_2() instead.")
sound_group_config_init :: proc() -> sound_group_config ---
sound_group_config_init2 :: proc(pEngine: ^engine) -> sound_group_config ---
sound_group_config_init_2 :: proc(pEngine: ^engine) -> sound_group_config ---
sound_group_init :: proc(pEngine: ^engine, flags: sound_flags, pParentGroup, pGroup: ^sound_group) -> result ---
sound_group_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_group_config, pGroup: ^sound_group) -> result ---

View File

@@ -1205,7 +1205,7 @@ foreign lib {
CameraMoveForward :: proc(camera: ^Camera, distance: f32, moveInWorldPlane: bool) --- // move the camera in its forward direction
CameraMoveUp :: proc(camera: ^Camera, distance: f32) --- // move camera in its up direction
CameraMoveRight :: proc(camera: ^Camera, distance: f32, delta: f32) --- // move camera in it's current right direction
CameraMoveRight :: proc(camera: ^Camera, distance: f32, moveInWorldPlane: bool) --- // move camera in it's current right direction
CameraMoveToTarget :: proc(camera: ^Camera, delta: f32) --- // moves the camera position closer/farther to/from the camera target
CameraYaw :: proc(camera: ^Camera, angle: f32, rotateAroundTarget: bool) --- // rotates the camera around its up vector (left and right)
CameraPitch :: proc(camera: ^Camera, angle: f32, lockView: bool, rotateAroundTarget: bool, rotateUp: bool) --- // rotates the camera around its right vector (up and down)

View File

@@ -26,8 +26,10 @@ import "core:c"
import "base:intrinsics"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -3,8 +3,10 @@ package sdl2
import "core:c"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -4,8 +4,10 @@ import "core:c"
import vk "vendor:vulkan"
when ODIN_OS == .Windows {
@(ignore_duplicates)
foreign import lib "SDL2.lib"
} else {
@(ignore_duplicates)
foreign import lib "system:SDL2"
}

View File

@@ -1,6 +1,6 @@
package stb_image
import c "core:c/libc"
import "core:c"
@(private)
LIB :: (