Merge branch 'master' of github.com:odin-lang/Odin into posix-linux

This commit is contained in:
Isaac Andrade
2024-08-27 18:51:58 -06:00
67 changed files with 3045 additions and 2704 deletions
+2
View File
@@ -219,6 +219,8 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info ---
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) ---
constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
constant_log2 :: proc($v: $T) -> T where type_is_integer(T) --- constant_log2 :: proc($v: $T) -> T where type_is_integer(T) ---
+2 -2
View File
@@ -1,8 +1,8 @@
package runtime package runtime
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int, size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) { old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch mode { switch mode {
case .Alloc, .Alloc_Non_Zeroed: case .Alloc, .Alloc_Non_Zeroed:
return nil, .Out_Of_Memory return nil, .Out_Of_Memory
+34
View File
@@ -0,0 +1,34 @@
package runtime
Thread_Local_Cleaner :: #type proc "odin" ()
@(private="file")
thread_local_cleaners: [8]Thread_Local_Cleaner
// Add a procedure that will be run at the end of a thread for the purpose of
// deallocating state marked as `thread_local`.
//
// Intended to be called in an `init` procedure of a package with
// dynamically-allocated memory that is stored in `thread_local` variables.
add_thread_local_cleaner :: proc "contextless" (p: Thread_Local_Cleaner) {
for &v in thread_local_cleaners {
if v == nil {
v = p
return
}
}
panic_contextless("There are no more thread-local cleaner slots available.")
}
// Run all of the thread-local cleaner procedures.
//
// Intended to be called by the internals of a threading API at the end of a
// thread's lifetime.
run_thread_local_cleaners :: proc "odin" () {
for p in thread_local_cleaners {
if p == nil {
break
}
p()
}
}
+20 -15
View File
@@ -11,7 +11,7 @@ Write a UUID in the 8-4-4-4-12 format.
This procedure performs error checking with every byte written. This procedure performs error checking with every byte written.
If you can guarantee beforehand that your stream has enough space to hold the If you can guarantee beforehand that your stream has enough space to hold the
UUID (32 bytes), then it is better to use `unsafe_write` instead as that will UUID (36 bytes), then it is better to use `unsafe_write` instead as that will
be faster. be faster.
Inputs: Inputs:
@@ -22,7 +22,7 @@ Returns:
- error: An `io` error, if one occurred, otherwise `nil`. - error: An `io` error, if one occurred, otherwise `nil`.
*/ */
write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_check { write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_check {
write_octet :: proc (w: io.Writer, octet: u8) -> io.Error #no_bounds_check { write_octet :: proc(w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
high_nibble := octet >> 4 high_nibble := octet >> 4
low_nibble := octet & 0xF low_nibble := octet & 0xF
@@ -31,15 +31,15 @@ write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_chec
return nil return nil
} }
for index in 0 ..< 4 { write_octet(w, id[index]) or_return } for index in 0 ..< 4 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return io.write_byte(w, '-') or_return
for index in 4 ..< 6 { write_octet(w, id[index]) or_return } for index in 4 ..< 6 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return io.write_byte(w, '-') or_return
for index in 6 ..< 8 { write_octet(w, id[index]) or_return } for index in 6 ..< 8 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return io.write_byte(w, '-') or_return
for index in 8 ..< 10 { write_octet(w, id[index]) or_return } for index in 8 ..< 10 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return io.write_byte(w, '-') or_return
for index in 10 ..< 16 { write_octet(w, id[index]) or_return } for index in 10 ..< 16 {write_octet(w, id[index]) or_return}
return nil return nil
} }
@@ -54,7 +54,7 @@ Inputs:
- id: The identifier to convert. - id: The identifier to convert.
*/ */
unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check { unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
write_octet :: proc (w: io.Writer, octet: u8) #no_bounds_check { write_octet :: proc(w: io.Writer, octet: u8) #no_bounds_check {
high_nibble := octet >> 4 high_nibble := octet >> 4
low_nibble := octet & 0xF low_nibble := octet & 0xF
@@ -62,15 +62,15 @@ unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
io.write_byte(w, strconv.digits[low_nibble]) io.write_byte(w, strconv.digits[low_nibble])
} }
for index in 0 ..< 4 { write_octet(w, id[index]) } for index in 0 ..< 4 {write_octet(w, id[index])}
io.write_byte(w, '-') io.write_byte(w, '-')
for index in 4 ..< 6 { write_octet(w, id[index]) } for index in 4 ..< 6 {write_octet(w, id[index])}
io.write_byte(w, '-') io.write_byte(w, '-')
for index in 6 ..< 8 { write_octet(w, id[index]) } for index in 6 ..< 8 {write_octet(w, id[index])}
io.write_byte(w, '-') io.write_byte(w, '-')
for index in 8 ..< 10 { write_octet(w, id[index]) } for index in 8 ..< 10 {write_octet(w, id[index])}
io.write_byte(w, '-') io.write_byte(w, '-')
for index in 10 ..< 16 { write_octet(w, id[index]) } for index in 10 ..< 16 {write_octet(w, id[index])}
} }
/* /*
@@ -106,7 +106,7 @@ Convert a UUID to a string in the 8-4-4-4-12 format.
Inputs: Inputs:
- id: The identifier to convert. - id: The identifier to convert.
- buffer: A byte buffer to store the result. Must be at least 32 bytes large. - buffer: A byte buffer to store the result. Must be at least 36 bytes large.
- loc: The caller location for debugging purposes (default: #caller_location) - loc: The caller location for debugging purposes (default: #caller_location)
Returns: Returns:
@@ -119,7 +119,11 @@ to_string_buffer :: proc(
) -> ( ) -> (
str: string, str: string,
) { ) {
assert(len(buffer) >= EXPECTED_LENGTH, "The buffer provided is not at least 32 bytes large.", loc) assert(
len(buffer) >= EXPECTED_LENGTH,
"The buffer provided is not at least 36 bytes large.",
loc,
)
builder := strings.builder_from_bytes(buffer) builder := strings.builder_from_bytes(buffer)
unsafe_write(strings.to_writer(&builder), id) unsafe_write(strings.to_writer(&builder), id)
return strings.to_string(builder) return strings.to_string(builder)
@@ -129,3 +133,4 @@ to_string :: proc {
to_string_allocated, to_string_allocated,
to_string_buffer, to_string_buffer,
} }
+9 -9
View File
@@ -19,15 +19,15 @@ xxh_u64 :: u64
XXH64_DEFAULT_SEED :: XXH64_hash(0) XXH64_DEFAULT_SEED :: XXH64_hash(0)
XXH64_state :: struct { XXH64_state :: struct {
total_len: XXH64_hash, /*!< Total length hashed. This is always 64-bit. */ total_len: XXH64_hash, /*!< Total length hashed. This is always 64-bit. */
v1: XXH64_hash, /*!< First accumulator lane */ v1: XXH64_hash, /*!< First accumulator lane */
v2: XXH64_hash, /*!< Second accumulator lane */ v2: XXH64_hash, /*!< Second accumulator lane */
v3: XXH64_hash, /*!< Third accumulator lane */ v3: XXH64_hash, /*!< Third accumulator lane */
v4: XXH64_hash, /*!< Fourth accumulator lane */ v4: XXH64_hash, /*!< Fourth accumulator lane */
mem64: [4]XXH64_hash, /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ mem64: [4]XXH64_hash, /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */
memsize: XXH32_hash, /*!< Amount of data in @ref mem64 */ memsize: XXH32_hash, /*!< Amount of data in @ref mem64 */
reserved32: XXH32_hash, /*!< Reserved field, needed for padding anyways*/ reserved32: XXH32_hash, /*!< Reserved field, needed for padding anyways*/
reserved64: XXH64_hash, /*!< Reserved field. Do not read or write to it, it may be removed. */ reserved64: XXH64_hash, /*!< Reserved field. Do not read or write to it, it may be removed. */
} }
XXH64_canonical :: struct { XXH64_canonical :: struct {
+2
View File
@@ -1393,6 +1393,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
for p in inp { for p in inp {
out[0].rgb = p.r // Gray component. out[0].rgb = p.r // Gray component.
out[0].a = p.g // Alpha component. out[0].a = p.g // Alpha component.
out = out[1:]
} }
case: case:
@@ -1417,6 +1418,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
for p in inp { for p in inp {
out[0].rgb = p.r // Gray component. out[0].rgb = p.r // Gray component.
out[0].a = p.g // Alpha component. out[0].a = p.g // Alpha component.
out = out[1:]
} }
case: case:
+1 -1
View File
@@ -195,7 +195,7 @@ Error_String :: #sparse[Error]string{
} }
Primality_Flag :: enum u8 { Primality_Flag :: enum u8 {
Blum_Blum_Shub = 0, // Make prime congruent to 3 mod 4 Blum_Blum_Shub = 0, // Make prime congruent to 3 mod 4
Safe = 1, // Make sure (p-1)/2 is prime as well (implies .Blum_Blum_Shub) Safe = 1, // Make sure (p-1)/2 is prime as well (implies .Blum_Blum_Shub)
Second_MSB_On = 3, // Make the 2nd highest bit one Second_MSB_On = 3, // Make the 2nd highest bit one
} }
+2 -2
View File
@@ -178,11 +178,11 @@ make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocato
} }
@(require_results) @(require_results)
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) { make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
return runtime.make_dynamic_array(T, len, allocator, loc) return runtime.make_dynamic_array_len_cap(T, len, len, allocator, loc)
} }
@(require_results) @(require_results)
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) { make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) {
return runtime.make_dynamic_array(T, len, cap, allocator, loc) return runtime.make_dynamic_array_len_cap(T, len, cap, allocator, loc)
} }
@(require_results) @(require_results)
make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) { make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) {
+18 -14
View File
@@ -128,33 +128,37 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
append(&recs, record) append(&recs, record)
case .SRV: case .SRV:
target := strings.clone(string(r.Data.SRV.pNameTarget)) // The target hostname/address that the service can be found on
priority := int(r.Data.SRV.wPriority)
weight := int(r.Data.SRV.wWeight)
port := int(r.Data.SRV.wPort)
// NOTE(tetra): Srv record name should be of the form '_servicename._protocol.hostname' // NOTE(tetra): Srv record name should be of the form '_servicename._protocol.hostname'
// The record name is the name of the record. // The record name is the name of the record.
// Not to be confused with the _target_ of the record, which is--in combination with the port--what we're looking up // Not to be confused with the _target_ of the record, which is--in combination with the port--what we're looking up
// by making this request in the first place. // by making this request in the first place.
// NOTE(Jeroen): Service Name and Protocol Name can probably just be string slices into the record name. service_name, protocol_name: string
// It's already cloned, after all. I wouldn't put them on the temp allocator like this.
parts := strings.split_n(base_record.record_name, ".", 3, context.temp_allocator) s := base_record.record_name
if len(parts) != 3 { i := strings.index_byte(s, '.')
if i > -1 {
service_name = s[:i]
s = s[len(service_name) + 1:]
} else {
continue
}
i = strings.index_byte(s, '.')
if i > -1 {
protocol_name = s[:i]
} else {
continue continue
} }
service_name, protocol_name := parts[0], parts[1]
append(&recs, DNS_Record_SRV { append(&recs, DNS_Record_SRV {
base = base_record, base = base_record,
target = target, target = strings.clone(string(r.Data.SRV.pNameTarget)), // The target hostname/address that the service can be found on
port = port, port = int(r.Data.SRV.wPort),
service_name = service_name, service_name = service_name,
protocol_name = protocol_name, protocol_name = protocol_name,
priority = priority, priority = int(r.Data.SRV.wPriority),
weight = weight, weight = int(r.Data.SRV.wWeight),
}) })
} }
+5
View File
@@ -61,3 +61,8 @@ TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
return tmp, loc return tmp, loc
} }
@(init, private)
init_thread_local_cleaner :: proc() {
runtime.add_thread_local_cleaner(temp_allocator_fini)
}
-3
View File
@@ -125,9 +125,6 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
has_size = true has_size = true
size = int(size64) size = int(size64)
} }
} else if serr != .No_Size {
err = serr
return
} }
if has_size && size > 0 { if has_size && size > 0 {
+13 -12
View File
@@ -167,14 +167,14 @@ Process_Info :: struct {
This procedure obtains an information, specified by `selection` parameter of This procedure obtains an information, specified by `selection` parameter of
a process given by `pid`. a process given by `pid`.
Use `free_process_info` to free the memory allocated by this procedure. In Use `free_process_info` to free the memory allocated by this procedure. The
case the function returns an error it may only have been an error for one part `free_process_info` procedure needs to be called, even if this procedure
of the information and you would still need to call it to free the other parts. returned an error, as some of the fields may have been allocated.
**Note**: The resulting information may or may contain the fields specified **Note**: The resulting information may or may contain the fields specified
by the `selection` parameter. Always check whether the returned by the `selection` parameter. Always check whether the returned
`Process_Info` struct has the required fields before checking the error code `Process_Info` struct has the required fields before checking the error code
returned by this function. returned by this procedure.
*/ */
@(require_results) @(require_results)
process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) { process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
@@ -188,14 +188,14 @@ process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator:
about a process that has been opened by the application, specified in about a process that has been opened by the application, specified in
the `process` parameter. the `process` parameter.
Use `free_process_info` to free the memory allocated by this procedure. In Use `free_process_info` to free the memory allocated by this procedure. The
case the function returns an error it may only have been an error for one part `free_process_info` procedure needs to be called, even if this procedure
of the information and you would still need to call it to free the other parts. returned an error, as some of the fields may have been allocated.
**Note**: The resulting information may or may contain the fields specified **Note**: The resulting information may or may contain the fields specified
by the `selection` parameter. Always check whether the returned by the `selection` parameter. Always check whether the returned
`Process_Info` struct has the required fields before checking the error code `Process_Info` struct has the required fields before checking the error code
returned by this function. returned by this procedure.
*/ */
@(require_results) @(require_results)
process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) { process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
@@ -208,14 +208,14 @@ process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields,
This procedure obtains the information, specified by `selection` parameter This procedure obtains the information, specified by `selection` parameter
about the currently running process. about the currently running process.
Use `free_process_info` to free the memory allocated by this procedure. In Use `free_process_info` to free the memory allocated by this procedure. The
case the function returns an error it may only have been an error for one part `free_process_info` procedure needs to be called, even if this procedure
of the information and you would still need to call it to free the other parts. returned an error, as some of the fields may have been allocated.
**Note**: The resulting information may or may contain the fields specified **Note**: The resulting information may or may contain the fields specified
by the `selection` parameter. Always check whether the returned by the `selection` parameter. Always check whether the returned
`Process_Info` struct has the required fields before checking the error code `Process_Info` struct has the required fields before checking the error code
returned by this function. returned by this procedure.
*/ */
@(require_results) @(require_results)
current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) { current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
@@ -305,6 +305,7 @@ Process_Desc :: struct {
// A slice of strings, each having the format `KEY=VALUE` representing the // A slice of strings, each having the format `KEY=VALUE` representing the
// full environment that the child process will receive. // full environment that the child process will receive.
// In case this slice is `nil`, the current process' environment is used. // In case this slice is `nil`, the current process' environment is used.
// NOTE(laytan): maybe should be `Maybe([]string)` so you can do `nil` == current env, empty == empty/no env.
env: []string, env: []string,
// The `stderr` handle to give to the child process. It can be either a file // The `stderr` handle to give to the child process. It can be either a file
// or a writeable end of a pipe. Passing `nil` will shut down the process' // or a writeable end of a pipe. Passing `nil` will shut down the process'
+5 -11
View File
@@ -490,7 +490,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
if errno = linux.pipe2(&child_pipe_fds, {.CLOEXEC}); errno != .NONE { if errno = linux.pipe2(&child_pipe_fds, {.CLOEXEC}); errno != .NONE {
return process, _get_platform_error(errno) return process, _get_platform_error(errno)
} }
defer linux.close(child_pipe_fds[WRITE])
defer linux.close(child_pipe_fds[READ]) defer linux.close(child_pipe_fds[READ])
@@ -508,6 +507,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
// //
pid: linux.Pid pid: linux.Pid
if pid, errno = linux.fork(); errno != .NONE { if pid, errno = linux.fork(); errno != .NONE {
linux.close(child_pipe_fds[WRITE])
return process, _get_platform_error(errno) return process, _get_platform_error(errno)
} }
@@ -573,25 +573,19 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
} }
success_byte: [1]u8
linux.write(child_pipe_fds[WRITE], success_byte[:])
errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH}) errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH})
// NOTE: we can't tell the parent about this failure because we already wrote the success byte.
// So if this happens the user will just see the process failed when they call process_wait.
assert(errno != nil) assert(errno != nil)
intrinsics.trap() write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
} }
linux.close(child_pipe_fds[WRITE])
process.pid = int(pid) process.pid = int(pid)
n: int
child_byte: [1]u8 child_byte: [1]u8
errno = .EINTR errno = .EINTR
for errno == .EINTR { for errno == .EINTR {
n, errno = linux.read(child_pipe_fds[READ], child_byte[:]) _, errno = linux.read(child_pipe_fds[READ], child_byte[:])
} }
// If the read failed, something weird happened. Do not return the read // If the read failed, something weird happened. Do not return the read
+8 -11
View File
@@ -139,20 +139,22 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
err = _get_platform_error() err = _get_platform_error()
return return
} }
defer posix.close(pipe[WRITE])
defer posix.close(pipe[READ]) defer posix.close(pipe[READ])
if posix.fcntl(pipe[READ], .SETFD, i32(posix.FD_CLOEXEC)) == -1 { if posix.fcntl(pipe[READ], .SETFD, i32(posix.FD_CLOEXEC)) == -1 {
posix.close(pipe[WRITE])
err = _get_platform_error() err = _get_platform_error()
return return
} }
if posix.fcntl(pipe[WRITE], .SETFD, i32(posix.FD_CLOEXEC)) == -1 { if posix.fcntl(pipe[WRITE], .SETFD, i32(posix.FD_CLOEXEC)) == -1 {
posix.close(pipe[WRITE])
err = _get_platform_error() err = _get_platform_error()
return return
} }
switch pid := posix.fork(); pid { switch pid := posix.fork(); pid {
case -1: case -1:
posix.close(pipe[WRITE])
err = _get_platform_error() err = _get_platform_error()
return return
@@ -179,25 +181,20 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
if posix.chdir(cwd) != .OK { abort(pipe[WRITE]) } if posix.chdir(cwd) != .OK { abort(pipe[WRITE]) }
} }
ok := u8(0)
posix.write(pipe[WRITE], &ok, 1)
res := posix.execve(strings.to_cstring(&exe_builder), raw_data(cmd), env) res := posix.execve(strings.to_cstring(&exe_builder), raw_data(cmd), env)
// NOTE: we can't tell the parent about this failure because we already wrote the success byte.
// So if this happens the user will just see the process failed when they call process_wait.
assert(res == -1) assert(res == -1)
runtime.trap() abort(pipe[WRITE])
case: case:
posix.close(pipe[WRITE])
errno: posix.Errno errno: posix.Errno
for { for {
errno_byte: u8 errno_byte: u8
switch posix.read(pipe[READ], &errno_byte, 1) { switch posix.read(pipe[READ], &errno_byte, 1) {
case 1: case 1:
errno = posix.Errno(errno_byte) errno = posix.Errno(errno_byte)
case: case -1:
errno = posix.errno() errno = posix.errno()
if errno == .EINTR { if errno == .EINTR {
continue continue
+185 -141
View File
@@ -93,34 +93,11 @@ read_memory_as_slice :: proc(h: win32.HANDLE, addr: rawptr, dest: []$T) -> (byte
@(private="package") @(private="package")
_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
info.pid = pid info.pid = pid
defer if err != nil { // Note(flysand): Open the process handle right away to prevent some race
free_process_info(info, allocator) // conditions. Once the handle is open, the process will be kept alive by
} // the OS.
// Data obtained from process snapshots
if selection >= {.PPid, .Priority} {
entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil {
err = General_Error.Not_Exist
return
}
if .PPid in selection {
info.fields += {.PPid}
info.ppid = int(entry.th32ParentProcessID)
}
if .Priority in selection {
info.fields += {.Priority}
info.priority = int(entry.pcPriClassBase)
}
}
if .Executable_Path in selection { // snap module
info.executable_path = _process_exe_by_pid(pid, allocator) or_return
info.fields += {.Executable_Path}
}
ph := win32.INVALID_HANDLE_VALUE ph := win32.INVALID_HANDLE_VALUE
if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} {
if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { // need process handle
ph = win32.OpenProcess( ph = win32.OpenProcess(
win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ, win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ,
false, false,
@@ -134,84 +111,15 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
defer if ph != win32.INVALID_HANDLE_VALUE { defer if ph != win32.INVALID_HANDLE_VALUE {
win32.CloseHandle(ph) win32.CloseHandle(ph)
} }
snapshot_process: if selection >= {.PPid, .Priority} {
if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb
process_info_size: u32
process_info: win32.PROCESS_BASIC_INFORMATION
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
if status != 0 {
// TODO(flysand): There's probably a mismatch between NTSTATUS and
// windows userland error codes, I haven't checked.
err = Platform_Error(status)
return
}
if process_info.PebBaseAddress == nil {
// Not sure what the error is
err = General_Error.Unsupported
return
}
process_peb: win32.PEB
_ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return
process_params: win32.RTL_USER_PROCESS_PARAMETERS
_ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return
if selection >= {.Command_Line, .Command_Args} {
TEMP_ALLOCATOR_GUARD()
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
_ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return
if .Command_Line in selection {
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
info.fields += {.Command_Line}
}
if .Command_Args in selection {
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
info.fields += {.Command_Args}
}
}
if .Environment in selection {
TEMP_ALLOCATOR_GUARD()
env_len := process_params.EnvironmentSize / 2
envs_w := make([]u16, env_len, temp_allocator()) or_return
_ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
info.fields += {.Environment}
}
if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
_ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
info.fields += {.Working_Dir}
}
}
if .Username in selection {
info.username = _get_process_user(ph, allocator) or_return
info.fields += {.Username}
}
err = nil
return
}
@(private="package")
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
pid := process.pid
info.pid = pid
defer if err != nil {
free_process_info(info, allocator)
}
// Data obtained from process snapshots
if selection >= {.PPid, .Priority} { // snap process
entry, entry_err := _process_entry_by_pid(info.pid) entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil { if entry_err != nil {
err = General_Error.Not_Exist err = entry_err
return if entry_err == General_Error.Not_Exist {
return
} else {
break snapshot_process
}
} }
if .PPid in selection { if .PPid in selection {
info.fields += {.PPid} info.fields += {.PPid}
@@ -222,12 +130,18 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.priority = int(entry.pcPriClassBase) info.priority = int(entry.pcPriClassBase)
} }
} }
if .Executable_Path in selection { // snap module snapshot_modules: if .Executable_Path in selection {
info.executable_path = _process_exe_by_pid(pid, allocator) or_return exe_path: string
exe_path, err = _process_exe_by_pid(pid, allocator)
if _, ok := err.(runtime.Allocator_Error); ok {
return
} else if err != nil {
break snapshot_modules
}
info.executable_path = exe_path
info.fields += {.Executable_Path} info.fields += {.Executable_Path}
} }
ph := win32.HANDLE(process.handle) read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} {
if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb
process_info_size: u32 process_info_size: u32
process_info: win32.PROCESS_BASIC_INFORMATION process_info: win32.PROCESS_BASIC_INFORMATION
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size) status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
@@ -235,25 +149,26 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
// TODO(flysand): There's probably a mismatch between NTSTATUS and // TODO(flysand): There's probably a mismatch between NTSTATUS and
// windows userland error codes, I haven't checked. // windows userland error codes, I haven't checked.
err = Platform_Error(status) err = Platform_Error(status)
return break read_peb
} }
if process_info.PebBaseAddress == nil { assert(process_info.PebBaseAddress != nil)
// Not sure what the error is
err = General_Error.Unsupported
return
}
process_peb: win32.PEB process_peb: win32.PEB
_ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return _, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb)
if err != nil {
break read_peb
}
process_params: win32.RTL_USER_PROCESS_PARAMETERS process_params: win32.RTL_USER_PROCESS_PARAMETERS
_ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return _, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params)
if err != nil {
break read_peb
}
if selection >= {.Command_Line, .Command_Args} { if selection >= {.Command_Line, .Command_Args} {
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
_ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
if err != nil {
break read_peb
}
if .Command_Line in selection { if .Command_Line in selection {
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
info.fields += {.Command_Line} info.fields += {.Command_Line}
@@ -263,28 +178,147 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.fields += {.Command_Args} info.fields += {.Command_Args}
} }
} }
if .Environment in selection { if .Environment in selection {
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
env_len := process_params.EnvironmentSize / 2 env_len := process_params.EnvironmentSize / 2
envs_w := make([]u16, env_len, temp_allocator()) or_return envs_w := make([]u16, env_len, temp_allocator()) or_return
_ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return _, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
if err != nil {
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return break read_peb
}
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
info.fields += {.Environment} info.fields += {.Environment}
} }
if .Working_Dir in selection { if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD() TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
_ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
if err != nil {
break read_peb
}
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
info.fields += {.Working_Dir} info.fields += {.Working_Dir}
} }
} }
if .Username in selection { read_username: if .Username in selection {
info.username = _get_process_user(ph, allocator) or_return username: string
username, err = _get_process_user(ph, allocator)
if _, ok := err.(runtime.Allocator_Error); ok {
return
} else if err != nil {
break read_username
}
info.username = username
info.fields += {.Username}
}
err = nil
return
}
@(private="package")
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
pid := process.pid
info.pid = pid
// Data obtained from process snapshots
snapshot_process: if selection >= {.PPid, .Priority} {
entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil {
err = entry_err
if entry_err == General_Error.Not_Exist {
return
} else {
break snapshot_process
}
}
if .PPid in selection {
info.fields += {.PPid}
info.ppid = int(entry.th32ParentProcessID)
}
if .Priority in selection {
info.fields += {.Priority}
info.priority = int(entry.pcPriClassBase)
}
}
snapshot_module: if .Executable_Path in selection {
exe_path: string
exe_path, err = _process_exe_by_pid(pid, allocator)
if _, ok := err.(runtime.Allocator_Error); ok {
return
} else if err != nil {
break snapshot_module
}
info.executable_path = exe_path
info.fields += {.Executable_Path}
}
ph := win32.HANDLE(process.handle)
read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} {
process_info_size: u32
process_info: win32.PROCESS_BASIC_INFORMATION
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
if status != 0 {
// TODO(flysand): There's probably a mismatch between NTSTATUS and
// windows userland error codes, I haven't checked.
err = Platform_Error(status)
return
}
assert(process_info.PebBaseAddress != nil)
process_peb: win32.PEB
_, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb)
if err != nil {
break read_peb
}
process_params: win32.RTL_USER_PROCESS_PARAMETERS
_, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params)
if err != nil {
break read_peb
}
if selection >= {.Command_Line, .Command_Args} {
TEMP_ALLOCATOR_GUARD()
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
if err != nil {
break read_peb
}
if .Command_Line in selection {
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
info.fields += {.Command_Line}
}
if .Command_Args in selection {
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return
info.fields += {.Command_Args}
}
}
if .Environment in selection {
TEMP_ALLOCATOR_GUARD()
env_len := process_params.EnvironmentSize / 2
envs_w := make([]u16, env_len, temp_allocator()) or_return
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
if err != nil {
break read_peb
}
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
info.fields += {.Environment}
}
if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
if err != nil {
break read_peb
}
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
info.fields += {.Working_Dir}
}
}
read_username: if .Username in selection {
username: string
username, err = _get_process_user(ph, allocator)
if _, ok := err.(runtime.Allocator_Error); ok {
return
} else if err != nil {
break read_username
}
info.username = username
info.fields += {.Username} info.fields += {.Username}
} }
err = nil err = nil
@@ -294,15 +328,15 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
@(private="package") @(private="package")
_current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
info.pid = get_pid() info.pid = get_pid()
defer if err != nil { snapshot_process: if selection >= {.PPid, .Priority} {
free_process_info(info, allocator)
}
if selection >= {.PPid, .Priority} { // snap process
entry, entry_err := _process_entry_by_pid(info.pid) entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil { if entry_err != nil {
err = General_Error.Not_Exist err = entry_err
return if entry_err == General_Error.Not_Exist {
return
} else {
break snapshot_process
}
} }
if .PPid in selection { if .PPid in selection {
info.fields += {.PPid} info.fields += {.PPid}
@@ -313,14 +347,16 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
info.priority = int(entry.pcPriClassBase) info.priority = int(entry.pcPriClassBase)
} }
} }
if .Executable_Path in selection { module_filename: if .Executable_Path in selection {
exe_filename_w: [256]u16 exe_filename_w: [256]u16
path_len := win32.GetModuleFileNameW(nil, raw_data(exe_filename_w[:]), len(exe_filename_w)) path_len := win32.GetModuleFileNameW(nil, raw_data(exe_filename_w[:]), len(exe_filename_w))
assert(path_len > 0)
info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_return info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_return
info.fields += {.Executable_Path} info.fields += {.Executable_Path}
} }
if selection >= {.Command_Line, .Command_Args} { command_line: if selection >= {.Command_Line, .Command_Args} {
command_line_w := win32.GetCommandLineW() command_line_w := win32.GetCommandLineW()
assert(command_line_w != nil)
if .Command_Line in selection { if .Command_Line in selection {
info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_return info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_return
info.fields += {.Command_Line} info.fields += {.Command_Line}
@@ -330,14 +366,22 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
info.fields += {.Command_Args} info.fields += {.Command_Args}
} }
} }
if .Environment in selection { read_environment: if .Environment in selection {
env_block := win32.GetEnvironmentStringsW() env_block := win32.GetEnvironmentStringsW()
assert(env_block != nil)
info.environment = _parse_environment_block(env_block, allocator) or_return info.environment = _parse_environment_block(env_block, allocator) or_return
info.fields += {.Environment} info.fields += {.Environment}
} }
if .Username in selection { read_username: if .Username in selection {
process_handle := win32.GetCurrentProcess() process_handle := win32.GetCurrentProcess()
info.username = _get_process_user(process_handle, allocator) or_return username: string
username, err = _get_process_user(process_handle, allocator)
if _, ok := err.(runtime.Allocator_Error); ok {
return
} else if err != nil {
break read_username
}
info.username = username
info.fields += {.Username} info.fields += {.Username}
} }
if .Working_Dir in selection { if .Working_Dir in selection {
+3 -3
View File
@@ -398,9 +398,9 @@ SIOCGIFFLAG :: enum c.int {
PORTSEL = 13, /* Can set media type. */ PORTSEL = 13, /* Can set media type. */
AUTOMEDIA = 14, /* Auto media select active. */ AUTOMEDIA = 14, /* Auto media select active. */
DYNAMIC = 15, /* Dialup device with changing addresses. */ DYNAMIC = 15, /* Dialup device with changing addresses. */
LOWER_UP = 16, LOWER_UP = 16,
DORMANT = 17, DORMANT = 17,
ECHO = 18, ECHO = 18,
} }
SIOCGIFFLAGS :: bit_set[SIOCGIFFLAG; c.int] SIOCGIFFLAGS :: bit_set[SIOCGIFFLAG; c.int]
+5
View File
@@ -19,6 +19,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
elem.data = rawptr(uintptr(val.data) + uintptr(it^ * info.elem_size)) elem.data = rawptr(uintptr(val.data) + uintptr(it^ * info.elem_size))
elem.id = info.elem.id elem.id = info.elem.id
ok = true ok = true
index = it^
it^ += 1 it^ += 1
} }
case Type_Info_Slice: case Type_Info_Slice:
@@ -27,6 +28,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size)) elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size))
elem.id = info.elem.id elem.id = info.elem.id
ok = true ok = true
index = it^
it^ += 1 it^ += 1
} }
case Type_Info_Dynamic_Array: case Type_Info_Dynamic_Array:
@@ -35,6 +37,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size)) elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size))
elem.id = info.elem.id elem.id = info.elem.id
ok = true ok = true
index = it^
it^ += 1 it^ += 1
} }
} }
@@ -69,6 +72,7 @@ iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
key.id = info.key.id key.id = info.key.id
value.id = info.value.id value.id = info.value.id
ok = true ok = true
it^ += 1
break break
} }
@@ -76,3 +80,4 @@ iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
} }
return return
} }
+145 -152
View File
@@ -9,157 +9,157 @@ String :: distinct TypeRef // same as CFStringRef
StringEncoding :: distinct u32 StringEncoding :: distinct u32
StringBuiltInEncodings :: enum StringEncoding { StringBuiltInEncodings :: enum StringEncoding {
MacRoman = 0, MacRoman = 0,
WindowsLatin1 = 0x0500, WindowsLatin1 = 0x0500,
ISOLatin1 = 0x0201, ISOLatin1 = 0x0201,
NextStepLatin = 0x0B01, NextStepLatin = 0x0B01,
ASCII = 0x0600, ASCII = 0x0600,
Unicode = 0x0100, Unicode = 0x0100,
UTF8 = 0x08000100, UTF8 = 0x08000100,
NonLossyASCII = 0x0BFF, NonLossyASCII = 0x0BFF,
UTF16 = 0x0100, UTF16 = 0x0100,
UTF16BE = 0x10000100, UTF16BE = 0x10000100,
UTF16LE = 0x14000100, UTF16LE = 0x14000100,
UTF32 = 0x0c000100, UTF32 = 0x0c000100,
UTF32BE = 0x18000100, UTF32BE = 0x18000100,
UTF32LE = 0x1c000100, UTF32LE = 0x1c000100,
} }
StringEncodings :: enum Index { StringEncodings :: enum Index {
MacJapanese = 1, MacJapanese = 1,
MacChineseTrad = 2, MacChineseTrad = 2,
MacKorean = 3, MacKorean = 3,
MacArabic = 4, MacArabic = 4,
MacHebrew = 5, MacHebrew = 5,
MacGreek = 6, MacGreek = 6,
MacCyrillic = 7, MacCyrillic = 7,
MacDevanagari = 9, MacDevanagari = 9,
MacGurmukhi = 10, MacGurmukhi = 10,
MacGujarati = 11, MacGujarati = 11,
MacOriya = 12, MacOriya = 12,
MacBengali = 13, MacBengali = 13,
MacTamil = 14, MacTamil = 14,
MacTelugu = 15, MacTelugu = 15,
MacKannada = 16, MacKannada = 16,
MacMalayalam = 17, MacMalayalam = 17,
MacSinhalese = 18, MacSinhalese = 18,
MacBurmese = 19, MacBurmese = 19,
MacKhmer = 20, MacKhmer = 20,
MacThai = 21, MacThai = 21,
MacLaotian = 22, MacLaotian = 22,
MacGeorgian = 23, MacGeorgian = 23,
MacArmenian = 24, MacArmenian = 24,
MacChineseSimp = 25, MacChineseSimp = 25,
MacTibetan = 26, MacTibetan = 26,
MacMongolian = 27, MacMongolian = 27,
MacEthiopic = 28, MacEthiopic = 28,
MacCentralEurRoman = 29, MacCentralEurRoman = 29,
MacVietnamese = 30, MacVietnamese = 30,
MacExtArabic = 31, MacExtArabic = 31,
MacSymbol = 33, MacSymbol = 33,
MacDingbats = 34, MacDingbats = 34,
MacTurkish = 35, MacTurkish = 35,
MacCroatian = 36, MacCroatian = 36,
MacIcelandic = 37, MacIcelandic = 37,
MacRomanian = 38, MacRomanian = 38,
MacCeltic = 39, MacCeltic = 39,
MacGaelic = 40, MacGaelic = 40,
MacFarsi = 0x8C, MacFarsi = 0x8C,
MacUkrainian = 0x98, MacUkrainian = 0x98,
MacInuit = 0xEC, MacInuit = 0xEC,
MacVT100 = 0xFC, MacVT100 = 0xFC,
MacHFS = 0xFF, MacHFS = 0xFF,
ISOLatin2 = 0x0202, ISOLatin2 = 0x0202,
ISOLatin3 = 0x0203, ISOLatin3 = 0x0203,
ISOLatin4 = 0x0204, ISOLatin4 = 0x0204,
ISOLatinCyrillic = 0x0205, ISOLatinCyrillic = 0x0205,
ISOLatinArabic = 0x0206, ISOLatinArabic = 0x0206,
ISOLatinGreek = 0x0207, ISOLatinGreek = 0x0207,
ISOLatinHebrew = 0x0208, ISOLatinHebrew = 0x0208,
ISOLatin5 = 0x0209, ISOLatin5 = 0x0209,
ISOLatin6 = 0x020A, ISOLatin6 = 0x020A,
ISOLatinThai = 0x020B, ISOLatinThai = 0x020B,
ISOLatin7 = 0x020D, ISOLatin7 = 0x020D,
ISOLatin8 = 0x020E, ISOLatin8 = 0x020E,
ISOLatin9 = 0x020F, ISOLatin9 = 0x020F,
ISOLatin10 = 0x0210, ISOLatin10 = 0x0210,
DOSLatinUS = 0x0400, DOSLatinUS = 0x0400,
DOSGreek = 0x0405, DOSGreek = 0x0405,
DOSBalticRim = 0x0406, DOSBalticRim = 0x0406,
DOSLatin1 = 0x0410, DOSLatin1 = 0x0410,
DOSGreek1 = 0x0411, DOSGreek1 = 0x0411,
DOSLatin2 = 0x0412, DOSLatin2 = 0x0412,
DOSCyrillic = 0x0413, DOSCyrillic = 0x0413,
DOSTurkish = 0x0414, DOSTurkish = 0x0414,
DOSPortuguese = 0x0415, DOSPortuguese = 0x0415,
DOSIcelandic = 0x0416, DOSIcelandic = 0x0416,
DOSHebrew = 0x0417, DOSHebrew = 0x0417,
DOSCanadianFrench = 0x0418, DOSCanadianFrench = 0x0418,
DOSArabic = 0x0419, DOSArabic = 0x0419,
DOSNordic = 0x041A, DOSNordic = 0x041A,
DOSRussian = 0x041B, DOSRussian = 0x041B,
DOSGreek2 = 0x041C, DOSGreek2 = 0x041C,
DOSThai = 0x041D, DOSThai = 0x041D,
DOSJapanese = 0x0420, DOSJapanese = 0x0420,
DOSChineseSimplif = 0x0421, DOSChineseSimplif = 0x0421,
DOSKorean = 0x0422, DOSKorean = 0x0422,
DOSChineseTrad = 0x0423, DOSChineseTrad = 0x0423,
WindowsLatin2 = 0x0501, WindowsLatin2 = 0x0501,
WindowsCyrillic = 0x0502, WindowsCyrillic = 0x0502,
WindowsGreek = 0x0503, WindowsGreek = 0x0503,
WindowsLatin5 = 0x0504, WindowsLatin5 = 0x0504,
WindowsHebrew = 0x0505, WindowsHebrew = 0x0505,
WindowsArabic = 0x0506, WindowsArabic = 0x0506,
WindowsBalticRim = 0x0507, WindowsBalticRim = 0x0507,
WindowsVietnamese = 0x0508, WindowsVietnamese = 0x0508,
WindowsKoreanJohab = 0x0510, WindowsKoreanJohab = 0x0510,
ANSEL = 0x0601, ANSEL = 0x0601,
JIS_X0201_76 = 0x0620, JIS_X0201_76 = 0x0620,
JIS_X0208_83 = 0x0621, JIS_X0208_83 = 0x0621,
JIS_X0208_90 = 0x0622, JIS_X0208_90 = 0x0622,
JIS_X0212_90 = 0x0623, JIS_X0212_90 = 0x0623,
JIS_C6226_78 = 0x0624, JIS_C6226_78 = 0x0624,
ShiftJIS_X0213 = 0x0628, ShiftJIS_X0213 = 0x0628,
ShiftJIS_X0213_MenKuTen = 0x0629, ShiftJIS_X0213_MenKuTen = 0x0629,
GB_2312_80 = 0x0630, GB_2312_80 = 0x0630,
GBK_95 = 0x0631, GBK_95 = 0x0631,
GB_18030_2000 = 0x0632, GB_18030_2000 = 0x0632,
KSC_5601_87 = 0x0640, KSC_5601_87 = 0x0640,
KSC_5601_92_Johab = 0x0641, KSC_5601_92_Johab = 0x0641,
CNS_11643_92_P1 = 0x0651, CNS_11643_92_P1 = 0x0651,
CNS_11643_92_P2 = 0x0652, CNS_11643_92_P2 = 0x0652,
CNS_11643_92_P3 = 0x0653, CNS_11643_92_P3 = 0x0653,
ISO_2022_JP = 0x0820, ISO_2022_JP = 0x0820,
ISO_2022_JP_2 = 0x0821, ISO_2022_JP_2 = 0x0821,
ISO_2022_JP_1 = 0x0822, ISO_2022_JP_1 = 0x0822,
ISO_2022_JP_3 = 0x0823, ISO_2022_JP_3 = 0x0823,
ISO_2022_CN = 0x0830, ISO_2022_CN = 0x0830,
ISO_2022_CN_EXT = 0x0831, ISO_2022_CN_EXT = 0x0831,
ISO_2022_KR = 0x0840, ISO_2022_KR = 0x0840,
EUC_JP = 0x0920, EUC_JP = 0x0920,
EUC_CN = 0x0930, EUC_CN = 0x0930,
EUC_TW = 0x0931, EUC_TW = 0x0931,
EUC_KR = 0x0940, EUC_KR = 0x0940,
ShiftJIS = 0x0A01, ShiftJIS = 0x0A01,
KOI8_R = 0x0A02, KOI8_R = 0x0A02,
Big5 = 0x0A03, Big5 = 0x0A03,
MacRomanLatin1 = 0x0A04, MacRomanLatin1 = 0x0A04,
HZ_GB_2312 = 0x0A05, HZ_GB_2312 = 0x0A05,
Big5_HKSCS_1999 = 0x0A06, Big5_HKSCS_1999 = 0x0A06,
VISCII = 0x0A07, VISCII = 0x0A07,
KOI8_U = 0x0A08, KOI8_U = 0x0A08,
Big5_E = 0x0A09, Big5_E = 0x0A09,
NextStepJapanese = 0x0B02, NextStepJapanese = 0x0B02,
EBCDIC_US = 0x0C01, EBCDIC_US = 0x0C01,
EBCDIC_CP037 = 0x0C02, EBCDIC_CP037 = 0x0C02,
UTF7 = 0x04000100, UTF7 = 0x04000100,
UTF7_IMAP = 0x0A10, UTF7_IMAP = 0x0A10,
ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead. ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
} }
@(link_prefix = "CF", default_calling_convention = "c") @(link_prefix="CF", default_calling_convention="c")
foreign CoreFoundation { foreign CoreFoundation {
// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding. // Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
StringGetCString :: proc(theString: String, buffer: [^]byte, bufferSize: Index, encoding: StringEncoding) -> b8 --- StringGetCString :: proc(theString: String, buffer: [^]byte, bufferSize: Index, encoding: StringEncoding) -> b8 ---
@@ -181,23 +181,16 @@ foreign CoreFoundation {
STR :: StringMakeConstantString STR :: StringMakeConstantString
StringCopyToOdinString :: proc( StringCopyToOdinString :: proc(theString: String, allocator := context.allocator) -> (str: string, ok: bool) #optional_ok {
theString: String,
allocator := context.allocator,
) -> (
str: string,
ok: bool,
) #optional_ok {
length := StringGetLength(theString) length := StringGetLength(theString)
max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8)) max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8))
buf, err := make([]byte, max, allocator) buf, err := make([]byte, max, allocator)
if err != nil { return } if err != nil {
return
raw_str := runtime.Raw_String {
data = raw_data(buf),
} }
StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), max, (^Index)(&raw_str.len))
return transmute(string)raw_str, true n: Index
StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), Index(len(buf)), &n)
return string(buf[:n]), true
} }
+3 -3
View File
@@ -15,9 +15,9 @@ sys_write_string :: proc (fd: c.int, message: string) -> bool {
Offset_From :: enum c.int { Offset_From :: enum c.int {
SEEK_SET = 0, // the offset is set to offset bytes. 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_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_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_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. 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 { Open_Flags_Enum :: enum u8 {
+29 -29
View File
@@ -192,43 +192,43 @@ _STRUCT_TIMEVAL :: struct {
/* pwd.h */ /* pwd.h */
_Password_Entry :: struct { _Password_Entry :: struct {
pw_name: cstring, /* username */ pw_name: cstring, /* username */
pw_passwd: cstring, /* user password */ pw_passwd: cstring, /* user password */
pw_uid: i32, /* user ID */ pw_uid: i32, /* user ID */
pw_gid: i32, /* group ID */ pw_gid: i32, /* group ID */
pw_change: u64, /* password change time */ pw_change: u64, /* password change time */
pw_class: cstring, /* user access class */ pw_class: cstring, /* user access class */
pw_gecos: cstring, /* full user name */ pw_gecos: cstring, /* full user name */
pw_dir: cstring, /* home directory */ pw_dir: cstring, /* home directory */
pw_shell: cstring, /* shell program */ pw_shell: cstring, /* shell program */
pw_expire: u64, /* account expiration */ pw_expire: u64, /* account expiration */
pw_fields: i32, /* filled fields */ pw_fields: i32, /* filled fields */
} }
/* processinfo.h */ /* processinfo.h */
_Proc_Bsdinfo :: struct { _Proc_Bsdinfo :: struct {
pbi_flags: u32, /* if is 64bit; emulated etc */ pbi_flags: u32, /* if is 64bit; emulated etc */
pbi_status: u32, pbi_status: u32,
pbi_xstatus: u32, pbi_xstatus: u32,
pbi_pid: u32, pbi_pid: u32,
pbi_ppid: u32, pbi_ppid: u32,
pbi_uid: u32, pbi_uid: u32,
pbi_gid: u32, pbi_gid: u32,
pbi_ruid: u32, pbi_ruid: u32,
pbi_rgid: u32, pbi_rgid: u32,
pbi_svuid: u32, pbi_svuid: u32,
pbi_svgid: u32, pbi_svgid: u32,
res: u32, res: u32,
pbi_comm: [DARWIN_MAXCOMLEN]u8, pbi_comm: [DARWIN_MAXCOMLEN]u8,
pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */ pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */
pbi_nfiles: u32, pbi_nfiles: u32,
pbi_pgid: u32, pbi_pgid: u32,
pbi_pjobc: u32, pbi_pjobc: u32,
e_tdev: u32, /* controlling tty dev */ e_tdev: u32, /* controlling tty dev */
e_tpgid: u32, /* tty process group id */ e_tpgid: u32, /* tty process group id */
pbi_nice: i32, pbi_nice: i32,
pbi_start_tvsec: u64, pbi_start_tvsec: u64,
pbi_start_tvusec: u64, pbi_start_tvusec: u64,
} }
/*--==========================================================================--*/ /*--==========================================================================--*/
+6 -6
View File
@@ -695,12 +695,12 @@ Record_Lock_Flag :: enum c.int {
// struct flock // struct flock
File_Lock :: struct { File_Lock :: struct {
start: off_t, /* starting offset */ start: off_t, /* starting offset */
len: off_t, /* len = 0 means until end of file */ len: off_t, /* len = 0 means until end of file */
pid: pid_t, /* lock owner */ pid: pid_t, /* lock owner */
type: Record_Lock_Flag, /* lock type: read/write, etc. */ type: Record_Lock_Flag, /* lock type: read/write, etc. */
whence: c.short, /* type of l_start */ whence: c.short, /* type of l_start */
sysid: c.int, /* remote system id or zero for local */ sysid: c.int, /* remote system id or zero for local */
} }
/* /*
+2 -2
View File
@@ -4,7 +4,7 @@ package sys_windows
foreign import dwmapi "system:Dwmapi.lib" foreign import dwmapi "system:Dwmapi.lib"
DWMWINDOWATTRIBUTE :: enum { DWMWINDOWATTRIBUTE :: enum {
DWMWA_NCRENDERING_ENABLED, DWMWA_NCRENDERING_ENABLED = 1,
DWMWA_NCRENDERING_POLICY, DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED, DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT, DWMWA_ALLOW_NCPAINT,
@@ -28,7 +28,7 @@ DWMWINDOWATTRIBUTE :: enum {
DWMWA_TEXT_COLOR, DWMWA_TEXT_COLOR,
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_SYSTEMBACKDROP_TYPE,
DWMWA_LAST, DWMWA_LAST,
} }
DWMNCRENDERINGPOLICY :: enum { DWMNCRENDERINGPOLICY :: enum {
+8 -8
View File
@@ -1175,17 +1175,17 @@ SYSTEM_POWER_STATUS :: struct {
} }
AC_Line_Status :: enum BYTE { AC_Line_Status :: enum BYTE {
Offline = 0, Offline = 0,
Online = 1, Online = 1,
Unknown = 255, Unknown = 255,
} }
Battery_Flag :: enum BYTE { Battery_Flag :: enum BYTE {
High = 0, High = 0,
Low = 1, Low = 1,
Critical = 2, Critical = 2,
Charging = 3, Charging = 3,
No_Battery = 7, No_Battery = 7,
} }
Battery_Flags :: bit_set[Battery_Flag; BYTE] Battery_Flags :: bit_set[Battery_Flag; BYTE]
+26 -26
View File
@@ -3546,11 +3546,11 @@ SIGDN :: enum c_int {
} }
SIATTRIBFLAGS :: enum c_int { SIATTRIBFLAGS :: enum c_int {
AND = 0x1, AND = 0x1,
OR = 0x2, OR = 0x2,
APPCOMPAT = 0x3, APPCOMPAT = 0x3,
MASK = 0x3, MASK = 0x3,
ALLITEMS = 0x4000, ALLITEMS = 0x4000,
} }
FDAP :: enum c_int { FDAP :: enum c_int {
@@ -4503,35 +4503,35 @@ DNS_INFO_NO_RECORDS :: 9501
DNS_QUERY_NO_RECURSION :: 0x00000004 DNS_QUERY_NO_RECURSION :: 0x00000004
DNS_RECORD :: struct { // aka DNS_RECORDA DNS_RECORD :: struct { // aka DNS_RECORDA
pNext: ^DNS_RECORD, pNext: ^DNS_RECORD,
pName: cstring, pName: cstring,
wType: WORD, wType: WORD,
wDataLength: USHORT, wDataLength: USHORT,
Flags: DWORD, Flags: DWORD,
dwTtl: DWORD, dwTtl: DWORD,
_: DWORD, _: DWORD,
Data: struct #raw_union { Data: struct #raw_union {
CNAME: DNS_PTR_DATAA, CNAME: DNS_PTR_DATAA,
A: u32be, // Ipv4 Address A: u32be, // Ipv4 Address
AAAA: u128be, // Ipv6 Address AAAA: u128be, // Ipv6 Address
TXT: DNS_TXT_DATAA, TXT: DNS_TXT_DATAA,
NS: DNS_PTR_DATAA, NS: DNS_PTR_DATAA,
MX: DNS_MX_DATAA, MX: DNS_MX_DATAA,
SRV: DNS_SRV_DATAA, SRV: DNS_SRV_DATAA,
}, },
} }
DNS_TXT_DATAA :: struct { DNS_TXT_DATAA :: struct {
dwStringCount: DWORD, dwStringCount: DWORD,
pStringArray: cstring, pStringArray: cstring,
} }
DNS_PTR_DATAA :: cstring DNS_PTR_DATAA :: cstring
DNS_MX_DATAA :: struct { DNS_MX_DATAA :: struct {
pNameExchange: cstring, // the hostname pNameExchange: cstring, // the hostname
wPreference: WORD, // lower values preferred wPreference: WORD, // lower values preferred
_: WORD, // padding. _: WORD, // padding.
} }
DNS_SRV_DATAA :: struct { DNS_SRV_DATAA :: struct {
pNameTarget: cstring, pNameTarget: cstring,
+1 -1
View File
@@ -56,7 +56,7 @@ Decorations :: struct {
// Connecting decorations: // Connecting decorations:
nw, n, ne, nw, n, ne,
w, x, e, w, x, e,
sw, s, se: string, sw, s, se: string,
// Straight lines: // Straight lines:
+6 -2
View File
@@ -175,10 +175,12 @@ pool_stop_task :: proc(pool: ^Pool, user_index: int, exit_code: int = 1) -> bool
intrinsics.atomic_sub(&pool.num_outstanding, 1) intrinsics.atomic_sub(&pool.num_outstanding, 1)
intrinsics.atomic_sub(&pool.num_in_processing, 1) intrinsics.atomic_sub(&pool.num_in_processing, 1)
old_thread_user_index := t.user_index
destroy(t) destroy(t)
replacement := create(pool_thread_runner) replacement := create(pool_thread_runner)
replacement.user_index = t.user_index replacement.user_index = old_thread_user_index
replacement.data = data replacement.data = data
data.task = {} data.task = {}
pool.threads[i] = replacement pool.threads[i] = replacement
@@ -207,10 +209,12 @@ pool_stop_all_tasks :: proc(pool: ^Pool, exit_code: int = 1) {
intrinsics.atomic_sub(&pool.num_outstanding, 1) intrinsics.atomic_sub(&pool.num_outstanding, 1)
intrinsics.atomic_sub(&pool.num_in_processing, 1) intrinsics.atomic_sub(&pool.num_in_processing, 1)
old_thread_user_index := t.user_index
destroy(t) destroy(t)
replacement := create(pool_thread_runner) replacement := create(pool_thread_runner)
replacement.user_index = t.user_index replacement.user_index = old_thread_user_index
replacement.data = data replacement.data = data
data.task = {} data.task = {}
pool.threads[i] = replacement pool.threads[i] = replacement
+5 -1
View File
@@ -2,6 +2,7 @@
// +private // +private
package thread package thread
import "base:runtime"
import "core:sync" import "core:sync"
import "core:sys/unix" import "core:sys/unix"
import "core:time" import "core:time"
@@ -55,7 +56,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition // Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition
// variable above. We must perform that waiting BEFORE we select the context! // variable above. We must perform that waiting BEFORE we select the context!
context = _select_context_for_thread(init_context) context = _select_context_for_thread(init_context)
defer _maybe_destroy_default_temp_allocator(init_context) defer {
_maybe_destroy_default_temp_allocator(init_context)
runtime.run_thread_local_cleaners()
}
t.procedure(t) t.procedure(t)
} }
+5 -1
View File
@@ -3,6 +3,7 @@
package thread package thread
import "base:intrinsics" import "base:intrinsics"
import "base:runtime"
import "core:sync" import "core:sync"
import win32 "core:sys/windows" import win32 "core:sys/windows"
@@ -39,7 +40,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call // Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call
// to t.procedure(). // to t.procedure().
context = _select_context_for_thread(init_context) context = _select_context_for_thread(init_context)
defer _maybe_destroy_default_temp_allocator(init_context) defer {
_maybe_destroy_default_temp_allocator(init_context)
runtime.run_thread_local_cleaners()
}
t.procedure(t) t.procedure(t)
} }
+61
View File
@@ -2048,6 +2048,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return ok; return ok;
} }
if (BuiltinProc__atomic_begin < id && id < BuiltinProc__atomic_end) {
if (build_context.metrics.arch == TargetArch_riscv64) {
if (!check_target_feature_is_enabled(str_lit("a"), nullptr)) {
error(call, "missing required target feature \"a\" for atomics, enable it by setting a different -microarch or explicitly adding it through -target-features");
}
}
}
switch (id) { switch (id) {
default: default:
GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name));
@@ -5665,6 +5673,59 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break; break;
} }
break; break;
case BuiltinProc_type_has_shared_fields:
{
Type *u = check_type(c, ce->args[0]);
Type *ut = base_type(u);
if (ut == nullptr || ut == t_invalid) {
error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name));
return false;
}
if (ut->kind != Type_Struct || ut->Struct.soa_kind != StructSoa_None) {
gbString t = type_to_string(ut);
error(ce->args[0], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t);
gb_string_free(t);
return false;
}
Type *v = check_type(c, ce->args[1]);
Type *vt = base_type(v);
if (vt == nullptr || vt == t_invalid) {
error(ce->args[1], "Expected a type for '%.*s'", LIT(builtin_name));
return false;
}
if (vt->kind != Type_Struct || vt->Struct.soa_kind != StructSoa_None) {
gbString t = type_to_string(vt);
error(ce->args[1], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t);
gb_string_free(t);
return false;
}
bool is_shared = true;
for (Entity *v_field : vt->Struct.fields) {
bool found = false;
for (Entity *u_field : ut->Struct.fields) {
if (v_field->token.string == u_field->token.string &&
are_types_identical(v_field->type, u_field->type)) {
found = true;
break;
}
}
if (!found) {
is_shared = false;
break;
}
}
operand->mode = Addressing_Constant;
operand->value = exact_value_bool(is_shared);
operand->type = t_untyped_bool;
break;
}
case BuiltinProc_type_field_type: case BuiltinProc_type_field_type:
{ {
Operand op = {}; Operand op = {};
+32 -9
View File
@@ -1180,11 +1180,15 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
LIT(article), LIT(article),
LIT(context_name)); LIT(context_name));
} else { } else {
ERROR_BLOCK();
error(operand->expr, error(operand->expr,
"Cannot assign '%s', a type, to %.*s%.*s", "Cannot assign '%s', a type, to %.*s%.*s",
op_type_str, op_type_str,
LIT(article), LIT(article),
LIT(context_name)); LIT(context_name));
if (type && are_types_identical(type, t_any)) {
error_line("\tSuggestion: 'typeid_of(%s)'", expr_str);
}
} }
break; break;
default: default:
@@ -3782,10 +3786,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
// NOTE(bill): Allow comparisons between types // NOTE(bill): Allow comparisons between types
if (is_ise_expr(be->left)) { if (is_ise_expr(be->left)) {
// Evalute the right before the left for an '.X' expression // Evalute the right before the left for an '.X' expression
check_expr_or_type(c, y, be->right, type_hint); check_expr_or_type(c, y, be->right, nullptr /* ignore type hint */);
check_expr_or_type(c, x, be->left, y->type); check_expr_or_type(c, x, be->left, y->type);
} else { } else {
check_expr_or_type(c, x, be->left, type_hint); check_expr_or_type(c, x, be->left, nullptr /* ignore type hint */);
check_expr_or_type(c, y, be->right, x->type); check_expr_or_type(c, y, be->right, x->type);
} }
bool xt = x->mode == Addressing_Type; bool xt = x->mode == Addressing_Type;
@@ -4658,7 +4662,8 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open
check_expr_with_type_hint(c, &operand, index_value, type_hint); check_expr_with_type_hint(c, &operand, index_value, type_hint);
if (operand.mode == Addressing_Invalid) { if (operand.mode == Addressing_Invalid) {
if (value) *value = 0; if (value) *value = 0;
return false; // NOTE(bill): return true here to propagate the errors better
return true;
} }
Type *index_type = t_int; Type *index_type = t_int;
@@ -4879,7 +4884,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
TypeAndValue tav = fv->value->tav; TypeAndValue tav = fv->value->tav;
if (success_) *success_ = true; if (success_) *success_ = true;
if (finish_) *finish_ = false; if (finish_) *finish_ = false;
return tav.value;; return tav.value;
} }
} }
@@ -4954,7 +4959,6 @@ gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *oper
return value; return value;
} }
} }
if (success_) *success_ = true; if (success_) *success_ = true;
return value; return value;
} else if (value.kind == ExactValue_Quaternion) { } else if (value.kind == ExactValue_Quaternion) {
@@ -7625,7 +7629,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
gbString s = gb_string_make_reserve(heap_allocator(), e->token.string.len+3); gbString s = gb_string_make_reserve(heap_allocator(), e->token.string.len+3);
s = gb_string_append_fmt(s, "%.*s(", LIT(e->token.string)); s = gb_string_append_fmt(s, "%.*s(", LIT(e->token.string));
TypeTuple *tuple = get_record_polymorphic_params(e->type); TypeTuple *tuple = get_record_polymorphic_params(bt);
if (tuple != nullptr) for_array(i, tuple->variables) { if (tuple != nullptr) for_array(i, tuple->variables) {
Entity *v = tuple->variables[i]; Entity *v = tuple->variables[i];
String name = v->token.string; String name = v->token.string;
@@ -7640,8 +7644,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
s = write_type_to_string(s, v->type, false); s = write_type_to_string(s, v->type, false);
} }
} else if (v->kind == Entity_Constant) { } else if (v->kind == Entity_Constant) {
s = gb_string_append_fmt(s, "="); if (v->Constant.value.kind != ExactValue_Invalid) {
s = write_exact_value_to_string(s, v->Constant.value); s = gb_string_append_fmt(s, "=");
s = write_exact_value_to_string(s, v->Constant.value);
}
} }
} }
s = gb_string_append_fmt(s, ")"); s = gb_string_append_fmt(s, ")");
@@ -10055,6 +10061,22 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
is_constant = o->mode == Addressing_Constant; is_constant = o->mode == Addressing_Constant;
} }
if (elem->kind == Ast_BinaryExpr) {
switch (elem->BinaryExpr.op.kind) {
case Token_Or:
{
gbString x = expr_to_string(elem->BinaryExpr.left);
gbString y = expr_to_string(elem->BinaryExpr.right);
gbString e = expr_to_string(elem);
error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e);
gb_string_free(e);
gb_string_free(y);
gb_string_free(x);
}
break;
}
}
check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal"));
if (o->mode == Addressing_Constant) { if (o->mode == Addressing_Constant) {
i64 lower = t->BitSet.lower; i64 lower = t->BitSet.lower;
@@ -10544,7 +10566,8 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
o->expr = node; o->expr = node;
return kind; return kind;
} else if (ok && !is_type_matrix(t)) { } else if (ok && !is_type_matrix(t)) {
ExactValue value = type_and_value_of_expr(ie->expr).value; TypeAndValue tav = type_and_value_of_expr(ie->expr);
ExactValue value = tav.value;
o->mode = Addressing_Constant; o->mode = Addressing_Constant;
bool success = false; bool success = false;
bool finish = false; bool finish = false;
+10 -1
View File
@@ -199,6 +199,9 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit)
} }
break; break;
case Ast_DeferStmt:
return check_has_break(stmt->DeferStmt.stmt, label, implicit);
case Ast_BlockStmt: case Ast_BlockStmt:
return check_has_break_list(stmt->BlockStmt.stmts, label, implicit); return check_has_break_list(stmt->BlockStmt.stmts, label, implicit);
@@ -1695,7 +1698,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
} }
} }
} }
bool is_ptr = type_deref(operand.type); bool is_ptr = is_type_pointer(type_deref(operand.type));
Type *t = base_type(type_deref(operand.type)); Type *t = base_type(type_deref(operand.type));
switch (t->kind) { switch (t->kind) {
@@ -1735,6 +1738,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
break; break;
case Type_EnumeratedArray: case Type_EnumeratedArray:
is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr;
array_add(&vals, t->EnumeratedArray.elem); array_add(&vals, t->EnumeratedArray.elem);
array_add(&vals, t->EnumeratedArray.index); array_add(&vals, t->EnumeratedArray.index);
break; break;
@@ -2706,6 +2710,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
error(bs->label, "A branch statement's label name must be an identifier"); error(bs->label, "A branch statement's label name must be an identifier");
return; return;
} }
Ast *ident = bs->label; Ast *ident = bs->label;
String name = ident->Ident.token.string; String name = ident->Ident.token.string;
Operand o = {}; Operand o = {};
@@ -2737,6 +2742,10 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
break; break;
} }
if (ctx->in_defer) {
error(bs->label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(token.string));
}
} }
case_end; case_end;
+29 -9
View File
@@ -3174,8 +3174,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
return true; return true;
} else if (name == "link_prefix") { } else if (name == "link_prefix") {
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
String link_prefix = ev.value_string; String link_prefix = string_trim_whitespace(ev.value_string);
if (!is_foreign_name_valid(link_prefix)) { if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) {
error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix)); error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix));
} else { } else {
c->foreign_context.link_prefix = link_prefix; c->foreign_context.link_prefix = link_prefix;
@@ -3186,8 +3186,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
return true; return true;
} else if (name == "link_suffix") { } else if (name == "link_suffix") {
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
String link_suffix = ev.value_string; String link_suffix = string_trim_whitespace(ev.value_string);
if (!is_foreign_name_valid(link_suffix)) { if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) {
error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix)); error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix));
} else { } else {
c->foreign_context.link_suffix = link_suffix; c->foreign_context.link_suffix = link_suffix;
@@ -3489,7 +3489,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
ac->link_prefix = ev.value_string; ac->link_prefix = ev.value_string;
if (!is_foreign_name_valid(ac->link_prefix)) { if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) {
error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix));
} }
} else { } else {
@@ -3501,7 +3501,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
ac->link_suffix = ev.value_string; ac->link_suffix = ev.value_string;
if (!is_foreign_name_valid(ac->link_suffix)) { if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) {
error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
} }
} else { } else {
@@ -3774,7 +3774,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ExactValue ev = check_decl_attribute_value(c, value); ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
ac->link_prefix = ev.value_string; ac->link_prefix = ev.value_string;
if (!is_foreign_name_valid(ac->link_prefix)) { if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) {
error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix));
} }
} else { } else {
@@ -3785,7 +3785,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ExactValue ev = check_decl_attribute_value(c, value); ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
ac->link_suffix = ev.value_string; ac->link_suffix = ev.value_string;
if (!is_foreign_name_valid(ac->link_suffix)) { if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) {
error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
} }
} else { } else {
@@ -4532,7 +4532,9 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
case_end; case_end;
case_ast_node(fb, ForeignBlockDecl, decl); case_ast_node(fb, ForeignBlockDecl, decl);
check_add_foreign_block_decl(c, decl); if (curr_file != nullptr) {
array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl);
}
case_end; case_end;
default: default:
@@ -4548,6 +4550,14 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
// NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something
// declared after this stmt in source // declared after this stmt in source
if (curr_file == nullptr) { if (curr_file == nullptr) {
// For 'foreign' block statements that are not in file scope.
for_array(decl_index, nodes) {
Ast *decl = nodes[decl_index];
if (decl->kind == Ast_ForeignBlockDecl) {
check_add_foreign_block_decl(c, decl);
}
}
for_array(decl_index, nodes) { for_array(decl_index, nodes) {
Ast *decl = nodes[decl_index]; Ast *decl = nodes[decl_index];
if (decl->kind == Ast_WhenStmt) { if (decl->kind == Ast_WhenStmt) {
@@ -5508,6 +5518,16 @@ gb_internal void check_import_entities(Checker *c) {
correct_type_aliases_in_scope(&ctx, pkg->scope); correct_type_aliases_in_scope(&ctx, pkg->scope);
} }
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
reset_checker_context(&ctx, f, &untyped);
for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) {
check_add_foreign_block_decl(&ctx, decl);
}
array_clear(&f->delayed_decls_queues[AstDelayQueue_ForeignBlock]);
}
for_array(i, pkg->files) { for_array(i, pkg->files) {
AstFile *f = pkg->files[i]; AstFile *f = pkg->files[i];
reset_checker_context(&ctx, f, &untyped); reset_checker_context(&ctx, f, &untyped);
+7
View File
@@ -99,6 +99,7 @@ enum BuiltinProcId {
BuiltinProc_prefetch_write_instruction, BuiltinProc_prefetch_write_instruction,
BuiltinProc_prefetch_write_data, BuiltinProc_prefetch_write_data,
BuiltinProc__atomic_begin,
BuiltinProc_atomic_type_is_lock_free, BuiltinProc_atomic_type_is_lock_free,
BuiltinProc_atomic_thread_fence, BuiltinProc_atomic_thread_fence,
BuiltinProc_atomic_signal_fence, BuiltinProc_atomic_signal_fence,
@@ -124,6 +125,7 @@ enum BuiltinProcId {
BuiltinProc_atomic_compare_exchange_strong_explicit, BuiltinProc_atomic_compare_exchange_strong_explicit,
BuiltinProc_atomic_compare_exchange_weak, BuiltinProc_atomic_compare_exchange_weak,
BuiltinProc_atomic_compare_exchange_weak_explicit, BuiltinProc_atomic_compare_exchange_weak_explicit,
BuiltinProc__atomic_end,
BuiltinProc_fixed_point_mul, BuiltinProc_fixed_point_mul,
BuiltinProc_fixed_point_div, BuiltinProc_fixed_point_div,
@@ -313,6 +315,8 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_map_info, BuiltinProc_type_map_info,
BuiltinProc_type_map_cell_info, BuiltinProc_type_map_cell_info,
BuiltinProc_type_has_shared_fields,
BuiltinProc__type_end, BuiltinProc__type_end,
BuiltinProc_procedure_of, BuiltinProc_procedure_of,
@@ -436,6 +440,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
@@ -461,6 +466,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -647,6 +653,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_has_shared_fields"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
+13 -3
View File
@@ -55,6 +55,16 @@ gb_internal void lb_debug_file_line(lbModule *m, Ast *node, LLVMMetadataRef *fil
} }
} }
gb_internal LLVMMetadataRef lb_debug_procedure_parameters(lbModule *m, Type *type) {
if (is_type_proc(type)) {
return lb_debug_type(m, t_rawptr);
}
if (type->kind == Type_Tuple && type->Tuple.variables.count == 1) {
return lb_debug_procedure_parameters(m, type->Tuple.variables[0]->type);
}
return lb_debug_type(m, type);
}
gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) { gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
i64 size = type_size_of(type); // Check size i64 size = type_size_of(type); // Check size
gb_unused(size); gb_unused(size);
@@ -78,7 +88,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type)
if (type->Proc.result_count == 0) { if (type->Proc.result_count == 0) {
parameters[param_index++] = nullptr; parameters[param_index++] = nullptr;
} else { } else {
parameters[param_index++] = lb_debug_type(m, type->Proc.results); parameters[param_index++] = lb_debug_procedure_parameters(m, type->Proc.results);
} }
LLVMMetadataRef file = nullptr; LLVMMetadataRef file = nullptr;
@@ -88,7 +98,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type)
if (e->kind != Entity_Variable) { if (e->kind != Entity_Variable) {
continue; continue;
} }
parameters[param_index] = lb_debug_type(m, e->type); parameters[param_index] = lb_debug_procedure_parameters(m, e->type);
param_index += 1; param_index += 1;
} }
@@ -969,7 +979,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
return lb_debug_struct(m, type, bt, name, scope, file, line); return lb_debug_struct(m, type, bt, name, scope, file, line);
} }
case Type_Struct: return lb_debug_struct(m, type, base_type(type), name, scope, file, line); case Type_Struct: return lb_debug_struct(m, type, bt, name, scope, file, line);
case Type_Slice: return lb_debug_slice(m, type, name, scope, file, line); case Type_Slice: return lb_debug_slice(m, type, name, scope, file, line);
case Type_DynamicArray: return lb_debug_dynamic_array(m, type, name, scope, file, line); case Type_DynamicArray: return lb_debug_dynamic_array(m, type, name, scope, file, line);
case Type_Union: return lb_debug_union(m, type, name, scope, file, line); case Type_Union: return lb_debug_union(m, type, name, scope, file, line);
+1 -1
View File
@@ -263,7 +263,7 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { if (is_type_simd_vector(src) && is_type_simd_vector(dst)) {
res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), "");
return res; return res;
} else if (is_type_array_like(src) && is_type_simd_vector(dst)) { } else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) {
unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst)); unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst));
lbValue ptr = lb_address_from_load_or_generate_local(p, value); lbValue ptr = lb_address_from_load_or_generate_local(p, value);
if (lb_try_update_alignment(ptr, align)) { if (lb_try_update_alignment(ptr, align)) {
+39 -9
View File
@@ -1921,6 +1921,9 @@ gb_internal Array<Ast *> parse_enum_field_list(AstFile *f) {
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
CommentGroup *docs = f->lead_comment; CommentGroup *docs = f->lead_comment;
CommentGroup *comment = nullptr; CommentGroup *comment = nullptr;
parse_enforce_tabs(f);
Ast *name = parse_value(f); Ast *name = parse_value(f);
Ast *value = nullptr; Ast *value = nullptr;
if (f->curr_token.kind == Token_Eq) { if (f->curr_token.kind == Token_Eq) {
@@ -2259,6 +2262,7 @@ gb_internal Array<Ast *> parse_union_variant_list(AstFile *f) {
auto variants = array_make<Ast *>(ast_allocator(f)); auto variants = array_make<Ast *>(ast_allocator(f));
while (f->curr_token.kind != Token_CloseBrace && while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
parse_enforce_tabs(f);
Ast *type = parse_type(f); Ast *type = parse_type(f);
if (type->kind != Ast_BadExpr) { if (type->kind != Ast_BadExpr) {
array_add(&variants, type); array_add(&variants, type);
@@ -4274,6 +4278,7 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
while (f->curr_token.kind != follow && while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_Colon &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
if (!is_signature) parse_enforce_tabs(f);
u32 flags = parse_field_prefixes(f); u32 flags = parse_field_prefixes(f);
Ast *param = parse_var_type(f, allow_ellipsis, allow_typeid_token); Ast *param = parse_var_type(f, allow_ellipsis, allow_typeid_token);
if (param->kind == Ast_Ellipsis) { if (param->kind == Ast_Ellipsis) {
@@ -4363,6 +4368,8 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
f->curr_token.kind != Token_EOF && f->curr_token.kind != Token_EOF &&
f->curr_token.kind != Token_Semicolon) { f->curr_token.kind != Token_Semicolon) {
CommentGroup *docs = f->lead_comment; CommentGroup *docs = f->lead_comment;
if (!is_signature) parse_enforce_tabs(f);
u32 set_flags = parse_field_prefixes(f); u32 set_flags = parse_field_prefixes(f);
Token tag = {}; Token tag = {};
Array<Ast *> names = parse_ident_list(f, allow_poly_names); Array<Ast *> names = parse_ident_list(f, allow_poly_names);
@@ -4532,6 +4539,10 @@ gb_internal Ast *parse_if_stmt(AstFile *f) {
return ast_bad_stmt(f, f->curr_token, f->curr_token); return ast_bad_stmt(f, f->curr_token, f->curr_token);
} }
Ast *top_if_stmt = nullptr;
Ast *prev_if_stmt = nullptr;
if_else_chain:;
Token token = expect_token(f, Token_if); Token token = expect_token(f, Token_if);
Ast *init = nullptr; Ast *init = nullptr;
Ast *cond = nullptr; Ast *cond = nullptr;
@@ -4573,12 +4584,24 @@ gb_internal Ast *parse_if_stmt(AstFile *f) {
ignore_strict_style = true; ignore_strict_style = true;
} }
skip_possible_newline_for_literal(f, ignore_strict_style); skip_possible_newline_for_literal(f, ignore_strict_style);
Ast *curr_if_stmt = ast_if_stmt(f, token, init, cond, body, nullptr);
if (top_if_stmt == nullptr) {
top_if_stmt = curr_if_stmt;
}
if (prev_if_stmt != nullptr) {
prev_if_stmt->IfStmt.else_stmt = curr_if_stmt;
}
if (f->curr_token.kind == Token_else) { if (f->curr_token.kind == Token_else) {
Token else_token = expect_token(f, Token_else); Token else_token = expect_token(f, Token_else);
switch (f->curr_token.kind) { switch (f->curr_token.kind) {
case Token_if: case Token_if:
else_stmt = parse_if_stmt(f); // NOTE(bill): Instead of relying on recursive descent for an if-else chain
break; // we can just inline the tail-recursion manually with a simple loop like
// construct using a `goto`
prev_if_stmt = curr_if_stmt;
goto if_else_chain;
case Token_OpenBrace: case Token_OpenBrace:
else_stmt = parse_block_stmt(f, false); else_stmt = parse_block_stmt(f, false);
break; break;
@@ -4593,7 +4616,9 @@ gb_internal Ast *parse_if_stmt(AstFile *f) {
} }
} }
return ast_if_stmt(f, token, init, cond, body, else_stmt); curr_if_stmt->IfStmt.else_stmt = else_stmt;
return top_if_stmt;
} }
gb_internal Ast *parse_when_stmt(AstFile *f) { gb_internal Ast *parse_when_stmt(AstFile *f) {
@@ -5357,6 +5382,11 @@ gb_internal u64 check_vet_flags(AstFile *file) {
gb_internal void parse_enforce_tabs(AstFile *f) { gb_internal void parse_enforce_tabs(AstFile *f) {
// Checks to see if tabs have been used for indentation
if ((check_vet_flags(f) & VetFlag_Tabs) == 0) {
return;
}
Token prev = f->prev_token; Token prev = f->prev_token;
Token curr = f->curr_token; Token curr = f->curr_token;
if (prev.pos.line < curr.pos.line) { if (prev.pos.line < curr.pos.line) {
@@ -5373,6 +5403,10 @@ gb_internal void parse_enforce_tabs(AstFile *f) {
isize len = end-it; isize len = end-it;
for (isize i = 0; i < len; i++) { for (isize i = 0; i < len; i++) {
if (it[i] == '/') {
// ignore comments
break;
}
if (it[i] == ' ') { if (it[i] == ' ') {
syntax_error(curr, "With '-vet-tabs', tabs must be used for indentation"); syntax_error(curr, "With '-vet-tabs', tabs must be used for indentation");
break; break;
@@ -5387,11 +5421,7 @@ gb_internal Array<Ast *> parse_stmt_list(AstFile *f) {
while (f->curr_token.kind != Token_case && while (f->curr_token.kind != Token_case &&
f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
parse_enforce_tabs(f);
// Checks to see if tabs have been used for indentation
if (check_vet_flags(f) & VetFlag_Tabs) {
parse_enforce_tabs(f);
}
Ast *stmt = parse_stmt(f); Ast *stmt = parse_stmt(f);
if (stmt && stmt->kind != Ast_EmptyStmt) { if (stmt && stmt->kind != Ast_EmptyStmt) {
@@ -6416,7 +6446,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
} }
f->total_file_decl_count += calc_decl_count(stmt); f->total_file_decl_count += calc_decl_count(stmt);
if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl) { if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl || stmt->kind == Ast_ForeignBlockDecl) {
f->delayed_decl_count += 1; f->delayed_decl_count += 1;
} }
} }
+4
View File
@@ -82,6 +82,7 @@ enum AstFileFlag : u32 {
enum AstDelayQueueKind { enum AstDelayQueueKind {
AstDelayQueue_Import, AstDelayQueue_Import,
AstDelayQueue_Expr, AstDelayQueue_Expr,
AstDelayQueue_ForeignBlock,
AstDelayQueue_COUNT, AstDelayQueue_COUNT,
}; };
@@ -886,3 +887,6 @@ gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind);
gb_internal gbString expr_to_string(Ast *expression); gb_internal gbString expr_to_string(Ast *expression);
gb_internal bool allow_field_separator(AstFile *f); gb_internal bool allow_field_separator(AstFile *f);
gb_internal void parse_enforce_tabs(AstFile *f);
@@ -69,18 +69,18 @@ test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, po
complex_power := LIBC_COMPLEX(complex(F(n), F(0.))) complex_power := LIBC_COMPLEX(complex(F(n), F(0.)))
result := pow(complex_base, complex_power) result := pow(complex_base, complex_power)
switch n%%4 { switch n%%4 {
case 0: case 0:
expected_real = value expected_real = value
expected_imag = 0. expected_imag = 0.
case 1: case 1:
expected_real = 0. expected_real = 0.
expected_imag = value expected_imag = value
case 2: case 2:
expected_real = -value expected_real = -value
expected_imag = 0. expected_imag = 0.
case 3: case 3:
expected_real = 0. expected_real = 0.
expected_imag = -value expected_imag = -value
} }
testing.expectf(t, isclose(t, expected_real, F(real(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol) testing.expectf(t, isclose(t, expected_real, F(real(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol)
testing.expectf(t, isclose(t, expected_imag, F(imag(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol) testing.expectf(t, isclose(t, expected_imag, F(imag(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol)
+1 -1
View File
@@ -187,7 +187,7 @@ validate_rbtree :: proc(t: ^testing.T, tree: ^$T/rb.Tree($Key, $Value)) {
} }
verify_rbtree_propery_1 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) { verify_rbtree_propery_1 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) {
testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.") testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.")
if n == nil { if n == nil {
return return
} }
+1 -1
View File
@@ -429,7 +429,7 @@ map_with_integer_keys :: proc(t: ^testing.T) {
defer delete_map(my_map2) defer delete_map(my_map2)
unmarshal_err := json.unmarshal(marshaled_data, &my_map2) unmarshal_err := json.unmarshal(marshaled_data, &my_map2)
defer for key, item in my_map2 { defer for _, item in my_map2 {
runtime.delete_string(item) runtime.delete_string(item)
} }
testing.expectf(t, unmarshal_err == nil, "Expected `json.unmarshal` to return nil, got %v", unmarshal_err) testing.expectf(t, unmarshal_err == nil, "Expected `json.unmarshal` to return nil, got %v", unmarshal_err)
+5 -5
View File
@@ -241,7 +241,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
written += fmt.wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) written += fmt.wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident)
if len(doc.doctype.rest) > 0 { if len(doc.doctype.rest) > 0 {
fmt.wprintf(writer, "\t%v\n", doc.doctype.rest) fmt.wprintf(writer, "\t%v\n", doc.doctype.rest)
} }
} }
@@ -250,10 +250,10 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
} }
if doc.element_count > 0 { if doc.element_count > 0 {
fmt.wprintln(writer, " --- ") fmt.wprintln(writer, " --- ")
print_element(writer, doc, 0) print_element(writer, doc, 0)
fmt.wprintln(writer, " --- ") fmt.wprintln(writer, " --- ")
} }
return written, .None return written, .None
} }
@@ -11,6 +11,7 @@ import "core:testing"
test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) { test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) {
arena: runtime.Arena arena: runtime.Arena
context.allocator = runtime.arena_allocator(&arena) context.allocator = runtime.arena_allocator(&arena)
defer runtime.arena_destroy(&arena)
_, _ = mem.alloc(int(runtime.DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE)-120) _, _ = mem.alloc(int(runtime.DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE)-120)
_, err := mem.alloc(112, 32) _, err := mem.alloc(112, 32)
@@ -22,6 +23,7 @@ test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) {
test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) { test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) {
arena: runtime.Arena arena: runtime.Arena
context.allocator = runtime.arena_allocator(&arena) context.allocator = runtime.arena_allocator(&arena)
defer runtime.arena_destroy(&arena)
mappy: map[[8]int]int mappy: map[[8]int]int
err := reserve(&mappy, 50000) err := reserve(&mappy, 50000)
@@ -32,6 +34,7 @@ test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) {
test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) { test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) {
arena: runtime.Arena arena: runtime.Arena
context.allocator = runtime.arena_allocator(&arena) context.allocator = runtime.arena_allocator(&arena)
defer runtime.arena_destroy(&arena)
bytes, err := mem.alloc_bytes(10, 16) bytes, err := mem.alloc_bytes(10, 16)
testing.expect(t, err == nil) testing.expect(t, err == nil)
+1 -2
View File
@@ -16,8 +16,7 @@ run_test_cases :: proc(t: ^testing.T, test_cases: []Test_Case, loc := #caller_lo
result, _, _ := utf8.grapheme_count(c.str) result, _, _ := utf8.grapheme_count(c.str)
if !testing.expectf(t, result == c.expected_clusters, if !testing.expectf(t, result == c.expected_clusters,
"(#% 4i) graphemes: %i != %i, %q %s", i, result, c.expected_clusters, c.str, c.str, "(#% 4i) graphemes: %i != %i, %q %s", i, result, c.expected_clusters, c.str, c.str,
loc = loc) loc = loc) {
{
failed += 1 failed += 1
} }
} }
+1 -1
View File
@@ -338,7 +338,7 @@ foreign lib {
node_set_list_tight :: proc(node: ^Node, tight: b32) -> (success: b32) --- node_set_list_tight :: proc(node: ^Node, tight: b32) -> (success: b32) ---
// Returns the info string from a fenced code block. // Returns the info string from a fenced code block.
get_fence_info :: proc(node: ^Node) -> (fence_info: cstring) --- node_get_fence_info :: proc(node: ^Node) -> (fence_info: cstring) ---
// Sets the info string in a fenced code block, returning `true` on success and `false` on failure. // Sets the info string in a fenced code block, returning `true` on success and `false` on failure.
node_set_fence_info :: proc(node: ^Node, fence_info: cstring) -> (success: b32) --- node_set_fence_info :: proc(node: ^Node, fence_info: cstring) -> (success: b32) ---
+4 -4
View File
@@ -3459,10 +3459,10 @@ DRED_DEVICE_STATE :: enum i32 {
} }
DRED_PAGE_FAULT_OUTPUT2 :: struct { DRED_PAGE_FAULT_OUTPUT2 :: struct {
PageFaultVA: GPU_VIRTUAL_ADDRESS, PageFaultVA: GPU_VIRTUAL_ADDRESS,
pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1, pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1,
pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1, pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1,
PageFaultFlags: DRED_PAGE_FAULT_FLAGS, PageFaultFlags: DRED_PAGE_FAULT_FLAGS,
} }
DEVICE_REMOVED_EXTENDED_DATA1 :: struct { DEVICE_REMOVED_EXTENDED_DATA1 :: struct {
+2 -2
View File
@@ -476,8 +476,8 @@ IVersionInfo3_VTable :: struct {
} }
ArgPair :: struct { ArgPair :: struct {
pName: wstring, pName: wstring,
pValue: wstring, pValue: wstring,
} }
IPdbUtils_UUID_STRING :: "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D" IPdbUtils_UUID_STRING :: "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D"
+1 -1
View File
@@ -575,7 +575,7 @@ PRELOAD_TABLE :: "_PRELOAD"
L_Reg :: struct { L_Reg :: struct {
name: cstring, name: cstring,
func: CFunction, func: CFunction,
} }
L_NUMSIZES :: size_of(Integer)*16 + size_of(Number) L_NUMSIZES :: size_of(Integer)*16 + size_of(Number)
+3 -3
View File
@@ -69,9 +69,9 @@ decoder :: struct {
outputSampleRate: u32, outputSampleRate: u32,
converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */ converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */
pInputCache: rawptr, /* In input format. Can be null if it's not needed. */ pInputCache: rawptr, /* In input format. Can be null if it's not needed. */
inputCacheCap: u64, /* The capacity of the input cache. */ inputCacheCap: u64, /* The capacity of the input cache. */
inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */ inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */ inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */
allocationCallbacks: allocation_callbacks, allocationCallbacks: allocation_callbacks,
data: struct #raw_union { data: struct #raw_union {
vfs: struct { vfs: struct {
+3 -3
View File
@@ -381,7 +381,7 @@ device_config :: struct {
noPreSilencedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */ noPreSilencedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will not be clipped after returning. Only applies when the playback sample format is f32. */ noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will not be clipped after returning. Only applies when the playback sample format is f32. */
noDisableDenormals: b8, /* Do not disable denormals when firing the data callback. */ noDisableDenormals: b8, /* Do not disable denormals when firing the data callback. */
noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */ noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
dataCallback: device_data_proc, dataCallback: device_data_proc,
notificationCallback: device_notification_proc, notificationCallback: device_notification_proc,
stopCallback: stop_proc, stopCallback: stop_proc,
@@ -813,7 +813,7 @@ context_type :: struct {
/*pa_mainloop**/ pMainLoop: rawptr, /*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr, /*pa_context**/ pPulseContext: rawptr,
pApplicationName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */ pApplicationName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */ pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
} when SUPPORT_PULSEAUDIO else struct {}), } when SUPPORT_PULSEAUDIO else struct {}),
jack: (struct { jack: (struct {
@@ -1140,7 +1140,7 @@ device :: struct {
pulse: (struct { pulse: (struct {
/*pa_mainloop**/ pMainLoop: rawptr, /*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr, /*pa_context**/ pPulseContext: rawptr,
/*pa_stream**/ pStreamPlayback: rawptr, /*pa_stream**/ pStreamPlayback: rawptr,
/*pa_stream**/ pStreamCapture: rawptr, /*pa_stream**/ pStreamCapture: rawptr,
} when SUPPORT_PULSEAUDIO else struct {}), } when SUPPORT_PULSEAUDIO else struct {}),
+23 -8
View File
@@ -84,7 +84,6 @@ package raylib
import "core:c" import "core:c"
import "core:fmt" import "core:fmt"
import "core:mem" import "core:mem"
import "core:strings"
import "core:math/linalg" import "core:math/linalg"
_ :: linalg _ :: linalg
@@ -447,9 +446,9 @@ VrStereoConfig :: struct #align(4) {
// File path list // File path list
FilePathList :: struct { FilePathList :: struct {
capacity: c.uint, // Filepaths max entries capacity: c.uint, // Filepaths max entries
count: c.uint, // Filepaths entries count count: c.uint, // Filepaths entries count
paths: [^]cstring, // Filepaths entries paths: [^]cstring, // Filepaths entries
} }
// Automation event // Automation event
@@ -1029,7 +1028,6 @@ foreign lib {
SetTraceLogLevel :: proc(logLevel: TraceLogLevel) --- // Set the current threshold (minimum) log level SetTraceLogLevel :: proc(logLevel: TraceLogLevel) --- // Set the current threshold (minimum) log level
MemAlloc :: proc(size: c.uint) -> rawptr --- // Internal memory allocator MemAlloc :: proc(size: c.uint) -> rawptr --- // Internal memory allocator
MemRealloc :: proc(ptr: rawptr, size: c.uint) -> rawptr --- // Internal memory reallocator MemRealloc :: proc(ptr: rawptr, size: c.uint) -> rawptr --- // Internal memory reallocator
MemFree :: proc(ptr: rawptr) --- // Internal memory free
// Set custom callbacks // Set custom callbacks
// WARNING: Callbacks setup is intended for advance users // WARNING: Callbacks setup is intended for advance users
@@ -1256,7 +1254,7 @@ foreign lib {
LoadImage :: proc(fileName: cstring) -> Image --- // Load image from file into CPU memory (RAM) LoadImage :: proc(fileName: cstring) -> Image --- // Load image from file into CPU memory (RAM)
LoadImageRaw :: proc(fileName: cstring, width, height: c.int, format: PixelFormat, headerSize: c.int) -> Image --- // Load image from RAW file data LoadImageRaw :: proc(fileName: cstring, width, height: c.int, format: PixelFormat, headerSize: c.int) -> Image --- // Load image from RAW file data
LoadImageSvg :: proc(fileNameOrString: cstring, width, height: c.int) -> Image --- // Load image from SVG file data or string with specified size LoadImageSvg :: proc(fileNameOrString: cstring, width, height: c.int) -> Image --- // Load image from SVG file data or string with specified size
LoadImageAnim :: proc(fileName: cstring, frames: [^]c.int) -> Image --- // Load image sequence from file (frames appended to image.data) LoadImageAnim :: proc(fileName: cstring, frames: ^c.int) -> Image --- // Load image sequence from file (frames appended to image.data)
LoadImageFromMemory :: proc(fileType: cstring, fileData: rawptr, dataSize: c.int) -> Image --- // Load image from memory buffer, fileType refers to extension: i.e. '.png' LoadImageFromMemory :: proc(fileType: cstring, fileData: rawptr, dataSize: c.int) -> Image --- // Load image from memory buffer, fileType refers to extension: i.e. '.png'
LoadImageFromTexture :: proc(texture: Texture2D) -> Image --- // Load image from GPU texture data LoadImageFromTexture :: proc(texture: Texture2D) -> Image --- // Load image from GPU texture data
LoadImageFromScreen :: proc() -> Image --- // Load image from screen buffer and (screenshot) LoadImageFromScreen :: proc() -> Image --- // Load image from screen buffer and (screenshot)
@@ -1684,8 +1682,25 @@ TextFormat :: proc(text: cstring, args: ..any) -> cstring {
// Text formatting with variables (sprintf style) and allocates (must be freed with 'MemFree') // Text formatting with variables (sprintf style) and allocates (must be freed with 'MemFree')
TextFormatAlloc :: proc(text: cstring, args: ..any) -> cstring { TextFormatAlloc :: proc(text: cstring, args: ..any) -> cstring {
str := fmt.tprintf(string(text), ..args) return fmt.caprintf(string(text), ..args, allocator=MemAllocator())
return strings.clone_to_cstring(str, MemAllocator()) }
// Internal memory free
MemFree :: proc{
MemFreePtr,
MemFreeCstring,
}
@(default_calling_convention="c")
foreign lib {
@(link_name="MemFree")
MemFreePtr :: proc(ptr: rawptr) ---
}
MemFreeCstring :: proc "c" (s: cstring) {
MemFreePtr(rawptr(s))
} }
+6
View File
@@ -41,6 +41,12 @@ MAJOR_VERSION :: 2
MINOR_VERSION :: 0 MINOR_VERSION :: 0
PATCHLEVEL :: 16 PATCHLEVEL :: 16
VERSION :: proc "contextless" (ver: ^version) {
ver.major = MAJOR_VERSION
ver.minor = MINOR_VERSION
ver.patch = PATCHLEVEL
}
@(default_calling_convention="c", link_prefix="SDL_") @(default_calling_convention="c", link_prefix="SDL_")
foreign lib { foreign lib {
GetVersion :: proc(ver: ^version) --- GetVersion :: proc(ver: ^version) ---
+4 -4
View File
@@ -171,9 +171,9 @@ KeyboardEvent :: struct {
TEXTEDITINGEVENT_TEXT_SIZE :: 32 TEXTEDITINGEVENT_TEXT_SIZE :: 32
TextEditingEvent :: struct { TextEditingEvent :: struct {
type: EventType, /**< ::SDL_TEXTEDITING */ type: EventType, /**< ::SDL_TEXTEDITING */
timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */ timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
windowID: u32, /**< The window with keyboard focus, if any */ windowID: u32, /**< The window with keyboard focus, if any */
text: [TEXTEDITINGEVENT_TEXT_SIZE]u8, /**< The editing text */ text: [TEXTEDITINGEVENT_TEXT_SIZE]u8, /**< The editing text */
start: i32, /**< The start cursor of selected editing text */ start: i32, /**< The start cursor of selected editing text */
length: i32, /**< The length of selected editing text */ length: i32, /**< The length of selected editing text */
} }
@@ -184,7 +184,7 @@ TextInputEvent :: struct {
type: EventType, /**< ::SDL_TEXTINPUT */ type: EventType, /**< ::SDL_TEXTINPUT */
timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */ timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
windowID: u32, /**< The window with keyboard focus, if any */ windowID: u32, /**< The window with keyboard focus, if any */
text: [TEXTINPUTEVENT_TEXT_SIZE]u8, /**< The input text */ text: [TEXTINPUTEVENT_TEXT_SIZE]u8, /**< The input text */
} }
MouseMotionEvent :: struct { MouseMotionEvent :: struct {
+23 -23
View File
@@ -54,29 +54,29 @@ GameControllerAxis :: enum c.int {
} }
GameControllerButton :: enum c.int { GameControllerButton :: enum c.int {
INVALID = -1, INVALID = -1,
A, A,
B, B,
X, X,
Y, Y,
BACK, BACK,
GUIDE, GUIDE,
START, START,
LEFTSTICK, LEFTSTICK,
RIGHTSTICK, RIGHTSTICK,
LEFTSHOULDER, LEFTSHOULDER,
RIGHTSHOULDER, RIGHTSHOULDER,
DPAD_UP, DPAD_UP,
DPAD_DOWN, DPAD_DOWN,
DPAD_LEFT, DPAD_LEFT,
DPAD_RIGHT, DPAD_RIGHT,
MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */ MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
PADDLE1, /* Xbox Elite paddle P1 */ PADDLE1, /* Xbox Elite paddle P1 */
PADDLE2, /* Xbox Elite paddle P3 */ PADDLE2, /* Xbox Elite paddle P3 */
PADDLE3, /* Xbox Elite paddle P2 */ PADDLE3, /* Xbox Elite paddle P2 */
PADDLE4, /* Xbox Elite paddle P4 */ PADDLE4, /* Xbox Elite paddle P4 */
TOUCHPAD, /* PS4/PS5 touchpad button */ TOUCHPAD, /* PS4/PS5 touchpad button */
MAX, MAX,
} }
+4 -4
View File
@@ -19,10 +19,10 @@ TouchDeviceType :: enum c.int {
} }
Finger :: struct { Finger :: struct {
id: FingerID, id: FingerID,
x: f32, x: f32,
y: f32, y: f32,
pressure: f32, pressure: f32,
} }
TOUCH_MOUSEID :: ~u32(0) TOUCH_MOUSEID :: ~u32(0)
+1 -1
View File
@@ -166,7 +166,7 @@ datatype :: enum c.int {
UINT32, UINT32,
FLOAT, FLOAT,
MAX_TYPES, MAX_TYPES,
} }
@(default_calling_convention="c", link_prefix="stbir_") @(default_calling_convention="c", link_prefix="stbir_")
+2 -2
View File
@@ -11,8 +11,8 @@ Have a look at the `example/` directory for the rendering of a basic triangle.
## Getting the wgpu-native libraries ## Getting the wgpu-native libraries
For native support (not the browser), some libraries are required. Fortunately this is For native support (not the browser), some libraries are required. Fortunately this is
extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1), extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1),
the bindings are for v0.19.4.1 at the moment. the bindings are for v22.1.0.1 at the moment.
These are expected in the `lib` folder under the same name as they are released (just unzipped). These are expected in the `lib` folder under the same name as they are released (just unzipped).
By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`), By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`),
+3 -1
View File
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
view = frame, view = frame,
loadOp = .Clear, loadOp = .Clear,
storeOp = .Store, storeOp = .Store,
depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
clearValue = { 0, 1, 0, 1 }, clearValue = { 0, 1, 0, 1 },
}, },
}, },
) )
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
wgpu.RenderPassEncoderEnd(render_pass_encoder) wgpu.RenderPassEncoderEnd(render_pass_encoder)
wgpu.RenderPassEncoderRelease(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer) defer wgpu.CommandBufferRelease(command_buffer)
+3 -1
View File
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
view = frame, view = frame,
loadOp = .Clear, loadOp = .Clear,
storeOp = .Store, storeOp = .Store,
depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
clearValue = { 0, 1, 0, 1 }, clearValue = { 0, 1, 0, 1 },
}, },
}, },
) )
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
wgpu.RenderPassEncoderEnd(render_pass_encoder) wgpu.RenderPassEncoderEnd(render_pass_encoder)
wgpu.RenderPassEncoderRelease(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer) defer wgpu.CommandBufferRelease(command_buffer)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -5,7 +5,9 @@ import "vendor:wgpu"
GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface { GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface {
window_info: sdl2.SysWMinfo window_info: sdl2.SysWMinfo
sdl2.VERSION(&window_info.version)
sdl2.GetWindowWMInfo(window, &window_info) sdl2.GetWindowWMInfo(window, &window_info)
if window_info.subsystem == .WAYLAND { if window_info.subsystem == .WAYLAND {
display := window_info.info.wl.display display := window_info.info.wl.display
surface := window_info.info.wl.surface surface := window_info.info.wl.surface
+91 -96
View File
@@ -44,6 +44,7 @@ class WebGPUInterface {
BlendFactor: ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", ], BlendFactor: ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", ],
PresentMode: ["fifo", "fifo-relaxed", "immediate", "mailbox", ], PresentMode: ["fifo", "fifo-relaxed", "immediate", "mailbox", ],
TextureAspect: ["all", "stencil-only", "depth-only"], TextureAspect: ["all", "stencil-only", "depth-only"],
DeviceLostReason: [undefined, "unknown", "destroyed"],
}; };
/** @type {WebGPUObjectManager<{}>} */ /** @type {WebGPUObjectManager<{}>} */
@@ -382,13 +383,19 @@ class WebGPUInterface {
*/ */
RenderPassColorAttachment(start) { RenderPassColorAttachment(start) {
const viewIdx = this.mem.loadPtr(start + 4); const viewIdx = this.mem.loadPtr(start + 4);
const resolveTargetIdx = this.mem.loadPtr(start + 8); const resolveTargetIdx = this.mem.loadPtr(start + 12);
let depthSlice = this.mem.loadU32(start + 8);
if (depthSlice == 0xFFFFFFFF) { // DEPTH_SLICE_UNDEFINED.
depthSlice = undefined;
}
return { return {
view: viewIdx > 0 ? this.textureViews.get(viewIdx) : undefined, view: viewIdx > 0 ? this.textureViews.get(viewIdx) : undefined,
resolveTarget: resolveTargetIdx > 0 ? this.textureViews.get(resolveTargetIdx) : undefined, resolveTarget: resolveTargetIdx > 0 ? this.textureViews.get(resolveTargetIdx) : undefined,
loadOp: this.enumeration("LoadOp", start + 12), depthSlice: depthSlice,
storeOp: this.enumeration("StoreOp", start + 16), loadOp: this.enumeration("LoadOp", start + 16),
storeOp: this.enumeration("StoreOp", start + 20),
clearValue: this.Color(start + 24), clearValue: this.Color(start + 24),
}; };
} }
@@ -950,14 +957,25 @@ class WebGPUInterface {
/** /**
* @param {number} adapterIdx * @param {number} adapterIdx
* @param {number} propertiesPtr * @param {number} infoPtr
*/ */
wgpuAdapterGetProperties: (adapterIdx, propertiesPtr) => { wgpuAdapterGetInfo: (adapterIdx, infoPtr) => {
this.assert(propertiesPtr != 0); this.assert(infoPtr != 0);
// Unknown adapter.
this.mem.storeI32(propertiesPtr + 28, 3);
// WebGPU backend. // WebGPU backend.
this.mem.storeI32(propertiesPtr + 32, 2); this.mem.storeI32(infoPtr + 20, 2);
// Unknown adapter.
this.mem.storeI32(infoPtr + 24, 3);
// NOTE: I don't think getting the other fields in this struct is possible.
// `adapter.requestAdapterInfo` is deprecated.
},
/**
* @param {number} infoPtr
*/
wgpuAdapterInfoFreeMembers: (infoPtr) => {
// NOTE: nothing to free.
}, },
/** /**
@@ -970,50 +988,6 @@ class WebGPUInterface {
return adapter.features.has(this.enums.FeatureName[featureInt]); return adapter.features.has(this.enums.FeatureName[featureInt]);
}, },
/**
* @param {number} adapterIdx
* @param {number} callbackPtr
* @param {0|number} userdata
*/
wgpuAdapterRequestAdapterInfo: async (adapterIdx, callbackPtr, userdata) => {
const adapter = this.adapters.get(adapterIdx);
const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
const info = await adapter.requestAdapterInfo();
const addr = this.mem.exports.wgpu_alloc(16);
const vendorLength = new TextEncoder().encode(info.vendor).length;
const vendorAddr = this.mem.exports.wgpu_alloc(vendorLength);
this.mem.storeString(vendorAddr, info.vendor);
this.mem.storeI32(addr + 0, vendorAddr);
const architectureLength = new TextEncoder().encode(info.architecture).length;
const architectureAddr = this.mem.exports.wgpu_alloc(architectureLength);
this.mem.storeString(architectureAddr, info.architecture);
this.mem.storeI32(addr + 4, architectureAddr);
const deviceLength = new TextEncoder().encode(info.device).length;
const deviceAddr = this.mem.exports.wgpu_alloc(deviceLength);
this.mem.storeString(deviceAddr, info.device);
this.mem.storeI32(addr + 8, deviceAddr);
const descriptionLength = new TextEncoder().encode(info.description).length;
const descriptionAddr = this.mem.exports.wgpu_alloc(descriptionLength);
this.mem.storeString(descriptionAddr, info.description);
this.mem.storeI32(addr + 12, descriptionAddr);
callback(addr, userdata);
this.mem.exports.wgpu_free(descriptionAddr);
this.mem.exports.wgpu_free(deviceAddr);
this.mem.exports.wgpu_free(architectureAddr);
this.mem.exports.wgpu_free(vendorAddr);
this.mem.exports.wgpu_free(addr);
},
/** /**
* @param {number} adapterIdx * @param {number} adapterIdx
* @param {0|number} descriptorPtr * @param {0|number} descriptorPtr
@@ -1040,14 +1014,69 @@ class WebGPUInterface {
}; };
} }
let device;
let deviceIdx; let deviceIdx;
try { try {
const device = await adapter.requestDevice(descriptor); device = await adapter.requestDevice(descriptor);
deviceIdx = this.devices.create(device); deviceIdx = this.devices.create(device);
// NOTE: don't callback here, any errors that happen later will then be caught by the catch here. // NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
} catch (e) { } catch (e) {
console.warn(e); const messageLength = new TextEncoder().encode(e.message).length;
callback(1, null, null, userdata); const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
this.mem.storeString(messageAddr, e.message);
callback(1, null, messageAddr, userdata);
this.mem.exports.wgpu_free(messageAddr);
}
let callbacksPtr = descriptorPtr + 24 + this.mem.intSize;
const deviceLostCallbackPtr = this.mem.loadPtr(callbacksPtr);
if (deviceLostCallbackPtr != 0) {
const deviceLostUserData = this.mem.loadPtr(callbacksPtr) + 4;
const deviceLostCallback = this.mem.exports.__indirect_function_table.get(deviceLostCallbackPtr);
device.lost.then((info) => {
const reason = this.enums.DeviceLostReason.indexOf(info.reason);
const messageLength = new TextEncoder().encode(info.message).length;
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
this.mem.storeString(messageAddr, info.message);
deviceLostCallback(reason, messageAddr, deviceLostUserData);
this.mem.exports.wgpu_free(messageAddr);
});
}
callbacksPtr += 8;
// Skip over `nextInChain`.
callbacksPtr += 4;
const uncapturedErrorCallbackPtr = this.mem.loadPtr(callbacksPtr);
if (uncapturedErrorCallbackPtr != 0) {
const uncapturedErrorUserData = this.mem.loadPtr(callbacksPtr + 4);
const uncapturedErrorCallback = this.mem.exports.__indirect_function_table.get(uncapturedErrorCallbackPtr);
device.onuncapturederror = (ev) => {
let status = 4; // Unknown
if (ev.error instanceof GPUValidationError) {
status = 1; // Validation
} else if (ev.error instanceof GPUOutOfMemoryError) {
status = 2; // OutOfMemory
} else if (ev.error instanceof GPUInternalError) {
status = 3; // Internal
}
const messageLength = new TextEncoder().encode(ev.error.message).length;
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
this.mem.storeString(messageAddr, ev.error.message);
uncapturedErrorCallback(status, messageAddr, uncapturedErrorUserData);
this.mem.exports.wgpu_free(messageAddr);
};
} }
callback(0, deviceIdx, null, userdata); callback(0, deviceIdx, null, userdata);
@@ -1918,29 +1947,6 @@ class WebGPUInterface {
device.pushErrorScope(this.enums.ErrorFilter[filterInt]); device.pushErrorScope(this.enums.ErrorFilter[filterInt]);
}, },
/**
* @param {number} deviceIdx
* @param {number} callbackPtr
* @param {number} userdata
*/
wgpuDeviceSetUncapturedErrorCallback: (deviceIdx, callbackPtr, userdata) => {
const device = this.devices.get(deviceIdx);
const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
device.onuncapturederror = (ev) => {
console.warn(ev.error);
let status = 4;
if (error instanceof GPUValidationError) {
status = 1;
} else if (error instanceof GPUOutOfMemoryError) {
status = 2;
} else if (error instanceof GPUInternalError) {
status = 3;
}
callback(status, null, userdata);
};
},
...this.devices.interface(true), ...this.devices.interface(true),
/* ---------------------- Instance ---------------------- */ /* ---------------------- Instance ---------------------- */
@@ -2646,23 +2652,23 @@ class WebGPUInterface {
const formatStr = navigator.gpu.getPreferredCanvasFormat(); const formatStr = navigator.gpu.getPreferredCanvasFormat();
const format = this.enums.TextureFormat.indexOf(formatStr); const format = this.enums.TextureFormat.indexOf(formatStr);
this.mem.storeUint(capabilitiesPtr + this.mem.intSize, 1); this.mem.storeUint(capabilitiesPtr + 8, 1);
const formatAddr = this.mem.exports.wgpu_alloc(4); const formatAddr = this.mem.exports.wgpu_alloc(4);
this.mem.storeI32(formatAddr, format); this.mem.storeI32(formatAddr, format);
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*2, formatAddr); this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize, formatAddr);
// NOTE: present modes don't seem to actually do anything in JS, we can just give back a default FIFO though. // NOTE: present modes don't seem to actually do anything in JS, we can just give back a default FIFO though.
this.mem.storeUint(capabilitiesPtr + this.mem.intSize*3, 1); this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*2, 1);
const presentModesAddr = this.mem.exports.wgpu_alloc(4); const presentModesAddr = this.mem.exports.wgpu_alloc(4);
this.mem.storeI32(presentModesAddr, 0); this.mem.storeI32(presentModesAddr, 0);
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*4, presentModesAddr); this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*3, presentModesAddr);
// Browser seems to support opaque (1) and premultiplied (2). // Browser seems to support opaque (1) and premultiplied (2).
this.mem.storeUint(capabilitiesPtr + this.mem.intSize*5, 2); this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*4, 2);
const alphaModesAddr = this.mem.exports.wgpu_alloc(8); const alphaModesAddr = this.mem.exports.wgpu_alloc(8);
this.mem.storeI32(alphaModesAddr + 0, 1); // Opaque. this.mem.storeI32(alphaModesAddr + 0, 1); // Opaque.
this.mem.storeI32(alphaModesAddr + 4, 2); // premultiplied. this.mem.storeI32(alphaModesAddr + 4, 2); // premultiplied.
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*6, alphaModesAddr); this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*5, alphaModesAddr);
}, },
/** /**
@@ -2680,17 +2686,6 @@ class WebGPUInterface {
// TODO: determine suboptimal and/or status. // TODO: determine suboptimal and/or status.
}, },
/**
* @param {number} surfaceIdx
* @param {number} texturePtr
* @returns {number}
*/
wgpuSurfaceGetPreferredFormat: (surfaceIdx, adapterIdx) => {
const formatStr = navigator.gpu.getPreferredCanvasFormat();
const format = this.enums.TextureFormat.indexOf(formatStr);
return format;
},
/** /**
* @param {number} surfaceIdx * @param {number} surfaceIdx
*/ */
+111 -53
View File
@@ -13,7 +13,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-windows-" + ARCH + "-" + TYPE + "/wgpu_native" + EXT @(private) LIB :: "lib/wgpu-windows-" + ARCH + "-" + TYPE + "/wgpu_native" + EXT
when !#exists(LIB) { when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'") #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
} }
foreign import libwgpu { foreign import libwgpu {
@@ -34,7 +34,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT @(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
when !#exists(LIB) { when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'") #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
} }
foreign import libwgpu { foreign import libwgpu {
@@ -49,7 +49,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT @(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
when !#exists(LIB) { when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'") #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
} }
foreign import libwgpu { foreign import libwgpu {
@@ -220,7 +220,8 @@ CullMode :: enum i32 {
DeviceLostReason :: enum i32 { DeviceLostReason :: enum i32 {
Undefined = 0x00000000, Undefined = 0x00000000,
Destroyed = 0x00000001, Unknown = 0x00000001,
Destroyed = 0x00000002,
} }
ErrorFilter :: enum i32 { ErrorFilter :: enum i32 {
@@ -264,6 +265,30 @@ FeatureName :: enum i32 {
PipelineStatisticsQuery, PipelineStatisticsQuery,
StorageResourceBindingArray, StorageResourceBindingArray,
PartiallyBoundBindingArray, PartiallyBoundBindingArray,
TextureFormat16bitNorm,
TextureCompressionAstcHdr,
// TODO: requires wgpu.h api change
// TimestampQueryInsidePasses,
MappablePrimaryBuffers = 0x0003000E,
BufferBindingArray,
UniformBufferAndStorageTextureArrayNonUniformIndexing,
// TODO: requires wgpu.h api change
// AddressModeClampToZero,
// AddressModeClampToBorder,
// PolygonModeLine,
// PolygonModePoint,
// ConservativeRasterization,
// ClearTexture,
// SprivShaderPassThrough,
// MultiView,
VertexAttribute64bit = 0x00030019,
TextureFormatNv12,
RayTracingAccelarationStructure,
RayQuery,
ShaderF64,
ShaderI16,
ShaderPrimitiveIndex,
ShaderEarlyDepthTest,
} }
FilterMode :: enum i32 { FilterMode :: enum i32 {
@@ -520,6 +545,18 @@ TextureFormat :: enum i32 {
ASTC12x10UnormSrgb = 0x0000005D, ASTC12x10UnormSrgb = 0x0000005D,
ASTC12x12Unorm = 0x0000005E, ASTC12x12Unorm = 0x0000005E,
ASTC12x12UnormSrgb = 0x0000005F, ASTC12x12UnormSrgb = 0x0000005F,
// Native.
// From FeatureName.TextureFormat16bitNorm
R16Unorm = 0x00030001,
R16Snorm,
Rg16Unorm,
Rg16Snorm,
Rgba16Unorm,
Rgba16Snorm,
// From FeatureName.TextureFormatNv12
NV12,
} }
TextureSampleType :: enum i32 { TextureSampleType :: enum i32 {
@@ -581,13 +618,13 @@ VertexStepMode :: enum i32 {
VertexBufferNotUsed = 0x00000002, VertexBufferNotUsed = 0x00000002,
} }
// WGSLFeatureName :: enum i32 { WGSLFeatureName :: enum i32 {
// Undefined = 0x00000000, Undefined = 0x00000000,
// ReadonlyAndReadwriteStorageTextures = 0x00000001, ReadonlyAndReadwriteStorageTextures = 0x00000001,
// Packed4x8IntegerDotProduct = 0x00000002, Packed4x8IntegerDotProduct = 0x00000002,
// UnrestrictedPointerParameters = 0x00000003, UnrestrictedPointerParameters = 0x00000003,
// PointerCompositeAccess = 0x00000004, PointerCompositeAccess = 0x00000004,
// } }
BufferUsage :: enum i32 { BufferUsage :: enum i32 {
MapRead = 0x00000000, MapRead = 0x00000000,
@@ -634,22 +671,18 @@ TextureUsage :: enum i32 {
} }
TextureUsageFlags :: bit_set[TextureUsage; Flags] TextureUsageFlags :: bit_set[TextureUsage; Flags]
Proc :: distinct rawptr
BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
DeviceLostCallback :: #type proc "c" (reason: DeviceLostReason, message: cstring, userdata: rawptr) DeviceLostCallback :: #type proc "c" (reason: DeviceLostReason, message: cstring, userdata: rawptr)
ErrorCallback :: #type proc "c" (type: ErrorType, message: cstring, userdata: rawptr) ErrorCallback :: #type proc "c" (type: ErrorType, message: cstring, userdata: rawptr)
Proc :: distinct rawptr
QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
AdapterRequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, device: Device, message: cstring, /* NULLABLE */ userdata: rawptr) AdapterRequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, device: Device, message: cstring, /* NULLABLE */ userdata: rawptr)
BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
// AdapterRequestAdapterInfoCallback :: #type proc "c" (adapterInfo: AdapterInfo, /* NULLABLE */ userdata: rawptr) DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
ChainedStruct :: struct { ChainedStruct :: struct {
next: ^ChainedStruct, next: ^ChainedStruct,
@@ -661,28 +694,23 @@ ChainedStructOut :: struct {
sType: SType, sType: SType,
} }
// AdapterInfo :: struct { AdapterInfo :: struct {
// next: ^ChainedStructOut,
// vendor: cstring,
// architecture: cstring,
// device: cstring,
// description: cstring,
// backendType: BackendType,
// adapterType: AdapterType,
// vendorID: u32,
// deviceID: u32,
// }
AdapterProperties :: struct {
nextInChain: ^ChainedStructOut, nextInChain: ^ChainedStructOut,
vendorID: u32, vendor: cstring,
vendorName: cstring,
architecture: cstring, architecture: cstring,
deviceID: u32, device: cstring,
name: cstring, description: cstring,
driverDescription: cstring,
adapterType: AdapterType,
backendType: BackendType, backendType: BackendType,
adapterType: AdapterType,
vendorID: u32,
deviceID: u32,
}
when ODIN_OS == .JS {
#assert(int(BackendType.WebGPU) == 2)
#assert(offset_of(AdapterInfo, backendType) == 20)
#assert(int(AdapterType.Unknown) == 3)
#assert(offset_of(AdapterInfo, adapterType) == 24)
} }
BindGroupEntry :: struct { BindGroupEntry :: struct {
@@ -943,6 +971,7 @@ StorageTextureBindingLayout :: struct {
SurfaceCapabilities :: struct { SurfaceCapabilities :: struct {
nextInChain: ^ChainedStructOut, nextInChain: ^ChainedStructOut,
usages: TextureUsageFlags,
formatCount: uint, formatCount: uint,
formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`, formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`,
presentModeCount: uint, presentModeCount: uint,
@@ -950,6 +979,16 @@ SurfaceCapabilities :: struct {
alphaModeCount: uint, alphaModeCount: uint,
alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`, alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`,
} }
when ODIN_OS == .JS {
#assert(offset_of(SurfaceCapabilities, formatCount) == 8)
#assert(offset_of(SurfaceCapabilities, formats) == 8 + 1*size_of(int))
#assert(offset_of(SurfaceCapabilities, presentModeCount) == 8 + 2*size_of(int))
#assert(offset_of(SurfaceCapabilities, presentModes) == 8 + 3*size_of(int))
#assert(offset_of(SurfaceCapabilities, alphaModeCount) == 8 + 4*size_of(int))
#assert(offset_of(SurfaceCapabilities, alphaModes) == 8 + 5*size_of(int))
}
SurfaceConfiguration :: struct { SurfaceConfiguration :: struct {
nextInChain: ^ChainedStruct, nextInChain: ^ChainedStruct,
@@ -1040,6 +1079,12 @@ TextureViewDescriptor :: struct {
aspect: TextureAspect, aspect: TextureAspect,
} }
UncapturedErrorCallbackInfo :: struct {
nextInChain: ^ChainedStruct,
callback: ErrorCallback,
userdata: rawptr,
}
VertexAttribute :: struct { VertexAttribute :: struct {
format: VertexFormat, format: VertexFormat,
offset: u64, offset: u64,
@@ -1120,12 +1165,21 @@ ProgrammableStageDescriptor :: struct {
RenderPassColorAttachment :: struct { RenderPassColorAttachment :: struct {
nextInChain: ^ChainedStruct, nextInChain: ^ChainedStruct,
/* NULLABLE */ view: TextureView, /* NULLABLE */ view: TextureView,
// depthSlice: u32, depthSlice: u32,
/* NULLABLE */ resolveTarget: TextureView, /* NULLABLE */ resolveTarget: TextureView,
loadOp: LoadOp, loadOp: LoadOp,
storeOp: StoreOp, storeOp: StoreOp,
clearValue: Color, clearValue: Color,
} }
when ODIN_OS == .JS {
#assert(size_of(RenderPassColorAttachment) == 56)
#assert(offset_of(RenderPassColorAttachment, view) == 4)
#assert(offset_of(RenderPassColorAttachment, depthSlice) == 8)
#assert(offset_of(RenderPassColorAttachment, resolveTarget) == 12)
#assert(offset_of(RenderPassColorAttachment, loadOp) == 16)
#assert(offset_of(RenderPassColorAttachment, storeOp) == 20)
#assert(offset_of(RenderPassColorAttachment, clearValue) == 24)
}
RequiredLimits :: struct { RequiredLimits :: struct {
nextInChain: ^ChainedStruct, nextInChain: ^ChainedStruct,
@@ -1194,6 +1248,10 @@ DeviceDescriptor :: struct {
defaultQueue: QueueDescriptor, defaultQueue: QueueDescriptor,
deviceLostCallback: DeviceLostCallback, deviceLostCallback: DeviceLostCallback,
deviceLostUserdata: rawptr, deviceLostUserdata: rawptr,
uncapturedErrorCallbackInfo: UncapturedErrorCallbackInfo,
}
when ODIN_OS == .JS {
#assert(offset_of(DeviceDescriptor, deviceLostCallback) == 24 + size_of(int))
} }
RenderPassDescriptor :: struct { RenderPassDescriptor :: struct {
@@ -1245,16 +1303,18 @@ foreign libwgpu {
// Methods of Adapter // Methods of Adapter
@(link_name="wgpuAdapterEnumerateFeatures") @(link_name="wgpuAdapterEnumerateFeatures")
RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint --- RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint ---
@(link_name="wgpuAdapterGetInfo")
RawAdapterGetInfo :: proc(adapter: Adapter, info: ^AdapterInfo) ---
@(link_name="wgpuAdapterGetLimits") @(link_name="wgpuAdapterGetLimits")
RawAdapterGetLimits :: proc(adapter: Adapter, limits: ^SupportedLimits) -> b32 --- RawAdapterGetLimits :: proc(adapter: Adapter, limits: ^SupportedLimits) -> b32 ---
@(link_name="wgpuAdapterGetProperties")
RawAdapterGetProperties :: proc(adapter: Adapter, properties: ^AdapterProperties) ---
AdapterHasFeature :: proc(adapter: Adapter, feature: FeatureName) -> b32 --- AdapterHasFeature :: proc(adapter: Adapter, feature: FeatureName) -> b32 ---
// AdapterRequestAdapterInfo :: proc(adapter: Adapter, callback: AdapterRequestAdapterInfoCallback, /* NULLABLE */ userdata: rawptr) ---
AdapterRequestDevice :: proc(adapter: Adapter, /* NULLABLE */ descriptor: /* const */ ^DeviceDescriptor, callback: AdapterRequestDeviceCallback, /* NULLABLE */ userdata: rawptr = nil) --- AdapterRequestDevice :: proc(adapter: Adapter, /* NULLABLE */ descriptor: /* const */ ^DeviceDescriptor, callback: AdapterRequestDeviceCallback, /* NULLABLE */ userdata: rawptr = nil) ---
AdapterReference :: proc(adapter: Adapter) --- AdapterReference :: proc(adapter: Adapter) ---
AdapterRelease :: proc(adapter: Adapter) --- AdapterRelease :: proc(adapter: Adapter) ---
// Procs of AdapterInfo
AdapterInfoFreeMembers :: proc(adapterInfo: AdapterInfo) ---
// Methods of BindGroup // Methods of BindGroup
BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) --- BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) ---
BindGroupReference :: proc(bindGroup: BindGroup) --- BindGroupReference :: proc(bindGroup: BindGroup) ---
@@ -1348,13 +1408,12 @@ foreign libwgpu {
DevicePopErrorScope :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) --- DevicePopErrorScope :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
DevicePushErrorScope :: proc(device: Device, filter: ErrorFilter) --- DevicePushErrorScope :: proc(device: Device, filter: ErrorFilter) ---
DeviceSetLabel :: proc(device: Device, label: cstring) --- DeviceSetLabel :: proc(device: Device, label: cstring) ---
DeviceSetUncapturedErrorCallback :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
DeviceReference :: proc(device: Device) --- DeviceReference :: proc(device: Device) ---
DeviceRelease :: proc(device: Device) --- DeviceRelease :: proc(device: Device) ---
// Methods of Instance // Methods of Instance
InstanceCreateSurface :: proc(instance: Instance, descriptor: /* const */ ^SurfaceDescriptor) -> Surface --- InstanceCreateSurface :: proc(instance: Instance, descriptor: /* const */ ^SurfaceDescriptor) -> Surface ---
// InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 --- InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 ---
InstanceProcessEvents :: proc(instance: Instance) --- InstanceProcessEvents :: proc(instance: Instance) ---
InstanceRequestAdapter :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^RequestAdapterOptions, callback: InstanceRequestAdapterCallback, /* NULLABLE */ userdata: rawptr = nil) --- InstanceRequestAdapter :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^RequestAdapterOptions, callback: InstanceRequestAdapterCallback, /* NULLABLE */ userdata: rawptr = nil) ---
InstanceReference :: proc(instance: Instance) --- InstanceReference :: proc(instance: Instance) ---
@@ -1455,9 +1514,8 @@ foreign libwgpu {
RawSurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter, capabilities: ^SurfaceCapabilities) --- RawSurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter, capabilities: ^SurfaceCapabilities) ---
@(link_name="wgpuSurfaceGetCurrentTexture") @(link_name="wgpuSurfaceGetCurrentTexture")
RawSurfaceGetCurrentTexture :: proc(surface: Surface, surfaceTexture: ^SurfaceTexture) --- RawSurfaceGetCurrentTexture :: proc(surface: Surface, surfaceTexture: ^SurfaceTexture) ---
SurfaceGetPreferredFormat :: proc(surface: Surface, adapter: Adapter) -> TextureFormat ---
SurfacePresent :: proc(surface: Surface) --- SurfacePresent :: proc(surface: Surface) ---
// SurfaceSetLabel :: proc(surface: Surface, label: cstring) --- SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
SurfaceUnconfigure :: proc(surface: Surface) --- SurfaceUnconfigure :: proc(surface: Surface) ---
SurfaceReference :: proc(surface: Surface) --- SurfaceReference :: proc(surface: Surface) ---
SurfaceRelease :: proc(surface: Surface) --- SurfaceRelease :: proc(surface: Surface) ---
@@ -1500,8 +1558,8 @@ AdapterGetLimits :: proc(adapter: Adapter) -> (limits: SupportedLimits, ok: bool
return return
} }
AdapterGetProperties :: proc(adapter: Adapter) -> (properties: AdapterProperties) { AdapterGetInfo :: proc(adapter: Adapter) -> (info: AdapterInfo) {
RawAdapterGetProperties(adapter, &properties) RawAdapterGetInfo(adapter, &info)
return return
} }
@@ -1634,8 +1692,8 @@ SurfaceGetCurrentTexture :: proc(surface: Surface) -> (surface_texture: SurfaceT
// WGPU Native bindings // WGPU Native bindings
BINDINGS_VERSION :: [4]u8{0, 19, 4, 1} BINDINGS_VERSION :: [4]u8{22, 1, 0, 1}
BINDINGS_VERSION_STRING :: "0.19.4.1" BINDINGS_VERSION_STRING :: "22.1.0.1"
when ODIN_OS != .JS { when ODIN_OS != .JS {
@(private="file", init) @(private="file", init)
+1675 -1675
View File
File diff suppressed because it is too large Load Diff
+311 -311
View File
@@ -47,9 +47,9 @@ XExtCodes :: struct {
} }
XPixmapFormatValues :: struct { XPixmapFormatValues :: struct {
depth: i32, depth: i32,
bits_per_pixel: i32, bits_per_pixel: i32,
scanline_pad: i32, scanline_pad: i32,
} }
XGCValues :: struct { XGCValues :: struct {
@@ -130,47 +130,47 @@ ScreenFormat :: struct {
} }
XSetWindowAttributes :: struct { XSetWindowAttributes :: struct {
background_pixmap: Pixmap, background_pixmap: Pixmap,
background_pixel: uint, background_pixel: uint,
border_pixmap: Pixmap, border_pixmap: Pixmap,
border_pixel: uint, border_pixel: uint,
bit_gravity: Gravity, bit_gravity: Gravity,
win_gravity: Gravity, win_gravity: Gravity,
backing_store: BackingStore, backing_store: BackingStore,
backing_planes: uint, backing_planes: uint,
backing_pixel: uint, backing_pixel: uint,
save_under: b32, save_under: b32,
event_mask: EventMask, event_mask: EventMask,
do_not_propagate_mask: EventMask, do_not_propagate_mask: EventMask,
override_redirect: b32, override_redirect: b32,
colormap: Colormap, colormap: Colormap,
cursor: Cursor, cursor: Cursor,
} }
XWindowAttributes :: struct { XWindowAttributes :: struct {
x: i32, x: i32,
y: i32, y: i32,
width: i32, width: i32,
height: i32, height: i32,
border_width: i32, border_width: i32,
depth: i32, depth: i32,
visual: ^Visual, visual: ^Visual,
root: Window, root: Window,
class: WindowClass, class: WindowClass,
bit_gravity: Gravity, bit_gravity: Gravity,
win_gravity: Gravity, win_gravity: Gravity,
backing_store: BackingStore, backing_store: BackingStore,
backing_planes: uint, backing_planes: uint,
backing_pixel: uint, backing_pixel: uint,
save_under: b32, save_under: b32,
colormap: Colormap, colormap: Colormap,
map_installed: b32, map_installed: b32,
map_state: WindowMapState, map_state: WindowMapState,
all_event_masks: EventMask, all_event_masks: EventMask,
your_event_mask: EventMask, your_event_mask: EventMask,
do_not_propagate_mask: EventMask, do_not_propagate_mask: EventMask,
override_redirect: b32, override_redirect: b32,
screen: ^Screen, screen: ^Screen,
} }
XHostAddress :: struct { XHostAddress :: struct {
@@ -187,50 +187,50 @@ XServerInterpretedAddress :: struct {
} }
XImage :: struct { XImage :: struct {
width: i32, width: i32,
height: i32, height: i32,
xoffset: i32, xoffset: i32,
format: ImageFormat, format: ImageFormat,
data: rawptr, data: rawptr,
byte_order: i32, byte_order: i32,
bitmap_unit: i32, bitmap_unit: i32,
bitmap_bit_order: ByteOrder, bitmap_bit_order: ByteOrder,
bitmap_pad: i32, bitmap_pad: i32,
depth: i32, depth: i32,
bytes_per_line: i32, bytes_per_line: i32,
bits_per_pixel: i32, bits_per_pixel: i32,
red_mask: uint, red_mask: uint,
green_mask: uint, green_mask: uint,
blue_mask: uint, blue_mask: uint,
obdata: rawptr, obdata: rawptr,
f: struct { f: struct {
create_image: proc "c" ( create_image: proc "c" (
display: ^Display, display: ^Display,
visual: ^Visual, visual: ^Visual,
depth: u32, depth: u32,
format: i32, format: i32,
offset: i32, offset: i32,
data: rawptr, data: rawptr,
width: u32, width: u32,
height: u32, height: u32,
pad: i32, pad: i32,
stride: i32) -> ^XImage, stride: i32) -> ^XImage,
destroy_image: proc "c" (image: ^XImage) -> i32, destroy_image: proc "c" (image: ^XImage) -> i32,
get_pixel: proc "c" (image: ^XImage) -> uint, get_pixel: proc "c" (image: ^XImage) -> uint,
put_pixel: proc "c" (image: ^XImage, x: i32, y: i32, pixel: uint) -> i32, put_pixel: proc "c" (image: ^XImage, x: i32, y: i32, pixel: uint) -> i32,
sub_image: proc "c" (image: ^XImage, x: i32, y: i32, w: u32, h: u32) -> ^XImage, sub_image: proc "c" (image: ^XImage, x: i32, y: i32, w: u32, h: u32) -> ^XImage,
add_pixel: proc "c" (image: ^XImage, val: int) -> i32, add_pixel: proc "c" (image: ^XImage, val: int) -> i32,
}, },
} }
XWindowChanges :: struct { XWindowChanges :: struct {
x: i32, x: i32,
y: i32, y: i32,
width: i32, width: i32,
height: i32, height: i32,
border_width: i32, border_width: i32,
sibling: Window, sibling: Window,
stack_mode: WindowStacking, stack_mode: WindowStacking,
} }
XColor :: struct { XColor :: struct {
@@ -243,42 +243,42 @@ XColor :: struct {
} }
XSegment :: struct { XSegment :: struct {
x1: i16, x1: i16,
y1: i16, y1: i16,
x2: i16, x2: i16,
y2: i16, y2: i16,
} }
XPoint :: struct { XPoint :: struct {
x: i16, x: i16,
y: i16, y: i16,
} }
XRectangle :: struct { XRectangle :: struct {
x: i16, x: i16,
y: i16, y: i16,
width: u16, width: u16,
height: u16, height: u16,
} }
XArc :: struct { XArc :: struct {
x: i16, x: i16,
y: i16, y: i16,
width: u16, width: u16,
height: u16, height: u16,
angle1: i16, angle1: i16,
angle2: i16, angle2: i16,
} }
XKeyboardControl :: struct { XKeyboardControl :: struct {
key_click_percent: i32, key_click_percent: i32,
bell_percent: i32, bell_percent: i32,
bell_pitch: i32, bell_pitch: i32,
bell_duration: i32, bell_duration: i32,
led: i32, led: i32,
led_mode: KeyboardLedMode, led_mode: KeyboardLedMode,
key: i32, key: i32,
auto_repeat_mode: KeyboardAutoRepeatMode, auto_repeat_mode: KeyboardAutoRepeatMode,
} }
XKeyboardState :: struct { XKeyboardState :: struct {
@@ -700,23 +700,23 @@ XAnyEvent :: struct {
} }
XGenericEvent :: struct { XGenericEvent :: struct {
type: EventType, type: EventType,
serial: uint, serial: uint,
send_event: b32, send_event: b32,
display: ^Display, display: ^Display,
extension: i32, extension: i32,
evtype: i32, evtype: i32,
} }
XGenericEventCookie :: struct { XGenericEventCookie :: struct {
type: EventType, type: EventType,
serial: uint, serial: uint,
send_event: b32, send_event: b32,
display: ^Display, display: ^Display,
extension: i32, extension: i32,
evtype: i32, evtype: i32,
cookie: u32, cookie: u32,
data: rawptr, data: rawptr,
} }
XEvent :: struct #raw_union { XEvent :: struct #raw_union {
@@ -758,55 +758,55 @@ XEvent :: struct #raw_union {
} }
XCharStruct :: struct { XCharStruct :: struct {
lbearing: i16, lbearing: i16,
rbearing: i16, rbearing: i16,
width: i16, width: i16,
ascent: i16, ascent: i16,
descent: i16, descent: i16,
attributes: u16, attributes: u16,
} }
XFontProp :: struct { XFontProp :: struct {
name: Atom, name: Atom,
card32: uint, card32: uint,
} }
XFontStruct :: struct { XFontStruct :: struct {
ext_data: ^XExtData, ext_data: ^XExtData,
fid: Font, fid: Font,
direction: u32, direction: u32,
min_char_or_byte2: u32, min_char_or_byte2: u32,
max_char_or_byte2: u32, max_char_or_byte2: u32,
min_byte1: u32, min_byte1: u32,
max_byte1: u32, max_byte1: u32,
all_chars_exist: i32, all_chars_exist: i32,
default_char: u32, default_char: u32,
n_properties: i32, n_properties: i32,
properties: ^XFontProp, properties: ^XFontProp,
min_bounds: XCharStruct, min_bounds: XCharStruct,
max_bounds: XCharStruct, max_bounds: XCharStruct,
per_char: ^XCharStruct, per_char: ^XCharStruct,
ascent: i32, ascent: i32,
descent: i32, descent: i32,
} }
XTextItem :: struct { XTextItem :: struct {
chars: [^]u8, chars: [^]u8,
nchars: i32, nchars: i32,
delta: i32, delta: i32,
font: Font, font: Font,
} }
XChar2b :: struct { XChar2b :: struct {
byte1: u8, byte1: u8,
byte2: u8, byte2: u8,
} }
XTextItem16 :: struct { XTextItem16 :: struct {
chars: ^XChar2b, chars: ^XChar2b,
nchars: i32, nchars: i32,
delta: i32, delta: i32,
font: Font, font: Font,
} }
XEDataObject :: struct #raw_union { XEDataObject :: struct #raw_union {
@@ -819,8 +819,8 @@ XEDataObject :: struct #raw_union {
} }
XFontSetExtents :: struct { XFontSetExtents :: struct {
max_ink_extent: XRectangle, max_ink_extent: XRectangle,
max_logical_extent: XRectangle, max_logical_extent: XRectangle,
} }
XOM :: distinct rawptr XOM :: distinct rawptr
@@ -828,41 +828,41 @@ XOC :: distinct rawptr
XFontSet :: XOC XFontSet :: XOC
XmbTextItem :: struct { XmbTextItem :: struct {
chars: [^]u8, chars: [^]u8,
nchars: i32, nchars: i32,
delta: i32, delta: i32,
font_set: XFontSet, font_set: XFontSet,
} }
XwcTextItem :: struct { XwcTextItem :: struct {
chars: [^]rune, chars: [^]rune,
nchars: i32, nchars: i32,
delta: i32, delta: i32,
font_set: XFontSet, font_set: XFontSet,
} }
XOMCharSetList :: struct { XOMCharSetList :: struct {
charset_count: i32, charset_count: i32,
charset_list: [^]cstring, charset_list: [^]cstring,
} }
XOrientation :: enum i32 { XOrientation :: enum i32 {
XOMOrientation_LTR_TTB = 0, XOMOrientation_LTR_TTB = 0,
XOMOrientation_RTL_TTB = 1, XOMOrientation_RTL_TTB = 1,
XOMOrientation_TTB_LTR = 2, XOMOrientation_TTB_LTR = 2,
XOMOrientation_TTB_RTL = 3, XOMOrientation_TTB_RTL = 3,
XOMOrientation_Context = 4, XOMOrientation_Context = 4,
} }
XOMOrientation :: struct { XOMOrientation :: struct {
num_orientation: i32, num_orientation: i32,
orientation: [^]XOrientation, orientation: [^]XOrientation,
} }
XOMFontInfo :: struct { XOMFontInfo :: struct {
num_font: i32, num_font: i32,
font_struct_list: [^]^XFontStruct, font_struct_list: [^]^XFontStruct,
font_name_list: [^]cstring, font_name_list: [^]cstring,
} }
XIM :: distinct rawptr XIM :: distinct rawptr
@@ -875,38 +875,38 @@ XIDProc :: #type proc "c" (xim: XIM, client_data: rawptr, call_data: rawptr)
XIMStyle :: uint XIMStyle :: uint
XIMStyles :: struct { XIMStyles :: struct {
count_styles: u16, count_styles: u16,
supported_styles: [^]XIMStyle, supported_styles: [^]XIMStyle,
} }
XVaNestedList :: distinct rawptr XVaNestedList :: distinct rawptr
XIMCallback :: struct { XIMCallback :: struct {
client_data: rawptr, client_data: rawptr,
callback: XIMProc, callback: XIMProc,
} }
XICCallback :: struct { XICCallback :: struct {
client_data: rawptr, client_data: rawptr,
callback: XICProc, callback: XICProc,
} }
XIMFeedback :: uint XIMFeedback :: uint
XIMText :: struct { XIMText :: struct {
length: u16, length: u16,
feedback: ^XIMFeedback, feedback: ^XIMFeedback,
encoding_is_wchar: b32, encoding_is_wchar: b32,
string: struct #raw_union { string: struct #raw_union {
multi_byte: [^]u8, multi_byte: [^]u8,
wide_char: [^]rune, wide_char: [^]rune,
}, },
} }
XIMPreeditState :: uint XIMPreeditState :: uint
XIMPreeditStateNotifyCallbackStruct :: struct { XIMPreeditStateNotifyCallbackStruct :: struct {
state: XIMPreeditState, state: XIMPreeditState,
} }
XIMResetState :: uint XIMResetState :: uint
@@ -914,13 +914,13 @@ XIMResetState :: uint
XIMStringConversionFeedback :: uint XIMStringConversionFeedback :: uint
XIMStringConversionText :: struct { XIMStringConversionText :: struct {
length: u16, length: u16,
feedback: ^XIMStringConversionFeedback, feedback: ^XIMStringConversionFeedback,
encoding_is_wchar: b32, encoding_is_wchar: b32,
string: struct #raw_union { string: struct #raw_union {
mbs: [^]u8, mbs: [^]u8,
wcs: [^]rune, wcs: [^]rune,
}, },
} }
XIMStringConversionPosition :: u16 XIMStringConversionPosition :: u16
@@ -928,76 +928,76 @@ XIMStringConversionType :: u16
XIMStringConversionOperation :: u16 XIMStringConversionOperation :: u16
XIMCaretDirection :: enum i32 { XIMCaretDirection :: enum i32 {
XIMForwardChar = 0, XIMForwardChar = 0,
XIMBackwardChar = 1, XIMBackwardChar = 1,
XIMForwardWord = 2, XIMForwardWord = 2,
XIMBackwardWord = 3, XIMBackwardWord = 3,
XIMCaretUp = 4, XIMCaretUp = 4,
XIMCaretDown = 5, XIMCaretDown = 5,
XIMNextLine = 6, XIMNextLine = 6,
XIMPreviousLine = 7, XIMPreviousLine = 7,
XIMLineStart = 8, XIMLineStart = 8,
XIMLineEnd = 9, XIMLineEnd = 9,
XIMAbsolutePosition = 10, XIMAbsolutePosition = 10,
XIMDontChang = 11, XIMDontChang = 11,
} }
XIMStringConversionCallbackStruct :: struct { XIMStringConversionCallbackStruct :: struct {
position: XIMStringConversionPosition, position: XIMStringConversionPosition,
direction: XIMCaretDirection, direction: XIMCaretDirection,
operation: XIMStringConversionOperation, operation: XIMStringConversionOperation,
factor: u16, factor: u16,
text: ^XIMStringConversionText, text: ^XIMStringConversionText,
} }
XIMPreeditDrawCallbackStruct :: struct { XIMPreeditDrawCallbackStruct :: struct {
caret: i32, caret: i32,
chg_first: i32, chg_first: i32,
chg_length: i32, chg_length: i32,
text: ^XIMText, text: ^XIMText,
} }
XIMCaretStyle :: enum i32 { XIMCaretStyle :: enum i32 {
XIMIsInvisible, XIMIsInvisible,
XIMIsPrimary, XIMIsPrimary,
XIMIsSecondary, XIMIsSecondary,
} }
XIMPreeditCaretCallbackStruct :: struct { XIMPreeditCaretCallbackStruct :: struct {
position: i32, position: i32,
direction: XIMCaretDirection, direction: XIMCaretDirection,
style: XIMCaretStyle, style: XIMCaretStyle,
} }
XIMStatusDataType :: enum { XIMStatusDataType :: enum {
XIMTextType, XIMTextType,
XIMBitmapType, XIMBitmapType,
} }
XIMStatusDrawCallbackStruct :: struct { XIMStatusDrawCallbackStruct :: struct {
type: XIMStatusDataType, type: XIMStatusDataType,
data: struct #raw_union { data: struct #raw_union {
text: ^XIMText, text: ^XIMText,
bitmap: Pixmap, bitmap: Pixmap,
}, },
} }
XIMHotKeyTrigger :: struct { XIMHotKeyTrigger :: struct {
keysym: KeySym, keysym: KeySym,
modifier: i32, modifier: i32,
modifier_mask: i32, modifier_mask: i32,
} }
XIMHotKeyTriggers :: struct { XIMHotKeyTriggers :: struct {
num_hot_key: i32, num_hot_key: i32,
key: [^]XIMHotKeyTrigger, key: [^]XIMHotKeyTrigger,
} }
XIMHotKeyState :: uint XIMHotKeyState :: uint
XIMValuesList :: struct { XIMValuesList :: struct {
count_values: u16, count_values: u16,
supported_values: [^]cstring, supported_values: [^]cstring,
} }
XConnectionWatchProc :: #type proc "c" ( XConnectionWatchProc :: #type proc "c" (
@@ -1775,62 +1775,62 @@ XcmsColorFormat :: uint
XcmsFloat :: f64 XcmsFloat :: f64
XcmsRGB :: struct { XcmsRGB :: struct {
red: u16, red: u16,
green: u16, green: u16,
blue: u16, blue: u16,
} }
XcmsRGBi :: struct { XcmsRGBi :: struct {
red: XcmsFloat, red: XcmsFloat,
green: XcmsFloat, green: XcmsFloat,
blue: XcmsFloat, blue: XcmsFloat,
} }
XcmsCIEXYZ :: struct { XcmsCIEXYZ :: struct {
X: XcmsFloat, X: XcmsFloat,
Y: XcmsFloat, Y: XcmsFloat,
Z: XcmsFloat, Z: XcmsFloat,
} }
XcmsCIEuvY :: struct { XcmsCIEuvY :: struct {
u_prime: XcmsFloat, u_prime: XcmsFloat,
v_prime: XcmsFloat, v_prime: XcmsFloat,
Y: XcmsFloat, Y: XcmsFloat,
} }
XcmsCIExyY :: struct { XcmsCIExyY :: struct {
x: XcmsFloat, x: XcmsFloat,
y: XcmsFloat, y: XcmsFloat,
Y: XcmsFloat, Y: XcmsFloat,
} }
XcmsCIELab :: struct { XcmsCIELab :: struct {
L_star: XcmsFloat, L_star: XcmsFloat,
a_star: XcmsFloat, a_star: XcmsFloat,
b_star: XcmsFloat, b_star: XcmsFloat,
} }
XcmsCIELuv :: struct { XcmsCIELuv :: struct {
L_star: XcmsFloat, L_star: XcmsFloat,
u_star: XcmsFloat, u_star: XcmsFloat,
v_star: XcmsFloat, v_star: XcmsFloat,
} }
XcmsTekHVC :: struct { XcmsTekHVC :: struct {
H: XcmsFloat, H: XcmsFloat,
V: XcmsFloat, V: XcmsFloat,
C: XcmsFloat, C: XcmsFloat,
} }
XcmsPad :: struct { XcmsPad :: struct {
_: XcmsFloat, _: XcmsFloat,
_: XcmsFloat, _: XcmsFloat,
_: XcmsFloat, _: XcmsFloat,
_: XcmsFloat, _: XcmsFloat,
} }
XcmsColor :: struct { XcmsColor :: struct {
spec: struct #raw_union { spec: struct #raw_union {
RGB: XcmsRGB, RGB: XcmsRGB,
RGBi: XcmsRGBi, RGBi: XcmsRGBi,
CIEXYZ: XcmsCIEXYZ, CIEXYZ: XcmsCIEXYZ,
@@ -1840,17 +1840,17 @@ XcmsColor :: struct {
CIELuv: XcmsCIELuv, CIELuv: XcmsCIELuv,
TekHVC: XcmsTekHVC, TekHVC: XcmsTekHVC,
_: XcmsPad, _: XcmsPad,
}, },
pixel: uint, pixel: uint,
format: XcmsColorFormat, format: XcmsColorFormat,
} }
XcmsPerScrnInfo :: struct { XcmsPerScrnInfo :: struct {
screenWhitePt: XcmsColor, screenWhitePt: XcmsColor,
functionSet: rawptr, functionSet: rawptr,
screenData: rawptr, screenData: rawptr,
state: u8, state: u8,
_: [3]u8, _: [3]u8,
} }
XcmsCCC :: distinct rawptr XcmsCCC :: distinct rawptr
@@ -1872,15 +1872,15 @@ XcmsWhiteAdjustProc :: #type proc "c" (
compression: [^]b32) -> Status compression: [^]b32) -> Status
XcmsCCCRec :: struct { XcmsCCCRec :: struct {
dpy: ^Display, dpy: ^Display,
screenNumber: i32, screenNumber: i32,
visual: ^Visual, visual: ^Visual,
clientWhitePt: XcmsColor, clientWhitePt: XcmsColor,
gamutCompProc: XcmsCompressionProc, gamutCompProc: XcmsCompressionProc,
gamutCompClientData: rawptr, gamutCompClientData: rawptr,
whitePtAdjProc: XcmsWhiteAdjustProc, whitePtAdjProc: XcmsWhiteAdjustProc,
whitePtAdjClientData: rawptr, whitePtAdjClientData: rawptr,
pPerScrnInfo: ^XcmsPerScrnInfo, pPerScrnInfo: ^XcmsPerScrnInfo,
} }
XcmsScreenInitProc :: #type proc "c" ( XcmsScreenInitProc :: #type proc "c" (
@@ -1909,18 +1909,18 @@ XcmsFuncListPtr :: [^]XcmsConversionProc
XcmsParseStringProc :: #type proc "c" (color_string: cstring, color: ^XcmsColor) -> i32 XcmsParseStringProc :: #type proc "c" (color_string: cstring, color: ^XcmsColor) -> i32
XcmsColorSpace :: struct { XcmsColorSpace :: struct {
prefix: cstring, prefix: cstring,
id: XcmsColorFormat, id: XcmsColorFormat,
parseString: XcmsParseStringProc, parseString: XcmsParseStringProc,
to_CIEXYZ: XcmsFuncListPtr, to_CIEXYZ: XcmsFuncListPtr,
from_CIEXYZ: XcmsFuncListPtr, from_CIEXYZ: XcmsFuncListPtr,
inverse_flag: i32, inverse_flag: i32,
} }
XcmsFunctionSet :: struct { XcmsFunctionSet :: struct {
DDColorSpaces: [^]^XcmsColorSpace, DDColorSpaces: [^]^XcmsColorSpace,
screenInitProc: XcmsScreenInitProc, screenInitProc: XcmsScreenInitProc,
screenFreeProc: XcmsScreenFreeProc, screenFreeProc: XcmsScreenFreeProc,
} }
@@ -1958,18 +1958,18 @@ XWMHints :: struct {
} }
XTextProperty :: struct { XTextProperty :: struct {
value: [^]u8, value: [^]u8,
encoding: Atom, encoding: Atom,
format: int, format: int,
nitems: uint, nitems: uint,
} }
XICCEncodingStyle :: enum i32 { XICCEncodingStyle :: enum i32 {
XStringStyle, XStringStyle,
XCompoundTextStyle, XCompoundTextStyle,
XTextStyle, XTextStyle,
XStdICCTextStyle, XStdICCTextStyle,
XUTF8StringStyle, XUTF8StringStyle,
} }
XIconSize :: struct { XIconSize :: struct {
@@ -1987,8 +1987,8 @@ XClassHint :: struct {
} }
XComposeStatus :: struct { XComposeStatus :: struct {
compose_ptr: rawptr, compose_ptr: rawptr,
chars_matched: i32, chars_matched: i32,
} }
Region :: distinct rawptr Region :: distinct rawptr
@@ -2041,8 +2041,8 @@ XrmClassList :: XrmQuarkList
XrmRepresentation :: XrmQuark XrmRepresentation :: XrmQuark
XrmValue :: struct { XrmValue :: struct {
size: u32, size: u32,
addr: rawptr, addr: rawptr,
} }
XrmValuePtr :: [^]XrmValue XrmValuePtr :: [^]XrmValue
@@ -2052,21 +2052,21 @@ XrmSearchList :: [^]XrmHashTable
XrmDatabase :: distinct rawptr XrmDatabase :: distinct rawptr
XrmOptionKind :: enum { XrmOptionKind :: enum {
XrmoptionNoArg, XrmoptionNoArg,
XrmoptionIsArg, XrmoptionIsArg,
XrmoptionStickyArg, XrmoptionStickyArg,
XrmoptionSepArg, XrmoptionSepArg,
XrmoptionResArg, XrmoptionResArg,
XrmoptionSkipArg, XrmoptionSkipArg,
XrmoptionSkipLine, XrmoptionSkipLine,
XrmoptionSkipNArgs, XrmoptionSkipNArgs,
} }
XrmOptionDescRec :: struct { XrmOptionDescRec :: struct {
option: cstring, option: cstring,
specifier: cstring, specifier: cstring,
argKind: XrmOptionKind, argKind: XrmOptionKind,
value: rawptr, value: rawptr,
} }
XrmOptionDescList :: [^]XrmOptionDescRec XrmOptionDescList :: [^]XrmOptionDescRec