Merge branch 'master' into windows-llvm-11.1.0

This commit is contained in:
gingerBill
2022-09-08 16:56:09 +01:00
87 changed files with 5011 additions and 660 deletions

View File

@@ -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

View File

@@ -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)"

View File

@@ -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}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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')
}
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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),
}
}

View File

@@ -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))) }

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -705,4 +705,4 @@ _alloc_command_line_arguments :: proc() -> []string {
res[i] = string(arg)
}
return res
}
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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]
}
/*

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View 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])
}
}

View File

@@ -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
View 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
*/

View 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
}
}

View 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)
}
}

View 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),
}
}

View 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)
}
}

View 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
}

View 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,
}

View 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

View File

@@ -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 {

View File

@@ -0,0 +1,6 @@
package unix
// OpenBSD 7.1 syscall numbers
// See: /usr/include/sys/syscall.h
SYS_sysctl : uintptr : 202

View 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

View 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

View 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

View File

@@ -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)
}

View 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")
}

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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] = {

View File

@@ -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},

View File

@@ -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"

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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:
{

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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

View 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
}
}
}
}
}

View File

@@ -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];

View File

@@ -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;

View File

@@ -1,5 +1,7 @@
package odin_gl
GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
FALSE :: false
TRUE :: true

View File

@@ -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

View File

@@ -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
View File

@@ -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
View 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
View 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
View 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

Binary file not shown.

117
vendor/commonmark/doc.odin vendored Normal file
View 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.
*/

View File

@@ -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 {

View File

@@ -200,7 +200,7 @@ Locale :: struct {
@(default_calling_convention="c", link_prefix="SDL_")
foreign lib {
GetPreferredLocales :: proc() -> ^Locale ---
GetPreferredLocales :: proc() -> [^]Locale ---
}
// misc

View File

@@ -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),