mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-23 13:31:35 +00:00
Merge branch 'master' into windows-llvm-11.1.0
This commit is contained in:
@@ -72,10 +72,12 @@ del *.ilk > NUL 2> NUL
|
||||
cl %compiler_settings% "src\main.cpp" "src\libtommath.cpp" /link %linker_settings% -OUT:%exe_name%
|
||||
if %errorlevel% neq 0 goto end_of_build
|
||||
|
||||
call build_vendor.bat
|
||||
if %errorlevel% neq 0 goto end_of_build
|
||||
rem call build_vendor.bat
|
||||
rem if %errorlevel% neq 0 goto end_of_build
|
||||
|
||||
if %release_mode% EQU 0 odin run examples/demo
|
||||
odin run examples/demo -vet -strict-style
|
||||
rem odin check examples/all
|
||||
rem odin run examples/bug
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
|
||||
@@ -50,7 +50,19 @@ config_darwin() {
|
||||
}
|
||||
|
||||
config_freebsd() {
|
||||
: ${LLVM_CONFIG=/usr/local/bin/llvm-config11}
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
if [ ! "$LLVM_CONFIG" ]; then
|
||||
if which llvm-config11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config11
|
||||
elif which llvm-config12 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config12
|
||||
elif which llvm-config13 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config13
|
||||
else
|
||||
panic "Unable to find LLVM-config"
|
||||
fi
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
|
||||
@@ -294,6 +294,24 @@ peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid
|
||||
}
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
|
||||
size :: size_of(T)
|
||||
|
||||
#no_bounds_check {
|
||||
if len(z.input_data) >= size + offset {
|
||||
buf := z.input_data[offset:][:size]
|
||||
return (^T)(&buf[0])^, .None
|
||||
}
|
||||
}
|
||||
|
||||
if len(z.input_data) == 0 {
|
||||
return T{}, .EOF
|
||||
} else {
|
||||
return T{}, .Short_Buffer
|
||||
}
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
|
||||
size :: size_of(T)
|
||||
@@ -321,7 +339,44 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
return res, .None
|
||||
}
|
||||
|
||||
peek_data :: proc{peek_data_from_memory, peek_data_from_stream}
|
||||
@(optimization_mode="speed")
|
||||
peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
|
||||
size :: size_of(T)
|
||||
|
||||
// Get current position to return to.
|
||||
cur_pos, e1 := z.input->impl_seek(0, .Current)
|
||||
if e1 != .None {
|
||||
return T{}, e1
|
||||
}
|
||||
|
||||
// Seek to offset.
|
||||
pos, e2 := z.input->impl_seek(offset, .Start)
|
||||
if e2 != .None {
|
||||
return T{}, e2
|
||||
}
|
||||
|
||||
r, e3 := io.to_reader_at(z.input)
|
||||
if !e3 {
|
||||
return T{}, .Empty
|
||||
}
|
||||
when size <= 128 {
|
||||
b: [size]u8
|
||||
} else {
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
}
|
||||
_, e4 := io.read_at(r, b[:], pos)
|
||||
if e4 != .None {
|
||||
return T{}, .Empty
|
||||
}
|
||||
|
||||
// Return read head to original position.
|
||||
z.input->impl_seek(cur_pos, .Start)
|
||||
|
||||
res = (^T)(&b[0])^
|
||||
return res, .None
|
||||
}
|
||||
|
||||
peek_data :: proc{peek_data_from_memory, peek_data_from_stream, peek_data_at_offset_from_memory, peek_data_at_offset_from_stream}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -73,11 +73,18 @@ get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
|
||||
front :: proc(q: ^$Q/Queue($T)) -> T {
|
||||
return q.data[q.offset]
|
||||
}
|
||||
front_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
|
||||
return &q.data[q.offset]
|
||||
}
|
||||
|
||||
back :: proc(q: ^$Q/Queue($T)) -> T {
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
return q.data[idx]
|
||||
}
|
||||
back_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
|
||||
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
|
||||
@@ -92,6 +99,18 @@ get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
peek_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||
runtime.bounds_check_error_loc(loc, 0, builtin.len(q.data))
|
||||
idx := q.offset%builtin.len(q.data)
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
|
||||
runtime.bounds_check_error_loc(loc, int(q.len - 1), builtin.len(q.data))
|
||||
idx := (uint(q.len - 1)+q.offset)%builtin.len(q.data)
|
||||
return &q.data[idx]
|
||||
}
|
||||
|
||||
// Push an element to the back of the queue
|
||||
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||
if space(q^) == 0 {
|
||||
|
||||
@@ -85,6 +85,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
case i16: u = u128(i)
|
||||
case i32: u = u128(i)
|
||||
case i64: u = u128(i)
|
||||
case i128: u = u128(i)
|
||||
case int: u = u128(i)
|
||||
case u8: u = u128(i)
|
||||
case u16: u = u128(i)
|
||||
|
||||
@@ -2059,18 +2059,33 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
|
||||
entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
|
||||
entry_size := ed.elem_size
|
||||
/*
|
||||
NOTE: The layout of a `map` is as follows:
|
||||
|
||||
map[Key]Value
|
||||
|
||||
## Internal Layout
|
||||
struct {
|
||||
hashes: []int,
|
||||
entries: [dynamic]struct{
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
key: Key,
|
||||
value: Value,
|
||||
},
|
||||
}
|
||||
*/
|
||||
for i in 0..<entries.len {
|
||||
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
|
||||
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size)
|
||||
|
||||
key := data + entry_type.offsets[2]
|
||||
key := data + entry_type.offsets[2] // key: Key
|
||||
fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v')
|
||||
|
||||
io.write_string(fi.writer, "=", &fi.n)
|
||||
|
||||
value := data + entry_type.offsets[3]
|
||||
value := data + entry_type.offsets[3] // value: Value
|
||||
fmt_arg(fi, any{rawptr(value), info.value.id}, 'v')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ Image :: struct {
|
||||
height: int,
|
||||
channels: int,
|
||||
depth: int, // Channel depth in bits, typically 8 or 16
|
||||
pixels: bytes.Buffer,
|
||||
pixels: bytes.Buffer `fmt:"-"`,
|
||||
/*
|
||||
Some image loaders/writers can return/take an optional background color.
|
||||
For convenience, we return them as u16 so we don't need to switch on the type
|
||||
@@ -61,6 +61,7 @@ Image_Metadata :: union #shared_nil {
|
||||
^Netpbm_Info,
|
||||
^PNG_Info,
|
||||
^QOI_Info,
|
||||
^TGA_Info,
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +169,7 @@ Error :: union #shared_nil {
|
||||
|
||||
General_Image_Error :: enum {
|
||||
None = 0,
|
||||
Unsupported_Option,
|
||||
// File I/O
|
||||
Unable_To_Read_File,
|
||||
Unable_To_Write_File,
|
||||
@@ -376,10 +378,20 @@ QOI_Info :: struct {
|
||||
header: QOI_Header,
|
||||
}
|
||||
|
||||
TGA_Data_Type :: enum u8 {
|
||||
No_Image_Data = 0,
|
||||
Uncompressed_Color_Mapped = 1,
|
||||
Uncompressed_RGB = 2,
|
||||
Uncompressed_Black_White = 3,
|
||||
Compressed_Color_Mapped = 9,
|
||||
Compressed_RGB = 10,
|
||||
Compressed_Black_White = 11,
|
||||
}
|
||||
|
||||
TGA_Header :: struct #packed {
|
||||
id_length: u8,
|
||||
color_map_type: u8,
|
||||
data_type_code: u8,
|
||||
data_type_code: TGA_Data_Type,
|
||||
color_map_origin: u16le,
|
||||
color_map_length: u16le,
|
||||
color_map_depth: u8,
|
||||
@@ -390,6 +402,52 @@ TGA_Header :: struct #packed {
|
||||
}
|
||||
#assert(size_of(TGA_Header) == 18)
|
||||
|
||||
New_TGA_Signature :: "TRUEVISION-XFILE.\x00"
|
||||
|
||||
TGA_Footer :: struct #packed {
|
||||
extension_area_offset: u32le,
|
||||
developer_directory_offset: u32le,
|
||||
signature: [18]u8 `fmt:"s,0"`, // Should match signature if New TGA.
|
||||
}
|
||||
#assert(size_of(TGA_Footer) == 26)
|
||||
|
||||
TGA_Extension :: struct #packed {
|
||||
extension_size: u16le, // Size of this struct. If not 495 bytes it means it's an unsupported version.
|
||||
author_name: [41]u8 `fmt:"s,0"`, // Author name, ASCII. Zero-terminated
|
||||
author_comments: [324]u8 `fmt:"s,0"`, // Author comments, formatted as 4 lines of 80 character lines, each zero terminated.
|
||||
datetime: struct {month, day, year, hour, minute, second: u16le},
|
||||
job_name: [41]u8 `fmt:"s,0"`, // Author name, ASCII. Zero-terminated
|
||||
job_time: struct {hour, minute, second: u16le},
|
||||
software_id: [41]u8 `fmt:"s,0"`, // Software ID name, ASCII. Zero-terminated
|
||||
software_version: struct #packed {
|
||||
number: u16le, // Version number * 100
|
||||
letter: u8 `fmt:"r"`, // " " if not used
|
||||
},
|
||||
key_color: [4]u8, // ARGB key color used at time of production
|
||||
aspect_ratio: [2]u16le, // Numerator / Denominator
|
||||
gamma: [2]u16le, // Numerator / Denominator, range should be 0.0..10.0
|
||||
color_correction_offset: u32le, // 0 if no color correction information
|
||||
postage_stamp_offset: u32le, // 0 if no thumbnail
|
||||
scanline_offset: u32le, // 0 if no scanline table
|
||||
attributes: TGA_Alpha_Kind,
|
||||
}
|
||||
#assert(size_of(TGA_Extension) == 495)
|
||||
|
||||
TGA_Alpha_Kind :: enum u8 {
|
||||
None,
|
||||
Undefined_Ignore,
|
||||
Undefined_Retain,
|
||||
Useful,
|
||||
Premultiplied,
|
||||
}
|
||||
|
||||
TGA_Info :: struct {
|
||||
header: TGA_Header,
|
||||
image_id: string,
|
||||
footer: Maybe(TGA_Footer),
|
||||
extension: Maybe(TGA_Extension),
|
||||
}
|
||||
|
||||
// Function to help with image buffer calculations
|
||||
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
|
||||
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
Benoit Jacquier: tga loader
|
||||
*/
|
||||
|
||||
|
||||
@@ -14,11 +15,16 @@ import "core:mem"
|
||||
import "core:image"
|
||||
import "core:bytes"
|
||||
import "core:os"
|
||||
import "core:compress"
|
||||
import "core:strings"
|
||||
|
||||
// TODO: alpha_premultiply support
|
||||
|
||||
Error :: image.Error
|
||||
Image :: image.Image
|
||||
Options :: image.Options
|
||||
|
||||
GA_Pixel :: image.GA_Pixel
|
||||
RGB_Pixel :: image.RGB_Pixel
|
||||
RGBA_Pixel :: image.RGBA_Pixel
|
||||
|
||||
@@ -57,7 +63,7 @@ save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
|
||||
}
|
||||
|
||||
header := image.TGA_Header{
|
||||
data_type_code = 0x02, // Color, uncompressed.
|
||||
data_type_code = .Uncompressed_RGB,
|
||||
dimensions = {u16le(img.width), u16le(img.height)},
|
||||
bits_per_pixel = u8(img.depth * img.channels),
|
||||
image_descriptor = 1 << 5, // Origin is top left.
|
||||
@@ -98,4 +104,337 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato
|
||||
return nil if write_ok else .Unable_To_Write_File
|
||||
}
|
||||
|
||||
save :: proc{save_to_memory, save_to_file}
|
||||
save :: proc{save_to_memory, save_to_file}
|
||||
|
||||
load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||
context.allocator = allocator
|
||||
options := options
|
||||
|
||||
if .alpha_premultiply in options {
|
||||
return nil, .Unsupported_Option
|
||||
}
|
||||
|
||||
if .info in options {
|
||||
options |= {.return_metadata, .do_not_decompress_image}
|
||||
options -= {.info}
|
||||
}
|
||||
|
||||
if .return_header in options && .return_metadata in options {
|
||||
options -= {.return_header}
|
||||
}
|
||||
|
||||
// First check for a footer.
|
||||
filesize := compress.input_size(ctx) or_return
|
||||
|
||||
footer: image.TGA_Footer
|
||||
have_valid_footer := false
|
||||
|
||||
extension: image.TGA_Extension
|
||||
have_valid_extension := false
|
||||
|
||||
if filesize >= size_of(image.TGA_Header) + size_of(image.TGA_Footer) {
|
||||
if f, f_err := compress.peek_data(ctx, image.TGA_Footer, filesize - i64(size_of(image.TGA_Footer))); f_err == .None {
|
||||
if string(f.signature[:]) == image.New_TGA_Signature {
|
||||
have_valid_footer = true
|
||||
footer = f
|
||||
|
||||
if i64(footer.extension_area_offset) + i64(size_of(image.TGA_Extension)) < filesize {
|
||||
if e, e_err := compress.peek_data(ctx, image.TGA_Extension, footer.extension_area_offset); e_err == .None {
|
||||
if e.extension_size == size_of(image.TGA_Extension) {
|
||||
have_valid_extension = true
|
||||
extension = e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header := image.read_data(ctx, image.TGA_Header) or_return
|
||||
|
||||
// Header checks
|
||||
rle_encoding := false
|
||||
color_mapped := false
|
||||
black_white := false
|
||||
src_channels := 0
|
||||
dest_depth := header.bits_per_pixel
|
||||
dest_channels := 0
|
||||
|
||||
#partial switch header.data_type_code {
|
||||
// Supported formats: RGB(A), RGB(A) RLE
|
||||
case .Compressed_RGB:
|
||||
rle_encoding = true
|
||||
case .Uncompressed_RGB:
|
||||
// Intentionally blank
|
||||
case .Uncompressed_Black_White:
|
||||
black_white = true
|
||||
dest_depth = 24
|
||||
case .Uncompressed_Color_Mapped:
|
||||
color_mapped = true
|
||||
case .Compressed_Color_Mapped:
|
||||
color_mapped = true
|
||||
rle_encoding = true
|
||||
case .Compressed_Black_White:
|
||||
black_white = true
|
||||
rle_encoding = true
|
||||
dest_depth = 24
|
||||
|
||||
case:
|
||||
return nil, .Unsupported_Format
|
||||
}
|
||||
|
||||
if color_mapped {
|
||||
if header.color_map_type != 1 {
|
||||
return nil, .Unsupported_Format
|
||||
}
|
||||
dest_depth = header.color_map_depth
|
||||
|
||||
// Expect LUT entry index to be 8 bits
|
||||
if header.bits_per_pixel != 8 || header.color_map_origin != 0 || header.color_map_length > 256 {
|
||||
return nil, .Unsupported_Format
|
||||
}
|
||||
}
|
||||
|
||||
switch dest_depth {
|
||||
case 15: // B5G5R5
|
||||
src_channels = 2
|
||||
dest_channels = 3
|
||||
if color_mapped {
|
||||
src_channels = 1
|
||||
}
|
||||
case 16: // B5G5R5A1
|
||||
src_channels = 2
|
||||
dest_channels = 3 // Alpha bit is dodgy in TGA, so we ignore it.
|
||||
if color_mapped {
|
||||
src_channels = 1
|
||||
}
|
||||
case 24: // RGB8
|
||||
src_channels = 1 if (color_mapped || black_white) else 3
|
||||
dest_channels = 3
|
||||
case 32: // RGBA8
|
||||
src_channels = 4 if !color_mapped else 1
|
||||
dest_channels = 4
|
||||
|
||||
case:
|
||||
return nil, .Unsupported_Format
|
||||
}
|
||||
|
||||
if header.image_descriptor & IMAGE_DESCRIPTOR_INTERLEAVING_MASK != 0 {
|
||||
return nil, .Unsupported_Format
|
||||
}
|
||||
|
||||
if int(header.dimensions[0]) * int(header.dimensions[1]) > image.MAX_DIMENSIONS {
|
||||
return nil, .Image_Dimensions_Too_Large
|
||||
}
|
||||
|
||||
if img == nil {
|
||||
img = new(Image)
|
||||
}
|
||||
|
||||
defer if err != nil {
|
||||
destroy(img)
|
||||
}
|
||||
|
||||
img.which = .TGA
|
||||
img.channels = 4 if .alpha_add_if_missing in options else dest_channels
|
||||
img.channels = 3 if .alpha_drop_if_present in options else img.channels
|
||||
|
||||
img.depth = 8
|
||||
img.width = int(header.dimensions[0])
|
||||
img.height = int(header.dimensions[1])
|
||||
|
||||
// Read Image ID if present
|
||||
image_id := ""
|
||||
if _id, e := compress.read_slice(ctx, int(header.id_length)); e != .None {
|
||||
return img, .Corrupt
|
||||
} else {
|
||||
if .return_metadata in options {
|
||||
id := strings.trim_right_null(string(_id))
|
||||
image_id = strings.clone(id)
|
||||
}
|
||||
}
|
||||
|
||||
color_map := make([]RGBA_Pixel, header.color_map_length)
|
||||
defer delete(color_map)
|
||||
|
||||
if color_mapped {
|
||||
switch header.color_map_depth {
|
||||
case 16:
|
||||
for i in 0..<header.color_map_length {
|
||||
if lut, lut_err := compress.read_data(ctx, GA_Pixel); lut_err != .None {
|
||||
return img, .Corrupt
|
||||
} else {
|
||||
color_map[i].rg = lut
|
||||
color_map[i].ba = 255
|
||||
}
|
||||
}
|
||||
|
||||
case 24:
|
||||
for i in 0..<header.color_map_length {
|
||||
if lut, lut_err := compress.read_data(ctx, RGB_Pixel); lut_err != .None {
|
||||
return img, .Corrupt
|
||||
} else {
|
||||
color_map[i].rgb = lut
|
||||
color_map[i].a = 255
|
||||
}
|
||||
}
|
||||
|
||||
case 32:
|
||||
for i in 0..<header.color_map_length {
|
||||
if lut, lut_err := compress.read_data(ctx, RGBA_Pixel); lut_err != .None {
|
||||
return img, .Corrupt
|
||||
} else {
|
||||
color_map[i] = lut
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if .return_metadata in options {
|
||||
info := new(image.TGA_Info)
|
||||
info.header = header
|
||||
info.image_id = image_id
|
||||
if have_valid_footer {
|
||||
info.footer = footer
|
||||
}
|
||||
if have_valid_extension {
|
||||
info.extension = extension
|
||||
}
|
||||
img.metadata = info
|
||||
}
|
||||
|
||||
if .do_not_decompress_image in options {
|
||||
return img, nil
|
||||
}
|
||||
|
||||
if !resize(&img.pixels.buf, dest_channels * img.width * img.height) {
|
||||
return img, .Unable_To_Allocate_Or_Resize
|
||||
}
|
||||
|
||||
origin_is_top := header.image_descriptor & IMAGE_DESCRIPTOR_TOP_MASK != 0
|
||||
origin_is_left := header.image_descriptor & IMAGE_DESCRIPTOR_RIGHT_MASK == 0
|
||||
rle_repetition_count := 0
|
||||
read_pixel := true
|
||||
is_packet_rle := false
|
||||
|
||||
pixel: RGBA_Pixel
|
||||
|
||||
stride := img.width * dest_channels
|
||||
line := 0 if origin_is_top else img.height - 1
|
||||
|
||||
for _ in 0..<img.height {
|
||||
offset := line * stride + (0 if origin_is_left else (stride - dest_channels))
|
||||
for _ in 0..<img.width {
|
||||
// handle RLE decoding
|
||||
if rle_encoding {
|
||||
if rle_repetition_count == 0 {
|
||||
rle_cmd, err := compress.read_u8(ctx)
|
||||
if err != .None {
|
||||
return img, .Corrupt
|
||||
}
|
||||
is_packet_rle = (rle_cmd >> 7) != 0
|
||||
rle_repetition_count = 1 + int(rle_cmd & 0x7F)
|
||||
read_pixel = true
|
||||
} else if !is_packet_rle {
|
||||
read_pixel = rle_repetition_count > 0
|
||||
} else {
|
||||
read_pixel = false
|
||||
}
|
||||
}
|
||||
// Read pixel
|
||||
if read_pixel {
|
||||
src, src_err := compress.read_slice(ctx, src_channels)
|
||||
if src_err != .None {
|
||||
return img, .Corrupt
|
||||
}
|
||||
switch src_channels {
|
||||
case 1:
|
||||
// Color-mapped or Black & White
|
||||
if black_white {
|
||||
pixel = {src[0], src[0], src[0], 255}
|
||||
} else if header.color_map_depth == 24 {
|
||||
pixel = color_map[src[0]].bgra
|
||||
} else if header.color_map_depth == 16 {
|
||||
lut := color_map[src[0]]
|
||||
v := u16(lut.r) | u16(lut.g) << 8
|
||||
b := u8( v & 31) << 3
|
||||
g := u8((v >> 5) & 31) << 3
|
||||
r := u8((v >> 10) & 31) << 3
|
||||
pixel = {r, g, b, 255}
|
||||
}
|
||||
|
||||
case 2:
|
||||
v := u16(src[0]) | u16(src[1]) << 8
|
||||
b := u8( v & 31) << 3
|
||||
g := u8((v >> 5) & 31) << 3
|
||||
r := u8((v >> 10) & 31) << 3
|
||||
pixel = {r, g, b, 255}
|
||||
|
||||
case 3:
|
||||
pixel = {src[2], src[1], src[0], 255}
|
||||
case 4:
|
||||
pixel = {src[2], src[1], src[0], src[3]}
|
||||
case:
|
||||
return img, .Corrupt
|
||||
}
|
||||
}
|
||||
|
||||
// Write pixel
|
||||
copy(img.pixels.buf[offset:], pixel[:dest_channels])
|
||||
offset += dest_channels if origin_is_left else -dest_channels
|
||||
rle_repetition_count -= 1
|
||||
}
|
||||
line += 1 if origin_is_top else -1
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||
ctx := &compress.Context_Memory_Input{
|
||||
input_data = data,
|
||||
}
|
||||
|
||||
img, err = load_from_context(ctx, options, allocator)
|
||||
return img, err
|
||||
}
|
||||
|
||||
load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
data, ok := os.read_entire_file(filename)
|
||||
defer delete(data)
|
||||
|
||||
if ok {
|
||||
return load_from_bytes(data, options)
|
||||
} else {
|
||||
return nil, .Unable_To_Read_File
|
||||
}
|
||||
}
|
||||
|
||||
load :: proc{load_from_file, load_from_bytes, load_from_context}
|
||||
|
||||
destroy :: proc(img: ^Image) {
|
||||
if img == nil || img.width == 0 || img.height == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
bytes.buffer_destroy(&img.pixels)
|
||||
if v, ok := img.metadata.(^image.TGA_Info); ok {
|
||||
delete(v.image_id)
|
||||
free(v)
|
||||
}
|
||||
|
||||
// Make destroy idempotent
|
||||
img.width = 0
|
||||
img.height = 0
|
||||
free(img)
|
||||
}
|
||||
|
||||
IMAGE_DESCRIPTOR_INTERLEAVING_MASK :: (1<<6) | (1<<7)
|
||||
IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4
|
||||
IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5
|
||||
|
||||
@(init, private)
|
||||
_register :: proc() {
|
||||
image.register(.TGA, load_from_bytes, destroy)
|
||||
}
|
||||
@@ -188,6 +188,8 @@ type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
|
||||
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) ---
|
||||
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
||||
|
||||
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
|
||||
|
||||
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||
|
||||
// SIMD related
|
||||
|
||||
@@ -356,7 +356,7 @@ Flux_Tween :: struct($T: typeid) {
|
||||
flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
|
||||
return {
|
||||
values = make(map[^T]Flux_Tween(T), value_capacity),
|
||||
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity)
|
||||
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package math
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:builtin"
|
||||
_ :: intrinsics
|
||||
|
||||
Float_Class :: enum {
|
||||
@@ -36,6 +37,11 @@ MAX_F16_PRECISION :: 4 // Maximum number of meaningful digits after the decimal
|
||||
RAD_PER_DEG :: TAU/360.0
|
||||
DEG_PER_RAD :: 360.0/TAU
|
||||
|
||||
abs :: builtin.abs
|
||||
min :: builtin.min
|
||||
max :: builtin.max
|
||||
clamp :: builtin.clamp
|
||||
|
||||
sqrt_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(sqrt_f16(f16(x))) }
|
||||
sqrt_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(sqrt_f16(f16(x))) }
|
||||
sqrt_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(sqrt_f32(f32(x))) }
|
||||
|
||||
@@ -54,48 +54,7 @@ compare :: proc "contextless" (a, b: []byte) -> int {
|
||||
}
|
||||
|
||||
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
|
||||
switch {
|
||||
case a == b:
|
||||
return 0
|
||||
case a == nil:
|
||||
return -1
|
||||
case b == nil:
|
||||
return -1
|
||||
case n == 0:
|
||||
return 0
|
||||
}
|
||||
|
||||
x := slice_ptr(a, n)
|
||||
y := slice_ptr(b, n)
|
||||
|
||||
SU :: size_of(uintptr)
|
||||
fast := n/SU + 1
|
||||
offset := (fast-1)*SU
|
||||
curr_block := 0
|
||||
if n < SU {
|
||||
fast = 0
|
||||
}
|
||||
|
||||
la := slice_ptr((^uintptr)(a), fast)
|
||||
lb := slice_ptr((^uintptr)(b), fast)
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
if la[curr_block] ~ lb[curr_block] != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
if x[pos] ~ y[pos] != 0 {
|
||||
return (int(x[pos]) - int(y[pos])) < 0 ? -1 : +1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
if x[offset] ~ y[offset] != 0 {
|
||||
return (int(x[offset]) - int(y[offset])) < 0 ? -1 : +1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
return runtime.memory_compare(a, b, n)
|
||||
}
|
||||
|
||||
check_zero :: proc(data: []byte) -> bool {
|
||||
|
||||
@@ -13,10 +13,10 @@ Growing_Arena :: struct {
|
||||
|
||||
DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
|
||||
|
||||
growing_arena_init :: proc(arena: ^Static_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
||||
arena.block = memory_block_alloc(0, reserved, {}) or_return
|
||||
growing_arena_init :: proc(arena: ^Growing_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
||||
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
||||
arena.total_used = 0
|
||||
arena.total_reserved = arena.block.reserved
|
||||
arena.total_reserved = arena.curr_block.reserved
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ munmap :: proc "contextless" (addr: rawptr, length: uint) -> c.int {
|
||||
}
|
||||
|
||||
mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: c.int) -> c.int {
|
||||
res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uint(prot))
|
||||
res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))
|
||||
return c.int(res)
|
||||
}
|
||||
|
||||
|
||||
@@ -596,7 +596,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||
return "", Errno(get_last_error())
|
||||
}
|
||||
|
||||
path := strings.clone_from_cstring(cstring(&buf[0]), context.temp_allocator)
|
||||
path := strings.clone_from_cstring(cstring(&buf[0]))
|
||||
return path, ERROR_NONE
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
||||
low := uintptr(offset & 0xFFFFFFFF)
|
||||
high := uintptr(offset >> 32)
|
||||
result: i64
|
||||
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
|
||||
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence)))
|
||||
return -1 if res < 0 else result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,4 +705,4 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
res[i] = string(arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package reflect
|
||||
|
||||
import "core:runtime"
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:mem"
|
||||
_ :: mem
|
||||
_ :: intrinsics
|
||||
|
||||
Type_Info :: runtime.Type_Info
|
||||
@@ -224,7 +225,7 @@ align_of_typeid :: proc(T: typeid) -> int {
|
||||
as_bytes :: proc(v: any) -> []byte {
|
||||
if v != nil {
|
||||
sz := size_of_typeid(v.id)
|
||||
return mem.slice_ptr((^byte)(v.data), sz)
|
||||
return ([^]byte)(v.data)[:sz]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -266,19 +267,19 @@ length :: proc(val: any) -> int {
|
||||
return a.count
|
||||
|
||||
case Type_Info_Slice:
|
||||
return (^mem.Raw_Slice)(val.data).len
|
||||
return (^runtime.Raw_Slice)(val.data).len
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
return (^mem.Raw_Dynamic_Array)(val.data).len
|
||||
return (^runtime.Raw_Dynamic_Array)(val.data).len
|
||||
|
||||
case Type_Info_Map:
|
||||
return (^mem.Raw_Map)(val.data).entries.len
|
||||
return (^runtime.Raw_Map)(val.data).entries.len
|
||||
|
||||
case Type_Info_String:
|
||||
if a.is_cstring {
|
||||
return len((^cstring)(val.data)^)
|
||||
} else {
|
||||
return (^mem.Raw_String)(val.data).len
|
||||
return (^runtime.Raw_String)(val.data).len
|
||||
}
|
||||
}
|
||||
return 0
|
||||
@@ -301,10 +302,10 @@ capacity :: proc(val: any) -> int {
|
||||
return a.count
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
return (^mem.Raw_Dynamic_Array)(val.data).cap
|
||||
return (^runtime.Raw_Dynamic_Array)(val.data).cap
|
||||
|
||||
case Type_Info_Map:
|
||||
return (^mem.Raw_Map)(val.data).entries.cap
|
||||
return (^runtime.Raw_Map)(val.data).entries.cap
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -344,14 +345,14 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
return any{data, a.elem.id}
|
||||
|
||||
case Type_Info_Slice:
|
||||
raw := (^mem.Raw_Slice)(val.data)
|
||||
raw := (^runtime.Raw_Slice)(val.data)
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len)
|
||||
offset := uintptr(a.elem.size * i)
|
||||
data := rawptr(uintptr(raw.data) + offset)
|
||||
return any{data, a.elem.id}
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
raw := (^mem.Raw_Dynamic_Array)(val.data)
|
||||
raw := (^runtime.Raw_Dynamic_Array)(val.data)
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len)
|
||||
offset := uintptr(a.elem.size * i)
|
||||
data := rawptr(uintptr(raw.data) + offset)
|
||||
@@ -360,7 +361,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
case Type_Info_String:
|
||||
if a.is_cstring { return nil }
|
||||
|
||||
raw := (^mem.Raw_String)(val.data)
|
||||
raw := (^runtime.Raw_String)(val.data)
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len)
|
||||
offset := uintptr(size_of(u8) * i)
|
||||
data := rawptr(uintptr(raw.data) + offset)
|
||||
@@ -729,6 +730,26 @@ get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||
panic("expected a union to reflect.get_union_variant_raw_tag")
|
||||
}
|
||||
|
||||
get_union_variant :: proc(a: any) -> any {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
id := union_variant_typeid(a)
|
||||
if id == nil {
|
||||
return nil
|
||||
}
|
||||
return any{a.data, id}
|
||||
}
|
||||
|
||||
get_union_as_ptr_variants :: proc(val: ^$T) -> (res: intrinsics.type_convert_variants_to_pointers(T)) where intrinsics.type_is_union(T) {
|
||||
ptr := rawptr(val)
|
||||
tag := get_union_variant_raw_tag(val^)
|
||||
mem.copy(&res, &ptr, size_of(ptr))
|
||||
set_union_variant_raw_tag(res, tag)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
set_union_variant_raw_tag :: proc(a: any, tag: i64) {
|
||||
if a == nil { return }
|
||||
@@ -826,17 +847,17 @@ set_union_value :: proc(dst: any, value: any) -> bool {
|
||||
ti := runtime.type_info_base(type_info_of(dst.id))
|
||||
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||
if value.id == nil {
|
||||
mem.zero(dst.data, ti.size)
|
||||
intrinsics.mem_zero(dst.data, ti.size)
|
||||
return true
|
||||
}
|
||||
if ti.id == runtime.typeid_base(value.id) {
|
||||
mem.copy(dst.data, value.data, ti.size)
|
||||
intrinsics.mem_copy(dst.data, value.data, ti.size)
|
||||
return true
|
||||
}
|
||||
|
||||
if type_info_union_is_pure_maybe(info) {
|
||||
if variant := info.variants[0]; variant.id == value.id {
|
||||
mem.copy(dst.data, value.data, variant.size)
|
||||
intrinsics.mem_copy(dst.data, value.data, variant.size)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -848,7 +869,7 @@ set_union_value :: proc(dst: any, value: any) -> bool {
|
||||
if !info.no_nil {
|
||||
tag += 1
|
||||
}
|
||||
mem.copy(dst.data, value.data, variant.size)
|
||||
intrinsics.mem_copy(dst.data, value.data, variant.size)
|
||||
set_union_variant_raw_tag(dst, tag)
|
||||
return true
|
||||
}
|
||||
@@ -1341,11 +1362,11 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||
|
||||
case Type_Info_Slice:
|
||||
valid = true
|
||||
value = (^mem.Raw_Slice)(a.data).data
|
||||
value = (^runtime.Raw_Slice)(a.data).data
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
valid = true
|
||||
value = (^mem.Raw_Dynamic_Array)(a.data).data
|
||||
value = (^runtime.Raw_Dynamic_Array)(a.data).data
|
||||
}
|
||||
|
||||
return
|
||||
@@ -1387,7 +1408,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
}
|
||||
|
||||
if .Simple_Compare in t.flags {
|
||||
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
|
||||
return runtime.memory_compare(a.data, b.data, t.size) == 0
|
||||
}
|
||||
|
||||
t = runtime.type_info_core(t)
|
||||
@@ -1425,7 +1446,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
Type_Info_Relative_Pointer,
|
||||
Type_Info_Soa_Pointer,
|
||||
Type_Info_Matrix:
|
||||
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
|
||||
return runtime.memory_compare(a.data, b.data, t.size) == 0
|
||||
|
||||
case Type_Info_String:
|
||||
if v.is_cstring {
|
||||
@@ -1479,8 +1500,8 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
if !including_indirect_array_recursion {
|
||||
return false
|
||||
}
|
||||
array_a := (^mem.Raw_Slice)(a.data)
|
||||
array_b := (^mem.Raw_Slice)(b.data)
|
||||
array_a := (^runtime.Raw_Slice)(a.data)
|
||||
array_b := (^runtime.Raw_Slice)(b.data)
|
||||
if array_a.len != array_b.len {
|
||||
return false
|
||||
}
|
||||
@@ -1499,8 +1520,8 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
if !including_indirect_array_recursion {
|
||||
return false
|
||||
}
|
||||
array_a := (^mem.Raw_Dynamic_Array)(a.data)
|
||||
array_b := (^mem.Raw_Dynamic_Array)(b.data)
|
||||
array_a := (^runtime.Raw_Dynamic_Array)(a.data)
|
||||
array_b := (^runtime.Raw_Dynamic_Array)(b.data)
|
||||
if array_a.len != array_b.len {
|
||||
return false
|
||||
}
|
||||
@@ -1508,7 +1529,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
return true
|
||||
}
|
||||
if .Simple_Compare in v.elem.flags {
|
||||
return mem.compare_byte_ptrs((^byte)(array_a.data), (^byte)(array_b.data), array_a.len * v.elem.size) == 0
|
||||
return runtime.memory_compare((^byte)(array_a.data), (^byte)(array_b.data), array_a.len * v.elem.size) == 0
|
||||
}
|
||||
|
||||
for i in 0..<array_a.len {
|
||||
|
||||
@@ -342,12 +342,13 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
|
||||
|
||||
@builtin
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
|
||||
if array == nil {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
when size_of(E) == 0 {
|
||||
a.len += 1
|
||||
array.len += 1
|
||||
return 1
|
||||
} else {
|
||||
if cap(array) < len(array)+1 {
|
||||
cap := 2 * cap(array) + max(8, 1)
|
||||
@@ -361,23 +362,26 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
data[a.len] = arg
|
||||
}
|
||||
a.len += 1
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) {
|
||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
|
||||
if array == nil {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
|
||||
arg_len := len(args)
|
||||
if arg_len <= 0 {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
|
||||
when size_of(E) == 0 {
|
||||
a.len += arg_len
|
||||
array.len += arg_len
|
||||
return arg_len
|
||||
} else {
|
||||
if cap(array) < len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len)
|
||||
@@ -393,23 +397,25 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
||||
}
|
||||
a.len += arg_len
|
||||
}
|
||||
return arg_len
|
||||
}
|
||||
}
|
||||
|
||||
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
|
||||
@builtin
|
||||
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) {
|
||||
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int {
|
||||
args := transmute([]E)arg
|
||||
append_elems(array=array, args=args, loc=loc)
|
||||
return append_elems(array=array, args=args, loc=loc)
|
||||
}
|
||||
|
||||
|
||||
// The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
|
||||
@builtin
|
||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) {
|
||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) {
|
||||
for arg in args {
|
||||
append(array = array, args = transmute([]E)(arg), loc = loc)
|
||||
n += append(array = array, args = transmute([]E)(arg), loc = loc)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The append built-in procedure appends elements to the end of a dynamic array
|
||||
@@ -417,11 +423,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
|
||||
|
||||
|
||||
@builtin
|
||||
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
|
||||
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
|
||||
if array == nil {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
prev_len := len(array)
|
||||
resize(array, len(array)+1)
|
||||
return len(array)-prev_len
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ _ :: mem
|
||||
Turn a pointer and a length into a slice.
|
||||
*/
|
||||
from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
|
||||
return ([^]T)(ptr)[:count]
|
||||
return ([^]T)(ptr)[:count]
|
||||
}
|
||||
|
||||
/*
|
||||
Turn a pointer and a length into a byte slice.
|
||||
*/
|
||||
bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
|
||||
return ([^]byte)(ptr)[:byte_count]
|
||||
return ([^]byte)(ptr)[:byte_count]
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,6 +38,52 @@ sort :: proc(data: $T/[]$E) where ORD(E) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sort_by_indices :: proc{ sort_by_indices_allocate, _sort_by_indices}
|
||||
|
||||
sort_by_indices_allocate :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) {
|
||||
assert(len(data) == len(indices))
|
||||
sorted = make(T, len(data), allocator)
|
||||
for v, i in indices {
|
||||
sorted[i] = data[v]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_sort_by_indices :: proc(data, sorted: $T/[]$E, indices: []int) {
|
||||
assert(len(data) == len(indices))
|
||||
assert(len(data) == len(sorted))
|
||||
for v, i in indices {
|
||||
sorted[i] = data[v]
|
||||
}
|
||||
}
|
||||
|
||||
sort_by_indices_overwrite :: proc(data: $T/[]$E, indices: []int) {
|
||||
assert(len(data) == len(indices))
|
||||
temp := make([]int, len(data), context.allocator)
|
||||
defer delete(temp)
|
||||
for v, i in indices {
|
||||
temp[i] = data[v]
|
||||
}
|
||||
swap_with_slice(data, temp)
|
||||
}
|
||||
|
||||
// sort sorts a slice and returns a slice of the original indices
|
||||
// This sort is not guaranteed to be stable
|
||||
sort_with_indices :: proc(data: $T/[]$E, allocator := context.allocator) -> (indices: []int) where ORD(E) {
|
||||
indices = make([]int, len(data), allocator)
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
for _, idx in indices {
|
||||
indices[idx] = idx
|
||||
}
|
||||
_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), struct{}{}, .Ordered)
|
||||
}
|
||||
return indices
|
||||
}
|
||||
return indices
|
||||
}
|
||||
|
||||
// sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
|
||||
// This sort is not guaranteed to be stable
|
||||
sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
||||
@@ -48,6 +94,22 @@ sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
|
||||
// This sort is not guaranteed to be stable
|
||||
sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocator := context.allocator) -> (indices : []int) {
|
||||
indices = make([]int, len(data), allocator)
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
for _, idx in indices {
|
||||
indices[idx] = idx
|
||||
}
|
||||
_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), less, .Less)
|
||||
return indices
|
||||
}
|
||||
}
|
||||
return indices
|
||||
}
|
||||
|
||||
sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
|
||||
@@ -198,3 +198,180 @@ _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (O
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_quick_sort_general_with_indices :: proc(data: $T/[]$E, indices: []int, a, b, max_depth: int, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
||||
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
||||
when KIND == .Ordered {
|
||||
return a < b
|
||||
} else when KIND == .Less {
|
||||
return call(a, b)
|
||||
} else when KIND == .Cmp {
|
||||
return call(a, b) == .Less
|
||||
} else {
|
||||
#panic("unhandled Sort_Kind")
|
||||
}
|
||||
}
|
||||
|
||||
insertion_sort :: proc(data: $T/[]$E, indices: []int, a, b: int, call: P) #no_bounds_check {
|
||||
for i in a+1..<b {
|
||||
for j := i; j > a && less(data[j], data[j-1], call); j -= 1 {
|
||||
swap(data, j, j-1)
|
||||
swap(indices, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
heap_sort :: proc(data: $T/[]$E, indices: []int, a, b: int, call: P) #no_bounds_check {
|
||||
sift_down :: proc(data: T, indices: []int, lo, hi, first: int, call: P) #no_bounds_check {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && less(data[first+child], data[first+child+1], call) {
|
||||
child += 1
|
||||
}
|
||||
if !less(data[first+root], data[first+child], call) {
|
||||
return
|
||||
}
|
||||
swap(data, first+root, first+child)
|
||||
swap(indices, first+root, first+child)
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
first, lo, hi := a, 0, b-a
|
||||
|
||||
for i := (hi-1)/2; i >= 0; i -= 1 {
|
||||
sift_down(data, indices, i, hi, first, call)
|
||||
}
|
||||
|
||||
for i := hi-1; i >= 0; i -= 1 {
|
||||
swap(data, first, first+i)
|
||||
swap(indices, first, first+i)
|
||||
sift_down(data, indices, lo, i, first, call)
|
||||
}
|
||||
}
|
||||
|
||||
median3 :: proc(data: T, indices: []int, m1, m0, m2: int, call: P) #no_bounds_check {
|
||||
if less(data[m1], data[m0], call) {
|
||||
swap(data, m1, m0)
|
||||
swap(indices, m1, m0)
|
||||
}
|
||||
if less(data[m2], data[m1], call) {
|
||||
swap(data, m2, m1)
|
||||
swap(indices, m2, m1)
|
||||
if less(data[m1], data[m0], call) {
|
||||
swap(data, m1, m0)
|
||||
swap(indices, m1, m0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_pivot :: proc(data: T, indices: []int, lo, hi: int, call: P) -> (midlo, midhi: int) #no_bounds_check {
|
||||
m := int(uint(lo+hi)>>1)
|
||||
if hi-lo > 40 {
|
||||
s := (hi-lo)/8
|
||||
median3(data, indices, lo, lo+s, lo+s*2, call)
|
||||
median3(data, indices, m, m-s, m+s, call)
|
||||
median3(data, indices, hi-1, hi-1-s, hi-1-s*2, call)
|
||||
}
|
||||
median3(data, indices, lo, m, hi-1, call)
|
||||
|
||||
pivot := lo
|
||||
a, c := lo+1, hi-1
|
||||
|
||||
|
||||
for ; a < c && less(data[a], data[pivot], call); a += 1 {
|
||||
}
|
||||
b := a
|
||||
|
||||
for {
|
||||
for ; b < c && !less(data[pivot], data[b], call); b += 1 { // data[b] <= pivot
|
||||
}
|
||||
for ; b < c && less(data[pivot], data[c-1], call); c -=1 { // data[c-1] > pivot
|
||||
}
|
||||
if b >= c {
|
||||
break
|
||||
}
|
||||
|
||||
swap(data, b, c-1)
|
||||
swap(indices, b, c-1)
|
||||
b += 1
|
||||
c -= 1
|
||||
}
|
||||
|
||||
protect := hi-c < 5
|
||||
if !protect && hi-c < (hi-lo)/4 {
|
||||
dups := 0
|
||||
if !less(data[pivot], data[hi-1], call) {
|
||||
swap(data, c, hi-1)
|
||||
swap(indices, c, hi-1)
|
||||
c += 1
|
||||
dups += 1
|
||||
}
|
||||
if !less(data[b-1], data[pivot], call) {
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
|
||||
if !less(data[m], data[pivot], call) {
|
||||
swap(data, m, b-1)
|
||||
swap(indices, m, b-1)
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
protect = dups > 1
|
||||
}
|
||||
if protect {
|
||||
for {
|
||||
for ; a < b && !less(data[b-1], data[pivot], call); b -= 1 {
|
||||
}
|
||||
for ; a < b && less(data[a], data[pivot], call); a += 1 {
|
||||
}
|
||||
if a >= b {
|
||||
break
|
||||
}
|
||||
swap(data, a, b-1)
|
||||
swap(indices, a, b-1)
|
||||
a += 1
|
||||
b -= 1
|
||||
}
|
||||
}
|
||||
swap(data, pivot, b-1)
|
||||
swap(indices, pivot, b-1)
|
||||
return b-1, c
|
||||
}
|
||||
|
||||
assert(len(data) == len(indices))
|
||||
|
||||
a, b, max_depth := a, b, max_depth
|
||||
|
||||
for b-a > 12 { // only use shell sort for lengths <= 12
|
||||
if max_depth == 0 {
|
||||
heap_sort(data, indices, a, b, call)
|
||||
return
|
||||
}
|
||||
max_depth -= 1
|
||||
mlo, mhi := do_pivot(data, indices, a, b, call)
|
||||
if mlo-a < b-mhi {
|
||||
_quick_sort_general_with_indices(data, indices, a, mlo, max_depth, call, KIND)
|
||||
a = mhi
|
||||
} else {
|
||||
_quick_sort_general_with_indices(data, indices, mhi, b, max_depth, call, KIND)
|
||||
b = mlo
|
||||
}
|
||||
}
|
||||
if b-a > 1 {
|
||||
// Shell short with gap 6
|
||||
for i in a+6..<b {
|
||||
if less(data[i], data[i-6], call) {
|
||||
swap(data, i, i-6)
|
||||
swap(indices, i, i-6)
|
||||
}
|
||||
}
|
||||
insertion_sort(data, indices, a, b, call)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package strconv
|
||||
|
||||
import "core:unicode/utf8"
|
||||
|
||||
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
|
||||
parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) {
|
||||
switch s {
|
||||
case "1", "t", "T", "true", "TRUE", "True":
|
||||
if n != nil { n^ = len(s) }
|
||||
return true, true
|
||||
case "0", "f", "F", "false", "FALSE", "False":
|
||||
if n != nil { n^ = len(s) }
|
||||
return false, true
|
||||
}
|
||||
return
|
||||
@@ -32,10 +34,13 @@ _digit_value :: proc(r: rune) -> int {
|
||||
// n, ok := strconv.parse_i64_of_base("-1234eeee", 10);
|
||||
// assert(n == -1234 && ok);
|
||||
// ```
|
||||
parse_i64_of_base :: proc(str: string, base: int) -> (value: i64, ok: bool) {
|
||||
parse_i64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i64, ok: bool) {
|
||||
assert(base <= 16, "base must be 1-16")
|
||||
|
||||
s := str
|
||||
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -87,8 +92,9 @@ parse_i64_of_base :: proc(str: string, base: int) -> (value: i64, ok: bool) {
|
||||
// n, ok = strconv.parse_i64_maybe_prefixed("0xeeee");
|
||||
// assert(n == 0xeeee && ok);
|
||||
// ```
|
||||
parse_i64_maybe_prefixed :: proc(str: string) -> (value: i64, ok: bool) {
|
||||
parse_i64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i64, ok: bool) {
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -155,9 +161,10 @@ parse_i64 :: proc{parse_i64_maybe_prefixed, parse_i64_of_base}
|
||||
// n, ok = strconv.parse_u64_of_base("5678eeee", 16);
|
||||
// assert(n == 0x5678eeee && ok);
|
||||
// ```
|
||||
parse_u64_of_base :: proc(str: string, base: int) -> (value: u64, ok: bool) {
|
||||
parse_u64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u64, ok: bool) {
|
||||
assert(base <= 16, "base must be 1-16")
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -198,8 +205,9 @@ parse_u64_of_base :: proc(str: string, base: int) -> (value: u64, ok: bool) {
|
||||
// n, ok = strconv.parse_u64_maybe_prefixed("0xeeee");
|
||||
// assert(n == 0xeeee && ok);
|
||||
// ```
|
||||
parse_u64_maybe_prefixed :: proc(str: string) -> (value: u64, ok: bool) {
|
||||
parse_u64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u64, ok: bool) {
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -259,11 +267,11 @@ parse_u64 :: proc{parse_u64_maybe_prefixed, parse_u64_of_base}
|
||||
// n, ok = strconv.parse_int("0xffff"); // with prefix and inferred base
|
||||
// assert(n == 0xffff && ok);
|
||||
// ```
|
||||
parse_int :: proc(s: string, base := 0) -> (value: int, ok: bool) {
|
||||
parse_int :: proc(s: string, base := 0, n: ^int = nil) -> (value: int, ok: bool) {
|
||||
v: i64 = ---
|
||||
switch base {
|
||||
case 0: v, ok = parse_i64_maybe_prefixed(s)
|
||||
case: v, ok = parse_i64_of_base(s, base)
|
||||
case 0: v, ok = parse_i64_maybe_prefixed(s, n)
|
||||
case: v, ok = parse_i64_of_base(s, base, n)
|
||||
}
|
||||
value = int(v)
|
||||
return
|
||||
@@ -289,11 +297,11 @@ parse_int :: proc(s: string, base := 0) -> (value: int, ok: bool) {
|
||||
// n, ok = strconv.parse_uint("0xffff"); // with prefix and inferred base
|
||||
// assert(n == 0xffff && ok);
|
||||
// ```
|
||||
parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
|
||||
parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: bool) {
|
||||
v: u64 = ---
|
||||
switch base {
|
||||
case 0: v, ok = parse_u64_maybe_prefixed(s)
|
||||
case: v, ok = parse_u64_of_base(s, base)
|
||||
case 0: v, ok = parse_u64_maybe_prefixed(s, n)
|
||||
case: v, ok = parse_u64_of_base(s, base, n)
|
||||
}
|
||||
value = uint(v)
|
||||
return
|
||||
@@ -309,10 +317,11 @@ parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
|
||||
// n, ok := strconv.parse_i128_of_base("-1234eeee", 10);
|
||||
// assert(n == -1234 && ok);
|
||||
// ```
|
||||
parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
|
||||
parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i128, ok: bool) {
|
||||
assert(base <= 16, "base must be 1-16")
|
||||
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -364,8 +373,9 @@ parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
|
||||
// n, ok = strconv.parse_i128_maybe_prefixed("0xeeee");
|
||||
// assert(n == 0xeeee && ok);
|
||||
// ```
|
||||
parse_i128_maybe_prefixed :: proc(str: string) -> (value: i128, ok: bool) {
|
||||
parse_i128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i128, ok: bool) {
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -432,9 +442,10 @@ parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
|
||||
// n, ok = strconv.parse_u128_of_base("5678eeee", 16);
|
||||
// assert(n == 0x5678eeee && ok);
|
||||
// ```
|
||||
parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
|
||||
parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u128, ok: bool) {
|
||||
assert(base <= 16, "base must be 1-16")
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -475,8 +486,9 @@ parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
|
||||
// n, ok = strconv.parse_u128_maybe_prefixed("0xeeee");
|
||||
// assert(n == 0xeeee && ok);
|
||||
// ```
|
||||
parse_u128_maybe_prefixed :: proc(str: string) -> (value: u128, ok: bool) {
|
||||
parse_u128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u128, ok: bool) {
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -535,9 +547,9 @@ parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
|
||||
// n, ok = strconv.parse_f32("12.34");
|
||||
// assert(n == 12.34 && ok);
|
||||
// ```
|
||||
parse_f32 :: proc(s: string) -> (value: f32, ok: bool) {
|
||||
parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
|
||||
v: f64 = ---
|
||||
v, ok = parse_f64(s)
|
||||
v, ok = parse_f64(s, n)
|
||||
return f32(v), ok
|
||||
}
|
||||
|
||||
@@ -553,8 +565,9 @@ parse_f32 :: proc(s: string) -> (value: f32, ok: bool) {
|
||||
// n, ok = strconv.parse_f32("12.34");
|
||||
// assert(n == 12.34 && ok);
|
||||
// ```
|
||||
parse_f64 :: proc(str: string) -> (value: f64, ok: bool) {
|
||||
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1686,7 +1686,7 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
|
||||
return clone(str, allocator)
|
||||
}
|
||||
|
||||
remains := length-1
|
||||
remains := length-n
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
@@ -1702,14 +1702,14 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
|
||||
return to_string(b)
|
||||
}
|
||||
|
||||
// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length
|
||||
// left_justify returns a string with a pad string at right side if the str's rune length is smaller than length
|
||||
left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str)
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator)
|
||||
}
|
||||
|
||||
remains := length-1
|
||||
remains := length-n
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
@@ -1724,14 +1724,14 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
|
||||
return to_string(b)
|
||||
}
|
||||
|
||||
// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length
|
||||
// right_justify returns a string with a pad string at left side if the str's rune length is smaller than length
|
||||
right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str)
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator)
|
||||
}
|
||||
|
||||
remains := length-1
|
||||
remains := length-n
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
|
||||
@@ -8,8 +8,9 @@ import "core:time"
|
||||
foreign import System "System.framework"
|
||||
|
||||
foreign System {
|
||||
// __ulock_wait is not available on 10.15
|
||||
// See https://github.com/odin-lang/Odin/issues/1959
|
||||
__ulock_wait :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_us: u32) -> c.int ---
|
||||
__ulock_wait2 :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ns: u64, value2: u64) -> c.int ---
|
||||
__ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
|
||||
}
|
||||
|
||||
@@ -28,9 +29,9 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
timeout_ns := u64(duration)
|
||||
timeout_ns := u32(duration) * 1000
|
||||
|
||||
s := __ulock_wait2(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns, 0)
|
||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
||||
if s >= 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
26
core/sys/info/cpu_arm.odin
Normal file
26
core/sys/info/cpu_arm.odin
Normal file
@@ -0,0 +1,26 @@
|
||||
//+build arm32, arm64
|
||||
package sysinfo
|
||||
|
||||
// TODO: Set up an enum with the ARM equivalent of the above.
|
||||
CPU_Feature :: enum u64 {}
|
||||
|
||||
cpu_features: Maybe(CPU_Feature)
|
||||
cpu_name: Maybe(string)
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc "c" () {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_cpu_name_buf: [72]u8
|
||||
|
||||
@(init, private)
|
||||
init_cpu_name :: proc "c" () {
|
||||
when ODIN_ARCH == .arm32 {
|
||||
copy(_cpu_name_buf[:], "ARM")
|
||||
cpu_name = string(_cpu_name_buf[:3])
|
||||
} else {
|
||||
copy(_cpu_name_buf[:], "ARM64")
|
||||
cpu_name = string(_cpu_name_buf[:5])
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
package sysinfo
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -9,7 +9,6 @@ cpuid :: intrinsics.x86_cpuid
|
||||
// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
||||
xgetbv :: intrinsics.x86_xgetbv
|
||||
|
||||
|
||||
CPU_Feature :: enum u64 {
|
||||
aes, // AES hardware implementation (AES NI)
|
||||
adx, // Multi-precision add-carry instruction extensions
|
||||
@@ -34,6 +33,7 @@ CPU_Feature :: enum u64 {
|
||||
CPU_Features :: distinct bit_set[CPU_Feature; u64]
|
||||
|
||||
cpu_features: Maybe(CPU_Features)
|
||||
cpu_name: Maybe(string)
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc "c" () {
|
||||
@@ -67,6 +67,13 @@ init_cpu_features :: proc "c" () {
|
||||
try_set(&set, .os_xsave, 27, ecx1)
|
||||
try_set(&set, .rdrand, 30, ecx1)
|
||||
|
||||
when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
|
||||
// xgetbv is an illegal instruction under FreeBSD 13 & OpenBSD 7.1
|
||||
// return before probing further
|
||||
cpu_features = set
|
||||
return
|
||||
}
|
||||
|
||||
os_supports_avx := false
|
||||
if .os_xsave in set {
|
||||
eax, _ := xgetbv(0)
|
||||
@@ -92,3 +99,31 @@ init_cpu_features :: proc "c" () {
|
||||
|
||||
cpu_features = set
|
||||
}
|
||||
|
||||
@(private)
|
||||
_cpu_name_buf: [72]u8
|
||||
|
||||
@(init, private)
|
||||
init_cpu_name :: proc "c" () {
|
||||
number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0)
|
||||
if number_of_extended_ids < 0x8000_0004 {
|
||||
return
|
||||
}
|
||||
|
||||
_buf := transmute(^[0x12]u32)&_cpu_name_buf
|
||||
_buf[ 0], _buf[ 1], _buf[ 2], _buf[ 3] = cpuid(0x8000_0002, 0)
|
||||
_buf[ 4], _buf[ 5], _buf[ 6], _buf[ 7] = cpuid(0x8000_0003, 0)
|
||||
_buf[ 8], _buf[ 9], _buf[10], _buf[11] = cpuid(0x8000_0004, 0)
|
||||
|
||||
// Some CPUs like may include leading or trailing spaces. Trim them.
|
||||
// e.g. ` Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz`
|
||||
|
||||
brand := string(_cpu_name_buf[:])
|
||||
for len(brand) > 0 && brand[0] == 0 || brand[0] == ' ' {
|
||||
brand = brand[1:]
|
||||
}
|
||||
for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' {
|
||||
brand = brand[:len(brand) - 1]
|
||||
}
|
||||
cpu_name = brand
|
||||
}
|
||||
78
core/sys/info/doc.odin
Normal file
78
core/sys/info/doc.odin
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
Package `core:sys/info` gathers system information on:
|
||||
Windows, Linux, macOS, FreeBSD & OpenBSD.
|
||||
|
||||
Simply import the package and you'll have access to the OS version, RAM amount
|
||||
and CPU information.
|
||||
|
||||
On Windows, GPUs will also be enumerated using the registry.
|
||||
|
||||
CPU feature flags can be tested against `cpu_features`, where applicable, e.g.
|
||||
`if .aes in si.aes { ... }`
|
||||
*/
|
||||
// +ignore
|
||||
package sysinfo
|
||||
|
||||
import "core:fmt"
|
||||
import si "core:sys/info"
|
||||
|
||||
main :: proc() {
|
||||
fmt.printf("Odin: %v\n", ODIN_VERSION)
|
||||
fmt.printf("OS: %v\n", si.os_version.as_string)
|
||||
fmt.printf("OS: %#v\n", si.os_version)
|
||||
fmt.printf("CPU: %v\n", si.cpu_name)
|
||||
fmt.printf("RAM: %v MiB\n", si.ram.total_ram / 1024 / 1024)
|
||||
|
||||
fmt.println()
|
||||
for gpu, i in si.gpus {
|
||||
fmt.printf("GPU #%v:\n", i)
|
||||
fmt.printf("\tVendor: %v\n", gpu.vendor_name)
|
||||
fmt.printf("\tModel: %v\n", gpu.model_name)
|
||||
fmt.printf("\tVRAM: %v MiB\n", gpu.total_ram / 1024 / 1024)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Example Windows output:
|
||||
Odin: dev-2022-09
|
||||
OS: Windows 10 Professional (version: 20H2), build: 19042.1466
|
||||
OS: OS_Version{
|
||||
platform = "Windows",
|
||||
major = 10,
|
||||
minor = 0,
|
||||
patch = 0,
|
||||
build = [
|
||||
19042,
|
||||
1466,
|
||||
],
|
||||
version = "20H2",
|
||||
as_string = "Windows 10 Professional (version: 20H2), build: 19042.1466",
|
||||
}
|
||||
CPU: AMD Ryzen 7 1800X Eight-Core Processor
|
||||
RAM: 65469 MiB
|
||||
|
||||
GPU #0:
|
||||
Vendor: Advanced Micro Devices, Inc.
|
||||
Model: Radeon RX Vega
|
||||
VRAM: 8176 MiB
|
||||
|
||||
Example macOS output:
|
||||
ODIN: dev-2022-09
|
||||
OS: OS_Version{
|
||||
platform = "MacOS",
|
||||
major = 21,
|
||||
minor = 5,
|
||||
patch = 0,
|
||||
build = [
|
||||
0,
|
||||
0,
|
||||
],
|
||||
version = "21F79",
|
||||
as_string = "macOS Monterey 12.4 (build 21F79, kernel 21.5.0)",
|
||||
}
|
||||
CPU: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
|
||||
RAM: 8192 MiB
|
||||
*/
|
||||
510
core/sys/info/platform_darwin.odin
Normal file
510
core/sys/info/platform_darwin.odin
Normal file
@@ -0,0 +1,510 @@
|
||||
// +build darwin
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .MacOS
|
||||
|
||||
// Start building display version
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_OSVERSION}
|
||||
build_buf: [12]u8
|
||||
|
||||
ok := sys.sysctl(mib, &build_buf)
|
||||
if !ok {
|
||||
strings.write_string(&b, "macOS Unknown")
|
||||
os_version.as_string = strings.to_string(b)
|
||||
return
|
||||
}
|
||||
|
||||
build := string(cstring(&build_buf[0]))
|
||||
|
||||
// Do we have an exact match?
|
||||
match: Darwin_Match
|
||||
rel, exact := macos_release_map[build]
|
||||
|
||||
if exact {
|
||||
match = .Exact
|
||||
} else {
|
||||
// Match on XNU kernel version
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
version_bits: [12]u8 // enough for 999.999.999\x00
|
||||
have_kernel_version := sys.sysctl(mib, &version_bits)
|
||||
|
||||
major_ok, minor_ok, patch_ok: bool
|
||||
|
||||
triplet := strings.split(string(cstring(&version_bits[0])), ".", context.temp_allocator)
|
||||
if len(triplet) != 3 {
|
||||
have_kernel_version = false
|
||||
} else {
|
||||
rel.darwin.x, major_ok = strconv.parse_int(triplet[0])
|
||||
rel.darwin.y, minor_ok = strconv.parse_int(triplet[1])
|
||||
rel.darwin.z, patch_ok = strconv.parse_int(triplet[2])
|
||||
|
||||
if !(major_ok && minor_ok && patch_ok) {
|
||||
have_kernel_version = false
|
||||
}
|
||||
}
|
||||
|
||||
if !have_kernel_version {
|
||||
// We don't know the kernel version, but we do know the build
|
||||
strings.write_string(&b, "macOS Unknown (build ")
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, build)
|
||||
os_version.version = strings.to_string(b)[l:]
|
||||
strings.write_rune(&b, ')')
|
||||
os_version.as_string = strings.to_string(b)
|
||||
return
|
||||
}
|
||||
rel, match = map_darwin_kernel_version_to_macos_release(build, rel.darwin)
|
||||
}
|
||||
|
||||
os_version.major = rel.darwin.x
|
||||
os_version.minor = rel.darwin.y
|
||||
os_version.patch = rel.darwin.z
|
||||
|
||||
strings.write_string(&b, rel.os_name)
|
||||
if match == .Exact || match == .Nearest {
|
||||
strings.write_rune(&b, ' ')
|
||||
strings.write_string(&b, rel.release.name)
|
||||
strings.write_rune(&b, ' ')
|
||||
strings.write_int(&b, rel.release.version.x)
|
||||
if rel.release.version.y > 0 || rel.release.version.z > 0 {
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.release.version.y)
|
||||
}
|
||||
if rel.release.version.z > 0 {
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.release.version.z)
|
||||
}
|
||||
if match == .Nearest {
|
||||
strings.write_rune(&b, '?')
|
||||
}
|
||||
} else {
|
||||
strings.write_string(&b, " Unknown")
|
||||
}
|
||||
|
||||
strings.write_string(&b, " (build ")
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, build)
|
||||
os_version.version = strings.to_string(b)[l:]
|
||||
|
||||
strings.write_string(&b, ", kernel ")
|
||||
strings.write_int(&b, rel.darwin.x)
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.darwin.y)
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.darwin.z)
|
||||
strings.write_rune(&b, ')')
|
||||
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
|
||||
mib := []i32{sys.CTL_HW, sys.HW_MEMSIZE}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
Darwin_To_Release :: struct {
|
||||
darwin: [3]int, // Darwin kernel triplet
|
||||
os_name: string, // OS X, MacOS
|
||||
release: struct {
|
||||
name: string, // Monterey, Mojave, etc.
|
||||
version: [3]int, // 12.4, etc.
|
||||
},
|
||||
}
|
||||
|
||||
// Important: Order from lowest to highest kernel version
|
||||
@(private)
|
||||
macos_release_map: map[string]Darwin_To_Release = {
|
||||
// MacOS Tiger
|
||||
"8A428" = {{8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
"8A432" = {{8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
"8B15" = {{8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
"8B17" = {{8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
"8C46" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8C47" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E102" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E45" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E90" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8F46" = {{8, 3, 0}, "macOS", {"Tiger", {10, 4, 3}}},
|
||||
"8G32" = {{8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
"8G1165" = {{8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
"8H14" = {{8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
"8G1454" = {{8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
"8I127" = {{8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
"8I1119" = {{8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
"8J135" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8J2135a" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8K1079" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8N5107" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8L127" = {{8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
"8L2127" = {{8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
"8P135" = {{8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
"8P2137" = {{8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
"8R218" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8R2218" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8R2232" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8S165" = {{8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
"8S2167" = {{8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
|
||||
// MacOS Leopard
|
||||
"9A581" = {{9, 0, 0}, "macOS", {"Leopard", {10, 5, 0}}},
|
||||
"9B18" = {{9, 1, 0}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
"9B2117" = {{9, 1, 1}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
"9C31" = {{9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
"9C7010" = {{9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
"9D34" = {{9, 3, 0}, "macOS", {"Leopard", {10, 5, 3}}},
|
||||
"9E17" = {{9, 4, 0}, "macOS", {"Leopard", {10, 5, 4}}},
|
||||
"9F33" = {{9, 5, 0}, "macOS", {"Leopard", {10, 5, 5}}},
|
||||
"9G55" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9G66" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9G71" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9J61" = {{9, 7, 0}, "macOS", {"Leopard", {10, 5, 7}}},
|
||||
"9L30" = {{9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
"9L34" = {{9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
|
||||
// MacOS Snow Leopard
|
||||
"10A432" = {{10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
"10A433" = {{10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
"10B504" = {{10, 1, 0}, "macOS", {"Snow Leopard", {10, 6, 1}}},
|
||||
"10C540" = {{10, 2, 0}, "macOS", {"Snow Leopard", {10, 6, 2}}},
|
||||
"10D573" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10D575" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10D578" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10F569" = {{10, 4, 0}, "macOS", {"Snow Leopard", {10, 6, 4}}},
|
||||
"10H574" = {{10, 5, 0}, "macOS", {"Snow Leopard", {10, 6, 5}}},
|
||||
"10J567" = {{10, 6, 0}, "macOS", {"Snow Leopard", {10, 6, 6}}},
|
||||
"10J869" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10J3250" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10J4138" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10K540" = {{10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
"10K549" = {{10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
|
||||
// MacOS Lion
|
||||
"11A511" = {{11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A511s" = {{11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A2061" = {{11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A2063" = {{11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11B26" = {{11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
"11B2118" = {{11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
"11C74" = {{11, 2, 0}, "macOS", {"Lion", {10, 7, 2}}},
|
||||
"11D50" = {{11, 3, 0}, "macOS", {"Lion", {10, 7, 3}}},
|
||||
"11E53" = {{11, 4, 0}, "macOS", {"Lion", {10, 7, 4}}},
|
||||
"11G56" = {{11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
"11G63" = {{11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
|
||||
// MacOS Mountain Lion
|
||||
"12A269" = {{12, 0, 0}, "macOS", {"Mountain Lion", {10, 8, 0}}},
|
||||
"12B19" = {{12, 1, 0}, "macOS", {"Mountain Lion", {10, 8, 1}}},
|
||||
"12C54" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C60" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C2034" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C3104" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12D78" = {{12, 3, 0}, "macOS", {"Mountain Lion", {10, 8, 3}}},
|
||||
"12E55" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12E3067" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12E4022" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12F37" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F45" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2501" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2518" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2542" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2560" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
|
||||
// MacOS Mavericks
|
||||
"13A603" = {{13, 0, 0}, "macOS", {"Mavericks", {10, 9, 0}}},
|
||||
"13B42" = {{13, 0, 0}, "macOS", {"Mavericks", {10, 9, 1}}},
|
||||
"13C64" = {{13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
"13C1021" = {{13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
"13D65" = {{13, 2, 0}, "macOS", {"Mavericks", {10, 9, 3}}},
|
||||
"13E28" = {{13, 3, 0}, "macOS", {"Mavericks", {10, 9, 4}}},
|
||||
"13F34" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1066" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1077" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1096" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1112" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1134" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1507" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1603" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1712" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1808" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1911" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
|
||||
// MacOS Yosemite
|
||||
"14A389" = {{14, 0, 0}, "macOS", {"Yosemite", {10, 10, 0}}},
|
||||
"14B25" = {{14, 0, 0}, "macOS", {"Yosemite", {10, 10, 1}}},
|
||||
"14C109" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C1510" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C2043" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C1514" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C2513" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14D131" = {{14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
"14D136" = {{14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
"14E46" = {{14, 4, 0}, "macOS", {"Yosemite", {10, 10, 4}}},
|
||||
"14F27" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1021" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1505" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1509" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1605" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1713" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1808" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1909" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1912" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2009" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2109" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2315" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2411" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2511" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
|
||||
// MacOS El Capitan
|
||||
"15A284" = {{15, 0, 0}, "macOS", {"El Capitan", {10, 11, 0}}},
|
||||
"15B42" = {{15, 0, 0}, "macOS", {"El Capitan", {10, 11, 1}}},
|
||||
"15C50" = {{15, 2, 0}, "macOS", {"El Capitan", {10, 11, 2}}},
|
||||
"15D21" = {{15, 3, 0}, "macOS", {"El Capitan", {10, 11, 3}}},
|
||||
"15E65" = {{15, 4, 0}, "macOS", {"El Capitan", {10, 11, 4}}},
|
||||
"15F34" = {{15, 5, 0}, "macOS", {"El Capitan", {10, 11, 5}}},
|
||||
"15G31" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1004" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1011" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1108" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1212" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1217" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1421" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1510" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1611" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G17023" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G18013" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G19009" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G20015" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G21013" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G22010" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
|
||||
// MacOS Sierra
|
||||
"16A323" = {{16, 0, 0}, "macOS", {"Sierra", {10, 12, 0}}},
|
||||
"16B2555" = {{16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
"16B2657" = {{16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
"16C67" = {{16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
"16C68" = {{16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
"16D32" = {{16, 4, 0}, "macOS", {"Sierra", {10, 12, 3}}},
|
||||
"16E195" = {{16, 5, 0}, "macOS", {"Sierra", {10, 12, 4}}},
|
||||
"16F73" = {{16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
"16F2073" = {{16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
"16G29" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1036" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1114" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1212" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1314" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1408" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1510" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1618" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1710" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1815" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1917" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1918" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2016" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2127" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2128" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2136" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
|
||||
// MacOS High Sierra
|
||||
"17A365" = {{17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
"17A405" = {{17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
"17B48" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17B1002" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17B1003" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17C88" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C89" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C205" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C2205" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17D47" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D2047" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D102" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D2102" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17E199" = {{17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
"17E202" = {{17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
"17F77" = {{17, 6, 0}, "macOS", {"High Sierra", {10, 13, 5}}},
|
||||
"17G65" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G2208" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G2307" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G3025" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G4015" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G5019" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G6029" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G6030" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G7024" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8029" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8030" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8037" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G9016" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G10021" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G11023" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G12034" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G13033" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G13035" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14019" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14033" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14042" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
|
||||
// MacOS Mojave
|
||||
"18A391" = {{18, 0, 0}, "macOS", {"Mojave", {10, 14, 0}}},
|
||||
"18B75" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18B2107" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18B3094" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18C54" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 2}}},
|
||||
"18D42" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18D43" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18D109" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18E226" = {{18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
"18E227" = {{18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
"18F132" = {{18, 6, 0}, "macOS", {"Mojave", {10, 14, 5}}},
|
||||
"18G84" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G87" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G95" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G103" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G1012" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G2022" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G3020" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G4032" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G5033" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6020" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6032" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6042" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G7016" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G8012" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G8022" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9028" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9216" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9323" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
|
||||
// MacOS Catalina
|
||||
"19A583" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19A602" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19A603" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19B88" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 1}}},
|
||||
"19C57" = {{19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
"19C58" = {{19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
"19D76" = {{19, 3, 0}, "macOS", {"Catalina", {10, 15, 3}}},
|
||||
"19E266" = {{19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
"19E287" = {{19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
"19F96" = {{19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
"19F101" = {{19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
"19G73" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
"19G2021" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
"19H2" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H4" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H15" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H114" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H512" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H524" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1030" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1217" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1323" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1417" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1419" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1519" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1615" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1713" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1715" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1824" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1922" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H2026" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
|
||||
// MacOS Big Sur
|
||||
"20A2411" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 0}}},
|
||||
"20B29" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
"20B50" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
"20C69" = {{20, 2, 0}, "macOS", {"Big Sur", {11, 1, 0}}},
|
||||
"20D64" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 0}}},
|
||||
"20D74" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
"20D75" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
"20D80" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 2}}},
|
||||
"20D91" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 3}}},
|
||||
"20E232" = {{20, 4, 0}, "macOS", {"Big Sur", {11, 3, 0}}},
|
||||
"20E241" = {{20, 4, 0}, "macOS", {"Big Sur", {11, 3, 1}}},
|
||||
"20F71" = {{20, 5, 0}, "macOS", {"Big Sur", {11, 4, 0}}},
|
||||
"20G71" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 0}}},
|
||||
"20G80" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 1}}},
|
||||
"20G95" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 2}}},
|
||||
"20G165" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 0}}},
|
||||
"20G224" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 1}}},
|
||||
"20G314" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 2}}},
|
||||
"20G415" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 3}}},
|
||||
"20G417" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 4}}},
|
||||
"20G527" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 5}}},
|
||||
"20G624" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 6}}},
|
||||
"20G630" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 7}}},
|
||||
"20G730" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 8}}},
|
||||
|
||||
// MacOS Monterey
|
||||
"21A344" = {{21, 0, 1}, "macOS", {"Monterey", {12, 0, 0}}},
|
||||
"21A559" = {{21, 1, 0}, "macOS", {"Monterey", {12, 0, 1}}},
|
||||
"21C52" = {{21, 2, 0}, "macOS", {"Monterey", {12, 1, 0}}},
|
||||
"21D49" = {{21, 3, 0}, "macOS", {"Monterey", {12, 2, 0}}},
|
||||
"21D62" = {{21, 3, 0}, "macOS", {"Monterey", {12, 2, 1}}},
|
||||
"21E230" = {{21, 4, 0}, "macOS", {"Monterey", {12, 3, 0}}},
|
||||
"21E258" = {{21, 4, 0}, "macOS", {"Monterey", {12, 3, 1}}},
|
||||
"21F79" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21F2081" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21F2092" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21G72" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
||||
"21G83" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
||||
}
|
||||
|
||||
@(private)
|
||||
Darwin_Match :: enum {
|
||||
Unknown,
|
||||
Exact,
|
||||
Nearest,
|
||||
}
|
||||
|
||||
@(private)
|
||||
map_darwin_kernel_version_to_macos_release :: proc(build: string, darwin: [3]int) -> (res: Darwin_To_Release, match: Darwin_Match) {
|
||||
// Find exact release match if possible.
|
||||
if v, v_ok := macos_release_map[build]; v_ok {
|
||||
return v, .Exact
|
||||
}
|
||||
|
||||
nearest: Darwin_To_Release
|
||||
for _, v in macos_release_map {
|
||||
// Try an exact match on XNU version first.
|
||||
if darwin == v.darwin {
|
||||
return v, .Exact
|
||||
}
|
||||
|
||||
// Major kernel version needs to match exactly,
|
||||
// otherwise the release is considered .Unknown
|
||||
if darwin.x == v.darwin.x {
|
||||
if nearest == {} {
|
||||
nearest = v
|
||||
}
|
||||
if darwin.y >= v.darwin.y && v.darwin != nearest.darwin {
|
||||
nearest = v
|
||||
if darwin.z >= v.darwin.z && v.darwin != nearest.darwin {
|
||||
nearest = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nearest == {} {
|
||||
return {darwin, "macOS", {"Unknown", {}}}, .Unknown
|
||||
} else {
|
||||
return nearest, .Nearest
|
||||
}
|
||||
}
|
||||
76
core/sys/info/platform_freebsd.odin
Normal file
76
core/sys/info/platform_freebsd.odin
Normal file
@@ -0,0 +1,76 @@
|
||||
// +build freebsd
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .FreeBSD
|
||||
|
||||
kernel_version_buf: [129]u8
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
// Retrieve kernel info using `sysctl`, e.g. FreeBSD 13.1-RELEASE-p2 GENERIC
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_VERSION}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
|
||||
pretty_name := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
pretty_name = strings.trim(pretty_name, "\n")
|
||||
strings.write_string(&b, pretty_name)
|
||||
|
||||
// l := strings.builder_len(b)
|
||||
|
||||
// Retrieve kernel revision using `sysctl`, e.g. 199506
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSREV}
|
||||
revision: int
|
||||
if !sys.sysctl(mib, &revision) {
|
||||
return
|
||||
}
|
||||
os_version.patch = revision
|
||||
|
||||
strings.write_string(&b, ", revision ")
|
||||
strings.write_int(&b, revision)
|
||||
|
||||
// Finalize pretty name.
|
||||
os_version.as_string = strings.to_string(b)
|
||||
|
||||
// Retrieve kernel release using `sysctl`, e.g. 13.1-RELEASE-p2
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse kernel version
|
||||
release := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
version_bits := strings.split_n(release, "-", 2, context.temp_allocator)
|
||||
if len(version_bits) > 1 {
|
||||
// Parse major, minor from KERN_OSRELEASE
|
||||
triplet := strings.split(version_bits[0], ".", context.temp_allocator)
|
||||
if len(triplet) == 2 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
minor, minor_ok := strconv.parse_int(triplet[1])
|
||||
|
||||
if major_ok && minor_ok {
|
||||
os_version.major = major
|
||||
os_version.minor = minor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
136
core/sys/info/platform_linux.odin
Normal file
136
core/sys/info/platform_linux.odin
Normal file
@@ -0,0 +1,136 @@
|
||||
// +build linux
|
||||
package sysinfo
|
||||
|
||||
import "core:c"
|
||||
import sys "core:sys/unix"
|
||||
import "core:intrinsics"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .Linux
|
||||
|
||||
// Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
|
||||
fd, err := os.open("/etc/os-release", os.O_RDONLY, 0)
|
||||
if err != 0 {
|
||||
return
|
||||
}
|
||||
defer os.close(fd)
|
||||
|
||||
os_release_buf: [2048]u8
|
||||
n, read_err := os.read(fd, os_release_buf[:])
|
||||
if read_err != 0 {
|
||||
return
|
||||
}
|
||||
release := string(os_release_buf[:n])
|
||||
|
||||
NEEDLE :: "PRETTY_NAME=\""
|
||||
pretty_start := strings.index(release, NEEDLE)
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
|
||||
if pretty_start > 0 {
|
||||
for r, i in release[pretty_start + len(NEEDLE):] {
|
||||
if r == '"' {
|
||||
strings.write_string(&b, release[pretty_start + len(NEEDLE):][:i])
|
||||
break
|
||||
} else if r == '\r' || r == '\n' {
|
||||
strings.write_string(&b, "Unknown Linux Distro")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NEW_UTS_LEN :: 64
|
||||
UTS_Name :: struct {
|
||||
sys_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
node_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
release: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
version: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
machine: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
domain_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
}
|
||||
uts: UTS_Name
|
||||
|
||||
// Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname
|
||||
if intrinsics.syscall(sys.SYS_uname, uintptr(&uts)) != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
strings.write_string(&b, ", ")
|
||||
strings.write_string(&b, string(cstring(&uts.sys_name[0])))
|
||||
strings.write_rune(&b, ' ')
|
||||
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, string(cstring(&uts.release[0])))
|
||||
|
||||
// Parse kernel version, as substrings of the version info in `version_string_buf`
|
||||
version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
|
||||
if len(version_bits) > 1 {
|
||||
os_version.version = version_bits[1]
|
||||
}
|
||||
|
||||
// Parse major, minor, patch from release info
|
||||
triplet := strings.split(version_bits[0], ".", context.temp_allocator)
|
||||
if len(triplet) == 3 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
minor, minor_ok := strconv.parse_int(triplet[1])
|
||||
patch, patch_ok := strconv.parse_int(triplet[2])
|
||||
|
||||
if major_ok && minor_ok && patch_ok {
|
||||
os_version.major = major
|
||||
os_version.minor = minor
|
||||
os_version.patch = patch
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the string
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
Sys_Info :: struct {
|
||||
uptime: c.long, // Seconds since boot
|
||||
loads: [3]c.long, // 1, 5, 15 minute load averages
|
||||
totalram: c.ulong, // Total usable main memory size
|
||||
freeram: c.ulong, // Available memory size
|
||||
sharedram: c.ulong, // Amount of shared memory
|
||||
bufferram: c.ulong, // Memory used by buffers
|
||||
totalswap: c.ulong, // Total swap space size
|
||||
freeswap: c.ulong, // Swap space still available
|
||||
procs: c.ushort, // Number of current processes
|
||||
totalhigh: c.ulong, // Total high memory size
|
||||
freehigh: c.ulong, // Available high memory size
|
||||
mem_unit: c.int, // Memory unit size in bytes
|
||||
_padding: [20 - (2 * size_of(c.long)) - size_of(c.int)]u8,
|
||||
}
|
||||
|
||||
get_sysinfo :: proc "c" () -> (res: Sys_Info, ok: bool) {
|
||||
si: Sys_Info
|
||||
err := intrinsics.syscall(sys.SYS_sysinfo, uintptr(rawptr(&si)))
|
||||
if err != 0 {
|
||||
// Unable to retrieve sysinfo
|
||||
return {}, false
|
||||
}
|
||||
return si, true
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysinfo`
|
||||
si, ok := get_sysinfo()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ram = RAM{
|
||||
total_ram = int(si.totalram) * int(si.mem_unit),
|
||||
free_ram = int(si.freeram) * int(si.mem_unit),
|
||||
total_swap = int(si.totalswap) * int(si.mem_unit),
|
||||
free_swap = int(si.freeswap) * int(si.mem_unit),
|
||||
}
|
||||
}
|
||||
69
core/sys/info/platform_openbsd.odin
Normal file
69
core/sys/info/platform_openbsd.odin
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build openbsd
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .OpenBSD
|
||||
|
||||
kernel_version_buf: [1024]u8
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
// Retrieve kernel info using `sysctl`, e.g. OpenBSD
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_OSTYPE}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
os_type := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
strings.write_string(&b, os_type)
|
||||
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
|
||||
strings.write_rune(&b, ' ')
|
||||
version := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
strings.write_string(&b, version)
|
||||
|
||||
// // Parse kernel version
|
||||
triplet := strings.split(version, ".", context.temp_allocator)
|
||||
if len(triplet) == 2 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
minor, minor_ok := strconv.parse_int(triplet[1])
|
||||
|
||||
if major_ok && minor_ok {
|
||||
os_version.major = major
|
||||
os_version.minor = minor
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve kernel revision using `sysctl`, e.g. 199506
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSREV}
|
||||
revision: int
|
||||
if !sys.sysctl(mib, &revision) {
|
||||
return
|
||||
}
|
||||
os_version.patch = revision
|
||||
strings.write_string(&b, ", build ")
|
||||
strings.write_int(&b, revision)
|
||||
|
||||
// Finalize pretty name.
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
375
core/sys/info/platform_windows.odin
Normal file
375
core/sys/info/platform_windows.odin
Normal file
@@ -0,0 +1,375 @@
|
||||
// +build windows
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/windows"
|
||||
import "core:intrinsics"
|
||||
import "core:strings"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
/*
|
||||
NOTE(Jeroen):
|
||||
`GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10.
|
||||
`RtlGetVersion` will return the true version.
|
||||
|
||||
Rather than include the WinDDK, we ask the kernel directly.
|
||||
`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion` is for the minor build version (Update Build Release)
|
||||
|
||||
*/
|
||||
os_version.platform = .Windows
|
||||
|
||||
osvi: sys.OSVERSIONINFOEXW
|
||||
osvi.dwOSVersionInfoSize = size_of(osvi)
|
||||
status := sys.RtlGetVersion(&osvi)
|
||||
|
||||
if status != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
product_type: sys.Windows_Product_Type
|
||||
sys.GetProductInfo(
|
||||
osvi.dwMajorVersion, osvi.dwMinorVersion,
|
||||
u32(osvi.wServicePackMajor), u32(osvi.wServicePackMinor),
|
||||
&product_type,
|
||||
)
|
||||
|
||||
os_version.major = int(osvi.dwMajorVersion)
|
||||
os_version.minor = int(osvi.dwMinorVersion)
|
||||
os_version.build[0] = int(osvi.dwBuildNumber)
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
strings.write_string(&b, "Windows ")
|
||||
|
||||
switch osvi.dwMajorVersion {
|
||||
case 10:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
if osvi.dwBuildNumber < 22000 {
|
||||
strings.write_string(&b, "10 ")
|
||||
} else {
|
||||
strings.write_string(&b, "11 ")
|
||||
}
|
||||
format_windows_product_type(&b, product_type)
|
||||
|
||||
case: // Server or Domain Controller
|
||||
switch osvi.dwBuildNumber {
|
||||
case 14393:
|
||||
strings.write_string(&b, "2016 Server")
|
||||
case 17763:
|
||||
strings.write_string(&b, "2019 Server")
|
||||
case 20348:
|
||||
strings.write_string(&b, "2022 Server")
|
||||
case:
|
||||
strings.write_string(&b, "Unknown Server")
|
||||
}
|
||||
}
|
||||
|
||||
case 6:
|
||||
switch osvi.dwMinorVersion {
|
||||
case 0:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION
|
||||
strings.write_string(&b, "Windows Vista ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2008")
|
||||
}
|
||||
|
||||
case 1:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
strings.write_string(&b, "Windows 7 ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2008 R2")
|
||||
}
|
||||
|
||||
case 2:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
strings.write_string(&b, "Windows 8 ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2012")
|
||||
}
|
||||
|
||||
case 3:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
strings.write_string(&b, "Windows 8.1 ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2012 R2")
|
||||
}
|
||||
}
|
||||
|
||||
case 5:
|
||||
switch osvi.dwMinorVersion {
|
||||
case 0:
|
||||
strings.write_string(&b, "Windows 2000")
|
||||
case 1:
|
||||
strings.write_string(&b, "Windows XP")
|
||||
case 2:
|
||||
strings.write_string(&b, "Windows Server 2003")
|
||||
}
|
||||
}
|
||||
|
||||
// Grab DisplayVersion
|
||||
os_version.version = format_display_version(&b)
|
||||
|
||||
// Grab build number and UBR
|
||||
os_version.build[1] = format_build_number(&b, int(osvi.dwBuildNumber))
|
||||
|
||||
// Finish the string
|
||||
os_version.as_string = strings.to_string(b)
|
||||
|
||||
format_windows_product_type :: proc (b: ^strings.Builder, prod_type: sys.Windows_Product_Type) {
|
||||
#partial switch prod_type {
|
||||
case .ULTIMATE:
|
||||
strings.write_string(b, "Ultimate")
|
||||
|
||||
case .HOME_BASIC:
|
||||
strings.write_string(b, "Home Basic")
|
||||
|
||||
case .HOME_PREMIUM:
|
||||
strings.write_string(b, "Home Premium")
|
||||
|
||||
case .ENTERPRISE:
|
||||
strings.write_string(b, "Enterprise")
|
||||
|
||||
case .CORE:
|
||||
strings.write_string(b, "Home Basic")
|
||||
|
||||
case .HOME_BASIC_N:
|
||||
strings.write_string(b, "Home Basic N")
|
||||
|
||||
case .EDUCATION:
|
||||
strings.write_string(b, "Education")
|
||||
|
||||
case .EDUCATION_N:
|
||||
strings.write_string(b, "Education N")
|
||||
|
||||
case .BUSINESS:
|
||||
strings.write_string(b, "Business")
|
||||
|
||||
case .STANDARD_SERVER:
|
||||
strings.write_string(b, "Standard Server")
|
||||
|
||||
case .DATACENTER_SERVER:
|
||||
strings.write_string(b, "Datacenter")
|
||||
|
||||
case .SMALLBUSINESS_SERVER:
|
||||
strings.write_string(b, "Windows Small Business Server")
|
||||
|
||||
case .ENTERPRISE_SERVER:
|
||||
strings.write_string(b, "Enterprise Server")
|
||||
|
||||
case .STARTER:
|
||||
strings.write_string(b, "Starter")
|
||||
|
||||
case .DATACENTER_SERVER_CORE:
|
||||
strings.write_string(b, "Datacenter Server Core")
|
||||
|
||||
case .STANDARD_SERVER_CORE:
|
||||
strings.write_string(b, "Server Standard Core")
|
||||
|
||||
case .ENTERPRISE_SERVER_CORE:
|
||||
strings.write_string(b, "Enterprise Server Core")
|
||||
|
||||
case .BUSINESS_N:
|
||||
strings.write_string(b, "Business N")
|
||||
|
||||
case .HOME_SERVER:
|
||||
strings.write_string(b, "Home Server")
|
||||
|
||||
case .SERVER_FOR_SMALLBUSINESS:
|
||||
strings.write_string(b, "Windows Server 2008 for Windows Essential Server Solutions")
|
||||
|
||||
case .SMALLBUSINESS_SERVER_PREMIUM:
|
||||
strings.write_string(b, "Small Business Server Premium")
|
||||
|
||||
case .HOME_PREMIUM_N:
|
||||
strings.write_string(b, "Home Premium N")
|
||||
|
||||
case .ENTERPRISE_N:
|
||||
strings.write_string(b, "Enterprise N")
|
||||
|
||||
case .ULTIMATE_N:
|
||||
strings.write_string(b, "Ultimate N")
|
||||
|
||||
case .HYPERV:
|
||||
strings.write_string(b, "HyperV")
|
||||
|
||||
case .STARTER_N:
|
||||
strings.write_string(b, "Starter N")
|
||||
|
||||
case .PROFESSIONAL:
|
||||
strings.write_string(b, "Professional")
|
||||
|
||||
case .PROFESSIONAL_N:
|
||||
strings.write_string(b, "Professional N")
|
||||
|
||||
case:
|
||||
strings.write_string(b, "Unknown Edition")
|
||||
}
|
||||
}
|
||||
|
||||
// Grab Windows DisplayVersion (like 20H02)
|
||||
format_display_version :: proc (b: ^strings.Builder) -> (version: string) {
|
||||
dv, ok := read_reg(
|
||||
sys.HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
"DisplayVersion",
|
||||
string,
|
||||
)
|
||||
defer delete(dv) // It'll be interned into `version_string_buf`
|
||||
|
||||
if ok {
|
||||
strings.write_string(b, " (version: ")
|
||||
l := strings.builder_len(b^)
|
||||
strings.write_string(b, dv)
|
||||
version = strings.to_string(b^)[l:][:len(dv)]
|
||||
strings.write_rune(b, ')')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Grab build number and UBR
|
||||
format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) {
|
||||
res, ok := read_reg(
|
||||
sys.HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
"UBR",
|
||||
i32,
|
||||
)
|
||||
|
||||
if ok {
|
||||
ubr = int(res)
|
||||
strings.write_string(b, ", build: ")
|
||||
strings.write_int(b, major_build)
|
||||
strings.write_rune(b, '.')
|
||||
strings.write_int(b, ubr)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
state: sys.MEMORYSTATUSEX
|
||||
|
||||
state.dwLength = size_of(state)
|
||||
ok := sys.GlobalMemoryStatusEx(&state)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
ram = RAM{
|
||||
total_ram = int(state.ullTotalPhys),
|
||||
free_ram = int(state.ullAvailPhys),
|
||||
total_swap = int(state.ullTotalPageFil),
|
||||
free_swap = int(state.ullAvailPageFil),
|
||||
}
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_gpu_info :: proc() {
|
||||
|
||||
GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
|
||||
|
||||
gpu_list: [dynamic]GPU
|
||||
gpu_index: int
|
||||
|
||||
for {
|
||||
key := fmt.tprintf("%v\\%04d", GPU_INFO_BASE, gpu_index)
|
||||
|
||||
if vendor, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "ProviderName", string); ok {
|
||||
append(&gpu_list, GPU{vendor_name = vendor})
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if desc, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc", string); ok {
|
||||
gpu_list[gpu_index].model_name = desc
|
||||
}
|
||||
|
||||
if vram, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize", i64); ok {
|
||||
gpu_list[gpu_index].total_ram = int(vram)
|
||||
}
|
||||
gpu_index += 1
|
||||
}
|
||||
gpus = gpu_list[:]
|
||||
}
|
||||
|
||||
@(private)
|
||||
read_reg :: proc(hkey: sys.HKEY, subkey, val: string, $T: typeid) -> (res: T, ok: bool) {
|
||||
BUF_SIZE :: 1024
|
||||
|
||||
if len(subkey) == 0 || len(val) == 0 {
|
||||
return {}, false
|
||||
}
|
||||
|
||||
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
|
||||
utf16.encode_string(key_name_wide, subkey)
|
||||
utf16.encode_string(val_name_wide, val)
|
||||
|
||||
when T == string {
|
||||
result_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
result_size := sys.DWORD(BUF_SIZE * size_of(u16))
|
||||
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
sys.RRF_RT_REG_SZ,
|
||||
nil,
|
||||
raw_data(result_wide[:]),
|
||||
&result_size,
|
||||
)
|
||||
if status != 0 {
|
||||
// Couldn't retrieve string
|
||||
return
|
||||
}
|
||||
|
||||
// Result string will be allocated for the caller.
|
||||
result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator)
|
||||
utf16.decode_to_utf8(result_utf8, result_wide[:result_size])
|
||||
return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true
|
||||
|
||||
} else when T == i32 {
|
||||
result_size := sys.DWORD(size_of(i32))
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
sys.RRF_RT_REG_DWORD,
|
||||
nil,
|
||||
&res,
|
||||
&result_size,
|
||||
)
|
||||
return res, status == 0
|
||||
|
||||
} else when T == i64 {
|
||||
result_size := sys.DWORD(size_of(i64))
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
sys.RRF_RT_REG_QWORD,
|
||||
nil,
|
||||
&res,
|
||||
&result_size,
|
||||
)
|
||||
return res, status == 0
|
||||
} else {
|
||||
#assert(false, "Unhandled type for read_reg")
|
||||
}
|
||||
return
|
||||
}
|
||||
45
core/sys/info/sysinfo.odin
Normal file
45
core/sys/info/sysinfo.odin
Normal file
@@ -0,0 +1,45 @@
|
||||
package sysinfo
|
||||
|
||||
when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64) {
|
||||
#assert(false, "This package is unsupported on this architecture.")
|
||||
}
|
||||
|
||||
os_version: OS_Version
|
||||
ram: RAM
|
||||
gpus: []GPU
|
||||
|
||||
OS_Version_Platform :: enum {
|
||||
Unknown,
|
||||
Windows,
|
||||
Linux,
|
||||
MacOS,
|
||||
iOS,
|
||||
FreeBSD,
|
||||
OpenBSD,
|
||||
NetBSD,
|
||||
}
|
||||
|
||||
OS_Version :: struct {
|
||||
platform: OS_Version_Platform,
|
||||
|
||||
major: int,
|
||||
minor: int,
|
||||
patch: int,
|
||||
build: [2]int,
|
||||
version: string,
|
||||
|
||||
as_string: string,
|
||||
}
|
||||
|
||||
RAM :: struct {
|
||||
total_ram: int,
|
||||
free_ram: int,
|
||||
total_swap: int,
|
||||
free_swap: int,
|
||||
}
|
||||
|
||||
GPU :: struct {
|
||||
vendor_name: string,
|
||||
model_name: string,
|
||||
total_ram: int,
|
||||
}
|
||||
7
core/sys/unix/syscalls_freebsd.odin
Normal file
7
core/sys/unix/syscalls_freebsd.odin
Normal file
@@ -0,0 +1,7 @@
|
||||
package unix
|
||||
|
||||
// FreeBSD 13 syscall numbers
|
||||
// See: https://alfonsosiciliano.gitlab.io/posts/2021-01-02-freebsd-system-calls-table.html
|
||||
|
||||
SYS_uname : uintptr : 164
|
||||
SYS_sysctl : uintptr : 202
|
||||
@@ -1568,7 +1568,7 @@ sys_gettid :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: int, flags: uint) -> int {
|
||||
return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags))
|
||||
return cast(int)intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags))
|
||||
}
|
||||
|
||||
sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int {
|
||||
@@ -1622,7 +1622,7 @@ sys_lseek :: proc "contextless" (fd: int, offset: i64, whence: int) -> i64 {
|
||||
low := uintptr(offset & 0xFFFFFFFF)
|
||||
high := uintptr(offset >> 32)
|
||||
result: i64
|
||||
res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
|
||||
res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence)))
|
||||
return res if res < 0 else result
|
||||
}
|
||||
}
|
||||
@@ -1748,7 +1748,7 @@ sys_unlink :: proc "contextless" (path: cstring) -> int {
|
||||
}
|
||||
|
||||
sys_unlinkat :: proc "contextless" (dfd: int, path: cstring, flag: int = 0) -> int {
|
||||
return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag))
|
||||
return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flag)))
|
||||
}
|
||||
|
||||
sys_rmdir :: proc "contextless" (path: cstring) -> int {
|
||||
|
||||
6
core/sys/unix/syscalls_openbsd.odin
Normal file
6
core/sys/unix/syscalls_openbsd.odin
Normal file
@@ -0,0 +1,6 @@
|
||||
package unix
|
||||
|
||||
// OpenBSD 7.1 syscall numbers
|
||||
// See: /usr/include/sys/syscall.h
|
||||
|
||||
SYS_sysctl : uintptr : 202
|
||||
45
core/sys/unix/sysctl_darwin.odin
Normal file
45
core/sys/unix/sysctl_darwin.odin
Normal file
@@ -0,0 +1,45 @@
|
||||
//+build darwin
|
||||
package unix
|
||||
|
||||
import "core:sys/darwin"
|
||||
import "core:intrinsics"
|
||||
|
||||
_ :: darwin
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := i64(size_of(T))
|
||||
|
||||
res := intrinsics.syscall(
|
||||
darwin.unix_offset_syscall(.sysctl),
|
||||
uintptr(raw_data(mib)), uintptr(len(mib)),
|
||||
uintptr(val), uintptr(&result_size),
|
||||
uintptr(0), uintptr(0),
|
||||
)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// See sysctl.h for darwin for details
|
||||
CTL_KERN :: 1
|
||||
KERN_OSTYPE :: 1 // Darwin
|
||||
KERN_OSRELEASE :: 2 // 21.5.0 for 12.4 Monterey
|
||||
KERN_OSREV :: 3 // i32: system revision
|
||||
KERN_VERSION :: 4 // Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:22 PDT 2022; root:darwin-8020.121.3~4/RELEASE_X86_64
|
||||
KERN_OSRELDATE :: 26 // i32: OS release date
|
||||
KERN_OSVERSION :: 65 // Build number, e.g. 21F79
|
||||
CTL_VM :: 2
|
||||
CTL_VFS :: 3
|
||||
CTL_NET :: 4
|
||||
CTL_DEBUG :: 5
|
||||
CTL_HW :: 6
|
||||
HW_MACHINE :: 1 // x86_64
|
||||
HW_MODEL :: 2 // MacbookPro14,1
|
||||
HW_NCPU :: 3 /* int: number of cpus */
|
||||
HW_BYTEORDER :: 4 /* int: machine byte order */
|
||||
HW_MACHINE_ARCH :: 12 /* string: machine architecture */
|
||||
HW_VECTORUNIT :: 13 /* int: has HW vector unit? */
|
||||
HW_MEMSIZE :: 24 // u64
|
||||
HW_AVAILCPU :: 25 /* int: number of available CPUs */
|
||||
|
||||
CTL_MACHDEP :: 7
|
||||
CTL_USER :: 8
|
||||
44
core/sys/unix/sysctl_freebsd.odin
Normal file
44
core/sys/unix/sysctl_freebsd.odin
Normal file
@@ -0,0 +1,44 @@
|
||||
//+build freebsd
|
||||
package unix
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := i64(size_of(T))
|
||||
|
||||
res := intrinsics.syscall(SYS_sysctl,
|
||||
uintptr(raw_data(mib)), uintptr(len(mib)),
|
||||
uintptr(val), uintptr(&result_size),
|
||||
uintptr(0), uintptr(0),
|
||||
)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// See /usr/include/sys/sysctl.h for details
|
||||
CTL_SYSCTL :: 0
|
||||
CTL_KERN :: 1
|
||||
KERN_OSTYPE :: 1
|
||||
KERN_OSRELEASE :: 2
|
||||
KERN_OSREV :: 3
|
||||
KERN_VERSION :: 4
|
||||
CTL_VM :: 2
|
||||
CTL_VFS :: 3
|
||||
CTL_NET :: 4
|
||||
CTL_DEBUG :: 5
|
||||
CTL_HW :: 6
|
||||
HW_MACHINE :: 1
|
||||
HW_MODEL :: 2
|
||||
HW_NCPU :: 3
|
||||
HW_BYTEORDER :: 4
|
||||
HW_PHYSMEM :: 5
|
||||
HW_USERMEM :: 6
|
||||
HW_PAGESIZE :: 7
|
||||
HW_DISKNAMES :: 8
|
||||
HW_DISKSTATS :: 9
|
||||
HW_FLOATINGPT :: 10
|
||||
HW_MACHINE_ARCH :: 11
|
||||
HW_REALMEM :: 12
|
||||
CTL_MACHDEP :: 7
|
||||
CTL_USER :: 8
|
||||
CTL_P1003_1B :: 9
|
||||
49
core/sys/unix/sysctl_openbsd.odin
Normal file
49
core/sys/unix/sysctl_openbsd.odin
Normal file
@@ -0,0 +1,49 @@
|
||||
//+build openbsd
|
||||
package unix
|
||||
|
||||
import "core:c"
|
||||
foreign import libc "system:c"
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
|
||||
}
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := c.size_t(size_of(T))
|
||||
res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// See /usr/include/sys/sysctl.h for details
|
||||
CTL_SYSCTL :: 0
|
||||
CTL_KERN :: 1
|
||||
KERN_OSTYPE :: 1
|
||||
KERN_OSRELEASE :: 2
|
||||
KERN_OSREV :: 3
|
||||
KERN_VERSION :: 4
|
||||
CTL_VM :: 2
|
||||
CTL_FS :: 3
|
||||
CTL_NET :: 4
|
||||
CTL_DEBUG :: 5
|
||||
CTL_HW :: 6
|
||||
HW_MACHINE :: 1
|
||||
HW_MODEL :: 2
|
||||
HW_NCPU :: 3
|
||||
HW_BYTEORDER :: 4
|
||||
HW_PHYSMEM :: 5
|
||||
HW_USERMEM :: 6
|
||||
HW_PAGESIZE :: 7
|
||||
HW_DISKNAMES :: 8
|
||||
HW_DISKSTATS :: 9
|
||||
HW_DISKCOUNT :: 10
|
||||
HW_SENSORS :: 11
|
||||
HW_CPUSPEED :: 12
|
||||
HW_SETPERF :: 13
|
||||
HW_VENDOR :: 14
|
||||
HW_PRODUCT :: 15
|
||||
HW_VERSION :: 16
|
||||
HW_SERIALNO :: 17
|
||||
HW_UUID :: 18
|
||||
HW_PHYSMEM64 :: 19
|
||||
@@ -13,10 +13,10 @@ Callgrind_Client_Request :: enum uintptr {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
callgrind_client_request_expr :: proc "c" (default: uintptr, request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
callgrind_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
callgrind_client_request_stmt :: proc "c" (request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
callgrind_client_request_stmt :: #force_inline proc "c" (request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
|
||||
178
core/sys/valgrind/helgrind.odin
Normal file
178
core/sys/valgrind/helgrind.odin
Normal file
@@ -0,0 +1,178 @@
|
||||
//+build amd64
|
||||
package sys_valgrind
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
Helgrind_Client_Request :: enum uintptr {
|
||||
Clean_Memory = 'H'<<24 | 'G'<<16,
|
||||
Set_My_pthread_t = ('H'<<25 | 'G'<<16)+256,
|
||||
Pthread_Join_Post,
|
||||
Pthread_Mutex_Init_Post,
|
||||
Pthread_Mutex_Destroy_Pre,
|
||||
Pthread_Mutex_Unlock_Pre,
|
||||
Pthread_Mutex_Unlock_Post,
|
||||
Pthread_Mutex_Lock_Pre,
|
||||
Pthread_Mutex_Lock_Post,
|
||||
Pthread_Cond_Signal_Pre,
|
||||
Pthread_Cond_Broadcast_Pre,
|
||||
Pthread_Cond_Wait_Pre,
|
||||
Pthread_Cond_Wait_Post,
|
||||
Pthread_Cond_Destroy_Pre,
|
||||
Pthread_Rwlock_Init_Post,
|
||||
Pthread_Rwlock_Destroy_Pre,
|
||||
Pthread_Rwlock_Lock_Pre,
|
||||
Pthread_Rwlock_Lock_Post,
|
||||
Pthread_Rwlock_Unlock_Pre,
|
||||
Pthread_Rwlock_Unlock_Post,
|
||||
Posix_Sem_Init_Post,
|
||||
Posix_Sem_Destroy_Pre,
|
||||
Posix_Sem_Post_Pre,
|
||||
Posix_Sem_Wait_Post,
|
||||
Pthread_Barrier_Init_Pre,
|
||||
Pthread_Barrier_Wait_Pre,
|
||||
Pthread_Barrier_Destroy_Pre,
|
||||
Pthread_Spin_Init_Or_Unlock_Pre,
|
||||
Pthread_Spin_Init_Or_Unlock_Post,
|
||||
Pthread_Spin_Lock_Pre,
|
||||
Pthread_Spin_Lock_Post,
|
||||
Pthread_Spin_Destroy_Pre,
|
||||
Clientreq_Unimp,
|
||||
Userso_Send_Pre,
|
||||
Userso_Recv_Post,
|
||||
Userso_Forget_All,
|
||||
Reserved2,
|
||||
Reserved3,
|
||||
Reserved4,
|
||||
Arange_Make_Untracked,
|
||||
Arange_Make_Tracked,
|
||||
Pthread_Barrier_Resize_Pre,
|
||||
Clean_Memory_Heapblock,
|
||||
Pthread_Cond_Init_Post,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
helgrind_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Helgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
helgrind_client_request_stmt :: #force_inline proc "c" (request: Helgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
helgrind_mutex_init_post :: proc "c" (mutex: rawptr, mb_rec: uint) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Init_Post, uintptr(mutex), uintptr(mb_rec), 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_destroy_pre :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Destroy_Pre, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_lock_pre :: proc "c" (mutex: rawptr, is_try_lock: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Lock_Pre, uintptr(mutex), uintptr(is_try_lock), 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_lock_post :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Lock_Post, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_unlock_pre :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Unlock_Pre, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_unlock_post :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Unlock_Post, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
helgrind_rwlock_init_post :: proc "c" (lock: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Init_Post, uintptr(lock), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_rwlock_destroy_pre :: proc "c" (lock: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Destroy_Pre, uintptr(lock), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_rwlock_lock_pre :: proc "c" (lock: rawptr, is_w: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Lock_Pre, uintptr(lock), uintptr(is_w), 0, 0, 0)
|
||||
}
|
||||
helgrind_rwlock_unlock_post :: proc "c" (lock: rawptr, is_w: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Unlock_Pre, uintptr(lock), uintptr(is_w), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_sem_init_post :: proc "c" (sem: rawptr, value: uint) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Init_Post, uintptr(sem), uintptr(value), 0, 0, 0)
|
||||
}
|
||||
helgrind_sem_wait_post :: proc "c" (sem: rawptr) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Wait_Post, uintptr(sem), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_sem_post_pre :: proc "c" (sem: rawptr) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Post_Pre, uintptr(sem), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_sem_destroy_pre :: proc "c" (sem: rawptr) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Destroy_Pre, uintptr(sem), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_barrier_init_pre :: proc "c" (bar: rawptr, count: uint, resizable: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Init_Pre, uintptr(bar), uintptr(count), uintptr(resizable), 0, 0)
|
||||
}
|
||||
helgrind_barrier_wait_pre :: proc "c" (bar: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Wait_Pre, uintptr(bar), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_barrier_resize_pre :: proc "c" (bar: rawptr, new_count: uint) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Resize_Pre, uintptr(bar), uintptr(new_count), 0, 0, 0)
|
||||
}
|
||||
helgrind_barrier_destroy_pre :: proc "c" (bar: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Destroy_Pre, uintptr(bar), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
helgrind_clean_memory :: proc "c" (qzz_start: rawptr, qzz_len: uint) {
|
||||
helgrind_client_request_stmt(.Clean_Memory, uintptr(qzz_start), uintptr(qzz_len), 0, 0, 0)
|
||||
}
|
||||
helgrind_clean_memory_slice :: proc "c" (qzz: []byte) {
|
||||
helgrind_client_request_stmt(.Clean_Memory, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
||||
}
|
||||
helgrind_clean_memory_heap_block :: proc "c" (qzz_blockstart: rawptr) -> int {
|
||||
return int(helgrind_client_request_expr(~uintptr(1), .Clean_Memory_Heapblock, uintptr(qzz_blockstart), 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
|
||||
helgrind_disable_checking :: proc "c" (qzz_start: rawptr, qzz_len: uint) {
|
||||
helgrind_client_request_stmt(.Arange_Make_Untracked, uintptr(qzz_start), uintptr(qzz_len), 0, 0, 0)
|
||||
}
|
||||
helgrind_enable_checking :: proc "c" (qzz_start: rawptr, qzz_len: uint) {
|
||||
helgrind_client_request_stmt(.Arange_Make_Tracked, uintptr(qzz_start), uintptr(qzz_len), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_cond_init_post :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Init_Post, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_destroy_pre :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Destroy_Pre, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_signal_pre :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Signal_Pre, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_broadcast_pre :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Broadcast_Pre, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_wait_pre :: proc "c" (cond: rawptr, lock: rawptr) -> bool {
|
||||
return 0 != helgrind_client_request_expr(0, .Pthread_Cond_Wait_Pre, uintptr(cond), uintptr(lock), 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_wait_post :: proc "c" (cond: rawptr, lock: rawptr) -> bool {
|
||||
return 0 != helgrind_client_request_expr(0, .Pthread_Cond_Wait_Post, uintptr(cond), uintptr(lock), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_client_request_unimp :: #force_inline proc "c" (msg: cstring) {
|
||||
helgrind_client_request_stmt(.Clientreq_Unimp, uintptr(rawptr(msg)), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_annotate_condvar_lock_wait :: #force_inline proc "c" (cv: rawptr, lock: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_LOCK_WAIT")
|
||||
}
|
||||
helgrind_annotate_condvar_wait :: proc "c" (cv: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_WAIT")
|
||||
}
|
||||
helgrind_annotate_condvar_signal :: proc "c" (cv: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_SIGNAL")
|
||||
}
|
||||
helgrind_annotate_condvar_signal_all :: proc "c" (cv: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_SIGNAL_ALL")
|
||||
}
|
||||
@@ -22,10 +22,10 @@ Mem_Check_Client_Request :: enum uintptr {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
mem_check_client_request_expr :: proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
mem_check_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
mem_check_client_request_stmt :: proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
mem_check_client_request_stmt :: #force_inline proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ Client_Request :: enum uintptr {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
client_request_expr :: proc "c" (default: uintptr, request: Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
client_request_expr :: #force_inline proc "c" (default: uintptr, request: Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
client_request_stmt :: proc "c" (request: Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
client_request_stmt :: #force_inline proc "c" (request: Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ client_request_stmt :: proc "c" (request: Client_Request, a0, a1, a2, a3, a4: ui
|
||||
// 0 - running natively
|
||||
// 1 - running under Valgrind
|
||||
// 2 - running under Valgrind which is running under another Valgrind
|
||||
running_on_valgrind :: proc "c" () -> uintptr {
|
||||
return client_request_expr(0, .Running_On_Valgrind, 0, 0, 0, 0, 0)
|
||||
running_on_valgrind :: proc "c" () -> uint {
|
||||
return uint(client_request_expr(0, .Running_On_Valgrind, 0, 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
// Discard translation of code in the slice qzz. Useful if you are debugging a JIT-er or some such,
|
||||
|
||||
@@ -24,6 +24,8 @@ foreign kernel32 {
|
||||
lpMode: LPDWORD) -> BOOL ---
|
||||
SetConsoleMode :: proc(hConsoleHandle: HANDLE,
|
||||
dwMode: DWORD) -> BOOL ---
|
||||
SetConsoleCursorPosition :: proc(hConsoleHandle: HANDLE,
|
||||
dwCursorPosition: COORD) -> BOOL ---
|
||||
|
||||
GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL ---
|
||||
SetHandleInformation :: proc(hObject: HANDLE,
|
||||
@@ -94,6 +96,15 @@ foreign kernel32 {
|
||||
dwCreationFlags: DWORD,
|
||||
lpThreadId: LPDWORD,
|
||||
) -> HANDLE ---
|
||||
CreateRemoteThread :: proc(
|
||||
hProcess: HANDLE,
|
||||
lpThreadAttributes: LPSECURITY_ATTRIBUTES,
|
||||
dwStackSize: SIZE_T,
|
||||
lpStartAddress: proc "stdcall" (rawptr) -> DWORD,
|
||||
lpParameter: LPVOID,
|
||||
dwCreationFlags: DWORD,
|
||||
lpThreadId: LPDWORD,
|
||||
) -> HANDLE ---
|
||||
SwitchToThread :: proc() -> BOOL ---
|
||||
ResumeThread :: proc(thread: HANDLE) -> DWORD ---
|
||||
GetThreadPriority :: proc(thread: HANDLE) -> c_int ---
|
||||
@@ -326,6 +337,15 @@ foreign kernel32 {
|
||||
SetEndOfFile :: proc(hFile: HANDLE) -> BOOL ---
|
||||
|
||||
CreatePipe :: proc(hReadPipe, hWritePipe: ^HANDLE, lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD) -> BOOL ---
|
||||
|
||||
ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED,) -> BOOL ---
|
||||
DisconnectNamedPipe :: proc(hNamedPipe: HANDLE,) -> BOOL ---
|
||||
WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD,) -> BOOL ---
|
||||
|
||||
SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL ---
|
||||
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
|
||||
FreeConsole :: proc() -> BOOL ---
|
||||
GetConsoleWindow :: proc() -> HWND ---
|
||||
}
|
||||
|
||||
|
||||
@@ -637,6 +657,13 @@ foreign kernel32 {
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign kernel32 {
|
||||
GlobalMemoryStatusEx :: proc(
|
||||
lpBuffer: ^MEMORYSTATUSEX,
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
PBAD_MEMORY_CALLBACK_ROUTINE :: #type proc "stdcall" ()
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
@@ -782,15 +809,14 @@ foreign kernel32 {
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign kernel32 {
|
||||
@(link_name="SetConsoleCtrlHandler") set_console_ctrl_handler :: proc(handler: Handler_Routine, add: BOOL) -> BOOL ---
|
||||
GetProductInfo :: proc(
|
||||
OSMajorVersion: DWORD,
|
||||
OSMinorVersion: DWORD,
|
||||
SpMajorVersion: DWORD,
|
||||
SpMinorVersion: DWORD,
|
||||
product_type: ^Windows_Product_Type,
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
Handler_Routine :: proc(dwCtrlType: Control_Event) -> BOOL
|
||||
|
||||
Control_Event :: enum DWORD {
|
||||
control_c = 0,
|
||||
_break = 1,
|
||||
close = 2,
|
||||
logoff = 5,
|
||||
shutdown = 6,
|
||||
}
|
||||
HandlerRoutine :: proc "stdcall" (dwCtrlType: DWORD) -> BOOL
|
||||
PHANDLER_ROUTINE :: HandlerRoutine
|
||||
|
||||
@@ -17,6 +17,7 @@ size_t :: c.size_t
|
||||
wchar_t :: c.wchar_t
|
||||
|
||||
DWORD :: c_ulong
|
||||
DWORDLONG :: c.ulonglong
|
||||
QWORD :: c.ulonglong
|
||||
HANDLE :: distinct LPVOID
|
||||
HINSTANCE :: HANDLE
|
||||
@@ -978,6 +979,35 @@ WS_TILEDWINDOW : UINT : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKF
|
||||
WS_VISIBLE : UINT : 0x1000_0000
|
||||
WS_VSCROLL : UINT : 0x0020_0000
|
||||
|
||||
WS_EX_ACCEPTFILES : UINT : 0x0000_0010
|
||||
WS_EX_APPWINDOW : UINT : 0x0004_0000
|
||||
WS_EX_CLIENTEDGE : UINT : 0x0000_0200
|
||||
WS_EX_COMPOSITED : UINT : 0x0200_0000
|
||||
WS_EX_CONTEXTHELP : UINT : 0x0000_0400
|
||||
WS_EX_CONTROLPARENT : UINT : 0x0001_0000
|
||||
WS_EX_DLGMODALFRAME : UINT : 0x0000_0001
|
||||
WS_EX_DRAGDETECT : UINT : 0x0000_0002 // undocumented
|
||||
WS_EX_LAYERED : UINT : 0x0008_0000
|
||||
WS_EX_LAYOUTRTL : UINT : 0x0040_0000
|
||||
WS_EX_LEFT : UINT : 0x0000_0000
|
||||
WS_EX_LEFTSCROLLBAR : UINT : 0x0000_4000
|
||||
WS_EX_LTRREADING : UINT : 0x0000_0000
|
||||
WS_EX_MDICHILD : UINT : 0x0000_0040
|
||||
WS_EX_NOACTIVATE : UINT : 0x0800_0000
|
||||
WS_EX_NOINHERITLAYOUT : UINT : 0x0010_0000
|
||||
WS_EX_NOPARENTNOTIFY : UINT : 0x0000_0004
|
||||
WS_EX_NOREDIRECTIONBITMAP : UINT : 0x0020_0000
|
||||
WS_EX_OVERLAPPEDWINDOW : UINT : WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE
|
||||
WS_EX_PALETTEWINDOW : UINT : WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST
|
||||
WS_EX_RIGHT : UINT : 0x0000_1000
|
||||
WS_EX_RIGHTSCROLLBAR : UINT : 0x0000_0000
|
||||
WS_EX_RTLREADING : UINT : 0x0000_2000
|
||||
WS_EX_STATICEDGE : UINT : 0x0002_0000
|
||||
WS_EX_TOOLWINDOW : UINT : 0x0000_0080
|
||||
WS_EX_TOPMOST : UINT : 0x0000_0008
|
||||
WS_EX_TRANSPARENT : UINT : 0x0000_0020
|
||||
WS_EX_WINDOWEDGE : UINT : 0x0000_0100
|
||||
|
||||
PBS_SMOOTH :: 0x01
|
||||
PBS_VERTICAL :: 0x04
|
||||
|
||||
@@ -1628,6 +1658,8 @@ CONDITION_VARIABLE_INIT :: CONDITION_VARIABLE{}
|
||||
SRWLOCK_INIT :: SRWLOCK{}
|
||||
|
||||
DETACHED_PROCESS: DWORD : 0x00000008
|
||||
CREATE_NEW_CONSOLE: DWORD : 0x00000010
|
||||
CREATE_NO_WINDOW: DWORD : 0x08000000
|
||||
CREATE_NEW_PROCESS_GROUP: DWORD : 0x00000200
|
||||
CREATE_UNICODE_ENVIRONMENT: DWORD : 0x00000400
|
||||
STARTF_USESTDHANDLES: DWORD : 0x00000100
|
||||
@@ -1689,6 +1721,7 @@ PIPE_WAIT: DWORD : 0x00000000
|
||||
PIPE_TYPE_BYTE: DWORD : 0x00000000
|
||||
PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008
|
||||
PIPE_READMODE_BYTE: DWORD : 0x00000000
|
||||
PIPE_ACCEPT_REMOTE_CLIENTS: DWORD : 0x00000000
|
||||
|
||||
FD_SETSIZE :: 64
|
||||
|
||||
@@ -3265,3 +3298,141 @@ IFileSaveDialogVtbl :: struct {
|
||||
GetProperties: proc "stdcall" (this: ^IFileSaveDialog, ppStore: ^^IPropertyStore) -> HRESULT,
|
||||
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
|
||||
}
|
||||
|
||||
MEMORYSTATUSEX :: struct {
|
||||
dwLength: DWORD,
|
||||
dwMemoryLoad: DWORD,
|
||||
ullTotalPhys: DWORDLONG,
|
||||
ullAvailPhys: DWORDLONG,
|
||||
ullTotalPageFil: DWORDLONG,
|
||||
ullAvailPageFil: DWORDLONG,
|
||||
ullTotalVirtual: DWORDLONG,
|
||||
ullAvailVirtual: DWORDLONG,
|
||||
ullAvailExtendedVirtual: DWORDLONG,
|
||||
}
|
||||
|
||||
Windows_Product_Type :: enum DWORD {
|
||||
BUSINESS = 0x00000006, // Business
|
||||
BUSINESS_N = 0x00000010, // Business N
|
||||
CLUSTER_SERVER = 0x00000012, // HPC Edition
|
||||
CLUSTER_SERVER_V = 0x00000040, // Server Hyper Core V
|
||||
CORE = 0x00000065, // Windows 10 Home
|
||||
CORE_COUNTRYSPECIFIC = 0x00000063, // Windows 10 Home China
|
||||
CORE_N = 0x00000062, // Windows 10 Home N
|
||||
CORE_SINGLELANGUAGE = 0x00000064, // Windows 10 Home Single Language
|
||||
DATACENTER_EVALUATION_SERVER = 0x00000050, // Server Datacenter (evaluation installation)
|
||||
DATACENTER_A_SERVER_CORE = 0x00000091, // Server Datacenter, Semi-Annual Channel (core installation)
|
||||
STANDARD_A_SERVER_CORE = 0x00000092, // Server Standard, Semi-Annual Channel (core installation)
|
||||
DATACENTER_SERVER = 0x00000008, // Server Datacenter (full installation. For Server Core installations of Windows Server 2012 and later, use the method, Determining whether Server Core is running.)
|
||||
DATACENTER_SERVER_CORE = 0x0000000C, // Server Datacenter (core installation, Windows Server 2008 R2 and earlier)
|
||||
DATACENTER_SERVER_CORE_V = 0x00000027, // Server Datacenter without Hyper-V (core installation)
|
||||
DATACENTER_SERVER_V = 0x00000025, // Server Datacenter without Hyper-V (full installation)
|
||||
EDUCATION = 0x00000079, // Windows 10 Education
|
||||
EDUCATION_N = 0x0000007A, // Windows 10 Education N
|
||||
ENTERPRISE = 0x00000004, // Windows 10 Enterprise
|
||||
ENTERPRISE_E = 0x00000046, // Windows 10 Enterprise E
|
||||
ENTERPRISE_EVALUATION = 0x00000048, // Windows 10 Enterprise Evaluation
|
||||
ENTERPRISE_N = 0x0000001B, // Windows 10 Enterprise N
|
||||
ENTERPRISE_N_EVALUATION = 0x00000054, // Windows 10 Enterprise N Evaluation
|
||||
ENTERPRISE_S = 0x0000007D, // Windows 10 Enterprise 2015 LTSB
|
||||
ENTERPRISE_S_EVALUATION = 0x00000081, // Windows 10 Enterprise 2015 LTSB Evaluation
|
||||
ENTERPRISE_S_N = 0x0000007E, // Windows 10 Enterprise 2015 LTSB N
|
||||
ENTERPRISE_S_N_EVALUATION = 0x00000082, // Windows 10 Enterprise 2015 LTSB N Evaluation
|
||||
ENTERPRISE_SERVER = 0x0000000A, // Server Enterprise (full installation)
|
||||
ENTERPRISE_SERVER_CORE = 0x0000000E, // Server Enterprise (core installation)
|
||||
ENTERPRISE_SERVER_CORE_V = 0x00000029, // Server Enterprise without Hyper-V (core installation)
|
||||
ENTERPRISE_SERVER_IA64 = 0x0000000F, // Server Enterprise for Itanium-based Systems
|
||||
ENTERPRISE_SERVER_V = 0x00000026, // Server Enterprise without Hyper-V (full installation)
|
||||
ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C, // Windows Essential Server Solution Additional
|
||||
ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E, // Windows Essential Server Solution Additional SVC
|
||||
ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B, // Windows Essential Server Solution Management
|
||||
ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D, // Windows Essential Server Solution Management SVC
|
||||
HOME_BASIC = 0x00000002, // Home Basic
|
||||
HOME_BASIC_E = 0x00000043, // Not supported
|
||||
HOME_BASIC_N = 0x00000005, // Home Basic N
|
||||
HOME_PREMIUM = 0x00000003, // Home Premium
|
||||
HOME_PREMIUM_E = 0x00000044, // Not supported
|
||||
HOME_PREMIUM_N = 0x0000001A, // Home Premium N
|
||||
HOME_PREMIUM_SERVER = 0x00000022, // Windows Home Server 2011
|
||||
HOME_SERVER = 0x00000013, // Windows Storage Server 2008 R2 Essentials
|
||||
HYPERV = 0x0000002A, // Microsoft Hyper-V Server
|
||||
IOTENTERPRISE = 0x000000BC, // Windows IoT Enterprise
|
||||
IOTENTERPRISE_S = 0x000000BF, // Windows IoT Enterprise LTSC
|
||||
IOTUAP = 0x0000007B, // Windows 10 IoT Core
|
||||
IOTUAPCOMMERCIAL = 0x00000083, // Windows 10 IoT Core Commercial
|
||||
MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E, // Windows Essential Business Server Management Server
|
||||
MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020, // Windows Essential Business Server Messaging Server
|
||||
MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F, // Windows Essential Business Server Security Server
|
||||
MOBILE_CORE = 0x00000068, // Windows 10 Mobile
|
||||
MOBILE_ENTERPRISE = 0x00000085, // Windows 10 Mobile Enterprise
|
||||
MULTIPOINT_PREMIUM_SERVER = 0x0000004D, // Windows MultiPoint Server Premium (full installation)
|
||||
MULTIPOINT_STANDARD_SERVER = 0x0000004C, // Windows MultiPoint Server Standard (full installation)
|
||||
PRO_WORKSTATION = 0x000000A1, // Windows 10 Pro for Workstations
|
||||
PRO_WORKSTATION_N = 0x000000A2, // Windows 10 Pro for Workstations N
|
||||
PROFESSIONAL = 0x00000030, // Windows 10 Pro
|
||||
PROFESSIONAL_E = 0x00000045, // Not supported
|
||||
PROFESSIONAL_N = 0x00000031, // Windows 10 Pro N
|
||||
PROFESSIONAL_WMC = 0x00000067, // Professional with Media Center
|
||||
SB_SOLUTION_SERVER = 0x00000032, // Windows Small Business Server 2011 Essentials
|
||||
SB_SOLUTION_SERVER_EM = 0x00000036, // Server For SB Solutions EM
|
||||
SERVER_FOR_SB_SOLUTIONS = 0x00000033, // Server For SB Solutions
|
||||
SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037, // Server For SB Solutions EM
|
||||
SERVER_FOR_SMALLBUSINESS = 0x00000018, // Windows Server 2008 for Windows Essential Server Solutions
|
||||
SERVER_FOR_SMALLBUSINESS_V = 0x00000023, // Windows Server 2008 without Hyper-V for Windows Essential Server Solutions
|
||||
SERVER_FOUNDATION = 0x00000021, // Server Foundation
|
||||
SMALLBUSINESS_SERVER = 0x00000009, // Windows Small Business Server
|
||||
SMALLBUSINESS_SERVER_PREMIUM = 0x00000019, // Small Business Server Premium
|
||||
SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F, // Small Business Server Premium (core installation)
|
||||
SOLUTION_EMBEDDEDSERVER = 0x00000038, // Windows MultiPoint Server
|
||||
STANDARD_EVALUATION_SERVER = 0x0000004F, // Server Standard (evaluation installation)
|
||||
STANDARD_SERVER = 0x00000007, // Server Standard (full installation. For Server Core installations of Windows Server 2012 and later, use the method, Determining whether Server Core is running.)
|
||||
STANDARD_SERVER_CORE = 0x0000000D, // Server Standard (core installation, Windows Server 2008 R2 and earlier)
|
||||
STANDARD_SERVER_CORE_V = 0x00000028, // Server Standard without Hyper-V (core installation)
|
||||
STANDARD_SERVER_V = 0x00000024, // Server Standard without Hyper-V
|
||||
STANDARD_SERVER_SOLUTIONS = 0x00000034, // Server Solutions Premium
|
||||
STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035, // Server Solutions Premium (core installation)
|
||||
STARTER = 0x0000000B, // Starter
|
||||
STARTER_E = 0x00000042, // Not supported
|
||||
STARTER_N = 0x0000002F, // Starter N
|
||||
STORAGE_ENTERPRISE_SERVER = 0x00000017, // Storage Server Enterprise
|
||||
STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E, // Storage Server Enterprise (core installation)
|
||||
STORAGE_EXPRESS_SERVER = 0x00000014, // Storage Server Express
|
||||
STORAGE_EXPRESS_SERVER_CORE = 0x0000002B, // Storage Server Express (core installation)
|
||||
STORAGE_STANDARD_EVALUATION_SERVER = 0x00000060, // Storage Server Standard (evaluation installation)
|
||||
STORAGE_STANDARD_SERVER = 0x00000015, // Storage Server Standard
|
||||
STORAGE_STANDARD_SERVER_CORE = 0x0000002C, // Storage Server Standard (core installation)
|
||||
STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F, // Storage Server Workgroup (evaluation installation)
|
||||
STORAGE_WORKGROUP_SERVER = 0x00000016, // Storage Server Workgroup
|
||||
STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D, // Storage Server Workgroup (core installation)
|
||||
ULTIMATE = 0x00000001, // Ultimate
|
||||
ULTIMATE_E = 0x00000047, // Not supported
|
||||
ULTIMATE_N = 0x0000001C, // Ultimate N
|
||||
UNDEFINED = 0x00000000, // An unknown product
|
||||
WEB_SERVER = 0x00000011, // Web Server (full installation)
|
||||
WEB_SERVER_CORE = 0x0000001D, // Web Server (core installation)
|
||||
}
|
||||
|
||||
ENABLE_ECHO_INPUT : DWORD : 0x0004
|
||||
ENABLE_INSERT_MODE : DWORD : 0x0020
|
||||
ENABLE_LINE_INPUT : DWORD : 0x0002
|
||||
ENABLE_MOUSE_INPUT : DWORD : 0x0010
|
||||
ENABLE_PROCESSED_INPUT : DWORD : 0x0001
|
||||
ENABLE_QUICK_EDIT_MODE : DWORD : 0x0040
|
||||
ENABLE_WINDOW_INPUT : DWORD : 0x0008
|
||||
ENABLE_VIRTUAL_TERMINAL_INPUT : DWORD : 0x0200
|
||||
ENABLE_PROCESSED_OUTPUT : DWORD : 0x0001
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT : DWORD : 0x0002
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING : DWORD : 0x0004
|
||||
DISABLE_NEWLINE_AUTO_RETURN : DWORD : 0x0008
|
||||
ENABLE_LVB_GRID_WORLDWIDE : DWORD : 0x0010
|
||||
|
||||
CTRL_C_EVENT : DWORD : 0
|
||||
CTRL_BREAK_EVENT : DWORD : 1
|
||||
CTRL_CLOSE_EVENT : DWORD : 2
|
||||
CTRL_LOGOFF_EVENT : DWORD : 5
|
||||
CTRL_SHUTDOWN_EVENT : DWORD : 6
|
||||
|
||||
COORD :: struct {
|
||||
X: SHORT,
|
||||
Y: SHORT,
|
||||
}
|
||||
|
||||
@@ -190,6 +190,14 @@ foreign user32 {
|
||||
SetWindowTextW :: proc(hWnd: HWND, lpString: LPCWSTR) -> BOOL ---
|
||||
CallWindowProcW :: proc(lpPrevWndFunc: WNDPROC, hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT ---
|
||||
EnableWindow :: proc(hWnd: HWND, bEnable: BOOL) -> BOOL ---
|
||||
|
||||
DefRawInputProc :: proc(paRawInput: ^PRAWINPUT, nInput: INT, cbSizeHeader: UINT) -> LRESULT ---
|
||||
GetRawInputBuffer :: proc(pRawInput: PRAWINPUT, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT ---
|
||||
GetRawInputData :: proc(hRawInput: HRAWINPUT, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT ---
|
||||
GetRawInputDeviceInfoW :: proc(hDevice: HANDLE, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT) -> UINT ---
|
||||
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||
RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
|
||||
}
|
||||
|
||||
CreateWindowW :: #force_inline proc "stdcall" (
|
||||
@@ -277,3 +285,146 @@ DPI_AWARENESS_CONTEXT_SYSTEM_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(1))
|
||||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(2)) // -3
|
||||
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 :: DPI_AWARENESS_CONTEXT(~uintptr(3)) // -4
|
||||
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED :: DPI_AWARENESS_CONTEXT(~uintptr(4)) // -5
|
||||
|
||||
RAWINPUTHEADER :: struct {
|
||||
dwType: DWORD,
|
||||
dwSize: DWORD,
|
||||
hDevice: HANDLE,
|
||||
wParam: WPARAM,
|
||||
}
|
||||
|
||||
RAWHID :: struct {
|
||||
dwSizeHid: DWORD,
|
||||
dwCount: DWORD,
|
||||
bRawData: [1]BYTE,
|
||||
}
|
||||
|
||||
RAWMOUSE :: struct {
|
||||
usFlags: USHORT,
|
||||
DUMMYUNIONNAME: struct #raw_union {
|
||||
ulButtons: ULONG,
|
||||
DUMMYSTRUCTNAME: struct {
|
||||
usButtonFlags: USHORT,
|
||||
usButtonData: USHORT,
|
||||
},
|
||||
},
|
||||
ulRawButtons: ULONG,
|
||||
lLastX: LONG,
|
||||
lLastY: LONG,
|
||||
ulExtraInformation: ULONG,
|
||||
}
|
||||
|
||||
RAWKEYBOARD :: struct {
|
||||
MakeCode: USHORT,
|
||||
Flags: USHORT,
|
||||
Rserved: USHORT,
|
||||
VKey: USHORT,
|
||||
Message: UINT,
|
||||
ExtraInformation: ULONG,
|
||||
}
|
||||
|
||||
RAWINPUT :: struct {
|
||||
header: RAWINPUTHEADER,
|
||||
data: struct #raw_union {
|
||||
mouse: RAWMOUSE,
|
||||
keyboard: RAWKEYBOARD,
|
||||
hid: RAWHID,
|
||||
},
|
||||
}
|
||||
|
||||
PRAWINPUT :: ^RAWINPUT
|
||||
HRAWINPUT :: distinct LPARAM
|
||||
|
||||
RAWINPUTDEVICE :: struct {
|
||||
usUsagePage: USHORT,
|
||||
usUsage: USHORT,
|
||||
dwFlags: DWORD,
|
||||
hwndTarget: HWND,
|
||||
}
|
||||
|
||||
PRAWINPUTDEVICE :: ^RAWINPUTDEVICE
|
||||
PCRAWINPUTDEVICE :: PRAWINPUTDEVICE
|
||||
|
||||
RAWINPUTDEVICELIST :: struct {
|
||||
hDevice: HANDLE,
|
||||
dwType: DWORD,
|
||||
}
|
||||
|
||||
PRAWINPUTDEVICELIST :: ^RAWINPUTDEVICELIST
|
||||
|
||||
RID_DEVICE_INFO_HID :: struct {
|
||||
dwVendorId: DWORD,
|
||||
dwProductId: DWORD,
|
||||
dwVersionNumber: DWORD,
|
||||
usUsagePage: USHORT,
|
||||
usUsage: USHORT,
|
||||
}
|
||||
|
||||
RID_DEVICE_INFO_KEYBOARD :: struct {
|
||||
dwType: DWORD,
|
||||
dwSubType: DWORD,
|
||||
dwKeyboardMode: DWORD,
|
||||
dwNumberOfFunctionKeys: DWORD,
|
||||
dwNumberOfIndicators: DWORD,
|
||||
dwNumberOfKeysTotal: DWORD,
|
||||
}
|
||||
|
||||
RID_DEVICE_INFO_MOUSE :: struct {
|
||||
dwId: DWORD,
|
||||
dwNumberOfButtons: DWORD,
|
||||
dwSampleRate: DWORD,
|
||||
fHasHorizontalWheel: BOOL,
|
||||
}
|
||||
|
||||
RID_DEVICE_INFO :: struct {
|
||||
cbSize: DWORD,
|
||||
dwType: DWORD,
|
||||
DUMMYUNIONNAME: struct #raw_union {
|
||||
mouse: RID_DEVICE_INFO_MOUSE,
|
||||
keyboard: RID_DEVICE_INFO_KEYBOARD,
|
||||
hid: RID_DEVICE_INFO_HID,
|
||||
},
|
||||
}
|
||||
|
||||
RIDEV_REMOVE :: 0x00000001
|
||||
RIDEV_EXCLUDE :: 0x00000010
|
||||
RIDEV_PAGEONLY :: 0x00000020
|
||||
RIDEV_NOLEGACY :: 0x00000030
|
||||
RIDEV_INPUTSINK :: 0x00000100
|
||||
RIDEV_CAPTUREMOUSE :: 0x00000200
|
||||
RIDEV_NOHOTKEYS :: 0x00000200
|
||||
RIDEV_APPKEYS :: 0x00000400
|
||||
RIDEV_EXINPUTSINK :: 0x00001000
|
||||
RIDEV_DEVNOTIFY :: 0x00002000
|
||||
|
||||
RID_HEADER :: 0x10000005
|
||||
RID_INPUT :: 0x10000003
|
||||
|
||||
RIM_TYPEMOUSE :: 0
|
||||
RIM_TYPEKEYBOARD :: 1
|
||||
RIM_TYPEHID :: 2
|
||||
|
||||
MOUSE_MOVE_RELATIVE :: 0x00
|
||||
MOUSE_MOVE_ABSOLUTE :: 0x01
|
||||
MOUSE_VIRTUAL_DESKTOP :: 0x02
|
||||
MOUSE_ATTRIUBTTES_CHANGED :: 0x04
|
||||
MOUSE_MOVE_NOCOALESCE :: 0x08
|
||||
|
||||
RI_MOUSE_BUTTON_1_DOWN :: 0x0001
|
||||
RI_MOUSE_LEFT_BUTTON_DOWNS :: RI_MOUSE_BUTTON_1_DOWN
|
||||
RI_MOUSE_BUTTON_1_UP :: 0x0002
|
||||
RI_MOUSE_LEFT_BUTTON_UP :: RI_MOUSE_BUTTON_1_UP
|
||||
RI_MOUSE_BUTTON_2_DOWN :: 0x0004
|
||||
RI_MOUSE_RIGHT_BUTTON_DOWN :: RI_MOUSE_BUTTON_2_DOWN
|
||||
RI_MOUSE_BUTTON_2_UP :: 0x0008
|
||||
RI_MOUSE_RIGHT_BUTTON_UP :: RI_MOUSE_BUTTON_2_UP
|
||||
RI_MOUSE_BUTTON_3_DOWN :: 0x0010
|
||||
RI_MOUSE_MIDDLE_BUTTON_DOWN :: RI_MOUSE_BUTTON_3_DOWN
|
||||
RI_MOUSE_BUTTON_3_UP :: 0x0020
|
||||
RI_MOUSE_MIDDLE_BUTTON_UP :: RI_MOUSE_BUTTON_3_UP
|
||||
RI_MOUSE_BUTTON_4_DOWN :: 0x0040
|
||||
RI_MOUSE_BUTTON_4_UP :: 0x0080
|
||||
RI_MOUSE_BUTTON_5_DOWN :: 0x0100
|
||||
RI_MOUSE_BUTTON_5_UP :: 0x0200
|
||||
RI_MOUSE_WHEEL :: 0x0400
|
||||
RI_MOUSE_HWHEEL :: 0x0800
|
||||
|
||||
@@ -73,10 +73,10 @@ wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator)
|
||||
|
||||
// If N == -1 the call to WideCharToMultiByte assume the wide string is null terminated
|
||||
// and will scan it to find the first null terminated character. The resulting string will
|
||||
// also null terminated.
|
||||
// also be null terminated.
|
||||
// If N != -1 it assumes the wide string is not null terminated and the resulting string
|
||||
// will not be null terminated, we therefore have to force it to be null terminated manually.
|
||||
text := make([]byte, n+1 if N != -1 else n) or_return
|
||||
// will not be null terminated.
|
||||
text := make([]byte, n) or_return
|
||||
|
||||
n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(text), n, nil, nil)
|
||||
if n1 == 0 {
|
||||
|
||||
@@ -42,6 +42,8 @@ ERROR_TIMEOUT : DWORD : 1460
|
||||
ERROR_DATATYPE_MISMATCH : DWORD : 1629
|
||||
ERROR_UNSUPPORTED_TYPE : DWORD : 1630
|
||||
ERROR_NOT_SAME_OBJECT : DWORD : 1656
|
||||
ERROR_PIPE_CONNECTED : DWORD : 0x80070217
|
||||
ERROR_PIPE_BUSY : DWORD : 231
|
||||
|
||||
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
|
||||
|
||||
|
||||
@@ -109,6 +109,8 @@ import i18n "core:text/i18n"
|
||||
import thread "core:thread"
|
||||
import time "core:time"
|
||||
|
||||
import sysinfo "core:sys/info"
|
||||
|
||||
import unicode "core:unicode"
|
||||
import utf8 "core:unicode/utf8"
|
||||
import utf8string "core:unicode/utf8/utf8string"
|
||||
@@ -206,6 +208,7 @@ _ :: scanner
|
||||
_ :: i18n
|
||||
_ :: thread
|
||||
_ :: time
|
||||
_ :: sysinfo
|
||||
_ :: unicode
|
||||
_ :: utf8
|
||||
_ :: utf8string
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -116,6 +116,7 @@ struct TargetMetrics {
|
||||
TargetArchKind arch;
|
||||
isize word_size;
|
||||
isize max_align;
|
||||
isize max_simd_align;
|
||||
String target_triplet;
|
||||
String target_data_layout;
|
||||
TargetABIKind abi;
|
||||
@@ -224,6 +225,7 @@ struct BuildContext {
|
||||
String ODIN_VENDOR; // compiler vendor
|
||||
String ODIN_VERSION; // compiler version
|
||||
String ODIN_ROOT; // Odin ROOT
|
||||
String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
|
||||
bool ODIN_DEBUG; // Odin in debug mode
|
||||
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
|
||||
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
|
||||
@@ -235,8 +237,9 @@ struct BuildContext {
|
||||
TargetEndianKind endian_kind;
|
||||
|
||||
// In bytes
|
||||
i64 word_size; // Size of a pointer, must be >= 4
|
||||
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
|
||||
i64 word_size; // Size of a pointer, must be >= 4
|
||||
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
|
||||
i64 max_simd_align; // max alignment, must be >= 1 (and typically >= word_size)
|
||||
|
||||
CommandKind command_kind;
|
||||
String command;
|
||||
@@ -339,15 +342,13 @@ bool global_ignore_warnings(void) {
|
||||
gb_global TargetMetrics target_windows_i386 = {
|
||||
TargetOs_windows,
|
||||
TargetArch_i386,
|
||||
4,
|
||||
8,
|
||||
4, 4, 8,
|
||||
str_lit("i386-pc-windows-msvc"),
|
||||
};
|
||||
gb_global TargetMetrics target_windows_amd64 = {
|
||||
TargetOs_windows,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-pc-windows-msvc"),
|
||||
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
@@ -355,24 +356,21 @@ gb_global TargetMetrics target_windows_amd64 = {
|
||||
gb_global TargetMetrics target_linux_i386 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_i386,
|
||||
4,
|
||||
8,
|
||||
4, 4, 8,
|
||||
str_lit("i386-pc-linux-gnu"),
|
||||
|
||||
};
|
||||
gb_global TargetMetrics target_linux_amd64 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-pc-linux-gnu"),
|
||||
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
gb_global TargetMetrics target_linux_arm64 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_arm64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("aarch64-linux-elf"),
|
||||
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
|
||||
};
|
||||
@@ -380,8 +378,7 @@ gb_global TargetMetrics target_linux_arm64 = {
|
||||
gb_global TargetMetrics target_linux_arm32 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_arm32,
|
||||
4,
|
||||
8,
|
||||
4, 4, 8,
|
||||
str_lit("arm-linux-gnu"),
|
||||
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
|
||||
};
|
||||
@@ -389,8 +386,7 @@ gb_global TargetMetrics target_linux_arm32 = {
|
||||
gb_global TargetMetrics target_darwin_amd64 = {
|
||||
TargetOs_darwin,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-apple-darwin"),
|
||||
str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
@@ -398,8 +394,7 @@ gb_global TargetMetrics target_darwin_amd64 = {
|
||||
gb_global TargetMetrics target_darwin_arm64 = {
|
||||
TargetOs_darwin,
|
||||
TargetArch_arm64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("arm64-apple-macosx11.0.0"),
|
||||
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
|
||||
};
|
||||
@@ -407,16 +402,14 @@ gb_global TargetMetrics target_darwin_arm64 = {
|
||||
gb_global TargetMetrics target_freebsd_i386 = {
|
||||
TargetOs_freebsd,
|
||||
TargetArch_i386,
|
||||
4,
|
||||
8,
|
||||
4, 4, 8,
|
||||
str_lit("i386-unknown-freebsd-elf"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_freebsd_amd64 = {
|
||||
TargetOs_freebsd,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-unknown-freebsd-elf"),
|
||||
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
@@ -424,8 +417,7 @@ gb_global TargetMetrics target_freebsd_amd64 = {
|
||||
gb_global TargetMetrics target_openbsd_amd64 = {
|
||||
TargetOs_openbsd,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-unknown-openbsd-elf"),
|
||||
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
};
|
||||
@@ -433,62 +425,48 @@ gb_global TargetMetrics target_openbsd_amd64 = {
|
||||
gb_global TargetMetrics target_essence_amd64 = {
|
||||
TargetOs_essence,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-pc-none-elf"),
|
||||
};
|
||||
|
||||
|
||||
gb_global TargetMetrics target_freestanding_wasm32 = {
|
||||
TargetOs_freestanding,
|
||||
TargetArch_wasm32,
|
||||
4,
|
||||
8,
|
||||
4, 8, 16,
|
||||
str_lit("wasm32-freestanding-js"),
|
||||
str_lit(""),
|
||||
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_js_wasm32 = {
|
||||
TargetOs_js,
|
||||
TargetArch_wasm32,
|
||||
4,
|
||||
8,
|
||||
4, 8, 16,
|
||||
str_lit("wasm32-js-js"),
|
||||
str_lit(""),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_js_wasm64 = {
|
||||
TargetOs_js,
|
||||
TargetArch_wasm64,
|
||||
8,
|
||||
16,
|
||||
str_lit("wasm64-js-js"),
|
||||
str_lit(""),
|
||||
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_wasi_wasm32 = {
|
||||
TargetOs_wasi,
|
||||
TargetArch_wasm32,
|
||||
4,
|
||||
8,
|
||||
4, 8, 16,
|
||||
str_lit("wasm32-wasi-js"),
|
||||
str_lit(""),
|
||||
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
|
||||
};
|
||||
|
||||
|
||||
// gb_global TargetMetrics target_freestanding_wasm64 = {
|
||||
// TargetOs_freestanding,
|
||||
// TargetArch_wasm64,
|
||||
// 8,
|
||||
// 16,
|
||||
// str_lit("wasm64-freestanding-js"),
|
||||
// str_lit(""),
|
||||
// };
|
||||
gb_global TargetMetrics target_js_wasm64 = {
|
||||
TargetOs_js,
|
||||
TargetArch_wasm64,
|
||||
8, 8, 16,
|
||||
str_lit("wasm64-js-js"),
|
||||
str_lit(""),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_freestanding_amd64_sysv = {
|
||||
TargetOs_freestanding,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
8, 8, 16,
|
||||
str_lit("x86_64-pc-none-gnu"),
|
||||
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
TargetABI_SysV,
|
||||
@@ -517,7 +495,7 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
|
||||
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
|
||||
{ str_lit("js_wasm32"), &target_js_wasm32 },
|
||||
{ str_lit("js_wasm64"), &target_js_wasm64 },
|
||||
// { str_lit("js_wasm64"), &target_js_wasm64 },
|
||||
|
||||
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
|
||||
};
|
||||
@@ -853,10 +831,73 @@ String internal_odin_root_dir(void) {
|
||||
gb_mfree(argv);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
// copy argv[0] to path_buf
|
||||
|
||||
// NOTE(Jeroen):
|
||||
// On OpenBSD, if `odin` is on the path, `argv[0]` will contain just `odin`,
|
||||
// even though that isn't then the relative path.
|
||||
// When run from Odin's directory, it returns `./odin`.
|
||||
// Check argv[0] for lack of / to see if it's a reference to PATH.
|
||||
// If so, walk PATH to find the executable.
|
||||
|
||||
len = gb_strlen(argv[0]);
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], argv[0], len);
|
||||
|
||||
bool slash_found = false;
|
||||
bool odin_found = false;
|
||||
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
if (argv[0][i] == '/') {
|
||||
slash_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slash_found) {
|
||||
// copy argv[0] to path_buf
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], argv[0], len);
|
||||
odin_found = true;
|
||||
}
|
||||
} else {
|
||||
gbAllocator a = heap_allocator();
|
||||
char const *path_env = gb_get_env("PATH", a);
|
||||
defer (gb_free(a, cast(void *)path_env));
|
||||
|
||||
if (path_env) {
|
||||
int path_len = gb_strlen(path_env);
|
||||
int path_start = 0;
|
||||
int path_end = 0;
|
||||
|
||||
for (; path_start < path_len; ) {
|
||||
for (; path_end <= path_len; path_end++) {
|
||||
if (path_env[path_end] == ':' || path_end == path_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
String path_needle = (const String)make_string((const u8 *)(path_env + path_start), path_end - path_start);
|
||||
String argv0 = (const String)make_string((const u8 *)argv[0], len);
|
||||
String odin_candidate = concatenate3_strings(a, path_needle, STR_LIT("/"), argv0);
|
||||
defer (gb_free(a, odin_candidate.text));
|
||||
|
||||
if (gb_file_exists((const char *)odin_candidate.text)) {
|
||||
len = odin_candidate.len;
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], odin_candidate.text, len);
|
||||
}
|
||||
odin_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
path_start = path_end + 1;
|
||||
path_end = path_start;
|
||||
if (path_start > path_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!odin_found) {
|
||||
gb_printf_err("Odin could not locate itself in PATH, and ODIN_ROOT wasn't set either.\n");
|
||||
}
|
||||
}
|
||||
gb_mfree(argv);
|
||||
#endif
|
||||
@@ -1084,14 +1125,16 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
GB_ASSERT(metrics->arch != TargetArch_Invalid);
|
||||
GB_ASSERT(metrics->word_size > 1);
|
||||
GB_ASSERT(metrics->max_align > 1);
|
||||
GB_ASSERT(metrics->max_simd_align > 1);
|
||||
|
||||
|
||||
bc->metrics = *metrics;
|
||||
bc->ODIN_OS = target_os_names[metrics->os];
|
||||
bc->ODIN_ARCH = target_arch_names[metrics->arch];
|
||||
bc->endian_kind = target_endians[metrics->arch];
|
||||
bc->word_size = metrics->word_size;
|
||||
bc->max_align = metrics->max_align;
|
||||
bc->ODIN_OS = target_os_names[metrics->os];
|
||||
bc->ODIN_ARCH = target_arch_names[metrics->arch];
|
||||
bc->endian_kind = target_endians[metrics->arch];
|
||||
bc->word_size = metrics->word_size;
|
||||
bc->max_align = metrics->max_align;
|
||||
bc->max_simd_align = metrics->max_simd_align;
|
||||
bc->link_flags = str_lit(" ");
|
||||
|
||||
#if defined(DEFAULT_TO_THREADED_CHECKER)
|
||||
@@ -1495,6 +1538,12 @@ bool init_build_paths(String init_filename) {
|
||||
enable_target_feature({}, bc->target_features_string);
|
||||
}
|
||||
|
||||
{
|
||||
String build_project_name = last_path_element(bc->build_paths[BuildPath_Main_Package].basename);
|
||||
GB_ASSERT(build_project_name.len > 0);
|
||||
bc->ODIN_BUILD_PROJECT_NAME = build_project_name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -341,6 +341,13 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
|
||||
for (isize i = 2+arg_offset; i < ce->args.count; i++) {
|
||||
Operand x = {};
|
||||
check_expr(c, &x, ce->args[i]);
|
||||
if (is_type_untyped(x.type)) {
|
||||
gbString e = expr_to_string(x.expr);
|
||||
gbString t = type_to_string(x.type);
|
||||
error(x.expr, "'%.*s' expects typed parameters, got %s of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
}
|
||||
param_types[i-arg_offset] = x.type;
|
||||
}
|
||||
|
||||
@@ -4523,7 +4530,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
if (x.mode != Addressing_Invalid) {
|
||||
convert_to_typed(c, &x, t_uintptr);
|
||||
}
|
||||
if (!is_type_uintptr(operand->type)) {
|
||||
convert_to_typed(c, &x, t_uintptr);
|
||||
if (!is_type_uintptr(x.type)) {
|
||||
gbString t = type_to_string(x.type);
|
||||
error(x.expr, "Argument %td must be of type 'uintptr', got %s", i, t);
|
||||
gb_string_free(t);
|
||||
@@ -4605,6 +4613,46 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
|
||||
case BuiltinProc_type_convert_variants_to_pointers:
|
||||
if (operand->mode != Addressing_Type) {
|
||||
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
} else {
|
||||
Type *bt = base_type(operand->type);
|
||||
if (is_type_polymorphic(bt)) {
|
||||
// IGNORE polymorphic types
|
||||
return true;
|
||||
} else if (bt->kind != Type_Union) {
|
||||
gbString t = type_to_string(operand->type);
|
||||
error(operand->expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
} else if (bt->Union.is_polymorphic) {
|
||||
gbString t = type_to_string(operand->type);
|
||||
error(operand->expr, "Expected a non-polymorphic union type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *new_type = alloc_type_union();
|
||||
auto variants = slice_make<Type *>(permanent_allocator(), bt->Union.variants.count);
|
||||
for_array(i, bt->Union.variants) {
|
||||
variants[i] = alloc_type_pointer(bt->Union.variants[i]);
|
||||
}
|
||||
new_type->Union.variants = variants;
|
||||
|
||||
// NOTE(bill): Is this even correct?
|
||||
new_type->Union.scope = bt->Union.scope;
|
||||
|
||||
operand->type = new_type;
|
||||
}
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
|
||||
case BuiltinProc_type_is_boolean:
|
||||
case BuiltinProc_type_is_integer:
|
||||
@@ -5390,10 +5438,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
case BuiltinProc_valgrind_client_request:
|
||||
{
|
||||
if (!is_arch_x86()) {
|
||||
error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
// NOTE(bill): Check it but make it a no-op for non x86 (i386, amd64) targets
|
||||
|
||||
enum {ARG_COUNT = 7};
|
||||
GB_ASSERT(builtin_procs[BuiltinProc_valgrind_client_request].arg_count == ARG_COUNT);
|
||||
|
||||
@@ -3039,8 +3039,8 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
|
||||
x->type = xt;
|
||||
goto matrix_success;
|
||||
} else {
|
||||
GB_ASSERT(is_type_matrix(yt));
|
||||
GB_ASSERT(!is_type_matrix(xt));
|
||||
GB_ASSERT(is_type_matrix(yt));
|
||||
|
||||
if (op.kind == Token_Mul) {
|
||||
// NOTE(bill): no need to handle the matrix case here since it should be handled above
|
||||
@@ -3061,6 +3061,9 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
|
||||
x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count);
|
||||
}
|
||||
goto matrix_success;
|
||||
} else if (are_types_identical(yt->Matrix.elem, xt)) {
|
||||
x->type = check_matrix_type_hint(y->type, type_hint);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!are_types_identical(xt, yt)) {
|
||||
@@ -7359,6 +7362,14 @@ ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *t
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Type || y.mode == Addressing_Type) {
|
||||
Ast *type_expr = (x.mode == Addressing_Type) ? x.expr : y.expr;
|
||||
gbString type_string = expr_to_string(type_expr);
|
||||
error(node, "Type %s is invalid operand for ternary if expression", type_string);
|
||||
gb_string_free(type_string);
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (x.type == nullptr || x.type == t_invalid ||
|
||||
y.type == nullptr || y.type == t_invalid) {
|
||||
return kind;
|
||||
@@ -7395,6 +7406,7 @@ ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *t
|
||||
check_cast_internal(c, &y, type_hint)) {
|
||||
convert_to_typed(c, o, type_hint);
|
||||
update_untyped_expr_type(c, node, type_hint, !is_type_untyped(type_hint));
|
||||
o->type = type_hint;
|
||||
}
|
||||
}
|
||||
return kind;
|
||||
@@ -8769,7 +8781,10 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
Ast *first_arg = x.expr->SelectorExpr.expr;
|
||||
GB_ASSERT(first_arg != nullptr);
|
||||
|
||||
first_arg->state_flags |= StateFlag_SelectorCallExpr;
|
||||
Entity *e = entity_of_node(se->expr);
|
||||
if (!(e != nullptr && (e->kind == Entity_Procedure || e->kind == Entity_ProcGroup))) {
|
||||
first_arg->state_flags |= StateFlag_SelectorCallExpr;
|
||||
}
|
||||
|
||||
Type *pt = base_type(x.type);
|
||||
GB_ASSERT(pt->kind == Type_Proc);
|
||||
@@ -9571,6 +9586,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
case Ast_MapType:
|
||||
case Ast_BitSetType:
|
||||
case Ast_MatrixType:
|
||||
case Ast_RelativeType:
|
||||
o->mode = Addressing_Type;
|
||||
o->type = check_type(c, node);
|
||||
break;
|
||||
|
||||
@@ -1396,6 +1396,23 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) {
|
||||
return id != BuiltinProc_Invalid;
|
||||
}
|
||||
|
||||
bool check_expr_is_stack_variable(Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
Entity *e = entity_of_node(expr);
|
||||
if (e && e->kind == Entity_Variable) {
|
||||
if (e->flags & (EntityFlag_Static|EntityFlag_Using|EntityFlag_ImplicitReference|EntityFlag_ForValue)) {
|
||||
// okay
|
||||
} else if (e->Variable.thread_local_model.len != 0) {
|
||||
// okay
|
||||
} else if (e->scope) {
|
||||
if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Type)) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
|
||||
switch (node->kind) {
|
||||
@@ -1447,6 +1464,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
AstSelectorCallExpr *se = &expr->SelectorCallExpr;
|
||||
ast_node(ce, CallExpr, se->call);
|
||||
Type *t = base_type(type_of_expr(ce->proc));
|
||||
if (t == nullptr) {
|
||||
gbString expr_str = expr_to_string(ce->proc);
|
||||
error(node, "'%s' is not a value field nor procedure", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
return;
|
||||
}
|
||||
if (t->kind == Type_Proc) {
|
||||
do_require = t->Proc.require_results;
|
||||
} else if (check_stmt_internal_builtin_proc_id(ce->proc, &builtin_id)) {
|
||||
@@ -1678,6 +1701,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
if (is_type_untyped(o->type)) {
|
||||
update_untyped_expr_type(ctx, o->expr, e->type, true);
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): This is very basic escape analysis
|
||||
// This needs to be improved tremendously, and a lot of it done during the
|
||||
// middle-end (or LLVM side) to improve checks and error messages
|
||||
Ast *expr = unparen_expr(o->expr);
|
||||
if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
|
||||
Ast *x = unparen_expr(expr->UnaryExpr.expr);
|
||||
if (x->kind == Ast_CompoundLit) {
|
||||
error(expr, "Cannot return the address to a stack value from a procedure");
|
||||
} else if (x->kind == Ast_IndexExpr) {
|
||||
Ast *array = x->IndexExpr.expr;
|
||||
if (is_type_array_like(type_of_expr(array)) && check_expr_is_stack_variable(array)) {
|
||||
gbString t = type_to_string(type_of_expr(array));
|
||||
error(expr, "Cannot return the address to an element of stack variable from a procedure, of type %s", t);
|
||||
gb_string_free(t);
|
||||
}
|
||||
} else {
|
||||
if (check_expr_is_stack_variable(x)) {
|
||||
error(expr, "Cannot return the address to a stack variable from a procedure");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
@@ -1895,13 +1941,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
}
|
||||
if (found == nullptr) {
|
||||
entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved);
|
||||
entity->flags |= EntityFlag_ForValue;
|
||||
entity->flags |= EntityFlag_Value;
|
||||
if (i == addressable_index) {
|
||||
if (use_by_reference_for_value) {
|
||||
entity->flags &= ~EntityFlag_Value;
|
||||
} else {
|
||||
entity->flags |= EntityFlag_ForValue;
|
||||
}
|
||||
if (i == addressable_index && use_by_reference_for_value) {
|
||||
entity->flags &= ~EntityFlag_Value;
|
||||
}
|
||||
if (is_soa) {
|
||||
if (i == 0) {
|
||||
|
||||
@@ -1643,8 +1643,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
bool valid = false;
|
||||
if (is_type_proc(op.type)) {
|
||||
Entity *proc_entity = entity_from_expr(op.expr);
|
||||
valid = proc_entity != nullptr;
|
||||
poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr);
|
||||
valid = (proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure);
|
||||
if (valid) {
|
||||
poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr);
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
if (op.mode == Addressing_Constant) {
|
||||
|
||||
@@ -938,6 +938,7 @@ void init_universal(void) {
|
||||
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
|
||||
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
|
||||
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
|
||||
add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
|
||||
|
||||
{
|
||||
GlobalEnumValue values[TargetOs_COUNT] = {
|
||||
|
||||
@@ -200,6 +200,8 @@ BuiltinProc__type_begin,
|
||||
BuiltinProc_type_core_type,
|
||||
BuiltinProc_type_elem_type,
|
||||
|
||||
BuiltinProc_type_convert_variants_to_pointers,
|
||||
|
||||
BuiltinProc__type_simple_boolean_begin,
|
||||
BuiltinProc_type_is_boolean,
|
||||
BuiltinProc_type_is_integer,
|
||||
@@ -492,6 +494,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
@@ -38,6 +38,10 @@ i64 next_pow2(i64 n);
|
||||
isize next_pow2_isize(isize n);
|
||||
void debugf(char const *fmt, ...);
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS) && defined(GB_ARCH_32_BIT)
|
||||
#error Odin on Windows requires a 64-bit build-system. The 'Developer Command Prompt' for VS still defaults to 32-bit shell. The 64-bit shell can be found under the name 'x64 Native Tools Command Prompt' for VS. For more information, please see https://odin-lang.org/docs/install/#for-windows
|
||||
#endif
|
||||
|
||||
#include "threading.cpp"
|
||||
#include "unicode.cpp"
|
||||
#include "array.cpp"
|
||||
|
||||
@@ -294,7 +294,7 @@ i64 lb_alignof(LLVMTypeRef type) {
|
||||
i64 elem_size = lb_sizeof(elem);
|
||||
i64 count = LLVMGetVectorSize(type);
|
||||
i64 size = count * elem_size;
|
||||
return gb_clamp(next_pow2(size), 1, build_context.max_align);
|
||||
return gb_clamp(next_pow2(size), 1, build_context.max_simd_align);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1420,7 +1420,7 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
LLVMBool split_debug_inlining = false;
|
||||
LLVMBool split_debug_inlining = build_context.build_mode == BuildMode_Assembly;
|
||||
LLVMBool debug_info_for_profiling = false;
|
||||
|
||||
m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99,
|
||||
@@ -1615,6 +1615,7 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
if (is_foreign) {
|
||||
LLVMSetLinkage(g.value, LLVMExternalLinkage);
|
||||
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
|
||||
LLVMSetExternallyInitialized(g.value, true);
|
||||
lb_add_foreign_library_path(m, e->Variable.foreign_library);
|
||||
|
||||
|
||||
@@ -297,12 +297,16 @@ LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_
|
||||
}
|
||||
|
||||
if (!is_const) {
|
||||
LLVMTypeRef llvm_elem_type = lb_type(m, elem_type);
|
||||
lbProcedure *p = m->curr_procedure;
|
||||
GB_ASSERT(p != nullptr);
|
||||
lbAddr v = lb_add_local_generated(p, type, false);
|
||||
lbValue ptr = lb_addr_get_ptr(p, v);
|
||||
for (isize i = 0; i < count; i++) {
|
||||
lbValue elem = lb_emit_array_epi(p, ptr, i);
|
||||
if (is_type_proc(elem_type)) {
|
||||
values[i] = LLVMConstPointerCast(values[i], llvm_elem_type);
|
||||
}
|
||||
LLVMBuildStore(p->builder, values[i], elem.value);
|
||||
}
|
||||
return lb_addr_load(p, v).value;
|
||||
|
||||
@@ -1042,7 +1042,8 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
|
||||
// NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block
|
||||
// The reason is that if the parameter is at index 0 and a pointer, there is not such things as an
|
||||
// instruction "before" it.
|
||||
LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
|
||||
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
|
||||
// LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise=false);
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
||||
|
||||
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
||||
lbModule *m = p->module;
|
||||
@@ -137,7 +137,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
|
||||
lbAddr res_addr = lb_add_local(p, type, nullptr, false, 0, true);
|
||||
lbValue res = lb_addr_get_ptr(p, res_addr);
|
||||
|
||||
bool inline_array_arith = type_size_of(type) <= build_context.max_align;
|
||||
bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
|
||||
|
||||
i32 count = cast(i32)get_array_type_count(tl);
|
||||
|
||||
@@ -436,7 +436,7 @@ lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue r
|
||||
return direct_vector_res;
|
||||
}
|
||||
|
||||
bool inline_array_arith = type_size_of(type) <= build_context.max_align;
|
||||
bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
|
||||
if (inline_array_arith) {
|
||||
|
||||
auto dst_ptrs = slice_make<lbValue>(temporary_allocator(), n);
|
||||
@@ -987,7 +987,6 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
|
||||
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
|
||||
|
||||
|
||||
if (op == Token_Mul && !component_wise) {
|
||||
Type *xt = base_type(lhs.type);
|
||||
Type *yt = base_type(rhs.type);
|
||||
@@ -1001,8 +1000,22 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
|
||||
} else if (is_type_array_like(xt)) {
|
||||
GB_ASSERT(yt->kind == Type_Matrix);
|
||||
return lb_emit_vector_mul_matrix(p, lhs, rhs, type);
|
||||
}
|
||||
} else {
|
||||
GB_ASSERT(xt->kind == Type_Basic);
|
||||
GB_ASSERT(yt->kind == Type_Matrix);
|
||||
GB_ASSERT(is_type_matrix(type));
|
||||
|
||||
Type *array_type = alloc_type_array(yt->Matrix.elem, matrix_type_total_internal_elems(yt));
|
||||
GB_ASSERT(type_size_of(array_type) == type_size_of(yt));
|
||||
|
||||
lbValue array_lhs = lb_emit_conv(p, lhs, array_type);
|
||||
lbValue array_rhs = rhs;
|
||||
array_rhs.type = array_type;
|
||||
|
||||
lbValue array = lb_emit_arith(p, op, array_lhs, array_rhs, array_type);
|
||||
array.type = type;
|
||||
return array;
|
||||
}
|
||||
} else {
|
||||
if (is_type_matrix(lhs.type)) {
|
||||
rhs = lb_emit_conv(p, rhs, lhs.type);
|
||||
@@ -1047,7 +1060,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
|
||||
if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) {
|
||||
return lb_emit_arith_array(p, op, lhs, rhs, type);
|
||||
} else if (is_type_matrix(lhs.type) || is_type_matrix(rhs.type)) {
|
||||
return lb_emit_arith_matrix(p, op, lhs, rhs, type);
|
||||
return lb_emit_arith_matrix(p, op, lhs, rhs, type, false);
|
||||
} else if (is_type_complex(type)) {
|
||||
lhs = lb_emit_conv(p, lhs, type);
|
||||
rhs = lb_emit_conv(p, rhs, type);
|
||||
@@ -1320,7 +1333,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) {
|
||||
lbValue left = lb_build_expr(p, be->left);
|
||||
lbValue right = lb_build_expr(p, be->right);
|
||||
return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type));
|
||||
return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type), false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1777,9 +1790,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
lbValue res = {};
|
||||
res = lb_emit_conv(p, value, platform_src_type);
|
||||
res = lb_emit_conv(p, res, platform_dst_type);
|
||||
if (is_type_different_to_arch_endianness(dst)) {
|
||||
res = lb_emit_byte_swap(p, res, platform_dst_type);
|
||||
}
|
||||
return lb_emit_conv(p, res, t);
|
||||
}
|
||||
|
||||
@@ -1927,7 +1937,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
}
|
||||
if (dst->Union.variants.count == 1) {
|
||||
Type *vt = dst->Union.variants[0];
|
||||
if (internal_check_is_assignable_to(src, vt)) {
|
||||
if (internal_check_is_assignable_to(src_type, vt)) {
|
||||
value = lb_emit_conv(p, value, vt);
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
@@ -2306,7 +2316,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
|
||||
cmp_op = Token_And;
|
||||
}
|
||||
|
||||
bool inline_array_arith = type_size_of(tl) <= build_context.max_align;
|
||||
bool inline_array_arith = lb_can_try_to_inline_array_arith(tl);
|
||||
i32 count = 0;
|
||||
switch (tl->kind) {
|
||||
case Type_Array: count = cast(i32)tl->Array.count; break;
|
||||
|
||||
@@ -591,6 +591,9 @@ bool lb_try_update_alignment(lbValue ptr, unsigned alignment) {
|
||||
return lb_try_update_alignment(ptr.value, alignment);
|
||||
}
|
||||
|
||||
bool lb_can_try_to_inline_array_arith(Type *t) {
|
||||
return type_size_of(t) <= build_context.max_simd_align;
|
||||
}
|
||||
|
||||
bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) {
|
||||
Type *array_type = base_type(type_deref(ptr.type));
|
||||
@@ -599,7 +602,7 @@ bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) {
|
||||
Type *elem_type = base_array_type(array_type);
|
||||
|
||||
// TODO(bill): Determine what is the correct limit for doing vector arithmetic
|
||||
if (type_size_of(array_type) <= build_context.max_align &&
|
||||
if (lb_can_try_to_inline_array_arith(array_type) &&
|
||||
is_type_valid_vector_elem(elem_type)) {
|
||||
// Try to treat it like a vector if possible
|
||||
bool possible = false;
|
||||
@@ -874,18 +877,6 @@ bool lb_is_type_proc_recursive(Type *t) {
|
||||
case Type_Pointer:
|
||||
t = t->Pointer.elem;
|
||||
break;
|
||||
case Type_Array:
|
||||
t = t->Array.elem;
|
||||
break;
|
||||
case Type_EnumeratedArray:
|
||||
t = t->EnumeratedArray.elem;
|
||||
break;
|
||||
case Type_Slice:
|
||||
t = t->Slice.elem;
|
||||
break;
|
||||
case Type_DynamicArray:
|
||||
t = t->DynamicArray.elem;
|
||||
break;
|
||||
case Type_Proc:
|
||||
return true;
|
||||
default:
|
||||
@@ -1887,16 +1878,16 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
return LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
|
||||
|
||||
case Type_Array: {
|
||||
m->internal_type_level -= 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count);
|
||||
m->internal_type_level += 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count);
|
||||
m->internal_type_level -= 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
case Type_EnumeratedArray: {
|
||||
m->internal_type_level -= 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->EnumeratedArray.elem), cast(unsigned)type->EnumeratedArray.count);
|
||||
m->internal_type_level += 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->EnumeratedArray.elem), cast(unsigned)type->EnumeratedArray.count);
|
||||
m->internal_type_level -= 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -2098,14 +2089,11 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
}
|
||||
|
||||
case Type_Proc:
|
||||
// if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough?
|
||||
if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough?
|
||||
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
|
||||
} else {
|
||||
{
|
||||
LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type);
|
||||
return LLVMPointerType(proc_raw_type, 0);
|
||||
gb_unused(proc_raw_type);
|
||||
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
|
||||
}
|
||||
|
||||
break;
|
||||
case Type_BitSet:
|
||||
{
|
||||
|
||||
@@ -736,6 +736,9 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
|
||||
}
|
||||
for_array(i, processed_args) {
|
||||
lbValue arg = processed_args[i];
|
||||
if (is_type_proc(arg.type)) {
|
||||
arg.value = LLVMBuildPointerCast(p->builder, arg.value, lb_type(p->module, arg.type), "");
|
||||
}
|
||||
args[arg_index++] = arg.value;
|
||||
}
|
||||
if (context_ptr.addr.value != nullptr) {
|
||||
@@ -2867,9 +2870,9 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
return y;
|
||||
}
|
||||
|
||||
Ast *pexpr = unparen_expr(ce->proc);
|
||||
Ast *proc_expr = unparen_expr(ce->proc);
|
||||
if (proc_mode == Addressing_Builtin) {
|
||||
Entity *e = entity_of_node(pexpr);
|
||||
Entity *e = entity_of_node(proc_expr);
|
||||
BuiltinProcId id = BuiltinProc_Invalid;
|
||||
if (e != nullptr) {
|
||||
id = cast(BuiltinProcId)e->Builtin.id;
|
||||
@@ -2881,7 +2884,6 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
|
||||
// NOTE(bill): Regular call
|
||||
lbValue value = {};
|
||||
Ast *proc_expr = unparen_expr(ce->proc);
|
||||
|
||||
Entity *proc_entity = entity_of_node(proc_expr);
|
||||
if (proc_entity != nullptr) {
|
||||
|
||||
@@ -646,7 +646,7 @@ void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *sco
|
||||
|
||||
|
||||
lbAddr array = lb_build_addr(p, expr);
|
||||
if (is_type_pointer(type_deref(lb_addr_type(array)))) {
|
||||
if (is_type_pointer(lb_addr_type(array))) {
|
||||
array = lb_addr(lb_addr_load(p, array));
|
||||
}
|
||||
lbValue count = lb_soa_struct_len(p, lb_addr_load(p, array));
|
||||
@@ -1796,7 +1796,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
|
||||
|
||||
lbValue rhs = lb_emit_conv(p, value, lhs_type);
|
||||
|
||||
bool inline_array_arith = type_size_of(array_type) <= build_context.max_align;
|
||||
bool inline_array_arith = lb_can_try_to_inline_array_arith(array_type);
|
||||
|
||||
|
||||
if (lhs.kind == lbAddr_Swizzle) {
|
||||
@@ -1959,8 +1959,18 @@ void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
|
||||
} else {
|
||||
lbAddr lhs = lb_build_addr(p, as->lhs[0]);
|
||||
lbValue value = lb_build_expr(p, as->rhs[0]);
|
||||
|
||||
Type *lhs_type = lb_addr_type(lhs);
|
||||
|
||||
// NOTE(bill): Allow for the weird edge case of:
|
||||
// array *= matrix
|
||||
if (op == Token_Mul && is_type_matrix(value.type) && is_type_array(lhs_type)) {
|
||||
lbValue old_value = lb_addr_load(p, lhs);
|
||||
Type *type = old_value.type;
|
||||
lbValue new_value = lb_emit_vector_mul_matrix(p, old_value, value, type);
|
||||
lb_addr_store(p, lhs, new_value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_array(lhs_type)) {
|
||||
lb_build_assign_stmt_array(p, op, lhs, value);
|
||||
return;
|
||||
|
||||
@@ -225,6 +225,20 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
||||
if (is_type_simd_vector(src) && is_type_simd_vector(dst)) {
|
||||
res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), "");
|
||||
return res;
|
||||
} else if (is_type_array_like(src) && is_type_simd_vector(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);
|
||||
if (lb_try_update_alignment(ptr, align)) {
|
||||
LLVMTypeRef result_type = lb_type(p->module, t);
|
||||
res.value = LLVMBuildPointerCast(p->builder, ptr.value, LLVMPointerType(result_type, 0), "");
|
||||
res.value = LLVMBuildLoad2(p->builder, result_type, res.value, "");
|
||||
return res;
|
||||
}
|
||||
lbAddr addr = lb_add_local_generated(p, t, false);
|
||||
lbValue ap = lb_addr_get_ptr(p, addr);
|
||||
ap = lb_emit_conv(p, ap, alloc_type_pointer(value.type));
|
||||
lb_emit_store(p, ap, value);
|
||||
return lb_addr_load(p, addr);
|
||||
}
|
||||
|
||||
if (lb_is_type_aggregate(src) || lb_is_type_aggregate(dst)) {
|
||||
|
||||
86
src/main.cpp
86
src/main.cpp
@@ -288,11 +288,15 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
|
||||
char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
|
||||
if (!build_context.use_lld) { // msvc
|
||||
String res_path = {};
|
||||
defer (gb_free(heap_allocator(), res_path.text));
|
||||
if (build_context.has_resource) {
|
||||
String temp_res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]);
|
||||
res_path = concatenate3_strings(heap_allocator(), str_lit("\""), temp_res_path, str_lit("\""));
|
||||
gb_free(heap_allocator(), temp_res_path.text);
|
||||
|
||||
String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]);
|
||||
String res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]);
|
||||
defer (gb_free(heap_allocator(), rc_path.text));
|
||||
defer (gb_free(heap_allocator(), res_path.text));
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
|
||||
@@ -304,42 +308,25 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s \"%.*s\" -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
} else {
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
}
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
} else { // lld
|
||||
result = system_exec_command_line_app("msvc-lld-link",
|
||||
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
|
||||
@@ -590,8 +577,8 @@ void usage(String argv0) {
|
||||
print_usage_line(1, "version print version");
|
||||
print_usage_line(1, "report print information useful to reporting a bug");
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(0, "For further details on a command, use -help after the command name");
|
||||
print_usage_line(1, "e.g. odin build -help");
|
||||
print_usage_line(0, "For further details on a command, invoke command help:");
|
||||
print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
|
||||
}
|
||||
|
||||
enum BuildFlagKind {
|
||||
@@ -1963,13 +1950,13 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project");
|
||||
}
|
||||
|
||||
bool doc = command == "doc";
|
||||
bool build = command == "build";
|
||||
bool run_or_build = command == "run" || command == "build" || command == "test";
|
||||
bool test_only = command == "test";
|
||||
bool doc = command == "doc";
|
||||
bool build = command == "build";
|
||||
bool run_or_build = command == "run" || command == "build" || command == "test";
|
||||
bool test_only = command == "test";
|
||||
bool strip_semicolon = command == "strip-semicolon";
|
||||
bool check_only = command == "check" || strip_semicolon;
|
||||
bool check = run_or_build || check_only;
|
||||
bool check_only = command == "check" || strip_semicolon;
|
||||
bool check = run_or_build || check_only;
|
||||
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(1, "Flags");
|
||||
@@ -2085,7 +2072,7 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(3, "-build-mode:shared Build as a dynamically linked library");
|
||||
print_usage_line(3, "-build-mode:obj Build as an object file");
|
||||
print_usage_line(3, "-build-mode:object Build as an object file");
|
||||
print_usage_line(3, "-build-mode:assembly Build as an object file");
|
||||
print_usage_line(3, "-build-mode:assembly Build as an assembly file");
|
||||
print_usage_line(3, "-build-mode:assembler Build as an assembly file");
|
||||
print_usage_line(3, "-build-mode:asm Build as an assembly file");
|
||||
print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file");
|
||||
@@ -2701,6 +2688,14 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
build_context.command_kind = Command_bug_report;
|
||||
print_bug_report_help();
|
||||
return 0;
|
||||
} else if (command == "help") {
|
||||
if (args.count <= 2) {
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
} else {
|
||||
print_show_help(args[0], args[2]);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
@@ -2727,7 +2722,12 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
|
||||
if (!single_file_package) {
|
||||
gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command));
|
||||
gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
|
||||
if (init_filename == "-file") {
|
||||
gb_printf_err("Did you mean `%.*s %.*s <filename.odin> -file`?\n", LIT(args[0]), LIT(command));
|
||||
} else {
|
||||
gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
|
||||
}
|
||||
|
||||
gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n");
|
||||
return 1;
|
||||
} else {
|
||||
|
||||
@@ -5506,6 +5506,51 @@ isize calc_decl_count(Ast *decl) {
|
||||
return count;
|
||||
}
|
||||
|
||||
bool parse_build_project_directory_tag(Token token_for_pos, String s) {
|
||||
String const prefix = str_lit("+build-project-name");
|
||||
GB_ASSERT(string_starts_with(s, prefix));
|
||||
s = string_trim_whitespace(substring(s, prefix.len, s.len));
|
||||
if (s.len == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool any_correct = false;
|
||||
|
||||
while (s.len > 0) {
|
||||
bool this_kind_correct = true;
|
||||
|
||||
do {
|
||||
String p = string_trim_whitespace(build_tag_get_token(s, &s));
|
||||
if (p.len == 0) break;
|
||||
if (p == ",") break;
|
||||
|
||||
bool is_notted = false;
|
||||
if (p[0] == '!') {
|
||||
is_notted = true;
|
||||
p = substring(p, 1, p.len);
|
||||
if (p.len == 0) {
|
||||
syntax_error(token_for_pos, "Expected a build-project-name after '!'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_notted) {
|
||||
this_kind_correct = this_kind_correct && (p != build_context.ODIN_BUILD_PROJECT_NAME);
|
||||
} else {
|
||||
this_kind_correct = this_kind_correct && (p == build_context.ODIN_BUILD_PROJECT_NAME);
|
||||
}
|
||||
} while (s.len > 0);
|
||||
|
||||
any_correct = any_correct || this_kind_correct;
|
||||
}
|
||||
|
||||
return any_correct;
|
||||
}
|
||||
|
||||
bool parse_file(Parser *p, AstFile *f) {
|
||||
if (f->tokens.count == 0) {
|
||||
return true;
|
||||
@@ -5561,7 +5606,11 @@ bool parse_file(Parser *p, AstFile *f) {
|
||||
if (string_starts_with(str, str_lit("//"))) {
|
||||
String lc = string_trim_whitespace(substring(str, 2, str.len));
|
||||
if (lc.len > 0 && lc[0] == '+') {
|
||||
if (string_starts_with(lc, str_lit("+build"))) {
|
||||
if (string_starts_with(lc, str_lit("+build-project-name"))) {
|
||||
if (!parse_build_project_directory_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("+build"))) {
|
||||
if (!parse_build_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1428,7 +1428,7 @@ i64 matrix_align_of(Type *t, struct TypePath *tp) {
|
||||
}
|
||||
GB_ASSERT(min_alignment >= elem_align);
|
||||
|
||||
i64 align = gb_min(min_alignment, build_context.max_align);
|
||||
i64 align = gb_min(min_alignment, build_context.max_simd_align);
|
||||
return align;
|
||||
}
|
||||
|
||||
@@ -3556,7 +3556,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
|
||||
case Type_SimdVector: {
|
||||
// IMPORTANT TODO(bill): Figure out the alignment of vector types
|
||||
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align*2);
|
||||
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2);
|
||||
}
|
||||
|
||||
case Type_Matrix:
|
||||
@@ -3571,10 +3571,9 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
return build_context.word_size;
|
||||
}
|
||||
|
||||
// return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align);
|
||||
// NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types
|
||||
// TODO(bill): Is this correct for 128-bit types (integers)?
|
||||
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.word_size);
|
||||
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
|
||||
}
|
||||
|
||||
i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union) {
|
||||
|
||||
@@ -69,4 +69,9 @@ echo ---
|
||||
echo ---
|
||||
echo Running core:text/i18n tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe
|
||||
%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe
|
||||
|
||||
echo ---
|
||||
echo Running core:slice tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe
|
||||
182
tests/core/slice/test_core_slice.odin
Normal file
182
tests/core/slice/test_core_slice.odin
Normal file
@@ -0,0 +1,182 @@
|
||||
package test_core_slice
|
||||
|
||||
import "core:slice"
|
||||
import "core:testing"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:math/rand"
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
test_sort_with_indices(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_sort_with_indices :: proc(t: ^testing.T) {
|
||||
seed := rand.uint64()
|
||||
fmt.printf("Random seed: %v\n", seed)
|
||||
|
||||
// Test sizes are all prime.
|
||||
test_sizes :: []int{7, 13, 347, 1031, 10111, 100003}
|
||||
|
||||
for test_size in test_sizes {
|
||||
fmt.printf("Sorting %v random u64 values along with index.\n", test_size)
|
||||
|
||||
r := rand.create(seed)
|
||||
|
||||
vals := make([]u64, test_size)
|
||||
r_idx := make([]int, test_size) // Reverse index
|
||||
defer {
|
||||
delete(vals)
|
||||
delete(r_idx)
|
||||
}
|
||||
|
||||
// Set up test values
|
||||
for _, i in vals {
|
||||
vals[i] = rand.uint64(&r)
|
||||
}
|
||||
|
||||
// Sort
|
||||
f_idx := slice.sort_with_indices(vals)
|
||||
defer delete(f_idx)
|
||||
|
||||
// Verify sorted test values
|
||||
rand.init(&r, seed)
|
||||
|
||||
for v, i in f_idx {
|
||||
r_idx[v] = i
|
||||
}
|
||||
|
||||
last: u64
|
||||
for v, i in vals {
|
||||
if i > 0 {
|
||||
val_pass := v >= last
|
||||
expect(t, val_pass, "Expected values to have been sorted.")
|
||||
if !val_pass {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
idx_pass := vals[r_idx[i]] == rand.uint64(&r)
|
||||
expect(t, idx_pass, "Expected index to have been sorted.")
|
||||
if !idx_pass {
|
||||
break
|
||||
}
|
||||
last = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_sort_by_indices :: proc(t: ^testing.T) {
|
||||
seed := rand.uint64()
|
||||
fmt.printf("Random seed: %v\n", seed)
|
||||
|
||||
// Test sizes are all prime.
|
||||
test_sizes :: []int{7, 13, 347, 1031, 10111, 100003}
|
||||
|
||||
for test_size in test_sizes {
|
||||
fmt.printf("Sorting %v random u64 values along with index.\n", test_size)
|
||||
|
||||
r := rand.create(seed)
|
||||
|
||||
vals := make([]u64, test_size)
|
||||
r_idx := make([]int, test_size) // Reverse index
|
||||
defer {
|
||||
delete(vals)
|
||||
delete(r_idx)
|
||||
}
|
||||
|
||||
// Set up test values
|
||||
for _, i in vals {
|
||||
vals[i] = rand.uint64(&r)
|
||||
}
|
||||
|
||||
// Sort
|
||||
f_idx := slice.sort_with_indices(vals)
|
||||
defer delete(f_idx)
|
||||
|
||||
// Verify sorted test values
|
||||
rand.init(&r, seed)
|
||||
|
||||
{
|
||||
indices := make([]int, test_size)
|
||||
defer delete(indices)
|
||||
for _, i in indices {
|
||||
indices[i] = i
|
||||
}
|
||||
|
||||
sorted_indices := slice.sort_by_indices(indices, f_idx)
|
||||
defer delete(sorted_indices)
|
||||
for v, i in sorted_indices {
|
||||
idx_pass := v == f_idx[i]
|
||||
expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices")
|
||||
if !idx_pass {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
indices := make([]int, test_size)
|
||||
defer delete(indices)
|
||||
for _, i in indices {
|
||||
indices[i] = i
|
||||
}
|
||||
|
||||
slice.sort_by_indices_overwrite(indices, f_idx)
|
||||
for v, i in indices {
|
||||
idx_pass := v == f_idx[i]
|
||||
expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices")
|
||||
if !idx_pass {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
indices := make([]int, test_size)
|
||||
swap := make([]int, test_size)
|
||||
defer {
|
||||
delete(indices)
|
||||
delete(swap)
|
||||
}
|
||||
for _, i in indices {
|
||||
indices[i] = i
|
||||
}
|
||||
|
||||
slice.sort_by_indices(indices, swap, f_idx)
|
||||
for v, i in swap {
|
||||
idx_pass := v == f_idx[i]
|
||||
expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices")
|
||||
if !idx_pass {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ reflect_args_structure :: proc(ctx: ^Flag_Context, v: any) -> Flag_Error {
|
||||
type := types[i];
|
||||
|
||||
if named_type, ok := type.variant.(Type_Info_Named); ok {
|
||||
if union_type, ok := named_type.base.variant.(Type_Info_Union); ok && union_type.maybe && len(union_type.variants) == 1 {
|
||||
if union_type, ok := named_type.base.variant.(Type_Info_Union); ok && len(union_type.variants) == 1 {
|
||||
flag.optional = true;
|
||||
flag.tag_ptr = rawptr(uintptr(union_type.tag_offset) + uintptr(v.data) + uintptr(offsets[i]));
|
||||
type = union_type.variants[0];
|
||||
|
||||
@@ -70,7 +70,7 @@ walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
init_global_temporary_allocator(mem.megabytes(100));
|
||||
init_global_temporary_allocator(mem.Megabyte * 100)
|
||||
|
||||
args: Args;
|
||||
|
||||
|
||||
2
vendor/OpenGL/constants.odin
vendored
2
vendor/OpenGL/constants.odin
vendored
@@ -1,5 +1,7 @@
|
||||
package odin_gl
|
||||
|
||||
GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
|
||||
|
||||
FALSE :: false
|
||||
TRUE :: true
|
||||
|
||||
|
||||
2
vendor/OpenGL/helpers.odin
vendored
2
vendor/OpenGL/helpers.odin
vendored
@@ -46,7 +46,7 @@ get_last_error_message :: proc() -> (compile_message: string, compile_type: Shad
|
||||
// Shader checking and linking checking are identical
|
||||
// except for calling differently named GL functions
|
||||
// it's a bit ugly looking, but meh
|
||||
when ODIN_DEBUG {
|
||||
when GL_DEBUG {
|
||||
import "core:runtime"
|
||||
|
||||
@private
|
||||
|
||||
2
vendor/OpenGL/wrappers.odin
vendored
2
vendor/OpenGL/wrappers.odin
vendored
@@ -2,7 +2,7 @@ package odin_gl
|
||||
|
||||
#assert(size_of(bool) == size_of(u8))
|
||||
|
||||
when !ODIN_DEBUG {
|
||||
when !GL_DEBUG {
|
||||
// VERSION_1_0
|
||||
CullFace :: proc "c" (mode: u32) { impl_CullFace(mode) }
|
||||
FrontFace :: proc "c" (mode: u32) { impl_FrontFace(mode) }
|
||||
|
||||
9
vendor/README.md
vendored
9
vendor/README.md
vendored
@@ -134,4 +134,11 @@ See also LICENSE in the `GGPO` directory itself.
|
||||
`botan.lib` is available under Botan's [BSD](https://botan.randombit.net/license.txt) license.
|
||||
|
||||
See also LICENSE in the `botan` directory itself.
|
||||
Includes full bindings as well as wrappers to match the `core:crypto` API.
|
||||
Includes full bindings as well as wrappers to match the `core:crypto` API.
|
||||
|
||||
## CommonMark
|
||||
|
||||
[CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
|
||||
|
||||
See also LICENSE in the `commonmark` directory itself.
|
||||
Includes full bindings and Windows `.lib` and `.dll`.
|
||||
170
vendor/commonmark/LICENSE
vendored
Normal file
170
vendor/commonmark/LICENSE
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
Copyright (c) 2014, John MacFarlane
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-----
|
||||
|
||||
houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c
|
||||
|
||||
derive from https://github.com/vmg/houdini (with some modifications)
|
||||
|
||||
Copyright (C) 2012 Vicent Martí
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
buffer.h, buffer.c, chunk.h
|
||||
|
||||
are derived from code (C) 2012 Github, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
utf8.c and utf8.c
|
||||
|
||||
are derived from utf8proc
|
||||
(<http://www.public-software-group.org/utf8proc>),
|
||||
(C) 2009 Public Software Group e. V., Berlin, Germany.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
The normalization code in normalize.py was derived from the
|
||||
markdowntest project, Copyright 2013 Karl Dubost:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Karl Dubost
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-----
|
||||
|
||||
The CommonMark spec (test/spec.txt) is
|
||||
|
||||
Copyright (C) 2014-15 John MacFarlane
|
||||
|
||||
Released under the Creative Commons CC-BY-SA 4.0 license:
|
||||
<http://creativecommons.org/licenses/by-sa/4.0/>.
|
||||
|
||||
-----
|
||||
|
||||
The test software in test/ is
|
||||
|
||||
Copyright (c) 2014, John MacFarlane
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
4
vendor/commonmark/build.bat
vendored
Normal file
4
vendor/commonmark/build.bat
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
pushd W:\Odin-other\Odin-test
|
||||
call build.bat
|
||||
popd
|
||||
526
vendor/commonmark/cmark.odin
vendored
Normal file
526
vendor/commonmark/cmark.odin
vendored
Normal file
@@ -0,0 +1,526 @@
|
||||
/*
|
||||
Bindings against CMark (https://github.com/commonmark/cmark)
|
||||
|
||||
Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
|
||||
See LICENSE for license details.
|
||||
*/
|
||||
package commonmark
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
import "core:runtime"
|
||||
|
||||
BINDING_VERSION :: Version_Info{major = 0, minor = 30, patch = 2}
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import lib {
|
||||
"cmark_static.lib",
|
||||
}
|
||||
} else when ODIN_OS == .Linux {
|
||||
foreign import lib {
|
||||
"libcmark.a",
|
||||
}
|
||||
}
|
||||
|
||||
Option :: enum c.int {
|
||||
Source_Position = 1, // Include a `data-sourcepos` attribute on all block elements.
|
||||
Hard_Breaks = 2, // Render `softbreak` as hard line breaks.
|
||||
Safe = 3, // Defined for API compatibility, now enabled by default.
|
||||
Unsafe = 17, // Render raw HTML and unsafe links (`javascript:`, `vbscript:`,
|
||||
// `file:`, and `data:`, except for `image/png`, `image/gif`,
|
||||
// `image/jpeg`, or `image/webp` mime types). By default,
|
||||
// raw HTML is replaced by a placeholder HTML comment. Unsafe
|
||||
// links are replaced by empty strings.
|
||||
No_Breaks = 4, // Render `softbreak` elements as spaces.
|
||||
Normalize = 8, // Legacy option, no effect.
|
||||
Validate_UTF8 = 9, // Validate UTF-8 input before parsing, replacing illegal
|
||||
// sequences with the replacement character U+FFFD.
|
||||
Smart = 10, // Convert straight quotes to curly, --- to em dashes, -- to en dashes.
|
||||
}
|
||||
Options :: bit_set[Option; c.int]
|
||||
|
||||
DEFAULT_OPTIONS :: Options{}
|
||||
|
||||
Node_Type :: enum u16 {
|
||||
// Error status
|
||||
None = 0,
|
||||
|
||||
/* Block */
|
||||
Document,
|
||||
Block_Quote,
|
||||
List,
|
||||
Item,
|
||||
Code_Block,
|
||||
HTML_Block,
|
||||
Custom_Block,
|
||||
Paragraph,
|
||||
Heading,
|
||||
Thematic_Break,
|
||||
|
||||
/* Inline */
|
||||
Text,
|
||||
Soft_Break,
|
||||
Line_Break,
|
||||
Code,
|
||||
HTML_Inline,
|
||||
Custom_Inline,
|
||||
Emph,
|
||||
Strong,
|
||||
Link,
|
||||
Image,
|
||||
|
||||
First_Block = Document,
|
||||
Last_Block = Thematic_Break,
|
||||
|
||||
First_Inline = Text,
|
||||
Last_Inline = Image,
|
||||
}
|
||||
|
||||
List_Type :: enum c.int {
|
||||
None,
|
||||
Bullet,
|
||||
Ordered,
|
||||
}
|
||||
|
||||
Delim_Type :: enum c.int {
|
||||
None,
|
||||
Period,
|
||||
Paren,
|
||||
}
|
||||
|
||||
// Version information
|
||||
Version_Info :: struct {
|
||||
patch: u8,
|
||||
minor: u8,
|
||||
major: u8,
|
||||
_: u8,
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
version :: proc() -> (res: Version_Info) ---
|
||||
version_string :: proc() -> (res: cstring) ---
|
||||
}
|
||||
|
||||
// Simple API
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Convert 'text' (assumed to be a UTF-8 encoded string with length `len`) from CommonMark Markdown to HTML
|
||||
// returning a null-terminated, UTF-8-encoded string. It is the caller's responsibility
|
||||
// to free the returned buffer.
|
||||
markdown_to_html :: proc(text: cstring, length: c.size_t, options: Options) -> (html: cstring) ---
|
||||
}
|
||||
|
||||
markdown_to_html_from_string :: proc(text: string, options: Options) -> (html: string) {
|
||||
return string(markdown_to_html(cstring(raw_data(text)), len(text), options))
|
||||
}
|
||||
|
||||
// Custom allocator - Defines the memory allocation functions to be used by CMark
|
||||
// when parsing and allocating a document tree
|
||||
Allocator :: struct {
|
||||
calloc: proc "c" (num: c.size_t, size: c.size_t) -> rawptr,
|
||||
realloc: proc "c" (ptr: rawptr, new_size: c.size_t) -> rawptr,
|
||||
free: proc "c" (ptr: rawptr),
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Returns a pointer to the default memory allocator.
|
||||
get_default_mem_allocator :: proc() -> (mem: ^Allocator) ---
|
||||
}
|
||||
|
||||
bufsize_t :: distinct i32
|
||||
|
||||
// Node creation, destruction, and tree traversal
|
||||
Node :: struct {
|
||||
mem: ^Allocator,
|
||||
|
||||
next: ^Node,
|
||||
prev: ^Node,
|
||||
parent: ^Node,
|
||||
first_child: ^Node,
|
||||
last_child: ^Node,
|
||||
|
||||
user_data: rawptr,
|
||||
data: [^]u8,
|
||||
len: bufsize_t,
|
||||
|
||||
start_line: c.int,
|
||||
start_column: c.int,
|
||||
end_line: c.int,
|
||||
end_column: c.int,
|
||||
|
||||
type: Node_Type,
|
||||
flags: Node_Flags,
|
||||
|
||||
as: struct #raw_union {
|
||||
list: List,
|
||||
code: Code,
|
||||
heading: Heading,
|
||||
link: Link,
|
||||
custom: Custom,
|
||||
html_block_type: c.int,
|
||||
},
|
||||
}
|
||||
|
||||
Node_Flag :: enum u16 {
|
||||
Open = 0,
|
||||
Last_Line_Blank = 1,
|
||||
Last_Line_Checked = 2,
|
||||
}
|
||||
Node_Flags :: bit_set[Node_Flag; u16]
|
||||
|
||||
List :: struct {
|
||||
marker_offset: c.int,
|
||||
padding: c.int,
|
||||
start: c.int,
|
||||
list_type: u8,
|
||||
delimiter: u8,
|
||||
bullet_char: u8,
|
||||
tight: c.bool,
|
||||
}
|
||||
|
||||
Code :: struct {
|
||||
info: cstring,
|
||||
fence_length: u8,
|
||||
fence_offset: u8,
|
||||
fence_char: u8,
|
||||
fenced: b8,
|
||||
}
|
||||
|
||||
Heading :: struct {
|
||||
internal_offset: c.int,
|
||||
level: i8,
|
||||
setext: c.bool,
|
||||
}
|
||||
|
||||
|
||||
Link :: struct {
|
||||
url: cstring,
|
||||
title: cstring,
|
||||
}
|
||||
|
||||
Custom :: struct {
|
||||
on_enter: cstring,
|
||||
on_exit: cstring,
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Creates a new node of type 'type'.
|
||||
// Note that the node may have other required properties, which it is the caller's responsibility
|
||||
// to assign.
|
||||
node_new :: proc(type: Node_Type) -> (node: ^Node) ---
|
||||
|
||||
// Same as `node_new`, but explicitly listing the memory allocator used to allocate the node.
|
||||
// Note: be sure to use the same allocator for every node in a tree, or bad things can happen.
|
||||
node_new_with_mem :: proc(type: Node_Type, mem: ^Allocator) -> (node: ^Node) ---
|
||||
|
||||
// Frees the memory allocated for a node and any children.
|
||||
node_free :: proc(node: ^Node) ---
|
||||
|
||||
/*
|
||||
Tree Traversal
|
||||
*/
|
||||
// Returns the next node in the sequence after `node`, or nil if there is none.
|
||||
node_next :: proc(node: ^Node) -> (next: ^Node) ---
|
||||
|
||||
// Returns the previous node in the sequence after `node`, or nil if there is none.
|
||||
node_previous :: proc(node: ^Node) -> (prev: ^Node) ---
|
||||
|
||||
// Returns the parent of `node`, or nil if there is none.
|
||||
node_parent :: proc(node: ^Node) -> (parent: ^Node) ---
|
||||
|
||||
// Returns the first child of `node`, or nil if `node` has no children.
|
||||
node_first_child :: proc(node: ^Node) -> (child: ^Node) ---
|
||||
|
||||
// Returns the last child of `node`, or nil if `node` has no children.
|
||||
node_last_child :: proc(node: ^Node) -> (child: ^Node) ---
|
||||
|
||||
}
|
||||
|
||||
Iter :: distinct rawptr
|
||||
|
||||
Event_Type :: enum c.int {
|
||||
None,
|
||||
Done,
|
||||
Enter,
|
||||
Exit,
|
||||
}
|
||||
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Creates a new iterator starting at 'root'. The current node and event
|
||||
// type are undefined until `iter_next` is called for the first time.
|
||||
// The memory allocated for the iterator should be released using
|
||||
// 'iter_free' when it is no longer needed.
|
||||
iter_new :: proc(root: ^Node) -> (iter: ^Iter) ---
|
||||
|
||||
// Frees the memory allocated for an iterator.
|
||||
iter_free :: proc(iter: ^Iter) ---
|
||||
|
||||
// Advances to the next node and returns the event type (`.Enter`, `.Exit`, `.Done`)
|
||||
iter_next :: proc(iter: ^Iter) -> (event_type: Event_Type) ---
|
||||
|
||||
// Returns the current node.
|
||||
iter_get_node :: proc(iter: ^Iter) -> (node: ^Node) ---
|
||||
|
||||
// Returns the current event type.
|
||||
iter_get_event_type :: proc(iter: ^Iter) -> (event_type: Event_Type) ---
|
||||
|
||||
// Returns the root node.
|
||||
iter_get_root :: proc(iter: ^Iter) -> (root: ^Node) ---
|
||||
|
||||
// Resets the iterator so that the current node is `current` and
|
||||
// the event type is `event_type`. The new current node must be a
|
||||
// descendant of the root node or the root node itself.
|
||||
iter_reset :: proc(iter: ^Iter, current: ^Node, event_type: Event_Type) ---
|
||||
}
|
||||
|
||||
// Accessors
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Returns the user data of `node`.
|
||||
node_get_user_data :: proc(node: ^Node) -> (user_data: rawptr) ---
|
||||
|
||||
// Sets arbitrary user data for `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_user_data :: proc(node: ^Node, user_data: rawptr) -> (success: b32) ---
|
||||
|
||||
// Returns the type of `node`, or `.None` on error.
|
||||
node_get_type :: proc(node: ^Node) -> (node_type: Node_Type) ---
|
||||
|
||||
// Like `node_get_type`, but returns a string representation of the type, or "<unknown>".
|
||||
node_get_type_string :: proc(node: ^Node) -> (node_type: cstring) ---
|
||||
|
||||
// Returns the string contents of `node`, or an empty string if none is set.
|
||||
// Returns `nil` if called on a node that does not have string content.
|
||||
node_get_literal :: proc(node: ^Node) -> (content: cstring) ---
|
||||
|
||||
// Sets the string contents of `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_literal :: proc(node: ^Node, content: cstring) -> (success: b32) ---
|
||||
|
||||
// Returns the heading level of `node`, or 0 if `node` is not a heading.
|
||||
node_get_heading_level :: proc(node: ^Node) -> (level: c.int) ---
|
||||
|
||||
// Sets the heading level of `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_heading_level :: proc(node: ^Node, level: c.int) -> (success: b32) ---
|
||||
|
||||
// Returns the list type of `node`, or `.No_List` if not a list.
|
||||
node_get_list_type :: proc(node: ^Node) -> (list_type: List_Type) ---
|
||||
|
||||
// Sets the list type of `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_list_type :: proc(node: ^Node, list_type: List_Type) -> (success: b32) ---
|
||||
|
||||
// Returns the list delimiter type of `node`, or `.No_Delim` if not a list.
|
||||
node_get_list_delim :: proc(node: ^Node) -> (delim_type: Delim_Type) ---
|
||||
|
||||
// Sets the delimiter type of `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_list_delim :: proc(node: ^Node, delim_type: Delim_Type) -> (success: b32) ---
|
||||
|
||||
// Returns starting number of `node`, if it is an ordered list, otherwise 0.
|
||||
node_get_list_start :: proc(node: ^Node) -> (start: c.int) ---
|
||||
|
||||
// Sets starting number of `node`, if it is an ordered list.
|
||||
// Returns `true` on success, `false` on failure.
|
||||
node_set_list_start :: proc(node: ^Node, start: c.int) -> (success: b32) ---
|
||||
|
||||
// Returns `true` if `node` is a tight list, `false` otherwise.
|
||||
node_get_list_tight :: proc(node: ^Node) -> (tight: b32) ---
|
||||
|
||||
// Sets the "tightness" of a list. Returns `true` on success, `false` on failure.
|
||||
node_set_list_tight :: proc(node: ^Node, tight: b32) -> (success: b32) ---
|
||||
|
||||
// Returns the info string from a fenced code block.
|
||||
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.
|
||||
node_set_fence_info :: proc(node: ^Node, fence_info: cstring) -> (success: b32) ---
|
||||
|
||||
// Returns the URL of a link or image `node`, or an empty string if no URL is set.
|
||||
// Returns nil if called on a node that is not a link or image.
|
||||
node_get_url :: proc(node: ^Node) -> (url: cstring) ---
|
||||
|
||||
// Sets the URL of a link or image `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_url :: proc(node: ^Node, url: cstring) -> (success: b32) ---
|
||||
|
||||
// Returns the title of a link or image `node`, or an empty string if no title is set.
|
||||
// Returns nil if called on a node that is not a link or image.
|
||||
node_get_title :: proc(node: ^Node) -> (title: cstring) ---
|
||||
|
||||
// Sets the title of a link or image `node`. Returns `true` on success, `false` on failure.
|
||||
node_set_title :: proc(node: ^Node, title: cstring) -> (success: b32) ---
|
||||
|
||||
// Returns the literal "on enter" text for a custom `node`, or an empty string if no on_enter is set.
|
||||
// Returns nil if called on a non-custom node.
|
||||
node_get_on_enter :: proc(node: ^Node) -> (on_enter: cstring) ---
|
||||
|
||||
// Sets the literal text to render "on enter" for a custom `node`.
|
||||
// Any children of the node will be rendered after this text.
|
||||
// Returns `true` on success, `false`on failure.
|
||||
node_set_on_enter :: proc(node: ^Node, on_enter: cstring) -> (success: b32) ---
|
||||
|
||||
// Returns the line on which `node` begins.
|
||||
node_get_start_line :: proc(node: ^Node) -> (line: c.int) ---
|
||||
|
||||
// Returns the column at which `node` begins.
|
||||
node_get_start_column :: proc(node: ^Node) -> (column: c.int) ---
|
||||
|
||||
// Returns the line on which `node` ends.
|
||||
node_get_end_line :: proc(node: ^Node) -> (line: c.int) ---
|
||||
|
||||
// Returns the column at which `node` ends.
|
||||
node_get_end_column :: proc(node: ^Node) -> (column: c.int) ---
|
||||
}
|
||||
|
||||
// Tree Manipulation
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Unlinks a `node`, removing it from the tree, but not freeing its memory.
|
||||
// (Use `node_free` for that.)
|
||||
node_unlink :: proc(node: ^Node) ---
|
||||
|
||||
// Inserts 'sibling' before `node`. Returns `true` on success, `false` on failure.
|
||||
node_insert_before :: proc(node: ^Node, sibling: ^Node) -> (success: b32) ---
|
||||
|
||||
// Inserts 'sibling' after `node`. Returns `true` on success, `false` on failure.
|
||||
node_insert_after :: proc(node: ^Node, sibling: ^Node) -> (success: b32) ---
|
||||
|
||||
// Replaces 'oldnode' with 'newnode' and unlinks 'oldnode'
|
||||
// (but does not free its memory).
|
||||
// Returns `true` on success, `false` on failure.
|
||||
node_replace :: proc(old_node: ^Node, new_node: ^Node) -> (success: b32) ---
|
||||
|
||||
// Adds 'child' to the beginning of the children of `node`.
|
||||
// Returns `true` on success, `false` on failure.
|
||||
node_prepend_child :: proc(node: ^Node, child: ^Node) -> (success: b32) ---
|
||||
|
||||
// Adds 'child' to the end of the children of `node`.
|
||||
// Returns `true` on success, `false` on failure.
|
||||
node_append_child :: proc(node: ^Node, child: ^Node) -> (success: b32) ---
|
||||
|
||||
// Consolidates adjacent text nodes.
|
||||
consolidate_text_nodes :: proc(root: ^Node) ---
|
||||
}
|
||||
|
||||
Parser :: distinct rawptr
|
||||
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Creates a new parser object.
|
||||
parser_new :: proc(options: Options) -> (parser: ^Parser) ---
|
||||
|
||||
// Creates a new parser object with the given memory allocator.
|
||||
parser_new_with_mem :: proc(options: Options, mem: ^Allocator) -> (parser: ^Parser) ---
|
||||
|
||||
// Frees memory allocated for a parser object.
|
||||
parser_free :: proc(parser: ^Parser) ---
|
||||
|
||||
// Feeds a string of length 'len' to 'parser'.
|
||||
parser_feed :: proc(parser: ^Parser, buffer: [^]byte, len: c.size_t) ---
|
||||
|
||||
// Finish parsing and return a pointer to a tree of nodes.
|
||||
parser_finish :: proc(parser: ^Parser) -> (root: ^Node) ---
|
||||
|
||||
// Parse a CommonMark document in 'buffer' of length 'len'.
|
||||
// Returns a pointer to a tree of nodes. The memory allocated for
|
||||
// the node tree should be released using 'node_free' when it is no longer needed.
|
||||
parse_document :: proc(buffer: [^]byte, len: c.size_t, options: Options) -> (root: ^Node) ---
|
||||
|
||||
// Parse a CommonMark document in file 'f', returning a pointer to a tree of nodes.
|
||||
// The memory allocated for the node tree should be released using 'node_free'
|
||||
// when it is no longer needed.
|
||||
//
|
||||
// Called `parse_from_libc_file` so as not to confuse with Odin's file handling.
|
||||
|
||||
@(link_name = "parse_from_file")
|
||||
parse_from_libc_file :: proc(file: ^libc.FILE, options: Options) -> (root: ^Node) ---
|
||||
}
|
||||
|
||||
parser_feed_from_string :: proc "c" (parser: ^Parser, s: string) {
|
||||
parser_feed(parser, raw_data(s), len(s))
|
||||
}
|
||||
parse_document_from_string :: proc "c" (s: string, options: Options) -> (root: ^Node) {
|
||||
return parse_document(raw_data(s), len(s), options)
|
||||
}
|
||||
|
||||
// Rendering
|
||||
@(default_calling_convention="c", link_prefix="cmark_")
|
||||
foreign lib {
|
||||
// Render a `node` tree as XML.
|
||||
// It is the caller's responsibilityto free the returned buffer.
|
||||
render_xml :: proc(root: ^Node, options: Options) -> (xml: cstring) ---
|
||||
|
||||
// Render a `node` tree as an HTML fragment.
|
||||
// It is up to the user to add an appropriate header and footer.
|
||||
// It is the caller's responsibility to free the returned buffer.
|
||||
render_html :: proc(root: ^Node, options: Options) -> (html: cstring) ---
|
||||
|
||||
// Render a `node` tree as a groff man page, without the header.
|
||||
// It is the caller's responsibility to free the returned buffer.
|
||||
render_man :: proc(root: ^Node, options: Options, width: c.int) -> (groff: cstring) ---
|
||||
|
||||
// Render a `node` tree as a commonmark document.
|
||||
// It is the caller's responsibility to free the returned buffer.
|
||||
render_commonmark :: proc(root: ^Node, options: Options, width: c.int) -> (commonmark: cstring) ---
|
||||
|
||||
// Render a `node` tree as a LaTeX document.
|
||||
// It is the caller's responsibility to free the returned buffer.
|
||||
render_latex :: proc(root: ^Node, options: Options, width: c.int) -> (latex: cstring) ---
|
||||
}
|
||||
|
||||
// Helpers to free results from `render_*`.
|
||||
free_rawptr :: proc "c" (ptr: rawptr) {
|
||||
cmm := get_default_mem_allocator()
|
||||
cmm.free(ptr)
|
||||
}
|
||||
free_cstring :: proc "c" (str: cstring) {
|
||||
free_rawptr(rawptr(str))
|
||||
}
|
||||
free_string :: proc "c" (s: string) {
|
||||
free_rawptr(raw_data(s))
|
||||
}
|
||||
free :: proc{free_rawptr, free_cstring}
|
||||
|
||||
// Wrap CMark allocator as Odin allocator
|
||||
@(private)
|
||||
cmark_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) {
|
||||
|
||||
cmark_alloc := cast(^Allocator)allocator_data
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
ptr := cmark_alloc.calloc(1, c.size_t(size))
|
||||
res = transmute([]byte)runtime.Raw_Slice{ptr, size}
|
||||
return res, nil
|
||||
|
||||
case .Free:
|
||||
cmark_alloc.free(old_memory)
|
||||
return nil, nil
|
||||
|
||||
case .Free_All:
|
||||
return nil, .Mode_Not_Implemented
|
||||
|
||||
case .Resize:
|
||||
new_ptr := cmark_alloc.realloc(old_memory, c.size_t(size))
|
||||
res = transmute([]byte)runtime.Raw_Slice{new_ptr, size}
|
||||
if size > old_size {
|
||||
runtime.mem_zero(raw_data(res[old_size:]), size - old_size)
|
||||
}
|
||||
return res, nil
|
||||
|
||||
case .Query_Features:
|
||||
return nil, nil
|
||||
|
||||
case .Query_Info:
|
||||
return nil, .Mode_Not_Implemented
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
get_default_mem_allocator_as_odin :: proc() -> runtime.Allocator {
|
||||
return runtime.Allocator{
|
||||
procedure = cmark_allocator_proc,
|
||||
data = rawptr(get_default_mem_allocator()),
|
||||
}
|
||||
}
|
||||
BIN
vendor/commonmark/cmark_static.lib
vendored
Normal file
BIN
vendor/commonmark/cmark_static.lib
vendored
Normal file
Binary file not shown.
117
vendor/commonmark/doc.odin
vendored
Normal file
117
vendor/commonmark/doc.odin
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// +ignore
|
||||
/*
|
||||
Bindings against CMark (https://github.com/commonmark/cmark)
|
||||
|
||||
Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
|
||||
See LICENSE for license details.
|
||||
*/
|
||||
package commonmark
|
||||
|
||||
/*
|
||||
Parsing - Simple interface:
|
||||
|
||||
```odin
|
||||
import cm "vendor:commonmark"
|
||||
|
||||
hellope_world :: proc() {
|
||||
fmt.printf("CMark version: %v\n", cm.version_string())
|
||||
|
||||
str := "Hellope *world*!"
|
||||
root := cm.parse_document(raw_data(str), len(str), cm.DEFAULT_OPTIONS)
|
||||
defer cm.node_free(root)
|
||||
|
||||
html := cm.render_html(root, cm.DEFAULT_OPTIONS)
|
||||
defer cm.free(html)
|
||||
|
||||
fmt.println(html)
|
||||
}
|
||||
```
|
||||
|
||||
Parsing - Streaming interface:
|
||||
|
||||
```odin
|
||||
import cm "vendor:commonmark"
|
||||
|
||||
streaming :: proc() {
|
||||
using cm
|
||||
|
||||
STR :: "Hellope *world*!\n\n"
|
||||
N :: 50
|
||||
STREAM_SIZE :: 42
|
||||
|
||||
str_buf: [len(STR) * N]u8
|
||||
for i in 0..<N {
|
||||
copy(str_buf[i*len(STR):], STR)
|
||||
}
|
||||
|
||||
parser := parser_new(DEFAULT_OPTIONS)
|
||||
defer parser_free(parser)
|
||||
|
||||
buf := str_buf[:]
|
||||
for len(buf) > STREAM_SIZE {
|
||||
parser_feed(parser, raw_data(buf), STREAM_SIZE)
|
||||
buf = buf[STREAM_SIZE:]
|
||||
}
|
||||
|
||||
if len(buf) > 0 {
|
||||
parser_feed(parser, raw_data(buf), len(buf))
|
||||
buf = buf[len(buf):]
|
||||
}
|
||||
|
||||
root := parser_finish(parser)
|
||||
defer cm.node_free(root)
|
||||
|
||||
html := cm.render_html(root, cm.DEFAULT_OPTIONS)
|
||||
defer cm.free(html)
|
||||
|
||||
fmt.println(html)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
An iterator will walk through a tree of nodes, starting from a root
|
||||
node, returning one node at a time, together with information about
|
||||
whether the node is being entered or exited.
|
||||
|
||||
The iterator will first descend to a child node, if there is one.
|
||||
When there is no child, the iterator will go to the next sibling.
|
||||
When there is no next sibling, the iterator will return to the parent
|
||||
(but with an `Event_Type.Exit`).
|
||||
|
||||
The iterator will return `.Done` when it reaches the root node again.
|
||||
|
||||
One natural application is an HTML renderer, where an `.Enter` event
|
||||
outputs an open tag and an `.Exit` event outputs a close tag.
|
||||
|
||||
An iterator might also be used to transform an AST in some systematic
|
||||
way, for example, turning all level-3 headings into regular paragraphs.
|
||||
|
||||
```odin
|
||||
usage_example(root: ^Node) {
|
||||
ev_type: Event_Type
|
||||
iter := iter_new(root)
|
||||
defer iter_free(iter)
|
||||
for {
|
||||
ev_type = iter_next(iter)
|
||||
if ev_type == .Done do break
|
||||
cur := iter_get_node(iter)
|
||||
// Do something with `cur` and `ev_type`
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Iterators will never return `.Exit` events for leaf nodes,
|
||||
which are nodes of type:
|
||||
|
||||
* HTML_Block
|
||||
* Thematic_Break
|
||||
* Code_Block
|
||||
* Text
|
||||
* Soft_Break
|
||||
* Line_Break
|
||||
* Code
|
||||
* HTML_Inline
|
||||
|
||||
Nodes must only be modified after an `.Exit` event, or an `.Enter` event for
|
||||
leaf nodes.
|
||||
*/
|
||||
13
vendor/darwin/Foundation/NSWindow.odin
vendored
13
vendor/darwin/Foundation/NSWindow.odin
vendored
@@ -103,18 +103,7 @@ Window_alloc :: proc() -> ^Window {
|
||||
|
||||
@(objc_type=Window, objc_name="initWithContentRect")
|
||||
Window_initWithContentRect :: proc (self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: bool) -> ^Window {
|
||||
self := self
|
||||
// HACK: due to a compiler bug, the generated calling code does not
|
||||
// currently work for this message. Has to do with passing a struct along
|
||||
// with other parameters, so we don't send the rect here.
|
||||
// Omiting the rect argument here actually works, because of how the C
|
||||
// calling conventions are defined.
|
||||
self = msgSend(^Window, self, "initWithContentRect:styleMask:backing:defer:", styleMask, backing, doDefer)
|
||||
|
||||
// apply the contentRect now, since we did not pass it to the init call
|
||||
msgSend(nil, self, "setContentSize:", contentRect.size)
|
||||
msgSend(nil, self, "setFrameOrigin:", contentRect.origin)
|
||||
return self
|
||||
return msgSend(^Window, self, "initWithContentRect:styleMask:backing:defer:", contentRect, styleMask, backing, doDefer)
|
||||
}
|
||||
@(objc_type=Window, objc_name="contentView")
|
||||
Window_contentView :: proc(self: ^Window) -> ^View {
|
||||
|
||||
2
vendor/sdl2/sdl2.odin
vendored
2
vendor/sdl2/sdl2.odin
vendored
@@ -200,7 +200,7 @@ Locale :: struct {
|
||||
|
||||
@(default_calling_convention="c", link_prefix="SDL_")
|
||||
foreign lib {
|
||||
GetPreferredLocales :: proc() -> ^Locale ---
|
||||
GetPreferredLocales :: proc() -> [^]Locale ---
|
||||
}
|
||||
|
||||
// misc
|
||||
|
||||
2
vendor/wasm/js/runtime.js
vendored
2
vendor/wasm/js/runtime.js
vendored
@@ -1340,7 +1340,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
sqrt: (x) => Math.sqrt(x),
|
||||
sin: (x) => Math.sin(x),
|
||||
cos: (x) => Math.cos(x),
|
||||
pow: (x) => Math.pow(x),
|
||||
pow: (x, power) => Math.pow(x, power),
|
||||
fmuladd: (x, y, z) => x*y + z,
|
||||
ln: (x) => Math.log(x),
|
||||
exp: (x) => Math.exp(x),
|
||||
|
||||
Reference in New Issue
Block a user