mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-01 20:28:15 +00:00
Merge branch 'master' into macharena
This commit is contained in:
@@ -257,7 +257,7 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
|
||||
for b.r+utf8.UTF_MAX > b.w &&
|
||||
!utf8.full_rune(b.buf[b.r:b.w]) &&
|
||||
b.err == nil &&
|
||||
b.w-b.w < len(b.buf) {
|
||||
b.w-b.r < len(b.buf) {
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds
|
||||
}
|
||||
|
||||
c_vec: simd.u8x16 = c
|
||||
when !simd.IS_EMULATED {
|
||||
when simd.HAS_HARDWARE_SIMD {
|
||||
// Note: While this is something that could also logically take
|
||||
// advantage of AVX512, the various downclocking and power
|
||||
// consumption related woes make premature to have a dedicated
|
||||
@@ -485,7 +485,7 @@ last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_che
|
||||
}
|
||||
|
||||
c_vec: simd.u8x16 = c
|
||||
when !simd.IS_EMULATED {
|
||||
when simd.HAS_HARDWARE_SIMD {
|
||||
// Note: While this is something that could also logically take
|
||||
// advantage of AVX512, the various downclocking and power
|
||||
// consumption related woes make premature to have a dedicated
|
||||
|
||||
@@ -139,9 +139,6 @@ Context_Memory_Input :: struct #packed {
|
||||
}
|
||||
when size_of(rawptr) == 8 {
|
||||
#assert(size_of(Context_Memory_Input) == 64)
|
||||
} else {
|
||||
// e.g. `-target:windows_i386`
|
||||
#assert(size_of(Context_Memory_Input) == 52)
|
||||
}
|
||||
|
||||
Context_Stream_Input :: struct #packed {
|
||||
|
||||
@@ -129,7 +129,7 @@ remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||
return false
|
||||
}
|
||||
_remove_node(c, e)
|
||||
free(node, c.node_allocator)
|
||||
free(e, c.node_allocator)
|
||||
c.count -= 1
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -133,12 +133,10 @@ pop_safe :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value:
|
||||
remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) {
|
||||
n := builtin.len(pq.queue)
|
||||
if 0 <= i && i < n {
|
||||
if n != i {
|
||||
pq.swap(pq.queue[:], i, n)
|
||||
_shift_down(pq, i, n)
|
||||
_shift_up(pq, i)
|
||||
}
|
||||
value, ok = builtin.pop_safe(&pq.queue)
|
||||
pq.swap(pq.queue[:], i, n-1)
|
||||
_shift_down(pq, i, n-1)
|
||||
_shift_up(pq, i)
|
||||
value, ok = builtin.pop(&pq.queue), true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import "core:sys/info"
|
||||
// is_supported returns true iff hardware accelerated AES
|
||||
// is supported.
|
||||
is_supported :: proc "contextless" () -> bool {
|
||||
features, ok := info.cpu_features.?
|
||||
features, ok := info.cpu.features.?
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 {
|
||||
|
||||
// Some targets lack runtime feature detection, and will flat out refuse
|
||||
// to load binaries that have unknown instructions. This is distinct from
|
||||
// `simd.IS_EMULATED` as actually good designs support runtime feature
|
||||
// `simd.HAS_HARDWARE_SIMD` as actually good designs support runtime feature
|
||||
// detection and that constant establishes a baseline.
|
||||
//
|
||||
// See:
|
||||
@@ -227,7 +227,7 @@ is_performant :: proc "contextless" () -> bool {
|
||||
req_features :: info.CPU_Features{.V}
|
||||
}
|
||||
|
||||
features, ok := info.cpu_features.?
|
||||
features, ok := info.cpu.features.?
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ _VEC_TWO: simd.u64x4 : {2, 0, 2, 0}
|
||||
is_performant :: proc "contextless" () -> bool {
|
||||
req_features :: info.CPU_Features{.avx, .avx2}
|
||||
|
||||
features, ok := info.cpu_features.?
|
||||
features, ok := info.cpu.features.?
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ K_15 :: simd.u64x2{0xa4506ceb90befffa, 0xc67178f2bef9a3f7}
|
||||
// is_hardware_accelerated_256 returns true iff hardware accelerated
|
||||
// SHA-224/SHA-256 is supported.
|
||||
is_hardware_accelerated_256 :: proc "contextless" () -> bool {
|
||||
features, ok := info.cpu_features.?
|
||||
features, ok := info.cpu.features.?
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -385,17 +385,17 @@ to_diagnostic_format_writer :: proc(w: io.Writer, val: Value, padding := 0) -> i
|
||||
// which we want for the diagnostic format.
|
||||
case f16:
|
||||
buf: [64]byte
|
||||
str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16))
|
||||
str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16))
|
||||
if str[0] == '+' && str != "+Inf" { str = str[1:] }
|
||||
io.write_string(w, str) or_return
|
||||
case f32:
|
||||
buf: [128]byte
|
||||
str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32))
|
||||
str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32))
|
||||
if str[0] == '+' && str != "+Inf" { str = str[1:] }
|
||||
io.write_string(w, str) or_return
|
||||
case f64:
|
||||
buf: [256]byte
|
||||
str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64))
|
||||
str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64))
|
||||
if str[0] == '+' && str != "+Inf" { str = str[1:] }
|
||||
io.write_string(w, str) or_return
|
||||
|
||||
|
||||
@@ -612,6 +612,42 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er
|
||||
case:
|
||||
panic("unknown bit_size size")
|
||||
}
|
||||
case runtime.Type_Info_Matrix:
|
||||
count := info.column_count * info.elem_stride
|
||||
err_conv(_encode_u64(e, u64(count), .Array)) or_return
|
||||
|
||||
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
|
||||
for i in 0..<count {
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
|
||||
for i in 0..<count {
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
|
||||
}
|
||||
return
|
||||
|
||||
case runtime.Type_Info_Simd_Vector:
|
||||
err_conv(_encode_u64(e, u64(info.count), .Array)) or_return
|
||||
|
||||
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
|
||||
for i in 0..<info.count {
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
|
||||
for i in 0..<info.count {
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size)
|
||||
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return _unsupported(v.id, nil)
|
||||
|
||||
@@ -29,6 +29,7 @@ an input.
|
||||
unmarshal :: proc {
|
||||
unmarshal_from_reader,
|
||||
unmarshal_from_string,
|
||||
unmarshal_from_bytes,
|
||||
}
|
||||
|
||||
unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
|
||||
@@ -51,6 +52,11 @@ unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, all
|
||||
return
|
||||
}
|
||||
|
||||
// Unmarshals from a slice of bytes, see docs on the proc group `Unmarshal` for more info.
|
||||
unmarshal_from_bytes :: proc(bytes: []byte, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
|
||||
return unmarshal_from_string(string(bytes), ptr, flags, allocator, temp_allocator, loc)
|
||||
}
|
||||
|
||||
unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
|
||||
d := d
|
||||
|
||||
@@ -487,7 +493,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
|
||||
data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return
|
||||
defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) }
|
||||
|
||||
da := mem.Raw_Dynamic_Array{raw_data(data), 0, length, context.allocator }
|
||||
da := mem.Raw_Dynamic_Array{raw_data(data), 0, scap, context.allocator }
|
||||
|
||||
assign_array(d, &da, t.elem, length) or_return
|
||||
|
||||
@@ -585,6 +591,31 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
|
||||
if out_of_space { return _unsupported(v, hdr) }
|
||||
return
|
||||
|
||||
case reflect.Type_Info_Matrix:
|
||||
count := t.column_count * t.elem_stride
|
||||
length, _ := err_conv(_decode_len_container(d, add)) or_return
|
||||
if length > count {
|
||||
return _unsupported(v, hdr)
|
||||
}
|
||||
|
||||
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
|
||||
|
||||
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
|
||||
if out_of_space { return _unsupported(v, hdr) }
|
||||
return
|
||||
|
||||
case reflect.Type_Info_Simd_Vector:
|
||||
length, _ := err_conv(_decode_len_container(d, add)) or_return
|
||||
if length > t.count {
|
||||
return _unsupported(v, hdr)
|
||||
}
|
||||
|
||||
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
|
||||
|
||||
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
|
||||
if out_of_space { return _unsupported(v, hdr) }
|
||||
return
|
||||
|
||||
case: return _unsupported(v, hdr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,6 @@ Example:
|
||||
read_csv_from_string :: proc(filename: string) {
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
csv_data, ok := os.read_entire_file(filename)
|
||||
|
||||
@@ -130,7 +130,7 @@ reader_destroy :: proc(r: ^Reader) {
|
||||
for record, row_idx in csv.iterator_next(&r) { ... }
|
||||
|
||||
TIP: If you process the results within the loop and don't need to own the results,
|
||||
you can set the Reader's `reuse_record` and `reuse_record_reuse_record_buffer` to true;
|
||||
you can set the Reader's `reuse_record` and `reuse_record_buffer` to true;
|
||||
you won't need to delete the record or its fields.
|
||||
*/
|
||||
iterator_next :: proc(r: ^Reader) -> (record: []string, idx: int, err: Error, more: bool) {
|
||||
|
||||
@@ -108,13 +108,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) {
|
||||
switch i in a {
|
||||
case u8, u16, u32, u64, u128:
|
||||
s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
|
||||
s = strconv.write_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
|
||||
|
||||
case:
|
||||
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
||||
s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
||||
}
|
||||
} else {
|
||||
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
||||
s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
|
||||
}
|
||||
|
||||
io.write_string(w, s) or_return
|
||||
@@ -286,7 +286,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
case runtime.Type_Info_Integer:
|
||||
buf: [40]byte
|
||||
u := cast_any_int_to_u128(ka)
|
||||
name = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil)
|
||||
name = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil)
|
||||
|
||||
opt_write_key(w, opt, name) or_return
|
||||
case: return .Unsupported_Type
|
||||
|
||||
@@ -101,7 +101,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
}
|
||||
}
|
||||
|
||||
scan_espace :: proc(t: ^Tokenizer) -> bool {
|
||||
scan_escape :: proc(t: ^Tokenizer) -> bool {
|
||||
switch t.r {
|
||||
case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f':
|
||||
next_rune(t)
|
||||
@@ -310,7 +310,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
break
|
||||
}
|
||||
if r == '\\' {
|
||||
scan_espace(t)
|
||||
scan_escape(t)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -406,6 +406,9 @@ unmarshal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_loca
|
||||
return prev
|
||||
}
|
||||
|
||||
// Struct tags can include not only the name of the JSON key, but also a tag such as `omitempty`.
|
||||
// Example: `json:"key_name,omitempty"`
|
||||
// This returns the first field as `json_name`, and the rest are returned as `extra`.
|
||||
@(private)
|
||||
json_name_from_tag_value :: proc(value: string) -> (json_name, extra: string) {
|
||||
json_name = value
|
||||
@@ -441,12 +444,6 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
defer delete(key, p.allocator)
|
||||
|
||||
unmarshal_expect_token(p, .Colon)
|
||||
|
||||
field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool {
|
||||
prev_set := field_used[offset/8] & byte(offset&7) != 0
|
||||
field_used[offset/8] |= byte(offset&7)
|
||||
return prev_set
|
||||
}
|
||||
|
||||
field_used_bytes := (reflect.size_of_typeid(ti.id)+7)/8
|
||||
field_used := intrinsics.alloca(field_used_bytes + 1, 1) // + 1 to not overflow on size_of 0 types.
|
||||
@@ -465,7 +462,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
|
||||
if use_field_idx < 0 {
|
||||
for field, field_idx in fields {
|
||||
if key == field.name {
|
||||
tag_value := reflect.struct_tag_get(field.tag, "json")
|
||||
json_name, _ := json_name_from_tag_value(tag_value)
|
||||
if json_name == "" && key == field.name {
|
||||
use_field_idx = field_idx
|
||||
break
|
||||
}
|
||||
@@ -486,7 +485,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
}
|
||||
}
|
||||
|
||||
if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) {
|
||||
tag_value := reflect.struct_tag_get(field.tag, "json")
|
||||
json_name, _ := json_name_from_tag_value(tag_value)
|
||||
if (json_name == "" && field.name == key) || json_name == key {
|
||||
offset = field.offset
|
||||
type = field.type
|
||||
found = true
|
||||
@@ -508,6 +509,11 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
}
|
||||
|
||||
if field_found {
|
||||
field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool {
|
||||
prev_set := field_used[offset/8] & byte(offset&7) != 0
|
||||
field_used[offset/8] |= byte(offset&7)
|
||||
return prev_set
|
||||
}
|
||||
if field_test(field_used, offset) {
|
||||
return .Multiple_Use_Field
|
||||
}
|
||||
|
||||
+4
-4
@@ -1122,7 +1122,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
|
||||
flags: strconv.Int_Flags
|
||||
if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} }
|
||||
if fi.plus { flags += {.Plus} }
|
||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||
s := strconv.write_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||
prev_zero := fi.zero
|
||||
defer fi.zero = prev_zero
|
||||
fi.zero = false
|
||||
@@ -1207,7 +1207,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
|
||||
flags: strconv.Int_Flags
|
||||
if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} }
|
||||
if fi.plus { flags += {.Plus} }
|
||||
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||
s := strconv.write_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||
|
||||
if fi.hash && fi.zero && fi.indent == 0 {
|
||||
c: byte = 0
|
||||
@@ -1272,7 +1272,7 @@ _fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: st
|
||||
}
|
||||
|
||||
buf: [256]byte
|
||||
str := strconv.append_float(buf[:], amt, 'f', prec, 64)
|
||||
str := strconv.write_float(buf[:], amt, 'f', prec, 64)
|
||||
|
||||
// Add the unit at the end.
|
||||
copy(buf[len(str):], units[off:off+unit_len])
|
||||
@@ -1424,7 +1424,7 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b
|
||||
buf: [386]byte
|
||||
|
||||
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
|
||||
str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size)
|
||||
str := strconv.write_float(buf[:], v, float_fmt, prec, bit_size)
|
||||
|
||||
if !fi.plus {
|
||||
// Strip sign from "+<value>" but not "+Inf".
|
||||
|
||||
+1
-82
@@ -317,85 +317,4 @@ crc32_table := [8][256]u32{
|
||||
0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53,
|
||||
0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@(optimization_mode="speed")
|
||||
crc32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 {
|
||||
result := ~u32(seed);
|
||||
#no_bounds_check for b in data {
|
||||
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
|
||||
|
||||
@private _crc32_table := [256]u32{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
*/
|
||||
}
|
||||
@@ -1212,7 +1212,6 @@ Filter_Params :: struct #packed {
|
||||
|
||||
depth_scale_table :: []u8{0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01}
|
||||
|
||||
// @(optimization_mode="speed")
|
||||
defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
|
||||
using params
|
||||
@@ -1273,7 +1272,6 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// @(optimization_mode="speed")
|
||||
defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check {
|
||||
|
||||
using params
|
||||
@@ -1436,7 +1434,6 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check {
|
||||
return true
|
||||
}
|
||||
|
||||
// @(optimization_mode="speed")
|
||||
defilter_16 :: proc(params: ^Filter_Params) -> bool {
|
||||
using params
|
||||
|
||||
|
||||
+8
-8
@@ -22,12 +22,12 @@ write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64, n_wri
|
||||
|
||||
write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [32]byte
|
||||
s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [32]byte
|
||||
s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
|
||||
@@ -40,18 +40,18 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (
|
||||
|
||||
write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [39]byte
|
||||
s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
|
||||
s := strconv.write_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [40]byte
|
||||
s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
|
||||
s := strconv.write_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [386]byte
|
||||
|
||||
str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
|
||||
str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
|
||||
s := buf[:len(str)+1]
|
||||
if s[1] == '+' || s[1] == '-' {
|
||||
s = s[1:]
|
||||
@@ -67,7 +67,7 @@ write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: E
|
||||
write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [386]byte
|
||||
|
||||
str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
|
||||
str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
|
||||
s := buf[:len(str)+1]
|
||||
if s[1] == '+' || s[1] == '-' {
|
||||
s = s[1:]
|
||||
@@ -83,7 +83,7 @@ write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: E
|
||||
write_f64 :: proc(w: Writer, val: f64, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [386]byte
|
||||
|
||||
str := strconv.append_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val))
|
||||
str := strconv.write_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val))
|
||||
s := buf[:len(str)+1]
|
||||
if s[1] == '+' || s[1] == '-' {
|
||||
s = s[1:]
|
||||
@@ -130,7 +130,7 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^
|
||||
write_string(w, `\x`, &n) or_return
|
||||
|
||||
buf: [2]byte
|
||||
s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
|
||||
switch len(s) {
|
||||
case 0:
|
||||
write_string(w, "00", &n) or_return
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
#+build !orca
|
||||
package log
|
||||
|
||||
import "core:encoding/ansi"
|
||||
import "base:runtime"
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
import "core:os"
|
||||
import "core:terminal"
|
||||
import "core:terminal/ansi"
|
||||
import "core:time"
|
||||
|
||||
Level_Headers := [?]string{
|
||||
@@ -37,11 +39,36 @@ File_Console_Logger_Data :: struct {
|
||||
ident: string,
|
||||
}
|
||||
|
||||
@(private) global_subtract_stdout_options: Options
|
||||
@(private) global_subtract_stderr_options: Options
|
||||
|
||||
@(init, private)
|
||||
init_standard_stream_status :: proc() {
|
||||
// NOTE(Feoramund): While it is technically possible for these streams to
|
||||
// be redirected during the runtime of the program, the cost of checking on
|
||||
// every single log message is not worth it to support such an
|
||||
// uncommonly-used feature.
|
||||
if terminal.color_enabled {
|
||||
// This is done this way because it's possible that only one of these
|
||||
// streams could be redirected to a file.
|
||||
if !terminal.is_terminal(os.stdout) {
|
||||
global_subtract_stdout_options = {.Terminal_Color}
|
||||
}
|
||||
if !terminal.is_terminal(os.stderr) {
|
||||
global_subtract_stderr_options = {.Terminal_Color}
|
||||
}
|
||||
} else {
|
||||
// Override any terminal coloring.
|
||||
global_subtract_stdout_options = {.Terminal_Color}
|
||||
global_subtract_stderr_options = {.Terminal_Color}
|
||||
}
|
||||
}
|
||||
|
||||
create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger {
|
||||
data := new(File_Console_Logger_Data, allocator)
|
||||
data.file_handle = h
|
||||
data.ident = ident
|
||||
return Logger{file_console_logger_proc, data, lowest, opt}
|
||||
return Logger{file_logger_proc, data, lowest, opt}
|
||||
}
|
||||
|
||||
destroy_file_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
@@ -56,19 +83,15 @@ create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logg
|
||||
data := new(File_Console_Logger_Data, allocator)
|
||||
data.file_handle = os.INVALID_HANDLE
|
||||
data.ident = ident
|
||||
return Logger{file_console_logger_proc, data, lowest, opt}
|
||||
return Logger{console_logger_proc, data, lowest, opt}
|
||||
}
|
||||
|
||||
destroy_console_logger :: proc(log: Logger, allocator := context.allocator) {
|
||||
free(log.data, allocator)
|
||||
}
|
||||
|
||||
file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
data := cast(^File_Console_Logger_Data)logger_data
|
||||
h: os.Handle = os.stdout if level <= Level.Error else os.stderr
|
||||
if data.file_handle != os.INVALID_HANDLE {
|
||||
h = data.file_handle
|
||||
}
|
||||
@(private)
|
||||
_file_console_logger_proc :: proc(h: os.Handle, ident: string, level: Level, text: string, options: Options, location: runtime.Source_Code_Location) {
|
||||
backing: [1024]byte //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths.
|
||||
buf := strings.builder_from_bytes(backing[:])
|
||||
|
||||
@@ -86,13 +109,32 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string
|
||||
fmt.sbprintf(&buf, "[{}] ", os.current_thread_id())
|
||||
}
|
||||
|
||||
if data.ident != "" {
|
||||
fmt.sbprintf(&buf, "[%s] ", data.ident)
|
||||
if ident != "" {
|
||||
fmt.sbprintf(&buf, "[%s] ", ident)
|
||||
}
|
||||
//TODO(Hoej): When we have better atomics and such, make this thread-safe
|
||||
fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text)
|
||||
}
|
||||
|
||||
file_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
data := cast(^File_Console_Logger_Data)logger_data
|
||||
_file_console_logger_proc(data.file_handle, data.ident, level, text, options, location)
|
||||
}
|
||||
|
||||
console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
options := options
|
||||
data := cast(^File_Console_Logger_Data)logger_data
|
||||
h: os.Handle = ---
|
||||
if level < Level.Error {
|
||||
h = os.stdout
|
||||
options -= global_subtract_stdout_options
|
||||
} else {
|
||||
h = os.stderr
|
||||
options -= global_subtract_stderr_options
|
||||
}
|
||||
_file_console_logger_proc(h, data.ident, level, text, options, location)
|
||||
}
|
||||
|
||||
do_level_header :: proc(opts: Options, str: ^strings.Builder, level: Level) {
|
||||
|
||||
RESET :: ansi.CSI + ansi.RESET + ansi.SGR
|
||||
|
||||
@@ -1370,8 +1370,8 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator :=
|
||||
|
||||
/*
|
||||
Slower bit-bang division... also smaller.
|
||||
Prefer `_int_div_school` for speed.
|
||||
*/
|
||||
@(deprecated="Use `_int_div_school`, it's 3.5x faster.")
|
||||
_private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
|
||||
|
||||
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{}
|
||||
|
||||
@@ -280,7 +280,7 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context
|
||||
}
|
||||
|
||||
pos := ch - '+'
|
||||
if RADIX_TABLE_REVERSE_SIZE <= pos {
|
||||
if RADIX_TABLE_REVERSE_SIZE <= u32(pos) {
|
||||
break
|
||||
}
|
||||
y := RADIX_TABLE_REVERSE[pos]
|
||||
|
||||
@@ -103,7 +103,7 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
write :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
Integer_Width :: 8*size_of(Backing) - Fraction_Width
|
||||
|
||||
x := x
|
||||
@@ -124,16 +124,16 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
|
||||
when size_of(Backing) < 16 {
|
||||
T :: u64
|
||||
append_uint :: strconv.append_uint
|
||||
write_uint :: strconv.write_uint
|
||||
} else {
|
||||
T :: u128
|
||||
append_uint :: strconv.append_u128
|
||||
write_uint :: strconv.write_u128
|
||||
}
|
||||
|
||||
integer := T(x.i) >> Fraction_Width
|
||||
fraction := T(x.i) & (1<<Fraction_Width - 1)
|
||||
|
||||
s := append_uint(buf[i:], integer, 10)
|
||||
s := write_uint(buf[i:], integer, 10)
|
||||
i += len(s)
|
||||
if fraction != 0 {
|
||||
buf[i] = '.'
|
||||
@@ -155,7 +155,7 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
@(require_results)
|
||||
to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
|
||||
buf: [48]byte
|
||||
s := append(buf[:], x)
|
||||
s := write(buf[:], x)
|
||||
str := make([]byte, len(s), allocator)
|
||||
copy(str, s)
|
||||
return string(str)
|
||||
@@ -294,3 +294,8 @@ _power_of_two_table := [129]string{
|
||||
"85070591730234615865843651857942052864",
|
||||
"170141183460469231731687303715884105728",
|
||||
}
|
||||
|
||||
@(deprecated="Use write instead")
|
||||
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
return write(dst, x)
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ Example:
|
||||
Possible Output:
|
||||
|
||||
6
|
||||
500
|
||||
13
|
||||
|
||||
*/
|
||||
@(require_results)
|
||||
|
||||
+25
-5
@@ -315,18 +315,38 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
|
||||
Offset a given pointer by a given amount.
|
||||
|
||||
This procedure offsets the pointer `ptr` to an object of type `T`, by the amount
|
||||
of bytes specified by `offset*size_of(T)`, and returns the pointer `ptr`.
|
||||
of bytes specified by `offset * size_of(T)`, and returns the pointer `ptr`.
|
||||
|
||||
**Note**: Prefer to use multipointer types, if possible.
|
||||
*/
|
||||
ptr_offset :: intrinsics.ptr_offset
|
||||
|
||||
/*
|
||||
Offset a given pointer by a given amount backwards.
|
||||
Subtract two pointers of the same type, and return the number of `T` between them.
|
||||
|
||||
This procedure offsets the pointer `ptr` to an object of type `T`, by the amount
|
||||
of bytes specified by `offset*size_of(T)` in the negative direction, and
|
||||
returns the pointer `ptr`.
|
||||
This procedure subtracts pointer `b` from pointer `a`, both of type `^T`,
|
||||
and returns an integer count of the `T` between them.
|
||||
|
||||
**Inputs**
|
||||
- `a`: A pointer to a type T
|
||||
- `b`: A pointer to a type T
|
||||
|
||||
**Returns**
|
||||
- `b` - `a` in items of T as an `int`.
|
||||
|
||||
Example:
|
||||
|
||||
import "core:mem"
|
||||
import "core:fmt"
|
||||
|
||||
ptr_sub_example :: proc() {
|
||||
arr: [2]int
|
||||
fmt.println(mem.ptr_sub(&arr[1], &arr[0]))
|
||||
}
|
||||
|
||||
Output:
|
||||
|
||||
1
|
||||
*/
|
||||
ptr_sub :: intrinsics.ptr_sub
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mem
|
||||
|
||||
import "base:runtime"
|
||||
import "base:sanitizer"
|
||||
|
||||
/*
|
||||
Rollback stack default block size.
|
||||
@@ -47,14 +48,14 @@ Rollback_Stack :: struct {
|
||||
block_allocator: Allocator,
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
@(private="file", require_results, no_sanitize_address)
|
||||
rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool {
|
||||
start := raw_data(block.buffer)
|
||||
end := start[block.offset:]
|
||||
return start < ptr && ptr <= end
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
@(private="file", require_results, no_sanitize_address)
|
||||
rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> (
|
||||
parent: ^Rollback_Stack_Block,
|
||||
block: ^Rollback_Stack_Block,
|
||||
@@ -71,7 +72,7 @@ rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> (
|
||||
return nil, nil, nil, .Invalid_Pointer
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
@(private="file", require_results, no_sanitize_address)
|
||||
rb_find_last_alloc :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> (
|
||||
block: ^Rollback_Stack_Block,
|
||||
header: ^Rollback_Stack_Header,
|
||||
@@ -86,9 +87,10 @@ rb_find_last_alloc :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> (
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
@(private="file", no_sanitize_address)
|
||||
rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_Header) {
|
||||
header := header
|
||||
|
||||
for block.offset > 0 && header.is_free {
|
||||
block.offset = header.prev_offset
|
||||
block.last_alloc = raw_data(block.buffer)[header.prev_ptr:]
|
||||
@@ -99,9 +101,10 @@ rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_
|
||||
/*
|
||||
Free memory to a rollback stack allocator.
|
||||
*/
|
||||
@(private="file", require_results)
|
||||
@(private="file", require_results, no_sanitize_address)
|
||||
rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error {
|
||||
parent, block, header := rb_find_ptr(stack, ptr) or_return
|
||||
|
||||
if header.is_free {
|
||||
return .Invalid_Pointer
|
||||
}
|
||||
@@ -120,7 +123,7 @@ rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error {
|
||||
/*
|
||||
Free all memory owned by the rollback stack allocator.
|
||||
*/
|
||||
@(private="file")
|
||||
@(private="file", no_sanitize_address)
|
||||
rb_free_all :: proc(stack: ^Rollback_Stack) {
|
||||
for block := stack.head.next_block; block != nil; /**/ {
|
||||
next_block := block.next_block
|
||||
@@ -131,12 +134,13 @@ rb_free_all :: proc(stack: ^Rollback_Stack) {
|
||||
stack.head.next_block = nil
|
||||
stack.head.last_alloc = nil
|
||||
stack.head.offset = 0
|
||||
sanitizer.address_poison(stack.head.buffer)
|
||||
}
|
||||
|
||||
/*
|
||||
Allocate memory using the rollback stack allocator.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_alloc :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
size: int,
|
||||
@@ -153,7 +157,7 @@ rb_alloc :: proc(
|
||||
/*
|
||||
Allocate memory using the rollback stack allocator.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_alloc_bytes :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
size: int,
|
||||
@@ -170,7 +174,7 @@ rb_alloc_bytes :: proc(
|
||||
/*
|
||||
Allocate non-initialized memory using the rollback stack allocator.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_alloc_non_zeroed :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
size: int,
|
||||
@@ -184,7 +188,7 @@ rb_alloc_non_zeroed :: proc(
|
||||
/*
|
||||
Allocate non-initialized memory using the rollback stack allocator.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_alloc_bytes_non_zeroed :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
size: int,
|
||||
@@ -194,6 +198,7 @@ rb_alloc_bytes_non_zeroed :: proc(
|
||||
assert(size >= 0, "Size must be positive or zero.", loc)
|
||||
assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", loc)
|
||||
parent: ^Rollback_Stack_Block
|
||||
|
||||
for block := stack.head; /**/; block = block.next_block {
|
||||
when !ODIN_DISABLE_ASSERT {
|
||||
allocated_new_block: bool
|
||||
@@ -235,7 +240,9 @@ rb_alloc_bytes_non_zeroed :: proc(
|
||||
// Prevent any further allocations on it.
|
||||
block.offset = cast(uintptr)len(block.buffer)
|
||||
}
|
||||
#no_bounds_check return ptr[:size], nil
|
||||
res := ptr[:size]
|
||||
sanitizer.address_unpoison(res)
|
||||
return res, nil
|
||||
}
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
@@ -243,7 +250,7 @@ rb_alloc_bytes_non_zeroed :: proc(
|
||||
/*
|
||||
Resize an allocation owned by rollback stack allocator.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_resize :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
old_ptr: rawptr,
|
||||
@@ -266,7 +273,7 @@ rb_resize :: proc(
|
||||
/*
|
||||
Resize an allocation owned by rollback stack allocator.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_resize_bytes :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
old_memory: []byte,
|
||||
@@ -289,7 +296,7 @@ rb_resize_bytes :: proc(
|
||||
Resize an allocation owned by rollback stack allocator without explicit
|
||||
zero-initialization.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_resize_non_zeroed :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
old_ptr: rawptr,
|
||||
@@ -306,7 +313,7 @@ rb_resize_non_zeroed :: proc(
|
||||
Resize an allocation owned by rollback stack allocator without explicit
|
||||
zero-initialization.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rb_resize_bytes_non_zeroed :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
old_memory: []byte,
|
||||
@@ -330,7 +337,9 @@ rb_resize_bytes_non_zeroed :: proc(
|
||||
if len(block.buffer) <= stack.block_size {
|
||||
block.offset += cast(uintptr)size - cast(uintptr)old_size
|
||||
}
|
||||
#no_bounds_check return (ptr)[:size], nil
|
||||
res := (ptr)[:size]
|
||||
sanitizer.address_unpoison(res)
|
||||
#no_bounds_check return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,7 +349,7 @@ rb_resize_bytes_non_zeroed :: proc(
|
||||
return
|
||||
}
|
||||
|
||||
@(private="file", require_results)
|
||||
@(private="file", require_results, no_sanitize_address)
|
||||
rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stack_Block, err: Allocator_Error) {
|
||||
buffer := runtime.mem_alloc(size_of(Rollback_Stack_Block) + size, align_of(Rollback_Stack_Block), allocator) or_return
|
||||
block = cast(^Rollback_Stack_Block)raw_data(buffer)
|
||||
@@ -351,6 +360,7 @@ rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stac
|
||||
/*
|
||||
Initialize the rollback stack allocator using a fixed backing buffer.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, location := #caller_location) {
|
||||
MIN_SIZE :: size_of(Rollback_Stack_Block) + size_of(Rollback_Stack_Header) + size_of(rawptr)
|
||||
assert(len(buffer) >= MIN_SIZE, "User-provided buffer to Rollback Stack Allocator is too small.", location)
|
||||
@@ -365,6 +375,7 @@ rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, loc
|
||||
/*
|
||||
Initialize the rollback stack alocator using a backing block allocator.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
rollback_stack_init_dynamic :: proc(
|
||||
stack: ^Rollback_Stack,
|
||||
block_size : int = ROLLBACK_STACK_DEFAULT_BLOCK_SIZE,
|
||||
@@ -396,6 +407,7 @@ rollback_stack_init :: proc {
|
||||
/*
|
||||
Destroy a rollback stack.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
rollback_stack_destroy :: proc(stack: ^Rollback_Stack) {
|
||||
if stack.block_allocator.procedure != nil {
|
||||
rb_free_all(stack)
|
||||
@@ -435,7 +447,7 @@ from the last allocation backwards.
|
||||
Each allocation has an overhead of 8 bytes and any extra bytes to satisfy
|
||||
the requested alignment.
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator {
|
||||
return Allocator {
|
||||
data = stack,
|
||||
@@ -443,7 +455,7 @@ rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator {
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
rollback_stack_allocator_proc :: proc(
|
||||
allocator_data: rawptr,
|
||||
mode: Allocator_Mode,
|
||||
|
||||
@@ -198,4 +198,4 @@ fls :: proc "contextless" (word: u32) -> (bit: i32) {
|
||||
fls_uint :: proc "contextless" (size: uint) -> (bit: i32) {
|
||||
N :: (size_of(uint) * 8) - 1
|
||||
return i32(N - intrinsics.count_leading_zeros(size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
package mem_tlsf
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:sanitizer"
|
||||
import "base:runtime"
|
||||
|
||||
// log2 of number of linear subdivisions of block sizes.
|
||||
@@ -209,6 +210,8 @@ alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) ->
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
||||
sanitizer.address_poison(new_pool_buf)
|
||||
|
||||
// Allocate a new link in the `control.pool` tracking structure.
|
||||
new_pool := new_clone(Pool{
|
||||
data = new_pool_buf,
|
||||
@@ -254,7 +257,7 @@ alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) ->
|
||||
return block_prepare_used(control, block, adjust)
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
alloc_bytes :: proc(control: ^Allocator, size: uint, align: uint) -> (res: []byte, err: runtime.Allocator_Error) {
|
||||
res, err = alloc_bytes_non_zeroed(control, size, align)
|
||||
if err == nil {
|
||||
@@ -273,6 +276,7 @@ free_with_size :: proc(control: ^Allocator, ptr: rawptr, size: uint) {
|
||||
|
||||
block := block_from_ptr(ptr)
|
||||
assert(!block_is_free(block), "block already marked as free") // double free
|
||||
sanitizer.address_poison(ptr, block.size)
|
||||
block_mark_as_free(block)
|
||||
block = block_merge_prev(control, block)
|
||||
block = block_merge_next(control, block)
|
||||
@@ -316,6 +320,7 @@ resize :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: uint, align
|
||||
|
||||
block_trim_used(control, block, adjust)
|
||||
res = ([^]byte)(ptr)[:new_size]
|
||||
sanitizer.address_unpoison(res)
|
||||
|
||||
if min_size < new_size {
|
||||
to_zero := ([^]byte)(ptr)[min_size:new_size]
|
||||
@@ -374,95 +379,96 @@ resize_non_zeroed :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size:
|
||||
NOTE: TLSF spec relies on ffs/fls returning a value in the range 0..31.
|
||||
*/
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_size :: proc "contextless" (block: ^Block_Header) -> (size: uint) {
|
||||
return block.size &~ (BLOCK_HEADER_FREE | BLOCK_HEADER_PREV_FREE)
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_set_size :: proc "contextless" (block: ^Block_Header, size: uint) {
|
||||
old_size := block.size
|
||||
block.size = size | (old_size & (BLOCK_HEADER_FREE | BLOCK_HEADER_PREV_FREE))
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_is_last :: proc "contextless" (block: ^Block_Header) -> (is_last: bool) {
|
||||
return block_size(block) == 0
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_is_free :: proc "contextless" (block: ^Block_Header) -> (is_free: bool) {
|
||||
return (block.size & BLOCK_HEADER_FREE) == BLOCK_HEADER_FREE
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_set_free :: proc "contextless" (block: ^Block_Header) {
|
||||
block.size |= BLOCK_HEADER_FREE
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_set_used :: proc "contextless" (block: ^Block_Header) {
|
||||
block.size &~= BLOCK_HEADER_FREE
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_is_prev_free :: proc "contextless" (block: ^Block_Header) -> (is_prev_free: bool) {
|
||||
return (block.size & BLOCK_HEADER_PREV_FREE) == BLOCK_HEADER_PREV_FREE
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_set_prev_free :: proc "contextless" (block: ^Block_Header) {
|
||||
block.size |= BLOCK_HEADER_PREV_FREE
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_set_prev_used :: proc "contextless" (block: ^Block_Header) {
|
||||
block.size &~= BLOCK_HEADER_PREV_FREE
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_from_ptr :: proc(ptr: rawptr) -> (block_ptr: ^Block_Header) {
|
||||
return (^Block_Header)(uintptr(ptr) - BLOCK_START_OFFSET)
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_to_ptr :: proc(block: ^Block_Header) -> (ptr: rawptr) {
|
||||
return rawptr(uintptr(block) + BLOCK_START_OFFSET)
|
||||
}
|
||||
|
||||
// Return location of next block after block of given size.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
offset_to_block :: proc(ptr: rawptr, size: uint) -> (block: ^Block_Header) {
|
||||
return (^Block_Header)(uintptr(ptr) + uintptr(size))
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
offset_to_block_backwards :: proc(ptr: rawptr, size: uint) -> (block: ^Block_Header) {
|
||||
return (^Block_Header)(uintptr(ptr) - uintptr(size))
|
||||
}
|
||||
|
||||
// Return location of previous block.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_prev :: proc(block: ^Block_Header) -> (prev: ^Block_Header) {
|
||||
assert(block_is_prev_free(block), "previous block must be free")
|
||||
|
||||
return block.prev_phys_block
|
||||
}
|
||||
|
||||
// Return location of next existing block.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) {
|
||||
return offset_to_block(block_to_ptr(block), block_size(block) - BLOCK_HEADER_OVERHEAD)
|
||||
}
|
||||
|
||||
// Link a new block with its physical neighbor, return the neighbor.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_link_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) {
|
||||
next = block_next(block)
|
||||
next.prev_phys_block = block
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_mark_as_free :: proc(block: ^Block_Header) {
|
||||
// Link the block to the next block, first.
|
||||
next := block_link_next(block)
|
||||
@@ -470,26 +476,26 @@ block_mark_as_free :: proc(block: ^Block_Header) {
|
||||
block_set_free(block)
|
||||
}
|
||||
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_mark_as_used :: proc(block: ^Block_Header) {
|
||||
next := block_next(block)
|
||||
block_set_prev_used(next)
|
||||
block_set_used(block)
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
align_up :: proc(x, align: uint) -> (aligned: uint) {
|
||||
assert(0 == (align & (align - 1)), "must align to a power of two")
|
||||
return (x + (align - 1)) &~ (align - 1)
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
align_down :: proc(x, align: uint) -> (aligned: uint) {
|
||||
assert(0 == (align & (align - 1)), "must align to a power of two")
|
||||
return x - (x & (align - 1))
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
align_ptr :: proc(ptr: rawptr, align: uint) -> (aligned: rawptr) {
|
||||
assert(0 == (align & (align - 1)), "must align to a power of two")
|
||||
align_mask := uintptr(align) - 1
|
||||
@@ -499,7 +505,7 @@ align_ptr :: proc(ptr: rawptr, align: uint) -> (aligned: rawptr) {
|
||||
}
|
||||
|
||||
// Adjust an allocation size to be aligned to word size, and no smaller than internal minimum.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
adjust_request_size :: proc(size, align: uint) -> (adjusted: uint) {
|
||||
if size == 0 {
|
||||
return 0
|
||||
@@ -513,7 +519,7 @@ adjust_request_size :: proc(size, align: uint) -> (adjusted: uint) {
|
||||
}
|
||||
|
||||
// Adjust an allocation size to be aligned to word size, and no smaller than internal minimum.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
adjust_request_size_with_err :: proc(size, align: uint) -> (adjusted: uint, err: runtime.Allocator_Error) {
|
||||
if size == 0 {
|
||||
return 0, nil
|
||||
@@ -531,7 +537,7 @@ adjust_request_size_with_err :: proc(size, align: uint) -> (adjusted: uint, err:
|
||||
// TLSF utility functions. In most cases these are direct translations of
|
||||
// the documentation in the research paper.
|
||||
|
||||
@(optimization_mode="favor_size", private, require_results)
|
||||
@(optimization_mode="favor_size", private, require_results, no_sanitize_address)
|
||||
mapping_insert :: proc(size: uint) -> (fl, sl: i32) {
|
||||
if size < SMALL_BLOCK_SIZE {
|
||||
// Store small blocks in first list.
|
||||
@@ -544,7 +550,7 @@ mapping_insert :: proc(size: uint) -> (fl, sl: i32) {
|
||||
return
|
||||
}
|
||||
|
||||
@(optimization_mode="favor_size", private, require_results)
|
||||
@(optimization_mode="favor_size", private, require_results, no_sanitize_address)
|
||||
mapping_round :: #force_inline proc(size: uint) -> (rounded: uint) {
|
||||
rounded = size
|
||||
if size >= SMALL_BLOCK_SIZE {
|
||||
@@ -555,12 +561,12 @@ mapping_round :: #force_inline proc(size: uint) -> (rounded: uint) {
|
||||
}
|
||||
|
||||
// This version rounds up to the next block size (for allocations)
|
||||
@(optimization_mode="favor_size", private, require_results)
|
||||
@(optimization_mode="favor_size", private, require_results, no_sanitize_address)
|
||||
mapping_search :: proc(size: uint) -> (fl, sl: i32) {
|
||||
return mapping_insert(mapping_round(size))
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
search_suitable_block :: proc(control: ^Allocator, fli, sli: ^i32) -> (block: ^Block_Header) {
|
||||
// First, search for a block in the list associated with the given fl/sl index.
|
||||
fl := fli^; sl := sli^
|
||||
@@ -587,7 +593,7 @@ search_suitable_block :: proc(control: ^Allocator, fli, sli: ^i32) -> (block: ^B
|
||||
}
|
||||
|
||||
// Remove a free block from the free list.
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
remove_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl: i32) {
|
||||
prev := block.prev_free
|
||||
next := block.next_free
|
||||
@@ -613,7 +619,7 @@ remove_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl
|
||||
}
|
||||
|
||||
// Insert a free block into the free block list.
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
insert_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl: i32) {
|
||||
current := control.blocks[fl][sl]
|
||||
assert(current != nil, "free lists cannot have a nil entry")
|
||||
@@ -631,26 +637,26 @@ insert_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl
|
||||
}
|
||||
|
||||
// Remove a given block from the free list.
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_remove :: proc(control: ^Allocator, block: ^Block_Header) {
|
||||
fl, sl := mapping_insert(block_size(block))
|
||||
remove_free_block(control, block, fl, sl)
|
||||
}
|
||||
|
||||
// Insert a given block into the free list.
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_insert :: proc(control: ^Allocator, block: ^Block_Header) {
|
||||
fl, sl := mapping_insert(block_size(block))
|
||||
insert_free_block(control, block, fl, sl)
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_can_split :: proc(block: ^Block_Header, size: uint) -> (can_split: bool) {
|
||||
return block_size(block) >= size_of(Block_Header) + size
|
||||
}
|
||||
|
||||
// Split a block into two, the second of which is free.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_split :: proc(block: ^Block_Header, size: uint) -> (remaining: ^Block_Header) {
|
||||
// Calculate the amount of space left in the remaining block.
|
||||
remaining = offset_to_block(block_to_ptr(block), size - BLOCK_HEADER_OVERHEAD)
|
||||
@@ -671,9 +677,10 @@ block_split :: proc(block: ^Block_Header, size: uint) -> (remaining: ^Block_Head
|
||||
}
|
||||
|
||||
// Absorb a free block's storage into an adjacent previous free block.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_absorb :: proc(prev: ^Block_Header, block: ^Block_Header) -> (absorbed: ^Block_Header) {
|
||||
assert(!block_is_last(prev), "previous block can't be last")
|
||||
|
||||
// Note: Leaves flags untouched.
|
||||
prev.size += block_size(block) + BLOCK_HEADER_OVERHEAD
|
||||
_ = block_link_next(prev)
|
||||
@@ -681,7 +688,7 @@ block_absorb :: proc(prev: ^Block_Header, block: ^Block_Header) -> (absorbed: ^B
|
||||
}
|
||||
|
||||
// Merge a just-freed block with an adjacent previous free block.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_merge_prev :: proc(control: ^Allocator, block: ^Block_Header) -> (merged: ^Block_Header) {
|
||||
merged = block
|
||||
if (block_is_prev_free(block)) {
|
||||
@@ -695,7 +702,7 @@ block_merge_prev :: proc(control: ^Allocator, block: ^Block_Header) -> (merged:
|
||||
}
|
||||
|
||||
// Merge a just-freed block with an adjacent free block.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_merge_next :: proc(control: ^Allocator, block: ^Block_Header) -> (merged: ^Block_Header) {
|
||||
merged = block
|
||||
next := block_next(block)
|
||||
@@ -710,7 +717,7 @@ block_merge_next :: proc(control: ^Allocator, block: ^Block_Header) -> (merged:
|
||||
}
|
||||
|
||||
// Trim any trailing block space off the end of a free block, return to pool.
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_trim_free :: proc(control: ^Allocator, block: ^Block_Header, size: uint) {
|
||||
assert(block_is_free(block), "block must be free")
|
||||
if (block_can_split(block, size)) {
|
||||
@@ -722,7 +729,7 @@ block_trim_free :: proc(control: ^Allocator, block: ^Block_Header, size: uint) {
|
||||
}
|
||||
|
||||
// Trim any trailing block space off the end of a used block, return to pool.
|
||||
@(private)
|
||||
@(private, no_sanitize_address)
|
||||
block_trim_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) {
|
||||
assert(!block_is_free(block), "Block must be used")
|
||||
if (block_can_split(block, size)) {
|
||||
@@ -736,7 +743,7 @@ block_trim_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) {
|
||||
}
|
||||
|
||||
// Trim leading block space, return to pool.
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_trim_free_leading :: proc(control: ^Allocator, block: ^Block_Header, size: uint) -> (remaining: ^Block_Header) {
|
||||
remaining = block
|
||||
if block_can_split(block, size) {
|
||||
@@ -750,7 +757,7 @@ block_trim_free_leading :: proc(control: ^Allocator, block: ^Block_Header, size:
|
||||
return remaining
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_locate_free :: proc(control: ^Allocator, size: uint) -> (block: ^Block_Header) {
|
||||
fl, sl: i32
|
||||
if size != 0 {
|
||||
@@ -774,13 +781,14 @@ block_locate_free :: proc(control: ^Allocator, size: uint) -> (block: ^Block_Hea
|
||||
return block
|
||||
}
|
||||
|
||||
@(private, require_results)
|
||||
@(private, require_results, no_sanitize_address)
|
||||
block_prepare_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) -> (res: []byte, err: runtime.Allocator_Error) {
|
||||
if block != nil {
|
||||
assert(size != 0, "Size must be non-zero")
|
||||
block_trim_free(control, block, size)
|
||||
block_mark_as_used(block)
|
||||
res = ([^]byte)(block_to_ptr(block))[:size]
|
||||
sanitizer.address_unpoison(res)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ This procedure initializes the tracking allocator `t` with a backing allocator
|
||||
specified with `backing_allocator`. The `internals_allocator` will used to
|
||||
allocate the tracked data.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Allocator, internals_allocator := context.allocator) {
|
||||
t.backing = backing_allocator
|
||||
t.allocation_map.allocator = internals_allocator
|
||||
@@ -77,6 +78,7 @@ tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Alloc
|
||||
/*
|
||||
Destroy the tracking allocator.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
|
||||
delete(t.allocation_map)
|
||||
delete(t.bad_free_array)
|
||||
@@ -90,6 +92,7 @@ This procedure clears the tracked data from a tracking allocator.
|
||||
**Note**: This procedure clears only the current allocation data while keeping
|
||||
the totals intact.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
|
||||
sync.mutex_lock(&t.mutex)
|
||||
clear(&t.allocation_map)
|
||||
@@ -103,6 +106,7 @@ Reset the tracking allocator.
|
||||
|
||||
Reset all of a Tracking Allocator's allocation data back to zero.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_reset :: proc(t: ^Tracking_Allocator) {
|
||||
sync.mutex_lock(&t.mutex)
|
||||
clear(&t.allocation_map)
|
||||
@@ -124,6 +128,7 @@ Override Tracking_Allocator.bad_free_callback to have something else happen. For
|
||||
example, you can use tracking_allocator_bad_free_callback_add_to_array to return
|
||||
the tracking allocator to the old behavior, where the bad_free_array was used.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_bad_free_callback_panic :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) {
|
||||
runtime.print_caller_location(location)
|
||||
runtime.print_string(" Tracking allocator error: Bad free of pointer ")
|
||||
@@ -136,6 +141,7 @@ tracking_allocator_bad_free_callback_panic :: proc(t: ^Tracking_Allocator, memor
|
||||
Alternative behavior for a bad free: Store in `bad_free_array`. If you use this,
|
||||
then you must make sure to check Tracking_Allocator.bad_free_array at some point.
|
||||
*/
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_bad_free_callback_add_to_array :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) {
|
||||
append(&t.bad_free_array, Tracking_Allocator_Bad_Free_Entry {
|
||||
memory = memory,
|
||||
@@ -175,7 +181,7 @@ Example:
|
||||
}
|
||||
}
|
||||
*/
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
data = data,
|
||||
@@ -183,6 +189,7 @@ tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
||||
}
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
tracking_allocator_proc :: proc(
|
||||
allocator_data: rawptr,
|
||||
mode: Allocator_Mode,
|
||||
@@ -191,6 +198,7 @@ tracking_allocator_proc :: proc(
|
||||
old_size: int,
|
||||
loc := #caller_location,
|
||||
) -> (result: []byte, err: Allocator_Error) {
|
||||
@(no_sanitize_address)
|
||||
track_alloc :: proc(data: ^Tracking_Allocator, entry: ^Tracking_Allocator_Entry) {
|
||||
data.total_memory_allocated += i64(entry.size)
|
||||
data.total_allocation_count += 1
|
||||
@@ -200,6 +208,7 @@ tracking_allocator_proc :: proc(
|
||||
}
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
track_free :: proc(data: ^Tracking_Allocator, entry: ^Tracking_Allocator_Entry) {
|
||||
data.total_memory_freed += i64(entry.size)
|
||||
data.total_free_count += 1
|
||||
|
||||
+32
-11
@@ -3,6 +3,8 @@ package mem_virtual
|
||||
import "core:mem"
|
||||
import "core:sync"
|
||||
|
||||
import "base:sanitizer"
|
||||
|
||||
Arena_Kind :: enum uint {
|
||||
Growing = 0, // Chained memory blocks (singly linked list).
|
||||
Static = 1, // Fixed reservation sized.
|
||||
@@ -43,7 +45,7 @@ DEFAULT_ARENA_STATIC_RESERVE_SIZE :: mem.Gigabyte when size_of(uintptr) == 8 els
|
||||
|
||||
// Initialization of an `Arena` to be a `.Growing` variant.
|
||||
// A growing arena is a linked list of `Memory_Block`s allocated with virtual memory.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
|
||||
arena.kind = .Growing
|
||||
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
|
||||
@@ -53,24 +55,26 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
|
||||
if arena.minimum_block_size == 0 {
|
||||
arena.minimum_block_size = reserved
|
||||
}
|
||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Initialization of an `Arena` to be a `.Static` variant.
|
||||
// A static arena contains a single `Memory_Block` allocated with virtual memory.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_init_static :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_STATIC_RESERVE_SIZE, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
|
||||
arena.kind = .Static
|
||||
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
||||
arena.total_used = 0
|
||||
arena.total_reserved = arena.curr_block.reserved
|
||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||
return
|
||||
}
|
||||
|
||||
// Initialization of an `Arena` to be a `.Buffer` variant.
|
||||
// A buffer arena contains single `Memory_Block` created from a user provided []byte.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Error) {
|
||||
if len(buffer) < size_of(Memory_Block) {
|
||||
return .Out_Of_Memory
|
||||
@@ -78,7 +82,7 @@ arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Erro
|
||||
|
||||
arena.kind = .Buffer
|
||||
|
||||
mem.zero_slice(buffer)
|
||||
sanitizer.address_poison(buffer[:])
|
||||
|
||||
block_base := raw_data(buffer)
|
||||
block := (^Memory_Block)(block_base)
|
||||
@@ -94,7 +98,7 @@ arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Erro
|
||||
}
|
||||
|
||||
// Allocates memory from the provided arena.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc)
|
||||
|
||||
@@ -158,10 +162,13 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
||||
data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=0)
|
||||
arena.total_used = arena.curr_block.used
|
||||
}
|
||||
|
||||
sanitizer.address_unpoison(data)
|
||||
return
|
||||
}
|
||||
|
||||
// Resets the memory of a Static or Buffer arena to a specific `position` (offset) and zeroes the previously used memory.
|
||||
@(no_sanitize_address)
|
||||
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
@@ -175,6 +182,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location)
|
||||
mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:prev_pos-pos])
|
||||
}
|
||||
arena.total_used = arena.curr_block.used
|
||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||
return true
|
||||
} else if pos == 0 {
|
||||
arena.total_used = 0
|
||||
@@ -184,6 +192,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location)
|
||||
}
|
||||
|
||||
// Frees the last memory block of a Growing Arena
|
||||
@(no_sanitize_address)
|
||||
arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
if free_block := arena.curr_block; free_block != nil {
|
||||
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
|
||||
@@ -191,11 +200,13 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat
|
||||
arena.total_reserved -= free_block.reserved
|
||||
|
||||
arena.curr_block = free_block.prev
|
||||
sanitizer.address_poison(free_block.base[:free_block.committed])
|
||||
memory_block_dealloc(free_block)
|
||||
}
|
||||
}
|
||||
|
||||
// Deallocates all but the first memory block of the arena and resets the allocator's usage to 0.
|
||||
@(no_sanitize_address)
|
||||
arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
switch arena.kind {
|
||||
case .Growing:
|
||||
@@ -208,7 +219,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
if arena.curr_block != nil {
|
||||
curr_block_used := int(arena.curr_block.used)
|
||||
arena.curr_block.used = 0
|
||||
sanitizer.address_unpoison(arena.curr_block.base[:curr_block_used])
|
||||
mem.zero(arena.curr_block.base, curr_block_used)
|
||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||
}
|
||||
arena.total_used = 0
|
||||
case .Static, .Buffer:
|
||||
@@ -219,6 +232,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
|
||||
// Frees all of the memory allocated by the arena and zeros all of the values of an arena.
|
||||
// A buffer based arena does not `delete` the provided `[]byte` bufffer.
|
||||
@(no_sanitize_address)
|
||||
arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
switch arena.kind {
|
||||
@@ -250,7 +264,7 @@ arena_static_bootstrap_new :: proc{
|
||||
}
|
||||
|
||||
// Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
||||
bootstrap: Arena
|
||||
bootstrap.kind = .Growing
|
||||
@@ -266,13 +280,13 @@ arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintp
|
||||
}
|
||||
|
||||
// Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
|
||||
return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
|
||||
}
|
||||
|
||||
// Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
||||
bootstrap: Arena
|
||||
bootstrap.kind = .Static
|
||||
@@ -288,19 +302,20 @@ arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintpt
|
||||
}
|
||||
|
||||
// Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
|
||||
return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
|
||||
}
|
||||
|
||||
|
||||
// Create an `Allocator` from the provided `Arena`
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
|
||||
return mem.Allocator{arena_allocator_proc, arena}
|
||||
}
|
||||
|
||||
// The allocator procedure used by an `Allocator` produced by `arena_allocator`
|
||||
@(no_sanitize_address)
|
||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int,
|
||||
@@ -334,6 +349,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
if size < old_size {
|
||||
// shrink data in-place
|
||||
data = old_data[:size]
|
||||
sanitizer.address_poison(old_data[size:old_size])
|
||||
return
|
||||
}
|
||||
|
||||
@@ -347,6 +363,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
_ = alloc_from_memory_block(block, new_end - old_end, 1, default_commit_size=arena.default_commit_size) or_return
|
||||
arena.total_used += block.used - prev_used
|
||||
data = block.base[start:new_end]
|
||||
sanitizer.address_unpoison(data)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -357,6 +374,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
return
|
||||
}
|
||||
copy(new_memory, old_data[:old_size])
|
||||
sanitizer.address_poison(old_data[:old_size])
|
||||
return new_memory, nil
|
||||
case .Query_Features:
|
||||
set := (^mem.Allocator_Mode_Set)(old_memory)
|
||||
@@ -382,7 +400,7 @@ Arena_Temp :: struct {
|
||||
}
|
||||
|
||||
// Begins the section of temporary arena memory.
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
assert(arena != nil, "nil arena", loc)
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
@@ -397,6 +415,7 @@ arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena
|
||||
}
|
||||
|
||||
// Ends the section of temporary arena memory by resetting the memory to the stored position.
|
||||
@(no_sanitize_address)
|
||||
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
assert(temp.arena != nil, "nil arena", loc)
|
||||
arena := temp.arena
|
||||
@@ -432,6 +451,7 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
}
|
||||
|
||||
// Ignore the use of a `arena_temp_begin` entirely by __not__ resetting to the stored position.
|
||||
@(no_sanitize_address)
|
||||
arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
assert(temp.arena != nil, "nil arena", loc)
|
||||
arena := temp.arena
|
||||
@@ -442,6 +462,7 @@ arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
}
|
||||
|
||||
// Asserts that all uses of `Arena_Temp` has been used by an `Arena`
|
||||
@(no_sanitize_address)
|
||||
arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package mem_virtual
|
||||
|
||||
import "core:mem"
|
||||
import "base:intrinsics"
|
||||
import "base:sanitizer"
|
||||
import "base:runtime"
|
||||
_ :: runtime
|
||||
|
||||
@@ -14,27 +15,33 @@ platform_memory_init :: proc() {
|
||||
|
||||
Allocator_Error :: mem.Allocator_Error
|
||||
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
return _reserve(size)
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
sanitizer.address_unpoison(data, size)
|
||||
return _commit(data, size)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
data = reserve(size) or_return
|
||||
commit(raw_data(data), size) or_return
|
||||
return
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
sanitizer.address_poison(data, size)
|
||||
_decommit(data, size)
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
sanitizer.address_unpoison(data, size)
|
||||
_release(data, size)
|
||||
}
|
||||
|
||||
@@ -46,13 +53,11 @@ Protect_Flag :: enum u32 {
|
||||
Protect_Flags :: distinct bit_set[Protect_Flag; u32]
|
||||
Protect_No_Access :: Protect_Flags{}
|
||||
|
||||
@(no_sanitize_address)
|
||||
protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
return _protect(data, size, flags)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Memory_Block :: struct {
|
||||
prev: ^Memory_Block,
|
||||
base: [^]byte,
|
||||
@@ -66,13 +71,13 @@ Memory_Block_Flag :: enum u32 {
|
||||
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
|
||||
|
||||
|
||||
@(private="file", require_results)
|
||||
@(private="file", require_results, no_sanitize_address)
|
||||
align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint {
|
||||
result := size + align-1
|
||||
return result - result%align
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags: Memory_Block_Flags = {}) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
page_size := DEFAULT_PAGE_SIZE
|
||||
assert(mem.is_power_of_two(uintptr(page_size)))
|
||||
@@ -116,8 +121,9 @@ memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags
|
||||
return &pmblock.block, nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@(require_results, no_sanitize_address)
|
||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint, default_commit_size: uint = 0) -> (data: []byte, err: Allocator_Error) {
|
||||
@(no_sanitize_address)
|
||||
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||
alignment_offset := uint(0)
|
||||
ptr := uintptr(block.base[block.used:])
|
||||
@@ -128,6 +134,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint,
|
||||
return alignment_offset
|
||||
|
||||
}
|
||||
@(no_sanitize_address)
|
||||
do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint, default_commit_size: uint) -> (err: Allocator_Error) {
|
||||
if block.committed - block.used < size {
|
||||
pmblock := (^Platform_Memory_Block)(block)
|
||||
@@ -172,10 +179,12 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint,
|
||||
|
||||
data = block.base[block.used+alignment_offset:][:min_size]
|
||||
block.used += size
|
||||
sanitizer.address_unpoison(data)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
|
||||
if block := (^Platform_Memory_Block)(block_to_free); block != nil {
|
||||
platform_memory_free(block)
|
||||
|
||||
@@ -7,6 +7,7 @@ Platform_Memory_Block :: struct {
|
||||
reserved: uint,
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
||||
to_commit, to_reserve := to_commit, to_reserve
|
||||
to_reserve = max(to_commit, to_reserve)
|
||||
@@ -26,12 +27,14 @@ platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (bl
|
||||
}
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) {
|
||||
if block != nil {
|
||||
release(block, block.reserved)
|
||||
}
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
|
||||
if to_commit < block.committed {
|
||||
return nil
|
||||
|
||||
@@ -83,6 +83,8 @@ foreign Kernel32 {
|
||||
dwNumberOfBytesToMap: uint,
|
||||
) -> rawptr ---
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
|
||||
if result == nil {
|
||||
@@ -93,6 +95,7 @@ _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Err
|
||||
return
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
|
||||
if result == nil {
|
||||
@@ -107,12 +110,18 @@ _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
VirtualFree(data, size, MEM_DECOMMIT)
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
VirtualFree(data, 0, MEM_RELEASE)
|
||||
}
|
||||
|
||||
@(no_sanitize_address)
|
||||
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
pflags: u32
|
||||
pflags = PAGE_NOACCESS
|
||||
@@ -136,7 +145,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
_platform_memory_init :: proc() {
|
||||
sys_info: SYSTEM_INFO
|
||||
GetSystemInfo(&sys_info)
|
||||
@@ -147,6 +156,7 @@ _platform_memory_init :: proc() {
|
||||
}
|
||||
|
||||
|
||||
@(no_sanitize_address)
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
page_flags: u32
|
||||
if flags == {.Read} {
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ percent_encode :: proc(s: string, allocator := context.allocator) -> string {
|
||||
bytes, n := utf8.encode_rune(ch)
|
||||
for byte in bytes[:n] {
|
||||
buf: [2]u8 = ---
|
||||
t := strconv.append_int(buf[:], i64(byte), 16)
|
||||
t := strconv.write_int(buf[:], i64(byte), 16)
|
||||
strings.write_rune(&b, '%')
|
||||
strings.write_string(&b, t)
|
||||
}
|
||||
|
||||
@@ -1276,28 +1276,28 @@ parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast
|
||||
args = make([dynamic]^ast.Expr)
|
||||
for p.curr_tok.kind != .Close_Paren &&
|
||||
p.curr_tok.kind != .EOF {
|
||||
arg := parse_value(p)
|
||||
arg := parse_value(p)
|
||||
|
||||
if p.curr_tok.kind == .Eq {
|
||||
eq := expect_token(p, .Eq)
|
||||
if arg != nil {
|
||||
if _, ok := arg.derived.(^ast.Ident); !ok {
|
||||
error(p, arg.pos, "expected an identifier for 'key=value'")
|
||||
}
|
||||
}
|
||||
value := parse_value(p)
|
||||
fv := ast.new(ast.Field_Value, arg.pos, value)
|
||||
fv.field = arg
|
||||
fv.sep = eq.pos
|
||||
fv.value = value
|
||||
if p.curr_tok.kind == .Eq {
|
||||
eq := expect_token(p, .Eq)
|
||||
if arg != nil {
|
||||
if _, ok := arg.derived.(^ast.Ident); !ok {
|
||||
error(p, arg.pos, "expected an identifier for 'key=value'")
|
||||
}
|
||||
}
|
||||
value := parse_value(p)
|
||||
fv := ast.new(ast.Field_Value, arg.pos, value)
|
||||
fv.field = arg
|
||||
fv.sep = eq.pos
|
||||
fv.value = value
|
||||
|
||||
arg = fv
|
||||
}
|
||||
arg = fv
|
||||
}
|
||||
|
||||
append(&args, arg)
|
||||
append(&args, arg)
|
||||
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.expr_level -= 1
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ write_encoded_rune :: proc(f: Handle, r: rune) -> (n: int, err: Error) {
|
||||
if r < 32 {
|
||||
if wrap(write_string(f, "\\x"), &n, &err) { return }
|
||||
b: [2]byte
|
||||
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
|
||||
switch len(s) {
|
||||
case 0: if wrap(write_string(f, "00"), &n, &err) { return }
|
||||
case 1: if wrap(write_rune(f, '0'), &n, &err) { return }
|
||||
|
||||
+42
-41
@@ -8,43 +8,13 @@ file_allocator :: proc() -> runtime.Allocator {
|
||||
return heap_allocator()
|
||||
}
|
||||
|
||||
temp_allocator_proc :: runtime.arena_allocator_proc
|
||||
|
||||
@(private="file")
|
||||
MAX_TEMP_ARENA_COUNT :: 2
|
||||
|
||||
@(private="file")
|
||||
MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1
|
||||
@(private="file", thread_local)
|
||||
global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena
|
||||
|
||||
@(private="file", thread_local)
|
||||
global_default_temp_allocator_index: uint
|
||||
|
||||
|
||||
@(require_results)
|
||||
temp_allocator :: proc() -> runtime.Allocator {
|
||||
arena := &global_default_temp_allocator_arenas[global_default_temp_allocator_index]
|
||||
if arena.backing_allocator.procedure == nil {
|
||||
arena.backing_allocator = heap_allocator()
|
||||
}
|
||||
|
||||
return runtime.Allocator{
|
||||
procedure = temp_allocator_proc,
|
||||
data = arena,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: runtime.Arena_Temp) {
|
||||
temp = runtime.arena_temp_begin(&global_default_temp_allocator_arenas[global_default_temp_allocator_index], loc)
|
||||
return
|
||||
}
|
||||
|
||||
temp_allocator_temp_end :: proc(temp: runtime.Arena_Temp, loc := #caller_location) {
|
||||
runtime.arena_temp_end(temp, loc)
|
||||
}
|
||||
|
||||
@(fini, private)
|
||||
temp_allocator_fini :: proc() {
|
||||
for &arena in global_default_temp_allocator_arenas {
|
||||
@@ -53,18 +23,49 @@ temp_allocator_fini :: proc() {
|
||||
global_default_temp_allocator_arenas = {}
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp, loc := #caller_location) {
|
||||
runtime.arena_temp_end(temp, loc)
|
||||
if temp.arena != nil {
|
||||
global_default_temp_allocator_index = (global_default_temp_allocator_index-1)%MAX_TEMP_ARENA_COUNT
|
||||
}
|
||||
Temp_Allocator :: struct {
|
||||
using arena: ^runtime.Arena,
|
||||
using allocator: runtime.Allocator,
|
||||
tmp: runtime.Arena_Temp,
|
||||
loc: runtime.Source_Code_Location,
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD_END :: proc(temp: Temp_Allocator) {
|
||||
runtime.arena_temp_end(temp.tmp, temp.loc)
|
||||
}
|
||||
|
||||
@(deferred_out=TEMP_ALLOCATOR_GUARD_END)
|
||||
TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) {
|
||||
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
|
||||
tmp := temp_allocator_temp_begin(loc)
|
||||
return tmp, loc
|
||||
TEMP_ALLOCATOR_GUARD :: #force_inline proc(collisions: []runtime.Allocator, loc := #caller_location) -> Temp_Allocator {
|
||||
assert(len(collisions) <= MAX_TEMP_ARENA_COLLISIONS, "Maximum collision count exceeded. MAX_TEMP_ARENA_COUNT must be increased!")
|
||||
good_arena: ^runtime.Arena
|
||||
for i in 0..<MAX_TEMP_ARENA_COUNT {
|
||||
good_arena = &global_default_temp_allocator_arenas[i]
|
||||
for c in collisions {
|
||||
if good_arena == c.data {
|
||||
good_arena = nil
|
||||
}
|
||||
}
|
||||
if good_arena != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
assert(good_arena != nil)
|
||||
if good_arena.backing_allocator.procedure == nil {
|
||||
good_arena.backing_allocator = heap_allocator()
|
||||
}
|
||||
tmp := runtime.arena_temp_begin(good_arena, loc)
|
||||
return { good_arena, runtime.arena_allocator(good_arena), tmp, loc }
|
||||
}
|
||||
|
||||
temp_allocator_begin :: runtime.arena_temp_begin
|
||||
temp_allocator_end :: runtime.arena_temp_end
|
||||
@(deferred_out=_temp_allocator_end)
|
||||
temp_allocator_scope :: proc(tmp: Temp_Allocator) -> (runtime.Arena_Temp) {
|
||||
return temp_allocator_begin(tmp.arena)
|
||||
}
|
||||
@(private="file")
|
||||
_temp_allocator_end :: proc(tmp: runtime.Arena_Temp) {
|
||||
temp_allocator_end(tmp)
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
|
||||
+44
-17
@@ -2,6 +2,7 @@ package os2
|
||||
|
||||
import "base:runtime"
|
||||
import "core:slice"
|
||||
import "core:strings"
|
||||
|
||||
read_dir :: read_directory
|
||||
|
||||
@@ -18,12 +19,12 @@ read_directory :: proc(f: ^File, n: int, allocator: runtime.Allocator) -> (files
|
||||
size = 100
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
it := read_directory_iterator_create(f)
|
||||
defer _read_directory_iterator_destroy(&it)
|
||||
|
||||
dfi := make([dynamic]File_Info, 0, size, temp_allocator())
|
||||
dfi := make([dynamic]File_Info, 0, size, temp_allocator)
|
||||
defer if err != nil {
|
||||
for fi in dfi {
|
||||
file_info_delete(fi, allocator)
|
||||
@@ -194,28 +195,54 @@ read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info,
|
||||
}
|
||||
|
||||
// Recursively copies a directory to `dst` from `src`
|
||||
copy_directory :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
||||
switch err := make_directory_all(dst, dst_perm); err {
|
||||
case nil, .Exist:
|
||||
// okay
|
||||
case:
|
||||
copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
||||
when #defined(_copy_directory_all_native) {
|
||||
return _copy_directory_all_native(dst, src, dst_perm)
|
||||
} else {
|
||||
return _copy_directory_all(dst, src, dst_perm)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
||||
err := make_directory(dst, dst_perm)
|
||||
if err != nil && err != .Exist {
|
||||
return err
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
file_infos := read_all_directory_by_path(src, temp_allocator()) or_return
|
||||
for fi in file_infos {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
abs_src := get_absolute_path(src, temp_allocator) or_return
|
||||
abs_dst := get_absolute_path(dst, temp_allocator) or_return
|
||||
|
||||
dst_path := join_path({dst, fi.name}, temp_allocator()) or_return
|
||||
src_path := fi.fullpath
|
||||
dst_buf := make([dynamic]byte, 0, len(abs_dst) + 256, temp_allocator) or_return
|
||||
|
||||
if fi.type == .Directory {
|
||||
copy_directory(dst_path, src_path) or_return
|
||||
w: Walker
|
||||
walker_init_path(&w, src)
|
||||
defer walker_destroy(&w)
|
||||
|
||||
for info in walker_walk(&w) {
|
||||
_ = walker_error(&w) or_break
|
||||
|
||||
rel := strings.trim_prefix(info.fullpath, abs_src)
|
||||
|
||||
non_zero_resize(&dst_buf, 0)
|
||||
reserve(&dst_buf, len(abs_dst) + len(Path_Separator_String) + len(rel)) or_return
|
||||
append(&dst_buf, abs_dst)
|
||||
append(&dst_buf, Path_Separator_String)
|
||||
append(&dst_buf, rel)
|
||||
|
||||
if info.type == .Directory {
|
||||
err = make_directory(string(dst_buf[:]), dst_perm)
|
||||
if err != nil && err != .Exist {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
copy_file(dst_path, src_path) or_return
|
||||
copy_file(string(dst_buf[:]), info.fullpath) or_return
|
||||
}
|
||||
}
|
||||
|
||||
_ = walker_error(&w) or_return
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
it.impl.prev_fi = fi
|
||||
|
||||
if err != nil {
|
||||
path, _ := _get_full_path(entry_fd, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
path, _ := _get_full_path(entry_fd, temp_allocator)
|
||||
read_directory_iterator_set_error(it, path, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#+private
|
||||
package os2
|
||||
|
||||
import "core:sys/darwin"
|
||||
|
||||
_copy_directory_all_native :: proc(dst, src: string, dst_perm := 0o755) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
csrc := clone_to_cstring(src, temp_allocator) or_return
|
||||
cdst := clone_to_cstring(dst, temp_allocator) or_return
|
||||
|
||||
if darwin.copyfile(csrc, cdst, nil, darwin.COPYFILE_ALL + {.RECURSIVE}) < 0 {
|
||||
err = _get_platform_error()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -14,7 +14,9 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
|
||||
if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
|
||||
return
|
||||
}
|
||||
path := concatenate({base_path, `\`, win32_utf16_to_utf8(d.cFileName[:], temp_allocator()) or_else ""}, allocator) or_return
|
||||
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
path := concatenate({base_path, `\`, win32_wstring_to_utf8(raw_data(d.cFileName[:]), temp_allocator) or_else ""}, allocator) or_return
|
||||
|
||||
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
|
||||
defer win32.CloseHandle(handle)
|
||||
@@ -49,8 +51,6 @@ Read_Directory_Iterator_Impl :: struct {
|
||||
|
||||
@(require_results)
|
||||
_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
|
||||
for !it.impl.no_more_files {
|
||||
err: Error
|
||||
file_info_delete(it.impl.prev_fi, file_allocator())
|
||||
@@ -116,9 +116,9 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
|
||||
wpath = impl.wname[:i]
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
wpath_search := make([]u16, len(wpath)+3, temp_allocator())
|
||||
wpath_search := make([]u16, len(wpath)+3, temp_allocator)
|
||||
copy(wpath_search, wpath)
|
||||
wpath_search[len(wpath)+0] = '\\'
|
||||
wpath_search[len(wpath)+1] = '*'
|
||||
|
||||
@@ -12,9 +12,9 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator())
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator)
|
||||
cval := posix.getenv(ckey)
|
||||
if cval == nil {
|
||||
return
|
||||
@@ -27,10 +27,10 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
}
|
||||
|
||||
_set_env :: proc(key, value: string) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator()) or_return
|
||||
cval := strings.clone_to_cstring(key, temp_allocator()) or_return
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator) or_return
|
||||
cval := strings.clone_to_cstring(value, temp_allocator) or_return
|
||||
|
||||
if posix.setenv(ckey, cval, true) != nil {
|
||||
err = _get_platform_error_from_errno()
|
||||
@@ -39,9 +39,9 @@ _set_env :: proc(key, value: string) -> (err: Error) {
|
||||
}
|
||||
|
||||
_unset_env :: proc(key: string) -> (ok: bool) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator())
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator)
|
||||
|
||||
ok = posix.unsetenv(ckey) == .OK
|
||||
return
|
||||
|
||||
@@ -39,9 +39,9 @@ build_env :: proc() -> (err: Error) {
|
||||
g_env_buf = make([]byte, size_of_envs, file_allocator()) or_return
|
||||
defer if err != nil { delete(g_env_buf, file_allocator()) }
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
envs := make([]cstring, num_envs, temp_allocator()) or_return
|
||||
envs := make([]cstring, num_envs, temp_allocator) or_return
|
||||
|
||||
_err = wasi.environ_get(raw_data(envs), raw_data(g_env_buf))
|
||||
if _err != nil {
|
||||
|
||||
@@ -8,8 +8,8 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
if key == "" {
|
||||
return
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
wkey, _ := win32_utf8_to_wstring(key, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
wkey, _ := win32_utf8_to_wstring(key, temp_allocator)
|
||||
|
||||
n := win32.GetEnvironmentVariableW(wkey, nil, 0)
|
||||
if n == 0 {
|
||||
@@ -20,7 +20,7 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
return "", true
|
||||
}
|
||||
|
||||
b := make([]u16, n+1, temp_allocator())
|
||||
b := make([]u16, n+1, temp_allocator)
|
||||
|
||||
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
|
||||
if n == 0 {
|
||||
@@ -37,9 +37,9 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
}
|
||||
|
||||
_set_env :: proc(key, value: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
k := win32_utf8_to_wstring(key, temp_allocator()) or_return
|
||||
v := win32_utf8_to_wstring(value, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
k := win32_utf8_to_wstring(key, temp_allocator) or_return
|
||||
v := win32_utf8_to_wstring(value, temp_allocator) or_return
|
||||
|
||||
if !win32.SetEnvironmentVariableW(k, v) {
|
||||
return _get_platform_error()
|
||||
@@ -48,14 +48,14 @@ _set_env :: proc(key, value: string) -> Error {
|
||||
}
|
||||
|
||||
_unset_env :: proc(key: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
k, _ := win32_utf8_to_wstring(key, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
k, _ := win32_utf8_to_wstring(key, temp_allocator)
|
||||
return bool(win32.SetEnvironmentVariableW(k, nil))
|
||||
}
|
||||
|
||||
_clear_env :: proc() {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
envs, _ := environ(temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
envs, _ := environ(temp_allocator)
|
||||
for env in envs {
|
||||
for j in 1..<len(env) {
|
||||
if env[j] == '=' {
|
||||
|
||||
+21
-16
@@ -27,6 +27,9 @@ General_Error :: enum u32 {
|
||||
|
||||
Pattern_Has_Separator,
|
||||
|
||||
No_HOME_Variable,
|
||||
Wordexp_Failed,
|
||||
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
@@ -59,20 +62,22 @@ error_string :: proc(ferr: Error) -> string {
|
||||
case General_Error:
|
||||
switch e {
|
||||
case .None: return ""
|
||||
case .Permission_Denied: return "permission denied"
|
||||
case .Exist: return "file already exists"
|
||||
case .Not_Exist: return "file does not exist"
|
||||
case .Closed: return "file already closed"
|
||||
case .Timeout: return "i/o timeout"
|
||||
case .Broken_Pipe: return "Broken pipe"
|
||||
case .No_Size: return "file has no definite size"
|
||||
case .Invalid_File: return "invalid file"
|
||||
case .Invalid_Dir: return "invalid directory"
|
||||
case .Invalid_Path: return "invalid path"
|
||||
case .Invalid_Callback: return "invalid callback"
|
||||
case .Invalid_Command: return "invalid command"
|
||||
case .Unsupported: return "unsupported"
|
||||
case .Pattern_Has_Separator: return "pattern has separator"
|
||||
case .Permission_Denied: return "permission denied"
|
||||
case .Exist: return "file already exists"
|
||||
case .Not_Exist: return "file does not exist"
|
||||
case .Closed: return "file already closed"
|
||||
case .Timeout: return "i/o timeout"
|
||||
case .Broken_Pipe: return "Broken pipe"
|
||||
case .No_Size: return "file has no definite size"
|
||||
case .Invalid_File: return "invalid file"
|
||||
case .Invalid_Dir: return "invalid directory"
|
||||
case .Invalid_Path: return "invalid path"
|
||||
case .Invalid_Callback: return "invalid callback"
|
||||
case .Invalid_Command: return "invalid command"
|
||||
case .Unsupported: return "unsupported"
|
||||
case .Pattern_Has_Separator: return "pattern has separator"
|
||||
case .No_HOME_Variable: return "no $HOME variable"
|
||||
case .Wordexp_Failed: return "posix.wordexp was unable to expand"
|
||||
}
|
||||
case io.Error:
|
||||
switch e {
|
||||
@@ -108,12 +113,12 @@ error_string :: proc(ferr: Error) -> string {
|
||||
}
|
||||
|
||||
print_error :: proc(f: ^File, ferr: Error, msg: string) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
err_str := error_string(ferr)
|
||||
|
||||
// msg + ": " + err_str + '\n'
|
||||
length := len(msg) + 2 + len(err_str) + 1
|
||||
buf := make([]u8, length, temp_allocator())
|
||||
buf := make([]u8, length, temp_allocator)
|
||||
|
||||
copy(buf, msg)
|
||||
buf[len(msg)] = ':'
|
||||
|
||||
+13
-4
@@ -291,8 +291,8 @@ exists :: proc(path: string) -> bool {
|
||||
|
||||
@(require_results)
|
||||
is_file :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := stat(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := stat(path, temp_allocator)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -303,8 +303,8 @@ is_dir :: is_directory
|
||||
|
||||
@(require_results)
|
||||
is_directory :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := stat(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := stat(path, temp_allocator)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -313,6 +313,15 @@ is_directory :: proc(path: string) -> bool {
|
||||
|
||||
|
||||
copy_file :: proc(dst_path, src_path: string) -> Error {
|
||||
when #defined(_copy_file_native) {
|
||||
return _copy_file_native(dst_path, src_path)
|
||||
} else {
|
||||
return _copy_file(dst_path, src_path)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_copy_file :: proc(dst_path, src_path: string) -> Error {
|
||||
src := open(src_path) or_return
|
||||
defer close(src)
|
||||
|
||||
|
||||
+29
-29
@@ -66,8 +66,8 @@ _standard_stream_init :: proc() {
|
||||
}
|
||||
|
||||
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
// Just default to using O_NOCTTY because needing to open a controlling
|
||||
// terminal would be incredibly rare. This has no effect on files while
|
||||
@@ -299,8 +299,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE {
|
||||
linux.close(fd)
|
||||
@@ -311,25 +311,25 @@ _remove :: proc(name: string) -> Error {
|
||||
}
|
||||
|
||||
_rename :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
|
||||
return _get_platform_error(linux.rename(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
|
||||
return _get_platform_error(linux.link(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
_symlink :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.symlink(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
@@ -352,14 +352,14 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st
|
||||
}
|
||||
|
||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, e: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _read_link_cstr(name_cstr, allocator)
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chdir(name_cstr))
|
||||
}
|
||||
|
||||
@@ -369,8 +369,8 @@ _fchdir :: proc(f: ^File) -> Error {
|
||||
}
|
||||
|
||||
_chmod :: proc(name: string, mode: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode))))
|
||||
}
|
||||
|
||||
@@ -381,15 +381,15 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
|
||||
|
||||
// NOTE: will throw error without super user priviledges
|
||||
_chown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chown(name_cstr, linux.Uid(uid), linux.Gid(gid)))
|
||||
}
|
||||
|
||||
// NOTE: will throw error without super user priviledges
|
||||
_lchown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.lchown(name_cstr, linux.Uid(uid), linux.Gid(gid)))
|
||||
}
|
||||
|
||||
@@ -400,8 +400,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
}
|
||||
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
times := [2]linux.Time_Spec {
|
||||
{
|
||||
uint(atime._nsec) / uint(time.Second),
|
||||
@@ -431,8 +431,8 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
}
|
||||
|
||||
_exists :: proc(name: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr, _ := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr, _ := clone_to_cstring(name, temp_allocator)
|
||||
return linux.access(name_cstr, linux.F_OK) == .NONE
|
||||
}
|
||||
|
||||
@@ -440,8 +440,8 @@ _exists :: proc(name: string) -> bool {
|
||||
_read_entire_pseudo_file :: proc { _read_entire_pseudo_file_string, _read_entire_pseudo_file_cstring }
|
||||
|
||||
_read_entire_pseudo_file_string :: proc(name: string, allocator: runtime.Allocator) -> (b: []u8, e: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := clone_to_cstring(name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _read_entire_pseudo_file_cstring(name_cstr, allocator)
|
||||
}
|
||||
|
||||
|
||||
+36
-35
@@ -69,8 +69,8 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
|
||||
if .Trunc in flags { sys_flags += {.TRUNC} }
|
||||
if .Inheritable in flags { sys_flags -= {.CLOEXEC} }
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(perm))
|
||||
if fd < 0 {
|
||||
@@ -183,39 +183,39 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_remove :: proc(name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.remove(cname) != 0 {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_rename :: proc(old_path, new_path: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cold := temp_cstring(old_path)
|
||||
cnew := temp_cstring(new_path)
|
||||
_rename :: proc(old_path, new_path: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cold := clone_to_cstring(old_path, temp_allocator) or_return
|
||||
cnew := clone_to_cstring(new_path, temp_allocator) or_return
|
||||
if posix.rename(cold, cnew) != 0 {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cold := temp_cstring(old_name)
|
||||
cnew := temp_cstring(new_name)
|
||||
_link :: proc(old_name, new_name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cold := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
cnew := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
if posix.link(cold, cnew) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_symlink :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cold := temp_cstring(old_name)
|
||||
cnew := temp_cstring(new_name)
|
||||
_symlink :: proc(old_name, new_name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cold := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
cnew := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
if posix.symlink(cold, cnew) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -223,8 +223,8 @@ _symlink :: proc(old_name, new_name: string) -> Error {
|
||||
}
|
||||
|
||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
buf: [dynamic]byte
|
||||
buf.allocator = allocator
|
||||
@@ -268,9 +268,9 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
|
||||
}
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_chdir :: proc(name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.chdir(cname) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -291,9 +291,9 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_chmod :: proc(name: string, mode: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_chmod :: proc(name: string, mode: int) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(mode)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -307,9 +307,9 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_chown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_chown :: proc(name: string, uid, gid: int) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.chown(cname, posix.uid_t(uid), posix.gid_t(gid)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -317,15 +317,15 @@ _chown :: proc(name: string, uid, gid: int) -> Error {
|
||||
}
|
||||
|
||||
_lchown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.lchown(cname, posix.uid_t(uid), posix.gid_t(gid)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> (err: Error) {
|
||||
times := [2]posix.timeval{
|
||||
{
|
||||
tv_sec = posix.time_t(atime._nsec/1e9), /* seconds */
|
||||
@@ -337,8 +337,8 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
},
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
if posix.utimes(cname, ×) != .OK {
|
||||
return _get_platform_error()
|
||||
@@ -365,8 +365,9 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
}
|
||||
|
||||
_exists :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cpath := temp_cstring(path)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cpath, err := clone_to_cstring(path, temp_allocator)
|
||||
if err != nil { return false }
|
||||
return posix.access(cpath) == .OK
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package os2
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
import "core:sys/darwin"
|
||||
import "core:sys/posix"
|
||||
|
||||
_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) {
|
||||
@@ -16,3 +17,30 @@ _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allo
|
||||
|
||||
return clone_to_cstring(string(cstring(&buf[0])), allocator)
|
||||
}
|
||||
|
||||
_copy_file_native :: proc(dst_path, src_path: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
csrc := clone_to_cstring(src_path, temp_allocator) or_return
|
||||
cdst := clone_to_cstring(dst_path, temp_allocator) or_return
|
||||
|
||||
// Disallow directories, as specified by the generic implementation.
|
||||
|
||||
stat: posix.stat_t
|
||||
if posix.stat(csrc, &stat) != .OK {
|
||||
err = _get_platform_error()
|
||||
return
|
||||
}
|
||||
|
||||
if posix.S_ISDIR(stat.st_mode) {
|
||||
err = .Invalid_File
|
||||
return
|
||||
}
|
||||
|
||||
ret := darwin.copyfile(csrc, cdst, nil, darwin.COPYFILE_ALL)
|
||||
if ret < 0 {
|
||||
err = _get_platform_error()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import "base:runtime"
|
||||
import "core:sys/posix"
|
||||
|
||||
_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
cname := clone_to_cstring(name, temp_allocator)
|
||||
|
||||
buf: [posix.PATH_MAX]byte
|
||||
path = posix.realpath(cname, raw_data(buf[:]))
|
||||
|
||||
@@ -59,7 +59,7 @@ write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
|
||||
if r < 32 {
|
||||
if wrap(write_string(f, "\\x"), &n, &err) { return }
|
||||
b: [2]byte
|
||||
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
|
||||
switch len(s) {
|
||||
case 0: if wrap(write_string(f, "00"), &n, &err) { return }
|
||||
case 1: if wrap(write_rune(f, '0'), &n, &err) { return }
|
||||
|
||||
@@ -86,9 +86,9 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
|
||||
err = .Not_Exist
|
||||
return
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
path := _fix_long_path(name, temp_allocator()) or_return
|
||||
path := _fix_long_path(name, temp_allocator) or_return
|
||||
access: u32
|
||||
switch flags & {.Read, .Write} {
|
||||
case {.Read}: access = win32.FILE_GENERIC_READ
|
||||
@@ -508,11 +508,12 @@ _file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) {
|
||||
length: win32.LARGE_INTEGER
|
||||
handle := _handle(&f.file)
|
||||
if f.kind == .Pipe {
|
||||
bytesAvail: u32
|
||||
if win32.PeekNamedPipe(handle, nil, 0, nil, &bytesAvail, nil) {
|
||||
return i64(bytesAvail), nil
|
||||
bytes_available: u32
|
||||
if win32.PeekNamedPipe(handle, nil, 0, nil, &bytes_available, nil) {
|
||||
return i64(bytes_available), nil
|
||||
} else {
|
||||
return 0, .No_Size
|
||||
err = _get_platform_error()
|
||||
return
|
||||
}
|
||||
}
|
||||
if !win32.GetFileSizeEx(handle, &length) {
|
||||
@@ -556,8 +557,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
p := _fix_long_path(name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
p := _fix_long_path(name, temp_allocator) or_return
|
||||
err, err1: Error
|
||||
if !win32.DeleteFileW(p) {
|
||||
err = _get_platform_error()
|
||||
@@ -594,9 +595,9 @@ _remove :: proc(name: string) -> Error {
|
||||
}
|
||||
|
||||
_rename :: proc(old_path, new_path: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
from := _fix_long_path(old_path, temp_allocator()) or_return
|
||||
to := _fix_long_path(new_path, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
from := _fix_long_path(old_path, temp_allocator) or_return
|
||||
to := _fix_long_path(new_path, temp_allocator) or_return
|
||||
if win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) {
|
||||
return nil
|
||||
}
|
||||
@@ -605,9 +606,9 @@ _rename :: proc(old_path, new_path: string) -> Error {
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
o := _fix_long_path(old_name, temp_allocator()) or_return
|
||||
n := _fix_long_path(new_name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
o := _fix_long_path(old_name, temp_allocator) or_return
|
||||
n := _fix_long_path(new_name, temp_allocator) or_return
|
||||
if win32.CreateHardLinkW(n, o, nil) {
|
||||
return nil
|
||||
}
|
||||
@@ -668,9 +669,9 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([]u16, n+1, temp_allocator())
|
||||
buf := make([]u16, n+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
@@ -694,9 +695,9 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
|
||||
@thread_local
|
||||
rdb_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
p := _fix_long_path(name, temp_allocator()) or_return
|
||||
p := _fix_long_path(name, temp_allocator) or_return
|
||||
handle := _open_sym_link(p) or_return
|
||||
defer win32.CloseHandle(handle)
|
||||
|
||||
@@ -771,8 +772,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
p := _fix_long_path(name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
p := _fix_long_path(name, temp_allocator) or_return
|
||||
if !win32.SetCurrentDirectoryW(p) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -799,19 +800,11 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
defer close(f)
|
||||
return _fchtimes(f, atime, mtime)
|
||||
}
|
||||
|
||||
_fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
if f == nil || f.impl == nil {
|
||||
return nil
|
||||
}
|
||||
d: win32.BY_HANDLE_FILE_INFORMATION
|
||||
if !win32.GetFileInformationByHandle(_handle(f), &d) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
|
||||
to_windows_time :: #force_inline proc(t: time.Time) -> win32.LARGE_INTEGER {
|
||||
// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)
|
||||
return win32.LARGE_INTEGER(time.time_to_unix_nano(t) * 100 + 116444736000000000)
|
||||
}
|
||||
|
||||
atime, mtime := atime, mtime
|
||||
if time.time_to_unix_nano(atime) < time.time_to_unix_nano(mtime) {
|
||||
@@ -819,17 +812,17 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
}
|
||||
|
||||
info: win32.FILE_BASIC_INFO
|
||||
info.LastAccessTime = to_windows_time(atime)
|
||||
info.LastWriteTime = to_windows_time(mtime)
|
||||
if !win32.SetFileInformationByHandle(_handle(f), .FileBasicInfo, &info, size_of(d)) {
|
||||
info.LastAccessTime = time_as_filetime(atime)
|
||||
info.LastWriteTime = time_as_filetime(mtime)
|
||||
if !win32.SetFileInformationByHandle(_handle(f), .FileBasicInfo, &info, size_of(info)) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_exists :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
wpath, _ := _fix_long_path(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
wpath, _ := _fix_long_path(path, temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
return attribs != win32.INVALID_FILE_ATTRIBUTES
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ clone_to_cstring :: proc(s: string, allocator: runtime.Allocator) -> (res: cstri
|
||||
return cstring(&buf[0]), nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
temp_cstring :: proc(s: string) -> (cstring, runtime.Allocator_Error) #optional_allocator_error {
|
||||
return clone_to_cstring(s, temp_allocator())
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
string_from_null_terminated_bytes :: proc(b: []byte) -> (res: string) {
|
||||
s := string(b)
|
||||
|
||||
@@ -119,11 +119,11 @@ clean_path :: proc(path: string, allocator: runtime.Allocator) -> (cleaned: stri
|
||||
return strings.clone(".", allocator)
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
// The extra byte is to simplify appending path elements by letting the
|
||||
// loop to end each with a separator. We'll trim the last one when we're done.
|
||||
buffer := make([]u8, len(path) + 1, temp_allocator()) or_return
|
||||
buffer := make([]u8, len(path) + 1, temp_allocator) or_return
|
||||
|
||||
// This is the only point where Windows and POSIX differ, as Windows has
|
||||
// alphabet-based volumes for root paths.
|
||||
@@ -326,8 +326,8 @@ For example, `join_path({"/home", "foo", "bar.txt"})` will result in `"/home/foo
|
||||
join_path :: proc(elems: []string, allocator: runtime.Allocator) -> (joined: string, err: Error) {
|
||||
for e, i in elems {
|
||||
if e != "" {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
p := strings.join(elems[i:], Path_Separator_String, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
p := strings.join(elems[i:], Path_Separator_String, temp_allocator) or_return
|
||||
return clean_path(p, allocator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ _is_path_separator :: proc(c: byte) -> bool {
|
||||
}
|
||||
|
||||
_mkdir :: proc(path: string, perm: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
path_cstr := temp_cstring(path) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
path_cstr := clone_to_cstring(path, temp_allocator) or_return
|
||||
return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)u32(perm)))
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
}
|
||||
return _get_platform_error(errno)
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
// need something we can edit, and use to generate cstrings
|
||||
path_bytes := make([]u8, len(path) + 1, temp_allocator())
|
||||
path_bytes := make([]u8, len(path) + 1, temp_allocator)
|
||||
|
||||
// zero terminate the byte slice to make it a valid cstring
|
||||
copy(path_bytes, path)
|
||||
@@ -129,8 +129,8 @@ _remove_all :: proc(path: string) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
path_cstr := temp_cstring(path) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
path_cstr := clone_to_cstring(path, temp_allocator) or_return
|
||||
|
||||
fd, errno := linux.open(path_cstr, _OPENDIR_FLAGS)
|
||||
#partial switch errno {
|
||||
@@ -168,14 +168,16 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (string, Error)
|
||||
}
|
||||
|
||||
_set_working_directory :: proc(dir: string) -> Error {
|
||||
dir_cstr := temp_cstring(dir) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
dir_cstr := clone_to_cstring(dir, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chdir(dir_cstr))
|
||||
}
|
||||
|
||||
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([dynamic]byte, 1024, temp_allocator()) or_return
|
||||
buf := make([dynamic]byte, 1024, temp_allocator) or_return
|
||||
for {
|
||||
n, errno := linux.readlink("/proc/self/exe", buf[:])
|
||||
if errno != .NONE {
|
||||
@@ -205,3 +207,21 @@ _get_full_path :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fullpath:
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) {
|
||||
rel := path
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
fd, errno := linux.open(clone_to_cstring(path, temp_allocator) or_return, {})
|
||||
if errno != nil {
|
||||
err = _get_platform_error(errno)
|
||||
return
|
||||
}
|
||||
defer linux.close(fd)
|
||||
|
||||
return _get_full_path(fd, allocator)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import "base:runtime"
|
||||
import "core:sys/posix"
|
||||
|
||||
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([dynamic]byte, 1024, temp_allocator()) or_return
|
||||
buf := make([dynamic]byte, 1024, temp_allocator) or_return
|
||||
for {
|
||||
n := posix.readlink("/proc/curproc/exe", raw_data(buf), len(buf))
|
||||
if n < 0 {
|
||||
|
||||
@@ -35,11 +35,11 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
|
||||
return real(arg, allocator)
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := strings.builder_make(temp_allocator())
|
||||
buf := strings.builder_make(temp_allocator)
|
||||
|
||||
paths := get_env("PATH", temp_allocator())
|
||||
paths := get_env("PATH", temp_allocator)
|
||||
for dir in strings.split_iterator(&paths, ":") {
|
||||
strings.builder_reset(&buf)
|
||||
strings.write_string(&buf, dir)
|
||||
|
||||
+30
-13
@@ -14,9 +14,9 @@ _is_path_separator :: proc(c: byte) -> bool {
|
||||
return c == _Path_Separator
|
||||
}
|
||||
|
||||
_mkdir :: proc(name: string, perm: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_mkdir :: proc(name: string, perm: int) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.mkdir(cname, transmute(posix.mode_t)posix._mode_t(perm)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -28,13 +28,13 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
return .Invalid_Path
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if exists(path) {
|
||||
return .Exist
|
||||
}
|
||||
|
||||
clean_path := clean_path(path, temp_allocator()) or_return
|
||||
clean_path := clean_path(path, temp_allocator) or_return
|
||||
return internal_mkdir_all(clean_path, perm)
|
||||
|
||||
internal_mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
@@ -52,9 +52,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
_remove_all :: proc(path: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cpath := temp_cstring(path)
|
||||
_remove_all :: proc(path: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cpath := clone_to_cstring(path, temp_allocator) or_return
|
||||
|
||||
dir := posix.opendir(cpath)
|
||||
if dir == nil {
|
||||
@@ -78,7 +78,7 @@ _remove_all :: proc(path: string) -> Error {
|
||||
continue
|
||||
}
|
||||
|
||||
fullpath, _ := concatenate({path, "/", string(cname), "\x00"}, temp_allocator())
|
||||
fullpath, _ := concatenate({path, "/", string(cname), "\x00"}, temp_allocator)
|
||||
if entry.d_type == .DIR {
|
||||
_remove_all(fullpath[:len(fullpath)-1]) or_return
|
||||
} else {
|
||||
@@ -95,10 +95,10 @@ _remove_all :: proc(path: string) -> Error {
|
||||
}
|
||||
|
||||
_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf: [dynamic]byte
|
||||
buf.allocator = temp_allocator()
|
||||
buf.allocator = temp_allocator
|
||||
size := uint(posix.PATH_MAX)
|
||||
|
||||
cwd: cstring
|
||||
@@ -116,10 +116,27 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, er
|
||||
}
|
||||
|
||||
_set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cdir := temp_cstring(dir)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cdir := clone_to_cstring(dir, temp_allocator) or_return
|
||||
if posix.chdir(cdir) != .OK {
|
||||
err = _get_platform_error()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) {
|
||||
rel := path
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
rel_cstr := clone_to_cstring(rel, temp_allocator) or_return
|
||||
path_ptr := posix.realpath(rel_cstr, nil)
|
||||
if path_ptr == nil {
|
||||
return "", Platform_Error(posix.errno())
|
||||
}
|
||||
defer posix.free(path_ptr)
|
||||
|
||||
path_str := clone_string(string(path_ptr), allocator) or_return
|
||||
return path_str, nil
|
||||
}
|
||||
|
||||
@@ -4,10 +4,6 @@ package os2
|
||||
|
||||
// This implementation is for all systems that have POSIX-compliant filesystem paths.
|
||||
|
||||
import "base:runtime"
|
||||
import "core:strings"
|
||||
import "core:sys/posix"
|
||||
|
||||
_are_paths_identical :: proc(a, b: string) -> (identical: bool) {
|
||||
return a == b
|
||||
}
|
||||
@@ -26,23 +22,6 @@ _is_absolute_path :: proc(path: string) -> bool {
|
||||
return len(path) > 0 && _is_path_separator(path[0])
|
||||
}
|
||||
|
||||
_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) {
|
||||
rel := path
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
rel_cstr := strings.clone_to_cstring(rel, temp_allocator())
|
||||
path_ptr := posix.realpath(rel_cstr, nil)
|
||||
if path_ptr == nil {
|
||||
return "", Platform_Error(posix.errno())
|
||||
}
|
||||
defer posix.free(path_ptr)
|
||||
|
||||
path_str := strings.clone(string(path_ptr), allocator)
|
||||
return path_str, nil
|
||||
}
|
||||
|
||||
_get_relative_path_handle_start :: proc(base, target: string) -> bool {
|
||||
base_rooted := len(base) > 0 && _is_path_separator(base[0])
|
||||
target_rooted := len(target) > 0 && _is_path_separator(target[0])
|
||||
|
||||
@@ -28,13 +28,13 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
return .Invalid_Path
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if exists(path) {
|
||||
return .Exist
|
||||
}
|
||||
|
||||
clean_path := clean_path(path, temp_allocator())
|
||||
clean_path := clean_path(path, temp_allocator)
|
||||
return internal_mkdir_all(clean_path)
|
||||
|
||||
internal_mkdir_all :: proc(path: string) -> Error {
|
||||
|
||||
@@ -14,8 +14,8 @@ _is_path_separator :: proc(c: byte) -> bool {
|
||||
}
|
||||
|
||||
_mkdir :: proc(name: string, perm: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator()) or_return, nil) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator) or_return, nil) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
@@ -33,9 +33,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
return p, false, nil
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
dir_stat, err := stat(path, temp_allocator())
|
||||
dir_stat, err := stat(path, temp_allocator)
|
||||
if err == nil {
|
||||
if dir_stat.type == .Directory {
|
||||
return nil
|
||||
@@ -63,7 +63,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
|
||||
err = mkdir(path, perm)
|
||||
if err != nil {
|
||||
new_dir_stat, err1 := lstat(path, temp_allocator())
|
||||
new_dir_stat, err1 := lstat(path, temp_allocator)
|
||||
if err1 == nil && new_dir_stat.type == .Directory {
|
||||
return nil
|
||||
}
|
||||
@@ -82,8 +82,8 @@ _remove_all :: proc(path: string) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
dir := win32_utf8_to_wstring(path, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
dir := win32_utf8_to_wstring(path, temp_allocator) or_return
|
||||
|
||||
empty: [1]u16
|
||||
|
||||
@@ -109,10 +109,10 @@ _remove_all :: proc(path: string) -> Error {
|
||||
_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
|
||||
dir_buf_wstr := make([]u16, sz_utf16, temp_allocator()) or_return
|
||||
dir_buf_wstr := make([]u16, sz_utf16, temp_allocator) or_return
|
||||
|
||||
sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr))
|
||||
assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL.
|
||||
@@ -123,8 +123,8 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, er
|
||||
}
|
||||
|
||||
_set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
wstr := win32_utf8_to_wstring(dir, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
wstr := win32_utf8_to_wstring(dir, temp_allocator) or_return
|
||||
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
@@ -138,9 +138,9 @@ _set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||
}
|
||||
|
||||
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([dynamic]u16, 512, temp_allocator()) or_return
|
||||
buf := make([dynamic]u16, 512, temp_allocator) or_return
|
||||
for {
|
||||
ret := win32.GetModuleFileNameW(nil, raw_data(buf), win32.DWORD(len(buf)))
|
||||
if ret == 0 {
|
||||
@@ -187,7 +187,6 @@ init_long_path_support :: proc() {
|
||||
if value == 1 {
|
||||
can_use_long_paths = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@@ -222,10 +221,10 @@ _fix_long_path_internal :: proc(path: string) -> string {
|
||||
return path
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
PREFIX :: `\\?`
|
||||
path_buf := make([]byte, len(PREFIX)+len(path)+1, temp_allocator())
|
||||
path_buf := make([]byte, len(PREFIX)+len(path)+1, temp_allocator)
|
||||
copy(path_buf, PREFIX)
|
||||
n := len(path)
|
||||
r, w := 0, len(PREFIX)
|
||||
@@ -271,6 +270,11 @@ _clean_path_handle_start :: proc(path: string, buffer: []u8) -> (rooted: bool, s
|
||||
start += 1
|
||||
}
|
||||
copy(buffer, path[:start])
|
||||
for n in 0..<start {
|
||||
if _is_path_separator(buffer[n]) {
|
||||
buffer[n] = _Path_Separator
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -297,14 +301,14 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator)
|
||||
n := win32.GetFullPathNameW(raw_data(rel_utf16), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", Platform_Error(win32.GetLastError())
|
||||
}
|
||||
|
||||
buf := make([]u16, n, temp_allocator()) or_return
|
||||
buf := make([]u16, n, temp_allocator) or_return
|
||||
n = win32.GetFullPathNameW(raw_data(rel_utf16), u32(n), raw_data(buf), nil)
|
||||
if n == 0 {
|
||||
return "", Platform_Error(win32.GetLastError())
|
||||
|
||||
@@ -264,7 +264,7 @@ specific process, even after it has died.
|
||||
**Note(linux)**: The `handle` will be referring to pidfd.
|
||||
*/
|
||||
Process :: struct {
|
||||
pid: int,
|
||||
pid: int,
|
||||
handle: uintptr,
|
||||
}
|
||||
|
||||
@@ -290,21 +290,10 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro
|
||||
return _process_open(pid, flags)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
OS-specific process attributes.
|
||||
*/
|
||||
Process_Attributes :: struct {
|
||||
sys_attr: _Sys_Process_Attributes,
|
||||
}
|
||||
|
||||
/*
|
||||
The description of how a process should be created.
|
||||
*/
|
||||
Process_Desc :: struct {
|
||||
// OS-specific attributes.
|
||||
sys_attr: Process_Attributes,
|
||||
|
||||
// The working directory of the process. If the string has length 0, the
|
||||
// working directory is assumed to be the current working directory of the
|
||||
// current process.
|
||||
|
||||
@@ -50,7 +50,7 @@ _get_ppid :: proc() -> int {
|
||||
|
||||
@(private="package")
|
||||
_process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
dir_fd, errno := linux.open("/proc/", _OPENDIR_FLAGS)
|
||||
#partial switch errno {
|
||||
@@ -68,9 +68,9 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
|
||||
}
|
||||
defer linux.close(dir_fd)
|
||||
|
||||
dynamic_list := make([dynamic]int, temp_allocator()) or_return
|
||||
dynamic_list := make([dynamic]int, temp_allocator) or_return
|
||||
|
||||
buf := make([dynamic]u8, 128, 128, temp_allocator()) or_return
|
||||
buf := make([dynamic]u8, 128, 128, temp_allocator) or_return
|
||||
loop: for {
|
||||
buflen: int
|
||||
buflen, errno = linux.getdents(dir_fd, buf[:])
|
||||
@@ -100,7 +100,7 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
|
||||
|
||||
@(private="package")
|
||||
_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
info.pid = pid
|
||||
|
||||
@@ -126,7 +126,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
|
||||
passwd_bytes: []u8
|
||||
passwd_err: Error
|
||||
passwd_bytes, passwd_err = _read_entire_pseudo_file_cstring("/etc/passwd", temp_allocator())
|
||||
passwd_bytes, passwd_err = _read_entire_pseudo_file_cstring("/etc/passwd", temp_allocator)
|
||||
if passwd_err != nil {
|
||||
err = passwd_err
|
||||
break username_if
|
||||
@@ -162,13 +162,13 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
}
|
||||
|
||||
cmdline_if: if selection & {.Working_Dir, .Command_Line, .Command_Args, .Executable_Path} != {} {
|
||||
cmdline_if: if selection & {.Working_Dir, .Command_Line, .Command_Args} != {} {
|
||||
strings.builder_reset(&path_builder)
|
||||
strings.write_string(&path_builder, "/proc/")
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/cmdline")
|
||||
|
||||
cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
|
||||
cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator)
|
||||
if cmdline_err != nil || len(cmdline_bytes) == 0 {
|
||||
err = cmdline_err
|
||||
break cmdline_if
|
||||
@@ -178,18 +178,18 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
terminator := strings.index_byte(cmdline, 0)
|
||||
assert(terminator > 0)
|
||||
|
||||
command_line_exec := cmdline[:terminator]
|
||||
// command_line_exec := cmdline[:terminator]
|
||||
|
||||
// Still need cwd if the execution on the command line is relative.
|
||||
cwd: string
|
||||
cwd_err: Error
|
||||
if .Working_Dir in selection || (.Executable_Path in selection && command_line_exec[0] != '/') {
|
||||
if .Working_Dir in selection {
|
||||
strings.builder_reset(&path_builder)
|
||||
strings.write_string(&path_builder, "/proc/")
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/cwd")
|
||||
|
||||
cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator()) // allowed to fail
|
||||
cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator) // allowed to fail
|
||||
if cwd_err == nil && .Working_Dir in selection {
|
||||
info.working_dir = strings.clone(cwd, allocator) or_return
|
||||
info.fields += {.Working_Dir}
|
||||
@@ -199,18 +199,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
}
|
||||
|
||||
if .Executable_Path in selection {
|
||||
if cmdline[0] == '/' {
|
||||
info.executable_path = strings.clone(cmdline[:terminator], allocator) or_return
|
||||
info.fields += {.Executable_Path}
|
||||
} else if cwd_err == nil {
|
||||
info.executable_path = join_path({ cwd, cmdline[:terminator] }, allocator) or_return
|
||||
info.fields += {.Executable_Path}
|
||||
} else {
|
||||
break cmdline_if
|
||||
}
|
||||
}
|
||||
|
||||
if selection & {.Command_Line, .Command_Args} != {} {
|
||||
// skip to first arg
|
||||
//cmdline = cmdline[terminator + 1:]
|
||||
@@ -257,7 +245,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/stat")
|
||||
|
||||
proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
|
||||
proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator)
|
||||
if stat_err != nil {
|
||||
err = stat_err
|
||||
break stat_if
|
||||
@@ -296,7 +284,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
Nice,
|
||||
//... etc,
|
||||
}
|
||||
stat_fields := strings.split(stats, " ", temp_allocator()) or_return
|
||||
stat_fields := strings.split(stats, " ", temp_allocator) or_return
|
||||
|
||||
if len(stat_fields) <= int(Fields.Nice) {
|
||||
break stat_if
|
||||
@@ -323,13 +311,37 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
}
|
||||
|
||||
if .Executable_Path in selection {
|
||||
/*
|
||||
NOTE(Jeroen):
|
||||
|
||||
The old version returned the wrong executable path for things like `bash` or `sh`,
|
||||
for whom `/proc/<pid>/cmdline` will just report "bash" or "sh",
|
||||
resulting in misleading paths like `$PWD/sh`, even though that executable doesn't exist there.
|
||||
|
||||
Thanks to Yawning for suggesting `/proc/self/exe`.
|
||||
*/
|
||||
|
||||
strings.builder_reset(&path_builder)
|
||||
strings.write_string(&path_builder, "/proc/")
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/exe")
|
||||
|
||||
if exe_bytes, exe_err := _read_link(strings.to_string(path_builder), temp_allocator); exe_err == nil {
|
||||
info.executable_path = strings.clone(string(exe_bytes), allocator) or_return
|
||||
info.fields += {.Executable_Path}
|
||||
} else {
|
||||
err = exe_err
|
||||
}
|
||||
}
|
||||
|
||||
if .Environment in selection {
|
||||
strings.builder_reset(&path_builder)
|
||||
strings.write_string(&path_builder, "/proc/")
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/environ")
|
||||
|
||||
if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()); env_err == nil {
|
||||
if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator); env_err == nil {
|
||||
env := string(env_bytes)
|
||||
|
||||
env_list := make([dynamic]string, allocator) or_return
|
||||
@@ -378,12 +390,9 @@ _process_open :: proc(pid: int, _: Process_Open_Flags) -> (process: Process, err
|
||||
return
|
||||
}
|
||||
|
||||
@(private="package")
|
||||
_Sys_Process_Attributes :: struct {}
|
||||
|
||||
@(private="package")
|
||||
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if len(desc.command) == 0 {
|
||||
return process, .Invalid_Command
|
||||
@@ -392,7 +401,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
dir_fd := linux.AT_FDCWD
|
||||
errno: linux.Errno
|
||||
if desc.working_dir != "" {
|
||||
dir_cstr := temp_cstring(desc.working_dir) or_return
|
||||
dir_cstr := clone_to_cstring(desc.working_dir, temp_allocator) or_return
|
||||
if dir_fd, errno = linux.open(dir_cstr, _OPENDIR_FLAGS); errno != .NONE {
|
||||
return process, _get_platform_error(errno)
|
||||
}
|
||||
@@ -405,10 +414,10 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
exe_path: cstring
|
||||
executable_name := desc.command[0]
|
||||
if strings.index_byte(executable_name, '/') < 0 {
|
||||
path_env := get_env("PATH", temp_allocator())
|
||||
path_dirs := split_path_list(path_env, temp_allocator()) or_return
|
||||
path_env := get_env("PATH", temp_allocator)
|
||||
path_dirs := split_path_list(path_env, temp_allocator) or_return
|
||||
|
||||
exe_builder := strings.builder_make(temp_allocator()) or_return
|
||||
exe_builder := strings.builder_make(temp_allocator) or_return
|
||||
|
||||
found: bool
|
||||
for dir in path_dirs {
|
||||
@@ -435,7 +444,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exe_path = temp_cstring(executable_name) or_return
|
||||
exe_path = clone_to_cstring(executable_name, temp_allocator) or_return
|
||||
if linux.access(exe_path, linux.X_OK) != .NONE {
|
||||
return process, .Not_Exist
|
||||
}
|
||||
@@ -443,20 +452,20 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
|
||||
// args and environment need to be a list of cstrings
|
||||
// that are terminated by a nil pointer.
|
||||
cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return
|
||||
cargs := make([]cstring, len(desc.command) + 1, temp_allocator) or_return
|
||||
for command, i in desc.command {
|
||||
cargs[i] = temp_cstring(command) or_return
|
||||
cargs[i] = clone_to_cstring(command, temp_allocator) or_return
|
||||
}
|
||||
|
||||
// Use current process' environment if description didn't provide it.
|
||||
env: [^]cstring
|
||||
if desc.env == nil {
|
||||
// take this process's current environment
|
||||
env = raw_data(export_cstring_environment(temp_allocator()))
|
||||
env = raw_data(export_cstring_environment(temp_allocator))
|
||||
} else {
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator()) or_return
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator) or_return
|
||||
for env, i in desc.env {
|
||||
cenv[i] = temp_cstring(env) or_return
|
||||
cenv[i] = clone_to_cstring(env, temp_allocator) or_return
|
||||
}
|
||||
env = &cenv[0]
|
||||
}
|
||||
@@ -584,7 +593,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
}
|
||||
|
||||
_process_state_update_times :: proc(state: ^Process_State) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
stat_path_buf: [48]u8
|
||||
path_builder := strings.builder_from_bytes(stat_path_buf[:])
|
||||
@@ -593,7 +602,7 @@ _process_state_update_times :: proc(state: ^Process_State) -> (err: Error) {
|
||||
strings.write_string(&path_builder, "/stat")
|
||||
|
||||
stat_buf: []u8
|
||||
stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
|
||||
stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -46,22 +46,20 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
|
||||
return _process_info_by_pid(_get_pid(), selection, allocator)
|
||||
}
|
||||
|
||||
_Sys_Process_Attributes :: struct {}
|
||||
|
||||
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
if len(desc.command) == 0 {
|
||||
err = .Invalid_Path
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
// search PATH if just a plain name is provided.
|
||||
exe_builder := strings.builder_make(temp_allocator())
|
||||
exe_builder := strings.builder_make(temp_allocator)
|
||||
exe_name := desc.command[0]
|
||||
if strings.index_byte(exe_name, '/') < 0 {
|
||||
path_env := get_env("PATH", temp_allocator())
|
||||
path_dirs := split_path_list(path_env, temp_allocator()) or_return
|
||||
path_env := get_env("PATH", temp_allocator)
|
||||
path_dirs := split_path_list(path_env, temp_allocator) or_return
|
||||
|
||||
found: bool
|
||||
for dir in path_dirs {
|
||||
@@ -110,12 +108,12 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
}
|
||||
|
||||
cwd: cstring; if desc.working_dir != "" {
|
||||
cwd = temp_cstring(desc.working_dir)
|
||||
cwd = clone_to_cstring(desc.working_dir, temp_allocator) or_return
|
||||
}
|
||||
|
||||
cmd := make([]cstring, len(desc.command) + 1, temp_allocator())
|
||||
cmd := make([]cstring, len(desc.command) + 1, temp_allocator)
|
||||
for part, i in desc.command {
|
||||
cmd[i] = temp_cstring(part)
|
||||
cmd[i] = clone_to_cstring(part, temp_allocator) or_return
|
||||
}
|
||||
|
||||
env: [^]cstring
|
||||
@@ -123,9 +121,9 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
// take this process's current environment
|
||||
env = posix.environ
|
||||
} else {
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator())
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator)
|
||||
for env, i in desc.env {
|
||||
cenv[i] = temp_cstring(env)
|
||||
cenv[i] = clone_to_cstring(env, temp_allocator) or_return
|
||||
}
|
||||
env = raw_data(cenv)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
|
||||
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
info.pid = pid
|
||||
|
||||
// Thought on errors is: allocation failures return immediately (also why the non-allocation stuff is done first),
|
||||
@@ -127,7 +128,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
break args
|
||||
}
|
||||
|
||||
buf := runtime.make_aligned([]byte, length, 4, temp_allocator())
|
||||
buf := runtime.make_aligned([]byte, length, 4, temp_allocator)
|
||||
if sysctl(raw_data(mib), 3, raw_data(buf), &length, nil, 0) != .OK {
|
||||
if err == nil {
|
||||
err = _get_platform_error()
|
||||
@@ -239,9 +240,9 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buffer := make([]i32, ret, temp_allocator())
|
||||
buffer := make([]i32, ret, temp_allocator)
|
||||
ret = darwin.proc_listallpids(raw_data(buffer), ret*size_of(i32))
|
||||
if ret < 0 {
|
||||
err = _get_platform_error()
|
||||
|
||||
@@ -44,8 +44,6 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
|
||||
return
|
||||
}
|
||||
|
||||
_Sys_Process_Attributes :: struct {}
|
||||
|
||||
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
err = .Unsupported
|
||||
return
|
||||
|
||||
@@ -162,9 +162,10 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -179,9 +180,9 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator_scope(temp_allocator)
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
envs_w := make([]u16, env_len, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -190,8 +191,8 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -272,9 +273,10 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -289,9 +291,9 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator_scope(temp_allocator)
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
envs_w := make([]u16, env_len, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -300,8 +302,8 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -417,35 +419,64 @@ _process_open :: proc(pid: int, flags: Process_Open_Flags) -> (process: Process,
|
||||
return
|
||||
}
|
||||
|
||||
@(private="package")
|
||||
_Sys_Process_Attributes :: struct {}
|
||||
|
||||
@(private="package")
|
||||
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
command_line := _build_command_line(desc.command, temp_allocator())
|
||||
command_line_w := win32_utf8_to_wstring(command_line, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
command_line := _build_command_line(desc.command, temp_allocator)
|
||||
command_line_w := win32_utf8_to_wstring(command_line, temp_allocator) or_return
|
||||
environment := desc.env
|
||||
if desc.env == nil {
|
||||
environment = environ(temp_allocator()) or_return
|
||||
environment = environ(temp_allocator) or_return
|
||||
}
|
||||
environment_block := _build_environment_block(environment, temp_allocator())
|
||||
environment_block_w := win32_utf8_to_utf16(environment_block, temp_allocator()) or_return
|
||||
stderr_handle := win32.GetStdHandle(win32.STD_ERROR_HANDLE)
|
||||
stdout_handle := win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)
|
||||
stdin_handle := win32.GetStdHandle(win32.STD_INPUT_HANDLE)
|
||||
environment_block := _build_environment_block(environment, temp_allocator)
|
||||
environment_block_w := win32_utf8_to_utf16(environment_block, temp_allocator) or_return
|
||||
|
||||
if desc.stdout != nil {
|
||||
stderr_handle: win32.HANDLE
|
||||
stdout_handle: win32.HANDLE
|
||||
stdin_handle: win32.HANDLE
|
||||
|
||||
null_handle: win32.HANDLE
|
||||
if desc.stdout == nil || desc.stderr == nil || desc.stdin == nil {
|
||||
null_handle = win32.CreateFileW(
|
||||
win32.L("NUL"),
|
||||
win32.GENERIC_READ|win32.GENERIC_WRITE,
|
||||
win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE,
|
||||
&win32.SECURITY_ATTRIBUTES{
|
||||
nLength = size_of(win32.SECURITY_ATTRIBUTES),
|
||||
bInheritHandle = true,
|
||||
},
|
||||
win32.OPEN_EXISTING,
|
||||
win32.FILE_ATTRIBUTE_NORMAL,
|
||||
nil,
|
||||
)
|
||||
// Opening NUL should always succeed.
|
||||
assert(null_handle != nil)
|
||||
}
|
||||
// NOTE(laytan): I believe it is fine to close this handle right after CreateProcess,
|
||||
// and we don't have to hold onto this until the process exits.
|
||||
defer if null_handle != nil {
|
||||
win32.CloseHandle(null_handle)
|
||||
}
|
||||
|
||||
if desc.stdout == nil {
|
||||
stdout_handle = null_handle
|
||||
} else {
|
||||
stdout_handle = win32.HANDLE((^File_Impl)(desc.stdout.impl).fd)
|
||||
}
|
||||
if desc.stderr != nil {
|
||||
|
||||
if desc.stderr == nil {
|
||||
stderr_handle = null_handle
|
||||
} else {
|
||||
stderr_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd)
|
||||
}
|
||||
if desc.stdin != nil {
|
||||
|
||||
if desc.stdin == nil {
|
||||
stdin_handle = null_handle
|
||||
} else {
|
||||
stdin_handle = win32.HANDLE((^File_Impl)(desc.stdin.impl).fd)
|
||||
}
|
||||
|
||||
working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator()) or_else nil) if len(desc.working_dir) > 0 else nil
|
||||
working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator) or_else nil) if len(desc.working_dir) > 0 else nil
|
||||
process_info: win32.PROCESS_INFORMATION
|
||||
ok := win32.CreateProcessW(
|
||||
nil,
|
||||
@@ -583,7 +614,7 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path
|
||||
}
|
||||
|
||||
_get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
token_handle: win32.HANDLE
|
||||
if !win32.OpenProcessToken(process_handle, win32.TOKEN_QUERY, &token_handle) {
|
||||
err = _get_platform_error()
|
||||
@@ -598,7 +629,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
token_user := (^win32.TOKEN_USER)(raw_data(make([]u8, token_user_size, temp_allocator()) or_return))
|
||||
token_user := (^win32.TOKEN_USER)(raw_data(make([]u8, token_user_size, temp_allocator) or_return))
|
||||
if !win32.GetTokenInformation(token_handle, .TokenUser, token_user, token_user_size, &token_user_size) {
|
||||
err = _get_platform_error()
|
||||
return
|
||||
@@ -614,8 +645,8 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
|
||||
err = _get_platform_error()
|
||||
return
|
||||
}
|
||||
username := win32_utf16_to_utf8(username_w[:username_chrs], temp_allocator()) or_return
|
||||
domain := win32_utf16_to_utf8(domain_w[:domain_chrs], temp_allocator()) or_return
|
||||
username := win32_utf16_to_utf8(username_w[:username_chrs], temp_allocator) or_return
|
||||
domain := win32_utf16_to_utf8(domain_w[:domain_chrs], temp_allocator) or_return
|
||||
return strings.concatenate({domain, "\\", username}, allocator)
|
||||
}
|
||||
|
||||
|
||||
@@ -73,14 +73,14 @@ last_write_time_by_name :: modification_time_by_path
|
||||
|
||||
@(require_results)
|
||||
modification_time :: proc(f: ^File) -> (time.Time, Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := fstat(f, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := fstat(f, temp_allocator)
|
||||
return fi.modification_time, err
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
modification_time_by_path :: proc(path: string) -> (time.Time, Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := stat(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := stat(path, temp_allocator)
|
||||
return fi.modification_time, err
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ _fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fi: File
|
||||
|
||||
// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
|
||||
_stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd, errno := linux.open(name_cstr, {})
|
||||
if errno != .NONE {
|
||||
@@ -59,8 +59,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err
|
||||
}
|
||||
|
||||
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd, errno := linux.open(name_cstr, {.PATH, .NOFOLLOW})
|
||||
if errno != .NONE {
|
||||
|
||||
@@ -69,8 +69,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd := posix.open(cname, {})
|
||||
if fd == -1 {
|
||||
@@ -96,33 +96,34 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
// NOTE: can't use realpath or open (+ fcntl F_GETPATH) here because it tries to resolve symlinks.
|
||||
|
||||
// NOTE: This might not be correct when given "/symlink/foo.txt",
|
||||
// you would want that to resolve "/symlink", but not resolve "foo.txt".
|
||||
|
||||
fullpath := clean_path(name, temp_allocator()) or_return
|
||||
fullpath := clean_path(name, temp_allocator) or_return
|
||||
assert(len(fullpath) > 0)
|
||||
switch {
|
||||
case fullpath[0] == '/':
|
||||
// nothing.
|
||||
case fullpath == ".":
|
||||
fullpath = getwd(temp_allocator()) or_return
|
||||
fullpath = getwd(temp_allocator) or_return
|
||||
case len(fullpath) > 1 && fullpath[0] == '.' && fullpath[1] == '/':
|
||||
fullpath = fullpath[2:]
|
||||
fallthrough
|
||||
case:
|
||||
fullpath = concatenate({
|
||||
getwd(temp_allocator()) or_return,
|
||||
getwd(temp_allocator) or_return,
|
||||
"/",
|
||||
fullpath,
|
||||
}, temp_allocator()) or_return
|
||||
}, temp_allocator) or_return
|
||||
}
|
||||
|
||||
stat: posix.stat_t
|
||||
if posix.lstat(temp_cstring(fullpath), &stat) != .OK {
|
||||
c_fullpath := clone_to_cstring(fullpath, temp_allocator) or_return
|
||||
if posix.lstat(c_fullpath, &stat) != .OK {
|
||||
err = _get_platform_error()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,15 +45,15 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path
|
||||
name = "."
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
p := win32_utf8_to_utf16(name, temp_allocator()) or_return
|
||||
p := win32_utf8_to_utf16(name, temp_allocator) or_return
|
||||
|
||||
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
buf := make([]u16, n+1, temp_allocator())
|
||||
buf := make([]u16, n+1, temp_allocator)
|
||||
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
@@ -65,9 +65,9 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runt
|
||||
if len(name) == 0 {
|
||||
return {}, .Not_Exist
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
wname := _fix_long_path(name, temp_allocator()) or_return
|
||||
wname := _fix_long_path(name, temp_allocator) or_return
|
||||
fa: win32.WIN32_FILE_ATTRIBUTE_DATA
|
||||
ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa)
|
||||
if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
||||
@@ -137,9 +137,9 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator())
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
|
||||
return _cleanpath_from_buf(buf[:n], allocator)
|
||||
}
|
||||
@@ -155,9 +155,9 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
|
||||
return nil, _get_platform_error()
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator())
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
|
||||
return _cleanpath_strip_prefix(buf[:n]), nil
|
||||
}
|
||||
@@ -236,14 +236,30 @@ _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: wi
|
||||
return
|
||||
}
|
||||
|
||||
// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)
|
||||
time_as_filetime :: #force_inline proc(t: time.Time) -> (ft: win32.LARGE_INTEGER) {
|
||||
win := u64(t._nsec / 100) + 116444736000000000
|
||||
return win32.LARGE_INTEGER(win)
|
||||
}
|
||||
|
||||
filetime_as_time_li :: #force_inline proc(ft: win32.LARGE_INTEGER) -> (t: time.Time) {
|
||||
return {_nsec=(i64(ft) - 116444736000000000) * 100}
|
||||
}
|
||||
|
||||
filetime_as_time_ft :: #force_inline proc(ft: win32.FILETIME) -> (t: time.Time) {
|
||||
return filetime_as_time_li(win32.LARGE_INTEGER(ft.dwLowDateTime) + win32.LARGE_INTEGER(ft.dwHighDateTime) << 32)
|
||||
}
|
||||
|
||||
filetime_as_time :: proc{filetime_as_time_ft, filetime_as_time_li}
|
||||
|
||||
_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
||||
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||
fi.type = type
|
||||
fi.mode |= mode
|
||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||
fi.creation_time = filetime_as_time(d.ftCreationTime)
|
||||
fi.modification_time = filetime_as_time(d.ftLastWriteTime)
|
||||
fi.access_time = filetime_as_time(d.ftLastAccessTime)
|
||||
fi.fullpath, e = full_path_from_name(name, allocator)
|
||||
fi.name = basename(fi.fullpath)
|
||||
return
|
||||
@@ -254,9 +270,9 @@ _file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string
|
||||
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||
fi.type = type
|
||||
fi.mode |= mode
|
||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||
fi.creation_time = filetime_as_time(d.ftCreationTime)
|
||||
fi.modification_time = filetime_as_time(d.ftLastWriteTime)
|
||||
fi.access_time = filetime_as_time(d.ftLastAccessTime)
|
||||
fi.fullpath, e = full_path_from_name(name, allocator)
|
||||
fi.name = basename(fi.fullpath)
|
||||
return
|
||||
@@ -286,9 +302,9 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA
|
||||
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, h, 0)
|
||||
fi.type = type
|
||||
fi.mode |= mode
|
||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||
fi.creation_time = filetime_as_time(d.ftCreationTime)
|
||||
fi.modification_time = filetime_as_time(d.ftLastWriteTime)
|
||||
fi.access_time = filetime_as_time(d.ftLastAccessTime)
|
||||
return fi, nil
|
||||
}
|
||||
|
||||
@@ -310,42 +326,68 @@ _is_reserved_name :: proc(path: string) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_is_UNC :: proc(path: string) -> bool {
|
||||
return _volume_name_len(path) > 2
|
||||
}
|
||||
|
||||
_volume_name_len :: proc(path: string) -> int {
|
||||
_volume_name_len :: proc(path: string) -> (length: int) {
|
||||
if len(path) < 2 {
|
||||
return 0
|
||||
}
|
||||
c := path[0]
|
||||
|
||||
if path[1] == ':' {
|
||||
switch c {
|
||||
switch path[0] {
|
||||
case 'a'..='z', 'A'..='Z':
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
// URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||
if l := len(path); l >= 5 && _is_path_separator(path[0]) && _is_path_separator(path[1]) &&
|
||||
!_is_path_separator(path[2]) && path[2] != '.' {
|
||||
for n := 3; n < l-1; n += 1 {
|
||||
if _is_path_separator(path[n]) {
|
||||
n += 1
|
||||
if !_is_path_separator(path[n]) {
|
||||
if path[n] == '.' {
|
||||
break
|
||||
}
|
||||
}
|
||||
for ; n < l; n += 1 {
|
||||
if _is_path_separator(path[n]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
/*
|
||||
See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||
Further allowed paths can be of the form of:
|
||||
- \\server\share or \\server\share\more\path
|
||||
- \\?\C:\...
|
||||
- \\.\PhysicalDriveX
|
||||
*/
|
||||
// Any remaining kind of path has to start with two slashes.
|
||||
if !_is_path_separator(path[0]) || !_is_path_separator(path[1]) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Device path. The volume name is the whole string
|
||||
if len(path) >= 5 && path[2] == '.' && _is_path_separator(path[3]) {
|
||||
return len(path)
|
||||
}
|
||||
|
||||
// We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share`
|
||||
prefix := 2
|
||||
|
||||
// File namespace.
|
||||
if len(path) >= 5 && path[2] == '?' && _is_path_separator(path[3]) {
|
||||
if _is_path_separator(path[4]) {
|
||||
// `\\?\\` UNC path in file namespace
|
||||
prefix = 5
|
||||
}
|
||||
|
||||
if len(path) >= 6 && path[5] == ':' {
|
||||
switch path[4] {
|
||||
case 'a'..='z', 'A'..='Z':
|
||||
return 6
|
||||
case:
|
||||
return 0
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// UNC path, minimum version of the volume is `\\h\s` for host, share.
|
||||
// Can also contain an IP address in the host position.
|
||||
slash_count := 0
|
||||
for i in prefix..<len(path) {
|
||||
// Host needs to be at least 1 character
|
||||
if _is_path_separator(path[i]) && i > 0 {
|
||||
slash_count += 1
|
||||
|
||||
if slash_count == 2 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len(path)
|
||||
}
|
||||
@@ -15,13 +15,13 @@ MAX_ATTEMPTS :: 1<<13 // Should be enough for everyone, right?
|
||||
// The caller must `close` the file once finished with.
|
||||
@(require_results)
|
||||
create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
|
||||
prefix, suffix := _prefix_and_suffix(pattern) or_return
|
||||
prefix = temp_join_path(dir, prefix) or_return
|
||||
|
||||
rand_buf: [10]byte
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator())
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
|
||||
|
||||
attempts := 0
|
||||
for {
|
||||
@@ -47,13 +47,13 @@ mkdir_temp :: make_directory_temp
|
||||
// If `dir` is an empty tring, `temp_directory()` will be used.
|
||||
@(require_results)
|
||||
make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (temp_path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
|
||||
prefix, suffix := _prefix_and_suffix(pattern) or_return
|
||||
prefix = temp_join_path(dir, prefix) or_return
|
||||
|
||||
rand_buf: [10]byte
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator())
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
|
||||
|
||||
attempts := 0
|
||||
for {
|
||||
@@ -70,7 +70,7 @@ make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator)
|
||||
return "", err
|
||||
}
|
||||
if err == .Not_Exist {
|
||||
if _, serr := stat(dir, temp_allocator()); serr == .Not_Exist {
|
||||
if _, serr := stat(dir, temp_allocator); serr == .Not_Exist {
|
||||
return "", serr
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,11 @@ temp_directory :: proc(allocator: runtime.Allocator) -> (string, Error) {
|
||||
|
||||
@(private="file")
|
||||
temp_join_path :: proc(dir, name: string) -> (string, runtime.Allocator_Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if len(dir) > 0 && is_path_separator(dir[len(dir)-1]) {
|
||||
return concatenate({dir, name}, temp_allocator(),)
|
||||
return concatenate({dir, name}, temp_allocator,)
|
||||
}
|
||||
|
||||
return concatenate({dir, Path_Separator_String, name}, temp_allocator())
|
||||
return concatenate({dir, Path_Separator_String, name}, temp_allocator)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ package os2
|
||||
import "base:runtime"
|
||||
|
||||
_temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
tmpdir := get_env("TMPDIR", temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
tmpdir := get_env("TMPDIR", temp_allocator)
|
||||
if tmpdir == "" {
|
||||
tmpdir = "/tmp"
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Er
|
||||
if n == 0 {
|
||||
return "", nil
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator())
|
||||
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator)
|
||||
n = win32.GetTempPathW(u32(len(b)), raw_data(b))
|
||||
|
||||
if n == 3 && b[1] == ':' && b[2] == '\\' {
|
||||
|
||||
+141
-71
@@ -2,78 +2,148 @@ package os2
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
@(require_results)
|
||||
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
dir = get_env("LocalAppData", temp_allocator())
|
||||
if dir != "" {
|
||||
dir = clone_string(dir, allocator) or_return
|
||||
}
|
||||
case .Darwin:
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
if dir != "" {
|
||||
dir = concatenate({dir, "/Library/Caches"}, allocator) or_return
|
||||
}
|
||||
case: // All other UNIX systems
|
||||
dir = get_env("XDG_CACHE_HOME", allocator)
|
||||
if dir == "" {
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
if dir == "" {
|
||||
return
|
||||
}
|
||||
dir = concatenate({dir, "/.cache"}, allocator) or_return
|
||||
}
|
||||
}
|
||||
if dir == "" {
|
||||
err = .Invalid_Path
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
dir = get_env("AppData", temp_allocator())
|
||||
if dir != "" {
|
||||
dir = clone_string(dir, allocator) or_return
|
||||
}
|
||||
case .Darwin:
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
if dir != "" {
|
||||
dir = concatenate({dir, "/.config"}, allocator) or_return
|
||||
}
|
||||
case: // All other UNIX systems
|
||||
dir = get_env("XDG_CONFIG_HOME", allocator)
|
||||
if dir == "" {
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
if dir == "" {
|
||||
return
|
||||
}
|
||||
dir = concatenate({dir, "/.config"}, allocator) or_return
|
||||
}
|
||||
}
|
||||
if dir == "" {
|
||||
err = .Invalid_Path
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice
|
||||
// macOS: /Users/Alice
|
||||
// Linux: /home/alice
|
||||
// ```
|
||||
@(require_results)
|
||||
user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
env := "HOME"
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
env = "USERPROFILE"
|
||||
}
|
||||
if v := get_env(env, allocator); v != "" {
|
||||
return v, nil
|
||||
}
|
||||
return "", .Invalid_Path
|
||||
return _user_home_dir(allocator)
|
||||
}
|
||||
|
||||
// Files that applications can regenerate/refetch at a loss of speed, e.g. shader caches
|
||||
//
|
||||
// Sometimes deleted for system maintenance
|
||||
//
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\AppData\Local
|
||||
// macOS: /Users/Alice/Library/Caches
|
||||
// Linux: /home/alice/.cache
|
||||
// ```
|
||||
@(require_results)
|
||||
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_cache_dir(allocator)
|
||||
}
|
||||
|
||||
// User-hidden application data
|
||||
//
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\AppData\Local ("C:\Users\Alice\AppData\Roaming" if `roaming`)
|
||||
// macOS: /Users/Alice/Library/Application Support
|
||||
// Linux: /home/alice/.local/share
|
||||
// ```
|
||||
//
|
||||
// NOTE: (Windows only) `roaming` is for syncing across multiple devices within a *domain network*
|
||||
@(require_results)
|
||||
user_data_dir :: proc(allocator: runtime.Allocator, roaming := false) -> (dir: string, err: Error) {
|
||||
return _user_data_dir(allocator, roaming)
|
||||
}
|
||||
|
||||
// Non-essential application data, e.g. history, ui layout state
|
||||
//
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\AppData\Local
|
||||
// macOS: /Users/Alice/Library/Application Support
|
||||
// Linux: /home/alice/.local/state
|
||||
// ```
|
||||
@(require_results)
|
||||
user_state_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_state_dir(allocator)
|
||||
}
|
||||
|
||||
// Application log files
|
||||
//
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\AppData\Local
|
||||
// macOS: /Users/Alice/Library/Logs
|
||||
// Linux: /home/alice/.local/state
|
||||
// ```
|
||||
@(require_results)
|
||||
user_log_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_log_dir(allocator)
|
||||
}
|
||||
|
||||
// Application settings/preferences
|
||||
//
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\AppData\Local ("C:\Users\Alice\AppData\Roaming" if `roaming`)
|
||||
// macOS: /Users/Alice/Library/Application Support
|
||||
// Linux: /home/alice/.config
|
||||
// ```
|
||||
//
|
||||
// NOTE: (Windows only) `roaming` is for syncing across multiple devices within a *domain network*
|
||||
@(require_results)
|
||||
user_config_dir :: proc(allocator: runtime.Allocator, roaming := false) -> (dir: string, err: Error) {
|
||||
return _user_config_dir(allocator, roaming)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Music
|
||||
// macOS: /Users/Alice/Music
|
||||
// Linux: /home/alice/Music
|
||||
// ```
|
||||
@(require_results)
|
||||
user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_music_dir(allocator)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Desktop
|
||||
// macOS: /Users/Alice/Desktop
|
||||
// Linux: /home/alice/Desktop
|
||||
// ```
|
||||
@(require_results)
|
||||
user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_desktop_dir(allocator)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Documents
|
||||
// macOS: /Users/Alice/Documents
|
||||
// Linux: /home/alice/Documents
|
||||
// ```
|
||||
@(require_results)
|
||||
user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_documents_dir(allocator)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Downloads
|
||||
// macOS: /Users/Alice/Downloads
|
||||
// Linux: /home/alice/Downloads
|
||||
// ```
|
||||
@(require_results)
|
||||
user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_downloads_dir(allocator)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Pictures
|
||||
// macOS: /Users/Alice/Pictures
|
||||
// Linux: /home/alice/Pictures
|
||||
// ```
|
||||
@(require_results)
|
||||
user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_pictures_dir(allocator)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Public
|
||||
// macOS: /Users/Alice/Public
|
||||
// Linux: /home/alice/Public
|
||||
// ```
|
||||
@(require_results)
|
||||
user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_public_dir(allocator)
|
||||
}
|
||||
|
||||
// ```
|
||||
// Windows: C:\Users\Alice\Videos
|
||||
// macOS: /Users/Alice/Movies
|
||||
// Linux: /home/alice/Videos
|
||||
// ```
|
||||
@(require_results)
|
||||
user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
return _user_videos_dir(allocator)
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
#+build !windows
|
||||
package os2
|
||||
|
||||
import "base:runtime"
|
||||
import "core:encoding/ini"
|
||||
import "core:strings"
|
||||
import "core:sys/posix"
|
||||
|
||||
_user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Library/Caches", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_CACHE_HOME", "/.cache", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_config_dir :: proc(allocator: runtime.Allocator, _roaming: bool) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Library/Application Support", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_CONFIG_HOME", "/.config", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_state_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Library/Application Support", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_STATE_HOME", "/.local/state", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_log_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Library/Logs", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_STATE_HOME", "/.local/state", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_data_dir :: proc(allocator: runtime.Allocator, _roaming: bool) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Library/Application Support", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_DATA_HOME", "/.local/share", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Music", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_MUSIC_DIR", "/Music", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Desktop", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_DESKTOP_DIR", "/Desktop", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Documents", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_DOCUMENTS_DIR", "/Documents", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Downloads", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_DOWNLOAD_DIR", "/Downloads", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Pictures", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_PICTURES_DIR", "/Pictures", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Public", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_PUBLICSHARE_DIR", "/Public", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
#partial switch ODIN_OS {
|
||||
case .Darwin:
|
||||
return _xdg_lookup("", "/Movies", allocator)
|
||||
case: // Unix
|
||||
return _xdg_lookup("XDG_VIDEOS_DIR", "/Videos", allocator)
|
||||
}
|
||||
}
|
||||
|
||||
_user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
if v := get_env("HOME", allocator); v != "" {
|
||||
return v, nil
|
||||
}
|
||||
err = .No_HOME_Variable
|
||||
return
|
||||
}
|
||||
|
||||
_xdg_lookup :: proc(xdg_key: string, fallback_suffix: string, allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
if xdg_key == "" { // Darwin doesn't have XDG paths.
|
||||
dir = get_env("HOME", temp_allocator)
|
||||
if dir == "" {
|
||||
err = .No_HOME_Variable
|
||||
return
|
||||
}
|
||||
return concatenate({dir, fallback_suffix}, allocator)
|
||||
} else {
|
||||
if strings.ends_with(xdg_key, "_DIR") {
|
||||
dir = _xdg_user_dirs_lookup(xdg_key, allocator) or_return
|
||||
} else {
|
||||
dir = get_env(xdg_key, allocator)
|
||||
}
|
||||
|
||||
if dir == "" {
|
||||
dir = get_env("HOME", temp_allocator)
|
||||
if dir == "" {
|
||||
err = .No_HOME_Variable
|
||||
return
|
||||
}
|
||||
dir = concatenate({dir, fallback_suffix}, allocator) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If `<config-dir>/user-dirs.dirs` doesn't exist, or `xdg_key` can't be found there: returns `""`
|
||||
_xdg_user_dirs_lookup :: proc(xdg_key: string, allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
config_dir := user_config_dir(temp_allocator) or_return
|
||||
user_dirs_path := concatenate({config_dir, "/user-dirs.dirs"}, temp_allocator) or_return
|
||||
content := read_entire_file(user_dirs_path, temp_allocator) or_return
|
||||
|
||||
it := ini.Iterator{
|
||||
section = "",
|
||||
_src = string(content),
|
||||
options = ini.Options{
|
||||
comment = "#",
|
||||
key_lower_case = false,
|
||||
},
|
||||
}
|
||||
|
||||
for k, v in ini.iterate(&it) {
|
||||
if k == xdg_key {
|
||||
we: posix.wordexp_t
|
||||
defer posix.wordfree(&we)
|
||||
|
||||
if _err := posix.wordexp(strings.clone_to_cstring(v, temp_allocator), &we, nil); _err != nil || we.we_wordc != 1 {
|
||||
return "", .Wordexp_Failed
|
||||
}
|
||||
|
||||
return strings.clone_from_cstring(we.we_wordv[0], allocator)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package os2
|
||||
|
||||
import "base:runtime"
|
||||
@(require) import win32 "core:sys/windows"
|
||||
|
||||
_local_appdata :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_LocalAppData
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_local_appdata_or_roaming :: proc(allocator: runtime.Allocator, roaming: bool) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_LocalAppData
|
||||
if roaming {
|
||||
guid = win32.FOLDERID_RoamingAppData
|
||||
}
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_config_dir :: _local_appdata_or_roaming
|
||||
_user_data_dir :: _local_appdata_or_roaming
|
||||
|
||||
_user_state_dir :: _local_appdata
|
||||
_user_log_dir :: _local_appdata
|
||||
_user_cache_dir :: _local_appdata
|
||||
|
||||
_user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Profile
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Music
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Desktop
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Documents
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Downloads
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Pictures
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Public
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
guid := win32.FOLDERID_Videos
|
||||
return _get_known_folder_path(&guid, allocator)
|
||||
}
|
||||
|
||||
_get_known_folder_path :: proc(rfid: win32.REFKNOWNFOLDERID, allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
|
||||
// See also `known_folders.odin` in `core:sys/windows` for the GUIDs.
|
||||
path_w: win32.LPWSTR
|
||||
res := win32.SHGetKnownFolderPath(rfid, 0, nil, &path_w)
|
||||
defer win32.CoTaskMemFree(path_w)
|
||||
|
||||
if res != 0 {
|
||||
return "", .Invalid_Path
|
||||
}
|
||||
|
||||
dir, _ = win32.wstring_to_utf8(path_w, -1, allocator)
|
||||
return
|
||||
}
|
||||
@@ -249,3 +249,7 @@ exit :: proc "contextless" (code: int) -> ! {
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return 0
|
||||
}
|
||||
|
||||
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
|
||||
return "", false
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package filepath
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
import "core:strings"
|
||||
|
||||
SEPARATOR :: '/'
|
||||
SEPARATOR_STRING :: `/`
|
||||
LIST_SEPARATOR :: ':'
|
||||
|
||||
is_reserved_name :: proc(path: string) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
is_abs :: proc(path: string) -> bool {
|
||||
return strings.has_prefix(path, "/")
|
||||
}
|
||||
|
||||
abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
|
||||
if is_abs(path) {
|
||||
return strings.clone(string(path), allocator), true
|
||||
}
|
||||
|
||||
return path, false
|
||||
}
|
||||
|
||||
join :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) #optional_allocator_error {
|
||||
for e, i in elems {
|
||||
if e != "" {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
|
||||
p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return
|
||||
return clean(p, allocator)
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
+211
-10
@@ -21,20 +21,17 @@ package simd
|
||||
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
|
||||
/*
|
||||
Check if SIMD is software-emulated on a target platform.
|
||||
|
||||
This value is `false`, when the compile-time target has the hardware support for
|
||||
at 128-bit (or wider) SIMD. If the compile-time target lacks the hardware support
|
||||
for 128-bit SIMD, this value is `true`, and all SIMD operations will likely be
|
||||
This value is `true`, when the compile-time target has the hardware support for
|
||||
at least 128-bit (or wider) SIMD. If the compile-time target lacks the hardware support
|
||||
for 128-bit SIMD, this value is `false`, and all SIMD operations will likely be
|
||||
emulated.
|
||||
*/
|
||||
IS_EMULATED :: true when (ODIN_ARCH == .amd64 || ODIN_ARCH == .i386) && !intrinsics.has_target_feature("sse2") else
|
||||
true when (ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32) && !intrinsics.has_target_feature("neon") else
|
||||
true when (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") else
|
||||
true when (ODIN_ARCH == .riscv64) && !intrinsics.has_target_feature("v") else
|
||||
false
|
||||
HAS_HARDWARE_SIMD :: runtime.HAS_HARDWARE_SIMD
|
||||
|
||||
/*
|
||||
Vector of 16 `u8` lanes (128 bits).
|
||||
@@ -1759,7 +1756,103 @@ Returns:
|
||||
replace :: intrinsics.simd_replace
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by adding up all the lanes.
|
||||
Reduce a vector to a scalar by adding up all the lanes in a bisecting fashion.
|
||||
|
||||
This procedure returns a scalar that is the sum of all lanes, calculated by
|
||||
bisecting the vector into two parts, where the first contains lanes [0, N/2)
|
||||
and the second contains lanes [N/2, N), and adding the two halves element-wise
|
||||
to produce N/2 values. This is repeated until only a single element remains.
|
||||
This order may be faster to compute than the ordered sum for floats, as it can
|
||||
often be better parallelized.
|
||||
|
||||
The order of the sum may be important for accounting for precision errors in
|
||||
floating-point computation, as floating-point addition is not associative, that
|
||||
is `(a+b)+c` may not be equal to `a+(b+c)`.
|
||||
|
||||
Inputs:
|
||||
- `v`: The vector to reduce.
|
||||
|
||||
Result:
|
||||
- Sum of all lanes, as a scalar.
|
||||
|
||||
**Operation**:
|
||||
|
||||
for n > 1 {
|
||||
n = n / 2
|
||||
for i in 0 ..< n {
|
||||
a[i] += a[i+n]
|
||||
}
|
||||
}
|
||||
res := a[0]
|
||||
|
||||
Graphical representation of the operation for N=4:
|
||||
|
||||
+-----------------------+
|
||||
| v0 | v1 | v2 | v3 |
|
||||
+-----------------------+
|
||||
| | | |
|
||||
[+]<-- | ---' |
|
||||
| [+]<--------'
|
||||
| |
|
||||
`>[+]<'
|
||||
|
|
||||
v
|
||||
+-----+
|
||||
result: | y0 |
|
||||
+-----+
|
||||
*/
|
||||
reduce_add_bisect :: intrinsics.simd_reduce_add_bisect
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by multiplying up all the lanes in a bisecting fashion.
|
||||
|
||||
This procedure returns a scalar that is the product of all lanes, calculated by
|
||||
bisecting the vector into two parts, where the first contains indices [0, N/2)
|
||||
and the second contains indices [N/2, N), and multiplying the two halves
|
||||
together element-wise to produce N/2 values. This is repeated until only a
|
||||
single element remains. This order may be faster to compute than the ordered
|
||||
product for floats, as it can often be better parallelized.
|
||||
|
||||
The order of the product may be important for accounting for precision errors
|
||||
in floating-point computation, as floating-point multiplication is not
|
||||
associative, that is `(a*b)*c` may not be equal to `a*(b*c)`.
|
||||
|
||||
Inputs:
|
||||
- `v`: The vector to reduce.
|
||||
|
||||
Result:
|
||||
- Product of all lanes, as a scalar.
|
||||
|
||||
**Operation**:
|
||||
|
||||
for n > 1 {
|
||||
n = n / 2
|
||||
for i in 0 ..< n {
|
||||
a[i] *= a[i+n]
|
||||
}
|
||||
}
|
||||
res := a[0]
|
||||
|
||||
Graphical representation of the operation for N=4:
|
||||
|
||||
+-----------------------+
|
||||
| v0 | v1 | v2 | v3 |
|
||||
+-----------------------+
|
||||
| | | |
|
||||
[x]<-- | ---' |
|
||||
| [x]<--------'
|
||||
| |
|
||||
`>[x]<'
|
||||
|
|
||||
v
|
||||
+-----+
|
||||
result: | y0 |
|
||||
+-----+
|
||||
*/
|
||||
reduce_mul_bisect :: intrinsics.simd_reduce_mul_bisect
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by adding up all the lanes in an ordered fashion.
|
||||
|
||||
This procedure returns a scalar that is the ordered sum of all lanes. The
|
||||
ordered sum may be important for accounting for precision errors in
|
||||
@@ -1782,7 +1875,7 @@ Result:
|
||||
reduce_add_ordered :: intrinsics.simd_reduce_add_ordered
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by multiplying all the lanes.
|
||||
Reduce a vector to a scalar by multiplying all the lanes in an ordered fashion.
|
||||
|
||||
This procedure returns a scalar that is the ordered product of all lanes.
|
||||
The ordered product may be important for accounting for precision errors in
|
||||
@@ -1804,6 +1897,100 @@ Result:
|
||||
*/
|
||||
reduce_mul_ordered :: intrinsics.simd_reduce_mul_ordered
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by adding up all the lanes in a pairwise fashion.
|
||||
|
||||
This procedure returns a scalar that is the sum of all lanes, calculated by
|
||||
adding each even-indexed element with the following odd-indexed element to
|
||||
produce N/2 values. This is repeated until only a single element remains. This
|
||||
order is supported by hardware instructions for some types/architectures (e.g.
|
||||
i16/i32/f32/f64 on x86 SSE, i8/i16/i32/f32 on ARM NEON).
|
||||
|
||||
The order of the sum may be important for accounting for precision errors in
|
||||
floating-point computation, as floating-point addition is not associative, that
|
||||
is `(a+b)+c` may not be equal to `a+(b+c)`.
|
||||
|
||||
Inputs:
|
||||
- `v`: The vector to reduce.
|
||||
|
||||
Result:
|
||||
- Sum of all lanes, as a scalar.
|
||||
|
||||
**Operation**:
|
||||
|
||||
for n > 1 {
|
||||
n = n / 2
|
||||
for i in 0 ..< n {
|
||||
a[i] = a[2*i+0] + a[2*i+1]
|
||||
}
|
||||
}
|
||||
res := a[0]
|
||||
|
||||
Graphical representation of the operation for N=4:
|
||||
|
||||
+-----------------------+
|
||||
v: | v0 | v1 | v2 | v3 |
|
||||
+-----------------------+
|
||||
| | | |
|
||||
`>[+]<' `>[+]<'
|
||||
| |
|
||||
`--->[+]<--'
|
||||
|
|
||||
v
|
||||
+-----+
|
||||
result: | y0 |
|
||||
+-----+
|
||||
*/
|
||||
reduce_add_pairs :: intrinsics.simd_reduce_add_pairs
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by multiplying all the lanes in a pairwise fashion.
|
||||
|
||||
This procedure returns a scalar that is the product of all lanes, calculated by
|
||||
bisecting the vector into two parts, where the first contains lanes [0, N/2)
|
||||
and the second contains lanes [N/2, N), and multiplying the two halves together
|
||||
multiplying each even-indexed element with the following odd-indexed element to
|
||||
produce N/2 values. This is repeated until only a single element remains. This
|
||||
order may be faster to compute than the ordered product for floats, as it can
|
||||
often be better parallelized.
|
||||
|
||||
The order of the product may be important for accounting for precision errors
|
||||
in floating-point computation, as floating-point multiplication is not
|
||||
associative, that is `(a*b)*c` may not be equal to `a*(b*c)`.
|
||||
|
||||
Inputs:
|
||||
- `v`: The vector to reduce.
|
||||
|
||||
Result:
|
||||
- Product of all lanes, as a scalar.
|
||||
|
||||
**Operation**:
|
||||
|
||||
for n > 1 {
|
||||
n = n / 2
|
||||
for i in 0 ..< n {
|
||||
a[i] = a[2*i+0] * a[2*i+1]
|
||||
}
|
||||
}
|
||||
res := a[0]
|
||||
|
||||
Graphical representation of the operation for N=4:
|
||||
|
||||
+-----------------------+
|
||||
v: | v0 | v1 | v2 | v3 |
|
||||
+-----------------------+
|
||||
| | | |
|
||||
`>[x]<' `>[x]<'
|
||||
| |
|
||||
`--->[x]<--'
|
||||
|
|
||||
v
|
||||
+-----+
|
||||
result: | y0 |
|
||||
+-----+
|
||||
*/
|
||||
reduce_mul_pairs :: intrinsics.simd_reduce_mul_pairs
|
||||
|
||||
/*
|
||||
Reduce a vector to a scalar by finding the minimum value between all of the lanes.
|
||||
|
||||
@@ -2510,3 +2697,17 @@ Example:
|
||||
recip :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
|
||||
return T(1) / v
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Create a vector where each lane contains the index of that lane.
|
||||
Inputs:
|
||||
- `V`: The type of the vector to create.
|
||||
Result:
|
||||
- A vector of the given type, where each lane contains the index of that lane.
|
||||
**Operation**:
|
||||
for i in 0 ..< N {
|
||||
res[i] = i
|
||||
}
|
||||
*/
|
||||
indices :: intrinsics.simd_indices
|
||||
@@ -0,0 +1,79 @@
|
||||
#+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_andn_u32 :: #force_inline proc "c" (a, b: u32) -> u32 {
|
||||
return a &~ b
|
||||
}
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_andn_u64 :: #force_inline proc "c" (a, b: u64) -> u64 {
|
||||
return a &~ b
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_bextr_u32 :: #force_inline proc "c" (a, start, len: u32) -> u32 {
|
||||
return bextr_u32(a, (start & 0xff) | (len << 8))
|
||||
}
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_bextr_u64 :: #force_inline proc "c" (a: u64, start, len: u32) -> u64 {
|
||||
return bextr_u64(a, cast(u64)((start & 0xff) | (len << 8)))
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_bextr2_u32 :: #force_inline proc "c" (a, control: u32) -> u32 {
|
||||
return bextr_u32(a, control)
|
||||
}
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_bextr2_u64 :: #force_inline proc "c" (a, control: u64) -> u64 {
|
||||
return bextr_u64(a, control)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_blsi_u32 :: #force_inline proc "c" (a: u32) -> u32 {
|
||||
return a & -a
|
||||
}
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_blsi_u64 :: #force_inline proc "c" (a: u64) -> u64 {
|
||||
return a & -a
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_blsmsk_u32 :: #force_inline proc "c" (a: u32) -> u32 {
|
||||
return a ~ (a-1)
|
||||
}
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_blsmsk_u64 :: #force_inline proc "c" (a: u64) -> u64 {
|
||||
return a ~ (a-1)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_blsr_u32 :: #force_inline proc "c" (a: u32) -> u32 {
|
||||
return a & (a-1)
|
||||
}
|
||||
@(require_results, enable_target_feature="bmi")
|
||||
_blsr_u64 :: #force_inline proc "c" (a: u64) -> u64 {
|
||||
return a & (a-1)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature = "bmi")
|
||||
_tzcnt_u16 :: #force_inline proc "c" (a: u16) -> u16 {
|
||||
return intrinsics.count_trailing_zeros(a)
|
||||
}
|
||||
@(require_results, enable_target_feature = "bmi")
|
||||
_tzcnt_u32 :: #force_inline proc "c" (a: u32) -> u32 {
|
||||
return intrinsics.count_trailing_zeros(a)
|
||||
}
|
||||
@(require_results, enable_target_feature = "bmi")
|
||||
_tzcnt_u64 :: #force_inline proc "c" (a: u64) -> u64 {
|
||||
return intrinsics.count_trailing_zeros(a)
|
||||
}
|
||||
|
||||
@(private, default_calling_convention = "none")
|
||||
foreign _ {
|
||||
@(link_name = "llvm.x86.bmi.bextr.32")
|
||||
bextr_u32 :: proc(a, control: u32) -> u32 ---
|
||||
@(link_name = "llvm.x86.bmi.bextr.64")
|
||||
bextr_u64 :: proc(a, control: u64) -> u64 ---
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
@(require_results, enable_target_feature = "bmi2")
|
||||
_bzhi_u32 :: #force_inline proc "c" (a, index: u32) -> u32 {
|
||||
return bzhi_u32(a, index)
|
||||
}
|
||||
@(require_results, enable_target_feature = "bmi2")
|
||||
_bzhi_u64 :: #force_inline proc "c" (a, index: u64) -> u64 {
|
||||
return bzhi_u64(a, index)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature = "bmi2")
|
||||
_pdep_u32 :: #force_inline proc "c" (a, mask: u32) -> u32 {
|
||||
return pdep_u32(a, mask)
|
||||
}
|
||||
@(require_results, enable_target_feature = "bmi2")
|
||||
_pdep_u64 :: #force_inline proc "c" (a, mask: u64) -> u64 {
|
||||
return pdep_u64(a, mask)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature = "bmi2")
|
||||
_pext_u32 :: #force_inline proc "c" (a, mask: u32) -> u32 {
|
||||
return pext_u32(a, mask)
|
||||
}
|
||||
@(require_results, enable_target_feature = "bmi2")
|
||||
_pext_u64 :: #force_inline proc "c" (a, mask: u64) -> u64 {
|
||||
return pext_u64(a, mask)
|
||||
}
|
||||
|
||||
|
||||
@(private, default_calling_convention = "none")
|
||||
foreign _ {
|
||||
@(link_name = "llvm.x86.bmi.bzhi.32")
|
||||
bzhi_u32 :: proc(a, index: u32) -> u32 ---
|
||||
@(link_name = "llvm.x86.bmi.bzhi.64")
|
||||
bzhi_u64 :: proc(a, index: u64) -> u64 ---
|
||||
@(link_name = "llvm.x86.bmi.pdep.32")
|
||||
pdep_u32 :: proc(a, mask: u32) -> u32 ---
|
||||
@(link_name = "llvm.x86.bmi.pdep.64")
|
||||
pdep_u64 :: proc(a, mask: u64) -> u64 ---
|
||||
@(link_name = "llvm.x86.bmi.pext.32")
|
||||
pext_u32 :: proc(a, mask: u32) -> u32 ---
|
||||
@(link_name = "llvm.x86.bmi.pext.64")
|
||||
pext_u64 :: proc(a, mask: u64) -> u64 ---
|
||||
}
|
||||
@@ -30,14 +30,6 @@ sort :: proc(it: Interface) {
|
||||
_quick_sort(it, 0, n, max_depth(n))
|
||||
}
|
||||
|
||||
|
||||
@(deprecated="use slice.sort")
|
||||
slice :: proc(array: $T/[]$E) where ORD(E) {
|
||||
_slice.sort(array)
|
||||
// s := array;
|
||||
// sort(slice_interface(&s));
|
||||
}
|
||||
|
||||
slice_interface :: proc(s: ^$T/[]$E) -> Interface where ORD(E) {
|
||||
return Interface{
|
||||
collection = rawptr(s),
|
||||
@@ -80,31 +72,6 @@ reverse_sort :: proc(it: Interface) {
|
||||
sort(reverse_interface(&it))
|
||||
}
|
||||
|
||||
@(deprecated="use slice.reverse")
|
||||
reverse_slice :: proc(array: $T/[]$E) where ORD(E) {
|
||||
_slice.reverse(array)
|
||||
/*
|
||||
s := array;
|
||||
sort(Interface{
|
||||
collection = rawptr(&s),
|
||||
len = proc(it: Interface) -> int {
|
||||
s := (^T)(it.collection);
|
||||
return len(s^);
|
||||
},
|
||||
less = proc(it: Interface, i, j: int) -> bool {
|
||||
s := (^T)(it.collection);
|
||||
return s[j] < s[i]; // manual set up
|
||||
},
|
||||
swap = proc(it: Interface, i, j: int) {
|
||||
s := (^T)(it.collection);
|
||||
s[i], s[j] = s[j], s[i];
|
||||
},
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
is_sorted :: proc(it: Interface) -> bool {
|
||||
n := it->len()
|
||||
for i := n-1; i > 0; i -= 1 {
|
||||
@@ -294,11 +261,6 @@ _insertion_sort :: proc(it: Interface, a, b: int) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// @(deprecated="use sort.sort or slice.sort_by")
|
||||
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil)
|
||||
count := len(array)
|
||||
@@ -327,7 +289,6 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
}
|
||||
}
|
||||
|
||||
// @(deprecated="use sort.sort_slice or slice.sort")
|
||||
bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
count := len(array)
|
||||
|
||||
@@ -355,7 +316,6 @@ bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
}
|
||||
}
|
||||
|
||||
// @(deprecated="use sort.sort or slice.sort_by")
|
||||
quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil)
|
||||
a := array
|
||||
@@ -384,7 +344,6 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
quick_sort_proc(a[i:n], f)
|
||||
}
|
||||
|
||||
// @(deprecated="use sort.sort_slice or slice.sort")
|
||||
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
a := array
|
||||
n := len(a)
|
||||
@@ -420,7 +379,6 @@ _log2 :: proc(x: int) -> int {
|
||||
return res
|
||||
}
|
||||
|
||||
// @(deprecated="use sort.sort or slice.sort_by")
|
||||
merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) {
|
||||
s, m := start, mid
|
||||
@@ -462,7 +420,6 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
internal_sort(array, 0, len(array)-1, f)
|
||||
}
|
||||
|
||||
// @(deprecated="use sort.sort_slice or slice.sort")
|
||||
merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
merge :: proc(a: A, start, mid, end: int) {
|
||||
s, m := start, mid
|
||||
@@ -504,8 +461,6 @@ merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
internal_sort(array, 0, len(array)-1)
|
||||
}
|
||||
|
||||
|
||||
// @(deprecated="use sort.sort or slice.sort_by")
|
||||
heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
sift_proc :: proc(a: A, pi: int, n: int, f: proc(T, T) -> int) #no_bounds_check {
|
||||
p := pi
|
||||
@@ -540,7 +495,6 @@ heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
}
|
||||
}
|
||||
|
||||
// @(deprecated="use sort.sort_slice or slice.sort")
|
||||
heap_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
sift :: proc(a: A, pi: int, n: int) #no_bounds_check {
|
||||
p := pi
|
||||
|
||||
@@ -12,11 +12,11 @@ Decimal :: struct {
|
||||
Sets a Decimal from a given string `s`. The string is expected to represent a float. Stores parsed number in the given Decimal structure.
|
||||
If parsing fails, the Decimal will be left in an undefined state.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- d: Pointer to a Decimal struct where the parsed result will be stored
|
||||
- s: The input string representing the floating-point number
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- ok: A boolean indicating whether the parsing was successful
|
||||
*/
|
||||
set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
|
||||
@@ -104,11 +104,11 @@ set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
|
||||
/*
|
||||
Converts a Decimal to a string representation, using the provided buffer as storage.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- buf: A byte slice buffer to hold the resulting string
|
||||
- a: The struct to be converted to a string
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- A string representation of the Decimal
|
||||
*/
|
||||
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||
@@ -150,7 +150,7 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||
/*
|
||||
Trims trailing zeros in the given Decimal, updating the count and decimal_point values as needed.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: Pointer to the Decimal struct to be trimmed
|
||||
*/
|
||||
trim :: proc(a: ^Decimal) {
|
||||
@@ -166,7 +166,7 @@ Converts a given u64 integer `idx` to its Decimal representation in the provided
|
||||
|
||||
**Used for internal Decimal Operations.**
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: Where the result will be stored
|
||||
- idx: The value to be assigned to the Decimal
|
||||
*/
|
||||
@@ -190,11 +190,11 @@ assign :: proc(a: ^Decimal, idx: u64) {
|
||||
trim(a)
|
||||
}
|
||||
/*
|
||||
Shifts the Decimal value to the right by k positions.
|
||||
Shifts the Decimal value to the right by k positions.
|
||||
|
||||
**Used for internal Decimal Operations.**
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal struct to be shifted
|
||||
- k: The number of positions to shift right
|
||||
*/
|
||||
@@ -344,7 +344,7 @@ Shifts the decimal of the input value to the left by `k` places
|
||||
|
||||
WARNING: asserts `k < 61`
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal to be modified
|
||||
- k: The number of places to shift the decimal to the left
|
||||
*/
|
||||
@@ -405,7 +405,7 @@ shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
|
||||
/*
|
||||
Shifts the decimal of the input value by the specified number of places
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal to be modified
|
||||
- i: The number of places to shift the decimal (positive for left shift, negative for right shift)
|
||||
*/
|
||||
@@ -435,7 +435,7 @@ shift :: proc(a: ^Decimal, i: int) {
|
||||
/*
|
||||
Determines if the Decimal can be rounded up at the given digit index
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal to check
|
||||
- nd: The digit index to consider for rounding up
|
||||
|
||||
@@ -455,7 +455,7 @@ can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
|
||||
/*
|
||||
Rounds the Decimal at the given digit index
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal to be modified
|
||||
- nd: The digit index to round
|
||||
*/
|
||||
@@ -470,7 +470,7 @@ round :: proc(a: ^Decimal, nd: int) {
|
||||
/*
|
||||
Rounds the Decimal up at the given digit index
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal to be modified
|
||||
- nd: The digit index to round up
|
||||
*/
|
||||
@@ -493,7 +493,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
|
||||
/*
|
||||
Rounds down the decimal value to the specified number of decimal places
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: The Decimal value to be rounded down
|
||||
- nd: The number of decimal places to round down to
|
||||
|
||||
@@ -522,7 +522,7 @@ round_down :: proc(a: ^Decimal, nd: int) {
|
||||
/*
|
||||
Extracts the rounded integer part of a decimal value
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- a: A pointer to the Decimal value to extract the rounded integer part from
|
||||
|
||||
WARNING: There are no guarantees about overflow.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package strconv
|
||||
|
||||
// (2025-06-05) These procedures are to be removed at a later release.
|
||||
|
||||
@(deprecated="Use write_bits instead")
|
||||
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
return write_bits(buf, x, base, is_signed, bit_size, digits, flags)
|
||||
}
|
||||
|
||||
@(deprecated="Use write_bits_128 instead")
|
||||
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
return write_bits_128(buf, x, base, is_signed, bit_size, digits, flags)
|
||||
}
|
||||
|
||||
@(deprecated="Use write_bool instead")
|
||||
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
return write_bool(buf, b)
|
||||
}
|
||||
|
||||
@(deprecated="Use write_uint instead")
|
||||
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return write_uint(buf, u, base)
|
||||
}
|
||||
|
||||
@(deprecated="Use write_int instead")
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return write_int(buf, i, base)
|
||||
}
|
||||
|
||||
@(deprecated="Use write_u128 instead")
|
||||
append_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
|
||||
return write_u128(buf, u, base)
|
||||
}
|
||||
|
||||
@(deprecated="Use write_float instead")
|
||||
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return write_float(buf, f, fmt, prec, bit_size)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ _f64_info := Float_Info{52, 11, -1023}
|
||||
/*
|
||||
Converts a floating-point number to a string with the specified format and precision.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
|
||||
buf: A byte slice to store the resulting string
|
||||
val: The floating-point value to be converted
|
||||
@@ -40,7 +40,7 @@ Example:
|
||||
bit_size := 64
|
||||
result := strconv.generic_ftoa(buf[:], val, fmt, precision, bit_size) -> "3.14"
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- A byte slice containing the formatted string
|
||||
*/
|
||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
|
||||
@@ -122,7 +122,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int)
|
||||
/*
|
||||
Converts a decimal floating-point number into a byte buffer with the given format
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- buf: The byte buffer to store the formatted number
|
||||
- shortest: If true, generates the shortest representation of the number
|
||||
- neg: If true, the number is negative
|
||||
@@ -130,7 +130,7 @@ Converts a decimal floating-point number into a byte buffer with the given forma
|
||||
- precision: The number of digits after the decimal point
|
||||
- fmt: The format specifier (accepted values: 'f', 'F', 'e', 'E', 'g', 'G')
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- A byte slice containing the formatted decimal floating-point number
|
||||
*/
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte {
|
||||
@@ -256,7 +256,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
|
||||
/*
|
||||
Rounds the given decimal number to its shortest representation, considering the provided floating-point format
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- d: The decimal number to round
|
||||
- mant: The mantissa of the floating-point number
|
||||
- exp: The exponent of the floating-point number
|
||||
@@ -331,11 +331,11 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
|
||||
/*
|
||||
Converts a decimal number to its floating-point representation with the given format and returns the resulting bits
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- d: Pointer to the decimal number to convert
|
||||
- info: Pointer to the Float_Info structure containing information about the floating-point format
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- b: The bits representing the floating-point number
|
||||
- overflow: A boolean indicating whether an overflow occurred during conversion
|
||||
*/
|
||||
|
||||
+15
-15
@@ -12,12 +12,12 @@ digits := "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
/*
|
||||
Determines whether the given unsigned 64-bit integer is a negative value by interpreting it as a signed integer with the specified bit size.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- x: The unsigned 64-bit integer to check for negativity
|
||||
- is_signed: A boolean indicating if the input should be treated as a signed integer
|
||||
- bit_size: The bit size of the signed integer representation (8, 16, 32, or 64)
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- u: The absolute value of the input integer
|
||||
- neg: A boolean indicating whether the input integer is negative
|
||||
*/
|
||||
@@ -48,9 +48,9 @@ is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64,
|
||||
return
|
||||
}
|
||||
/*
|
||||
Appends the string representation of an integer to a buffer with specified base, flags, and digit set.
|
||||
Writes the string representation of an integer to a buffer with specified base, flags, and digit set.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- buf: The buffer to append the integer representation to
|
||||
- x: The integer value to convert
|
||||
- base: The base for the integer representation (2 <= base <= MAX_BASE)
|
||||
@@ -59,12 +59,12 @@ Appends the string representation of an integer to a buffer with specified base,
|
||||
- digits: The digit set used for the integer representation
|
||||
- flags: The Int_Flags bit set to control integer formatting
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- The string containing the integer representation appended to the buffer
|
||||
*/
|
||||
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
write_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits")
|
||||
panic("strconv: illegal base passed to write_bits")
|
||||
}
|
||||
|
||||
a: [129]byte
|
||||
@@ -106,12 +106,12 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i
|
||||
/*
|
||||
Determines whether the given unsigned 128-bit integer is a negative value by interpreting it as a signed integer with the specified bit size.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- x: The unsigned 128-bit integer to check for negativity
|
||||
- is_signed: A boolean indicating if the input should be treated as a signed integer
|
||||
- bit_size: The bit size of the signed integer representation (8, 16, 32, 64, or 128)
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- u: The absolute value of the input integer
|
||||
- neg: A boolean indicating whether the input integer is negative
|
||||
*/
|
||||
@@ -146,9 +146,9 @@ is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u:
|
||||
return
|
||||
}
|
||||
/*
|
||||
Appends the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set.
|
||||
Writes the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set.
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- buf: The buffer to append the integer representation to
|
||||
- x: The 128-bit integer value to convert
|
||||
- base: The base for the integer representation (2 <= base <= MAX_BASE)
|
||||
@@ -157,12 +157,12 @@ Appends the string representation of a 128-bit integer to a buffer with specifie
|
||||
- digits: The digit set used for the integer representation
|
||||
- flags: The Int_Flags bit set to control integer formatting
|
||||
|
||||
**Returns**
|
||||
- The string containing the integer representation appended to the buffer
|
||||
**Returns**
|
||||
- The string containing the integer representation written to the buffer
|
||||
*/
|
||||
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
write_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits")
|
||||
panic("strconv: illegal base passed to write_bits")
|
||||
}
|
||||
|
||||
a: [140]byte
|
||||
|
||||
+171
-138
@@ -5,8 +5,8 @@ import "decimal"
|
||||
/*
|
||||
Parses a boolean value from the input string
|
||||
|
||||
**Inputs**
|
||||
- s: The input string
|
||||
**Inputs**
|
||||
- s: The input string
|
||||
- true: "1", "t", "T", "true", "TRUE", "True"
|
||||
- false: "0", "f", "F", "false", "FALSE", "False"
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
|
||||
@@ -386,7 +386,7 @@ Parses an unsigned integer value from the input string, using the specified base
|
||||
- If base is not 0, it will be used for parsing regardless of any prefix in the input string
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
parse_uint_example :: proc() {
|
||||
@@ -399,14 +399,14 @@ Example:
|
||||
n, ok = strconv.parse_uint("0xffff") // with prefix and inferred base
|
||||
fmt.println(n,ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1234 true
|
||||
65535 true
|
||||
65535 true
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
|
||||
value: The parsed uint value
|
||||
ok: `false` if no appropriate value could be found; the value was negative; he input string contained more than just the number
|
||||
@@ -423,7 +423,7 @@ parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: boo
|
||||
/*
|
||||
Parses an integer value from a string in the given base, without any prefix
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing the integer value
|
||||
- base: The base (radix) to use for parsing the integer (1-16)
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
|
||||
@@ -436,12 +436,12 @@ Example:
|
||||
n, ok := strconv.parse_i128_of_base("-1234eeee", 10)
|
||||
fmt.println(n,ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
-1234 false
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- value: The parsed i128 value
|
||||
- ok: false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -491,7 +491,7 @@ parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i12
|
||||
/*
|
||||
Parses an integer value from a string in base 10, unless there's a prefix
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing the integer value
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
|
||||
|
||||
@@ -506,13 +506,13 @@ Example:
|
||||
n, ok = strconv.parse_i128_maybe_prefixed("0xeeee")
|
||||
fmt.println(n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1234 true
|
||||
61166 true
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed i128 value
|
||||
- ok: `false` if a valid integer could not be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -574,7 +574,7 @@ parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
|
||||
/*
|
||||
Parses an unsigned integer value from a string in the given base, without any prefix
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing the integer value
|
||||
- base: The base (radix) to use for parsing the integer (1-16)
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
|
||||
@@ -590,13 +590,13 @@ Example:
|
||||
n, ok = strconv.parse_u128_of_base("5678eeee", 16)
|
||||
fmt.println(n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1234 false
|
||||
1450766062 true
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed u128 value
|
||||
- ok: `false` if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -634,7 +634,7 @@ parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u12
|
||||
/*
|
||||
Parses an unsigned integer value from a string in base 10, unless there's a prefix
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing the integer value
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
|
||||
|
||||
@@ -649,13 +649,13 @@ Example:
|
||||
n, ok = strconv.parse_u128_maybe_prefixed("5678eeee")
|
||||
fmt.println(n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1234 true
|
||||
5678 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed u128 value
|
||||
- ok: false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -706,10 +706,10 @@ parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
|
||||
/*
|
||||
Converts a byte to lowercase
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- ch: A byte character to be converted to lowercase.
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- A lowercase byte character.
|
||||
*/
|
||||
@(private)
|
||||
@@ -717,7 +717,7 @@ lower :: #force_inline proc "contextless" (ch: byte) -> byte { return ('a' - 'A'
|
||||
/*
|
||||
Parses a 32-bit floating point number from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- s: The input string containing a 32-bit floating point number.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -732,13 +732,13 @@ Example:
|
||||
n, ok = strconv.parse_f32("5678e2")
|
||||
fmt.printfln("%.3f %v", n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
0.000 false
|
||||
567800.000 true
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 32-bit floating point number.
|
||||
- ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -750,7 +750,7 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
|
||||
/*
|
||||
Parses a 64-bit floating point number from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 64-bit floating point number.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -765,13 +765,13 @@ Example:
|
||||
n, ok = strconv.parse_f64("5678e2")
|
||||
fmt.printfln("%.3f %v", n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
0.000 false
|
||||
567800.000 true
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 64-bit floating point number.
|
||||
- ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -787,7 +787,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||
/*
|
||||
Parses a 32-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 32-bit floating point number.
|
||||
|
||||
Example:
|
||||
@@ -801,14 +801,14 @@ Example:
|
||||
n, _, ok = strconv.parse_f32_prefix("5678e2")
|
||||
fmt.printfln("%.3f %v", n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
0.000 false
|
||||
567800.000 true
|
||||
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 32-bit floating point number.
|
||||
- nr: The length of the parsed substring.
|
||||
- ok: A boolean indicating whether the parsing was successful.
|
||||
@@ -822,7 +822,7 @@ parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) {
|
||||
/*
|
||||
Parses a 64-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 64-bit floating point number.
|
||||
|
||||
Example:
|
||||
@@ -846,7 +846,7 @@ Output:
|
||||
1234.000 true
|
||||
13.370 true
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- value: The parsed 64-bit floating point number.
|
||||
- nr: The length of the parsed substring.
|
||||
- ok: `false` if a base 10 float could not be found
|
||||
@@ -1095,6 +1095,39 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
|
||||
return transmute(f64)bits, ok
|
||||
}
|
||||
|
||||
if len(str) > 2 && str[0] == '0' && str[1] == 'h' {
|
||||
nr = 2
|
||||
|
||||
as_int: u64
|
||||
digits: int
|
||||
for r in str[2:] {
|
||||
if r == '_' {
|
||||
nr += 1
|
||||
continue
|
||||
}
|
||||
v := u64(_digit_value(r))
|
||||
if v >= 16 {
|
||||
break
|
||||
}
|
||||
as_int *= 16
|
||||
as_int += v
|
||||
digits += 1
|
||||
}
|
||||
nr += digits
|
||||
ok = len(str) == nr
|
||||
|
||||
switch digits {
|
||||
case 4:
|
||||
value = cast(f64)transmute(f16)cast(u16)as_int
|
||||
case 8:
|
||||
value = cast(f64)transmute(f32)cast(u32)as_int
|
||||
case 16:
|
||||
value = transmute(f64)as_int
|
||||
case:
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if value, nr, ok = check_special(str); ok {
|
||||
return
|
||||
@@ -1151,7 +1184,7 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
|
||||
/*
|
||||
Parses a 128-bit complex number from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 128-bit complex number.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -1167,13 +1200,13 @@ Example:
|
||||
c, ok = strconv.parse_complex128("5+7i hellope", &n)
|
||||
fmt.printfln("%v %i %t", c, n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
3+1i 4 true
|
||||
5+7i 4 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 128-bit complex number.
|
||||
- ok: `false` if a complex number could not be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -1199,12 +1232,12 @@ parse_complex128 :: proc(str: string, n: ^int = nil) -> (value: complex128, ok:
|
||||
}
|
||||
|
||||
value = complex(real_value, imag_value)
|
||||
return
|
||||
return
|
||||
}
|
||||
/*
|
||||
Parses a 64-bit complex number from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 64-bit complex number.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -1220,13 +1253,13 @@ Example:
|
||||
c, ok = strconv.parse_complex64("5+7i hellope", &n)
|
||||
fmt.printfln("%v %i %t", c, n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
3+1i 4 true
|
||||
5+7i 4 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 64-bit complex number.
|
||||
- ok: `false` if a complex number could not be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -1238,7 +1271,7 @@ parse_complex64 :: proc(str: string, n: ^int = nil) -> (value: complex64, ok: bo
|
||||
/*
|
||||
Parses a 32-bit complex number from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 32-bit complex number.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -1254,13 +1287,13 @@ Example:
|
||||
c, ok = strconv.parse_complex32("5+7i hellope", &n)
|
||||
fmt.printfln("%v %i %t", c, n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
3+1i 4 true
|
||||
5+7i 4 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 32-bit complex number.
|
||||
- ok: `false` if a complex number could not be found, or if the input string contained more than just the number.
|
||||
*/
|
||||
@@ -1272,7 +1305,7 @@ parse_complex32 :: proc(str: string, n: ^int = nil) -> (value: complex32, ok: bo
|
||||
/*
|
||||
Parses a 256-bit quaternion from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 256-bit quaternion.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -1288,13 +1321,13 @@ Example:
|
||||
q, ok = strconv.parse_quaternion256("1+2i+3j+4k hellope", &n)
|
||||
fmt.printfln("%v %i %t", q, n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1+2i+3j+4k 10 true
|
||||
1+2i+3j+4k 10 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 256-bit quaternion.
|
||||
- ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion.
|
||||
*/
|
||||
@@ -1352,7 +1385,7 @@ parse_quaternion256 :: proc(str: string, n: ^int = nil) -> (value: quaternion256
|
||||
/*
|
||||
Parses a 128-bit quaternion from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 128-bit quaternion.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -1368,13 +1401,13 @@ Example:
|
||||
q, ok = strconv.parse_quaternion128("1+2i+3j+4k hellope", &n)
|
||||
fmt.printfln("%v %i %t", q, n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1+2i+3j+4k 10 true
|
||||
1+2i+3j+4k 10 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 128-bit quaternion.
|
||||
- ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion.
|
||||
*/
|
||||
@@ -1386,7 +1419,7 @@ parse_quaternion128 :: proc(str: string, n: ^int = nil) -> (value: quaternion128
|
||||
/*
|
||||
Parses a 64-bit quaternion from a string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing a 64-bit quaternion.
|
||||
- n: An optional pointer to an int to store the length of the parsed substring (default: nil).
|
||||
|
||||
@@ -1402,13 +1435,13 @@ Example:
|
||||
q, ok = strconv.parse_quaternion64("1+2i+3j+4k hellope", &n)
|
||||
fmt.printfln("%v %i %t", q, n, ok)
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
1+2i+3j+4k 10 true
|
||||
1+2i+3j+4k 10 false
|
||||
|
||||
**Returns**
|
||||
|
||||
**Returns**
|
||||
- value: The parsed 64-bit quaternion.
|
||||
- ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion.
|
||||
*/
|
||||
@@ -1417,20 +1450,20 @@ parse_quaternion64 :: proc(str: string, n: ^int = nil) -> (value: quaternion64,
|
||||
v, ok = parse_quaternion256(str, n)
|
||||
return cast(quaternion64)v, ok
|
||||
}
|
||||
/*
|
||||
Appends a boolean value as a string to the given buffer
|
||||
/*
|
||||
Writes a boolean value as a string to the given buffer
|
||||
|
||||
**Inputs**
|
||||
- buf: The buffer to append the boolean value to
|
||||
- b: The boolean value to be appended
|
||||
**Inputs**
|
||||
- buf: The buffer to write the boolean value to
|
||||
- b: The boolean value to be written
|
||||
|
||||
Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
append_bool_example :: proc() {
|
||||
write_bool_example :: proc() {
|
||||
buf: [6]byte
|
||||
result := strconv.append_bool(buf[:], true)
|
||||
result := strconv.write_bool(buf[:], true)
|
||||
fmt.println(result, buf)
|
||||
}
|
||||
|
||||
@@ -1438,10 +1471,10 @@ Output:
|
||||
|
||||
true [116, 114, 117, 101, 0, 0]
|
||||
|
||||
**Returns**
|
||||
- The resulting string after appending the boolean value
|
||||
**Returns**
|
||||
- The resulting string after writing the boolean value
|
||||
*/
|
||||
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
write_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
n := 0
|
||||
if b {
|
||||
n = copy(buf, "true")
|
||||
@@ -1450,21 +1483,21 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
}
|
||||
return string(buf[:n])
|
||||
}
|
||||
/*
|
||||
Appends an unsigned integer value as a string to the given buffer with the specified base
|
||||
/*
|
||||
Writes an unsigned integer value as a string to the given buffer with the specified base
|
||||
|
||||
**Inputs**
|
||||
- buf: The buffer to append the unsigned integer value to
|
||||
- u: The unsigned integer value to be appended
|
||||
**Inputs**
|
||||
- buf: The buffer to write the unsigned integer value to
|
||||
- u: The unsigned integer value to be written
|
||||
- base: The base to use for converting the integer value
|
||||
|
||||
Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
append_uint_example :: proc() {
|
||||
write_uint_example :: proc() {
|
||||
buf: [4]byte
|
||||
result := strconv.append_uint(buf[:], 42, 16)
|
||||
result := strconv.write_uint(buf[:], 42, 16)
|
||||
fmt.println(result, buf)
|
||||
}
|
||||
|
||||
@@ -1472,27 +1505,27 @@ Output:
|
||||
|
||||
2a [50, 97, 0, 0]
|
||||
|
||||
**Returns**
|
||||
- The resulting string after appending the unsigned integer value
|
||||
**Returns**
|
||||
- The resulting string after writing the unsigned integer value
|
||||
*/
|
||||
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u, base, false, 8*size_of(uint), digits, nil)
|
||||
write_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return write_bits(buf, u, base, false, 8*size_of(uint), digits, nil)
|
||||
}
|
||||
/*
|
||||
Appends a signed integer value as a string to the given buffer with the specified base
|
||||
/*
|
||||
Writes a signed integer value as a string to the given buffer with the specified base
|
||||
|
||||
**Inputs**
|
||||
- buf: The buffer to append the signed integer value to
|
||||
- i: The signed integer value to be appended
|
||||
**Inputs**
|
||||
- buf: The buffer to write the signed integer value to
|
||||
- i: The signed integer value to be written
|
||||
- base: The base to use for converting the integer value
|
||||
|
||||
Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
append_int_example :: proc() {
|
||||
write_int_example :: proc() {
|
||||
buf: [4]byte
|
||||
result := strconv.append_int(buf[:], -42, 10)
|
||||
result := strconv.write_int(buf[:], -42, 10)
|
||||
fmt.println(result, buf)
|
||||
}
|
||||
|
||||
@@ -1500,23 +1533,23 @@ Output:
|
||||
|
||||
-42 [45, 52, 50, 0]
|
||||
|
||||
**Returns**
|
||||
- The resulting string after appending the signed integer value
|
||||
**Returns**
|
||||
- The resulting string after writing the signed integer value
|
||||
*/
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil)
|
||||
write_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return write_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil)
|
||||
}
|
||||
|
||||
|
||||
|
||||
append_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
|
||||
return append_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil)
|
||||
write_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
|
||||
return write_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil)
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
Converts an integer value to a string and stores it in the given buffer
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- buf: The buffer to store the resulting string
|
||||
- i: The integer value to be converted
|
||||
|
||||
@@ -1534,16 +1567,16 @@ Output:
|
||||
|
||||
42 [52, 50, 0, 0]
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- The resulting string after converting the integer value
|
||||
*/
|
||||
itoa :: proc(buf: []byte, i: int) -> string {
|
||||
return append_int(buf, i64(i), 10)
|
||||
return write_int(buf, i64(i), 10)
|
||||
}
|
||||
/*
|
||||
Converts a string to an integer value
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- s: The string to be converted
|
||||
|
||||
Example:
|
||||
@@ -1558,17 +1591,17 @@ Output:
|
||||
|
||||
42
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- The resulting integer value
|
||||
*/
|
||||
atoi :: proc(s: string) -> int {
|
||||
v, _ := parse_int(s)
|
||||
return v
|
||||
}
|
||||
/*
|
||||
/*
|
||||
Converts a string to a float64 value
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- s: The string to be converted
|
||||
|
||||
Example:
|
||||
@@ -1583,21 +1616,21 @@ Output:
|
||||
|
||||
3.140
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- The resulting float64 value after converting the string
|
||||
*/
|
||||
atof :: proc(s: string) -> f64 {
|
||||
v, _ := parse_f64(s)
|
||||
return v
|
||||
}
|
||||
// Alias to `append_float`
|
||||
ftoa :: append_float
|
||||
/*
|
||||
Appends a float64 value as a string to the given buffer with the specified format and precision
|
||||
// Alias to `write_float`
|
||||
ftoa :: write_float
|
||||
/*
|
||||
Writes a float64 value as a string to the given buffer with the specified format and precision
|
||||
|
||||
**Inputs**
|
||||
- buf: The buffer to append the float64 value to
|
||||
- f: The float64 value to be appended
|
||||
**Inputs**
|
||||
- buf: The buffer to write the float64 value to
|
||||
- f: The float64 value to be written
|
||||
- fmt: The byte specifying the format to use for the conversion
|
||||
- prec: The precision to use for the conversion
|
||||
- bit_size: The size of the float in bits (32 or 64)
|
||||
@@ -1606,9 +1639,9 @@ Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
append_float_example :: proc() {
|
||||
write_float_example :: proc() {
|
||||
buf: [8]byte
|
||||
result := strconv.append_float(buf[:], 3.14159, 'f', 2, 64)
|
||||
result := strconv.write_float(buf[:], 3.14159, 'f', 2, 64)
|
||||
fmt.println(result, buf)
|
||||
}
|
||||
|
||||
@@ -1616,20 +1649,20 @@ Output:
|
||||
|
||||
+3.14 [43, 51, 46, 49, 52, 0, 0, 0]
|
||||
|
||||
**Returns**
|
||||
- The resulting string after appending the float
|
||||
**Returns**
|
||||
- The resulting string after writing the float
|
||||
*/
|
||||
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
write_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size))
|
||||
}
|
||||
/*
|
||||
Appends a quoted string representation of the input string to a given byte slice and returns the result as a string
|
||||
Writes a quoted string representation of the input string to a given byte slice and returns the result as a string
|
||||
|
||||
**Inputs**
|
||||
- buf: The byte slice to which the quoted string will be appended
|
||||
**Inputs**
|
||||
- buf: The byte slice to which the quoted string will be written
|
||||
- str: The input string to be quoted
|
||||
|
||||
!! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected
|
||||
!! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected
|
||||
|
||||
Example:
|
||||
|
||||
@@ -1645,8 +1678,8 @@ Output:
|
||||
|
||||
"'h''e''l''l''o'" [34, 39, 104, 39, 39, 101, 39, 39, 108, 39, 39, 108, 39, 39, 111, 39, 34, 0, 0, 0]
|
||||
|
||||
**Returns**
|
||||
- The resulting string after appending the quoted string representation
|
||||
**Returns**
|
||||
- The resulting string after writing the quoted string representation
|
||||
*/
|
||||
quote :: proc(buf: []byte, str: string) -> string {
|
||||
write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) {
|
||||
@@ -1686,10 +1719,10 @@ quote :: proc(buf: []byte, str: string) -> string {
|
||||
return string(buf[:i])
|
||||
}
|
||||
/*
|
||||
Appends a quoted rune representation of the input rune to a given byte slice and returns the result as a string
|
||||
Writes a quoted rune representation of the input rune to a given byte slice and returns the result as a string
|
||||
|
||||
**Inputs**
|
||||
- buf: The byte slice to which the quoted rune will be appended
|
||||
**Inputs**
|
||||
- buf: The byte slice to which the quoted rune will be written
|
||||
- r: The input rune to be quoted
|
||||
|
||||
Example:
|
||||
@@ -1706,8 +1739,8 @@ Output:
|
||||
|
||||
'A' [39, 65, 39, 0]
|
||||
|
||||
**Returns**
|
||||
- The resulting string after appending the quoted rune representation
|
||||
**Returns**
|
||||
- The resulting string after writing the quoted rune representation
|
||||
*/
|
||||
quote_rune :: proc(buf: []byte, r: rune) -> string {
|
||||
write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) {
|
||||
@@ -1750,7 +1783,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
|
||||
if r < 32 {
|
||||
write_string(buf, &i, "\\x")
|
||||
b: [2]byte
|
||||
s := append_bits(b[:], u64(r), 16, true, 64, digits, nil)
|
||||
s := write_bits(b[:], u64(r), 16, true, 64, digits, nil)
|
||||
switch len(s) {
|
||||
case 0: write_string(buf, &i, "00")
|
||||
case 1: write_rune(buf, &i, '0')
|
||||
@@ -1767,11 +1800,11 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
|
||||
/*
|
||||
Unquotes a single character from the input string, considering the given quote character
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- str: The input string containing the character to unquote
|
||||
- quote: The quote character to consider (e.g., '"')
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
@@ -1782,12 +1815,12 @@ Example:
|
||||
fmt.printf("r: <%v>, multiple_bytes:%v, tail_string:<%s>, success:%v\n",r, multiple_bytes, tail_string, success)
|
||||
}
|
||||
|
||||
Output:
|
||||
Output:
|
||||
|
||||
Source: 'The' raven
|
||||
r: <'>, multiple_bytes:false, tail_string:<The' raven>, success:true
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- r: The unquoted rune
|
||||
- multiple_bytes: A boolean indicating if the rune has multiple bytes
|
||||
- tail_string: The remaining portion of the input string after unquoting the character
|
||||
@@ -1890,13 +1923,13 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool
|
||||
/*
|
||||
Unquotes the input string considering any type of quote character and returns the unquoted string
|
||||
|
||||
**Inputs**
|
||||
**Inputs**
|
||||
- lit: The input string to unquote
|
||||
- allocator: (default: context.allocator)
|
||||
|
||||
WARNING: This procedure gives unexpected results if the quotes are not the first and last characters.
|
||||
|
||||
Example:
|
||||
Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
@@ -1914,10 +1947,10 @@ Example:
|
||||
src="The raven \'Huginn\' is black."
|
||||
s, allocated, ok = strconv.unquote_string(src) // Will produce undesireable results
|
||||
fmt.println(src)
|
||||
fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok)
|
||||
fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok)
|
||||
}
|
||||
|
||||
Output:
|
||||
Output:
|
||||
|
||||
"The raven Huginn is black."
|
||||
Unquoted: <The raven Huginn is black.>, alloc:false, ok:true
|
||||
@@ -1928,7 +1961,7 @@ Output:
|
||||
The raven 'Huginn' is black.
|
||||
Unquoted: <he raven 'Huginn' is black>, alloc:false, ok:true
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- res: The resulting unquoted string
|
||||
- allocated: A boolean indicating if the resulting string was allocated using the provided allocator
|
||||
- success: A boolean indicating whether the unquoting was successful
|
||||
@@ -1969,7 +2002,7 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str
|
||||
return s, false, true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
context.allocator = allocator
|
||||
|
||||
buf_len := 3*len(s) / 2
|
||||
|
||||
@@ -311,7 +311,7 @@ Returns:
|
||||
- res: A cstring of the Builder's buffer upon success
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
to_cstring :: proc(b: ^Builder) -> (res: cstring, err: mem.Allocator_Error) {
|
||||
to_cstring :: proc(b: ^Builder) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
n := append(&b.buf, 0) or_return
|
||||
if n != 1 {
|
||||
return nil, .Out_Of_Memory
|
||||
@@ -675,7 +675,7 @@ Returns:
|
||||
*/
|
||||
write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) {
|
||||
buf: [384]byte
|
||||
s := strconv.append_float(buf[:], f, fmt, prec, bit_size)
|
||||
s := strconv.write_float(buf[:], f, fmt, prec, bit_size)
|
||||
// If the result starts with a `+` then unless we always want signed results,
|
||||
// we skip it unless it's followed by an `I` (because of +Inf).
|
||||
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||
@@ -699,7 +699,7 @@ Returns:
|
||||
*/
|
||||
write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) {
|
||||
buf: [384]byte
|
||||
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||
s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||
s = s[1:]
|
||||
}
|
||||
@@ -739,7 +739,7 @@ Output:
|
||||
*/
|
||||
write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) {
|
||||
buf: [384]byte
|
||||
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||
s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||
s = s[1:]
|
||||
}
|
||||
@@ -761,7 +761,7 @@ Returns:
|
||||
*/
|
||||
write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) {
|
||||
buf: [384]byte
|
||||
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||
s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
|
||||
if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
|
||||
s = s[1:]
|
||||
}
|
||||
@@ -782,7 +782,7 @@ Returns:
|
||||
*/
|
||||
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
|
||||
buf: [32]byte
|
||||
s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil)
|
||||
return write_string(b, s)
|
||||
}
|
||||
/*
|
||||
@@ -800,7 +800,7 @@ Returns:
|
||||
*/
|
||||
write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
|
||||
buf: [32]byte
|
||||
s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
|
||||
s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
|
||||
return write_string(b, s)
|
||||
}
|
||||
/*
|
||||
|
||||
+128
-81
@@ -2,6 +2,7 @@
|
||||
package strings
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:bytes"
|
||||
import "core:io"
|
||||
import "core:mem"
|
||||
@@ -27,24 +28,7 @@ clone :: proc(s: string, allocator := context.allocator, loc := #caller_location
|
||||
copy(c, s)
|
||||
return string(c), nil
|
||||
}
|
||||
/*
|
||||
Clones a string safely (returns early with an allocation error on failure)
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- s: The string to be cloned
|
||||
- allocator: (default: context.allocator)
|
||||
- loc: The caller location for debugging purposes (default: #caller_location)
|
||||
|
||||
Returns:
|
||||
- res: The cloned string
|
||||
- err: An allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
@(deprecated="Prefer clone. It now returns an optional allocator error")
|
||||
clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) {
|
||||
return clone(s, allocator, loc)
|
||||
}
|
||||
/*
|
||||
Clones a string and appends a null-byte to make it a cstring
|
||||
|
||||
@@ -65,6 +49,7 @@ clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #call
|
||||
c[len(s)] = 0
|
||||
return cstring(&c[0]), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Transmutes a raw pointer into a string. Non-allocating.
|
||||
|
||||
@@ -80,6 +65,7 @@ Returns:
|
||||
string_from_ptr :: proc(ptr: ^byte, len: int) -> (res: string) {
|
||||
return transmute(string)mem.Raw_String{ptr, len}
|
||||
}
|
||||
|
||||
/*
|
||||
Transmutes a raw pointer (null-terminated) into a string. Non-allocating. Searches for a null-byte from `0..<len`, otherwise `len` will be the end size
|
||||
|
||||
@@ -98,20 +84,7 @@ string_from_null_terminated_ptr :: proc "contextless" (ptr: [^]byte, len: int) -
|
||||
s = truncate_to_byte(s, 0)
|
||||
return s
|
||||
}
|
||||
/*
|
||||
Gets the raw byte pointer for the start of a string `str`
|
||||
|
||||
Inputs:
|
||||
- str: The input string
|
||||
|
||||
Returns:
|
||||
- res: A pointer to the start of the string's bytes
|
||||
*/
|
||||
@(deprecated="Prefer the builtin raw_data.")
|
||||
ptr_from_string :: proc(str: string) -> (res: ^byte) {
|
||||
d := transmute(mem.Raw_String)str
|
||||
return d.data
|
||||
}
|
||||
/*
|
||||
Converts a string `str` to a cstring
|
||||
|
||||
@@ -127,6 +100,7 @@ unsafe_string_to_cstring :: proc(str: string) -> (res: cstring) {
|
||||
d := transmute(mem.Raw_String)str
|
||||
return cstring(d.data)
|
||||
}
|
||||
|
||||
/*
|
||||
Truncates a string `str` at the first occurrence of char/byte `b`
|
||||
|
||||
@@ -146,6 +120,7 @@ truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) {
|
||||
}
|
||||
return str[:n]
|
||||
}
|
||||
|
||||
/*
|
||||
Truncates a string `str` at the first occurrence of rune `r` as a slice of the original, entire string if not found
|
||||
|
||||
@@ -163,6 +138,7 @@ truncate_to_rune :: proc(str: string, r: rune) -> (res: string) {
|
||||
}
|
||||
return str[:n]
|
||||
}
|
||||
|
||||
/*
|
||||
Clones a byte array `s` and appends a null-byte
|
||||
|
||||
@@ -183,6 +159,7 @@ clone_from_bytes :: proc(s: []byte, allocator := context.allocator, loc := #call
|
||||
c[len(s)] = 0
|
||||
return string(c[:len(s)]), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Clones a cstring `s` as a string
|
||||
|
||||
@@ -200,6 +177,7 @@ Returns:
|
||||
clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return clone(string(s), allocator, loc)
|
||||
}
|
||||
|
||||
/*
|
||||
Clones a string from a byte pointer `ptr` and a byte length `len`
|
||||
|
||||
@@ -221,6 +199,7 @@ clone_from_ptr :: proc(ptr: ^byte, len: int, allocator := context.allocator, loc
|
||||
s := string_from_ptr(ptr, len)
|
||||
return clone(s, allocator, loc)
|
||||
}
|
||||
|
||||
// Overloaded procedure to clone from a string, `[]byte`, `cstring` or a `^byte` + length
|
||||
clone_from :: proc{
|
||||
clone,
|
||||
@@ -228,6 +207,7 @@ clone_from :: proc{
|
||||
clone_from_cstring,
|
||||
clone_from_ptr,
|
||||
}
|
||||
|
||||
/*
|
||||
Clones a string from a null-terminated cstring `ptr` and a byte length `len`
|
||||
|
||||
@@ -250,6 +230,7 @@ clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context.
|
||||
s = truncate_to_byte(s, 0)
|
||||
return clone(s, allocator, loc)
|
||||
}
|
||||
|
||||
/*
|
||||
Compares two strings, returning a value representing which one comes first lexicographically.
|
||||
-1 for `lhs`; 1 for `rhs`, or 0 if they are equal.
|
||||
@@ -264,6 +245,7 @@ Returns:
|
||||
compare :: proc "contextless" (lhs, rhs: string) -> (result: int) {
|
||||
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs)
|
||||
}
|
||||
|
||||
/*
|
||||
Checks if rune `r` in the string `s`
|
||||
|
||||
@@ -282,6 +264,7 @@ contains_rune :: proc(s: string, r: rune) -> (result: bool) {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true when the string `substr` is contained inside the string `s`
|
||||
|
||||
@@ -313,6 +296,7 @@ Output:
|
||||
contains :: proc(s, substr: string) -> (res: bool) {
|
||||
return index(s, substr) >= 0
|
||||
}
|
||||
|
||||
/*
|
||||
Returns `true` when the string `s` contains any of the characters inside the string `chars`
|
||||
|
||||
@@ -385,6 +369,7 @@ Output:
|
||||
rune_count :: proc(s: string) -> (res: int) {
|
||||
return utf8.rune_count_in_string(s)
|
||||
}
|
||||
|
||||
/*
|
||||
Returns whether the strings `u` and `v` are the same alpha characters, ignoring different casings
|
||||
Works with UTF-8 string content
|
||||
@@ -458,6 +443,7 @@ equal_fold :: proc(u, v: string) -> (res: bool) {
|
||||
|
||||
return s == t
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the prefix length common between strings `a` and `b`
|
||||
|
||||
@@ -488,29 +474,58 @@ Output:
|
||||
0
|
||||
|
||||
*/
|
||||
prefix_length :: proc(a, b: string) -> (n: int) {
|
||||
_len := min(len(a), len(b))
|
||||
prefix_length :: proc "contextless" (a, b: string) -> (n: int) {
|
||||
RUNE_ERROR :: '\ufffd'
|
||||
RUNE_SELF :: 0x80
|
||||
UTF_MAX :: 4
|
||||
|
||||
// Scan for matches including partial codepoints.
|
||||
#no_bounds_check for n < _len && a[n] == b[n] {
|
||||
n += 1
|
||||
}
|
||||
|
||||
// Now scan to ignore partial codepoints.
|
||||
if n > 0 {
|
||||
s := a[:n]
|
||||
n = 0
|
||||
for {
|
||||
r0, w := utf8.decode_rune(s[n:])
|
||||
if r0 != utf8.RUNE_ERROR {
|
||||
n += w
|
||||
} else {
|
||||
break
|
||||
n = runtime.memory_prefix_length(raw_data(a), raw_data(b), min(len(a), len(b)))
|
||||
lim := max(n - UTF_MAX + 1, 0)
|
||||
for l := n; l > lim; l -= 1 {
|
||||
r, _ := runtime.string_decode_rune(a[l - 1:])
|
||||
if r != RUNE_ERROR {
|
||||
if l > 0 && (a[l - 1] & 0xc0 == 0xc0) {
|
||||
return l - 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the common prefix between strings `a` and `b`
|
||||
|
||||
Inputs:
|
||||
- a: The first input string
|
||||
- b: The second input string
|
||||
|
||||
Returns:
|
||||
- n: The string prefix common between strings `a` and `b`
|
||||
|
||||
Example:
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
|
||||
common_prefix_example :: proc() {
|
||||
fmt.println(strings.common_prefix("testing", "test"))
|
||||
fmt.println(strings.common_prefix("testing", "te"))
|
||||
fmt.println(strings.common_prefix("telephone", "te"))
|
||||
}
|
||||
|
||||
Output:
|
||||
|
||||
test
|
||||
te
|
||||
te
|
||||
|
||||
|
||||
*/
|
||||
common_prefix :: proc(a, b: string) -> string {
|
||||
return a[:prefix_length(a, b)]
|
||||
}
|
||||
|
||||
/*
|
||||
Determines if a string `s` starts with a given `prefix`
|
||||
|
||||
@@ -632,24 +647,7 @@ join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #c
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
/*
|
||||
Joins a slice of strings `a` with a `sep` string, returns an error on allocation failure
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- a: A slice of strings to join
|
||||
- sep: The separator string
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
- str: A combined string from the slice of strings `a` separated with the `sep` string
|
||||
- err: An allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
@(deprecated="Prefer join. It now returns an optional allocator error")
|
||||
join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
|
||||
return join(a, sep, allocator)
|
||||
}
|
||||
/*
|
||||
Returns a combined string from the slice of strings `a` without a separator
|
||||
|
||||
@@ -694,22 +692,6 @@ concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
/*
|
||||
Returns a combined string from the slice of strings `a` without a separator, or an error if allocation fails
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- a: A slice of strings to concatenate
|
||||
- allocator: (default is context.allocator)
|
||||
|
||||
Returns:
|
||||
The concatenated string, and an error if allocation fails
|
||||
*/
|
||||
@(deprecated="Prefer concatenate. It now returns an optional allocator error")
|
||||
concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
|
||||
return concatenate(a, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a substring of the input string `s` with the specified rune offset and length
|
||||
@@ -872,6 +854,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
|
||||
|
||||
return res[:i+1], nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into parts based on a separator.
|
||||
|
||||
@@ -907,6 +890,7 @@ Output:
|
||||
split :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return _split(s, sep, 0, -1, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into parts based on a separator. If n < count of seperators, the remainder of the string is returned in the last entry.
|
||||
|
||||
@@ -943,6 +927,7 @@ Output:
|
||||
split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return _split(s, sep, 0, n, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into parts after the separator, retaining it in the substrings.
|
||||
|
||||
@@ -978,6 +963,7 @@ Output:
|
||||
split_after :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return _split(s, sep, len(sep), -1, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into a total of `n` parts after the separator.
|
||||
|
||||
@@ -1014,6 +1000,7 @@ Output:
|
||||
split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return _split(s, sep, len(sep), n, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Searches for the first occurrence of `sep` in the given string and returns the substring
|
||||
up to (but not including) the separator, as well as a boolean indicating success.
|
||||
@@ -1054,6 +1041,7 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string by the byte separator in an iterator fashion.
|
||||
|
||||
@@ -1100,6 +1088,7 @@ split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string by the separator string in an iterator fashion.
|
||||
|
||||
@@ -1135,6 +1124,7 @@ Output:
|
||||
split_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) {
|
||||
return _split_iterator(s, sep, 0)
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string after every separator string in an iterator fashion.
|
||||
|
||||
@@ -1170,6 +1160,7 @@ Output:
|
||||
split_after_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) {
|
||||
return _split_iterator(s, sep, len(sep))
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the carriage return character from the end of the input string.
|
||||
|
||||
@@ -1191,6 +1182,7 @@ _trim_cr :: proc(s: string) -> (res: string) {
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string at every line break `\n`.
|
||||
|
||||
@@ -1228,6 +1220,7 @@ split_lines :: proc(s: string, allocator := context.allocator) -> (res: []string
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string at every line break `\n` for `n` parts.
|
||||
|
||||
@@ -1268,6 +1261,7 @@ split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> (res
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string at every line break `\n` leaving the `\n` in the resulting strings.
|
||||
|
||||
@@ -1307,6 +1301,7 @@ split_lines_after :: proc(s: string, allocator := context.allocator) -> (res: []
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string at every line break `\n` leaving the `\n` in the resulting strings.
|
||||
Only runs for n parts.
|
||||
@@ -1348,6 +1343,7 @@ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string at every line break `\n`.
|
||||
Returns the current split string every iteration until the string is consumed.
|
||||
@@ -1382,6 +1378,7 @@ split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
|
||||
line = _split_iterator(s, sep, 0) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string at every line break `\n`.
|
||||
Returns the current split string with line breaks included every iteration until the string is consumed.
|
||||
@@ -1419,6 +1416,7 @@ split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
|
||||
line = _split_iterator(s, sep, len(sep)) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the byte offset of the first byte `c` in the string s it finds, -1 when not found.
|
||||
NOTE: Can't find UTF-8 based runes.
|
||||
@@ -1453,6 +1451,7 @@ Output:
|
||||
index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
|
||||
return #force_inline bytes.index_byte(transmute([]u8)s, c)
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the byte offset of the last byte `c` in the string `s`, -1 when not found.
|
||||
|
||||
@@ -1488,6 +1487,7 @@ Output:
|
||||
last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
|
||||
return #force_inline bytes.last_index_byte(transmute([]u8)s, c)
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the byte offset of the first rune `r` in the string `s` it finds, -1 when not found.
|
||||
Invalid runes return -1
|
||||
@@ -1628,6 +1628,7 @@ index :: proc "contextless" (s, substr: string) -> (res: int) {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the last byte offset of the string `substr` in the string `s`, -1 when not found.
|
||||
|
||||
@@ -1705,6 +1706,7 @@ last_index :: proc(s, substr: string) -> (res: int) {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the index of any first char of `chars` found in `s`, -1 if not found.
|
||||
|
||||
@@ -1768,6 +1770,7 @@ index_any :: proc(s, chars: string) -> (res: int) {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/*
|
||||
Finds the last occurrence of any character in `chars` within `s`. Iterates in reverse.
|
||||
|
||||
@@ -1849,6 +1852,7 @@ last_index_any :: proc(s, chars: string) -> (res: int) {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/*
|
||||
Finds the first occurrence of any substring in `substrs` within `s`
|
||||
|
||||
@@ -1890,6 +1894,7 @@ index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Counts the number of non-overlapping occurrences of `substr` in `s`
|
||||
|
||||
@@ -1956,6 +1961,7 @@ count :: proc(s, substr: string) -> (res: int) {
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
/*
|
||||
Repeats the string `s` `count` times, concatenating the result
|
||||
|
||||
@@ -2001,6 +2007,7 @@ repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #ca
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Replaces all occurrences of `old` in `s` with `new`
|
||||
|
||||
@@ -2034,9 +2041,11 @@ Output:
|
||||
zzzz true
|
||||
|
||||
*/
|
||||
|
||||
replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) {
|
||||
return replace(s, old, new, -1, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Replaces n instances of old in the string s with the new string
|
||||
|
||||
@@ -2115,6 +2124,7 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator, loc
|
||||
output = string(t[0:w])
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Removes the key string `n` times from the `s` string
|
||||
|
||||
@@ -2153,6 +2163,7 @@ Output:
|
||||
remove :: proc(s, key: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) {
|
||||
return replace(s, key, "", n, allocator)
|
||||
}
|
||||
|
||||
/*
|
||||
Removes all the `key` string instances from the `s` string
|
||||
|
||||
@@ -2188,6 +2199,7 @@ Output:
|
||||
remove_all :: proc(s, key: string, allocator := context.allocator) -> (output: string, was_allocation: bool) {
|
||||
return remove(s, key, -1, allocator)
|
||||
}
|
||||
|
||||
// Returns true if is an ASCII space character ('\t', '\n', '\v', '\f', '\r', ' ')
|
||||
@(private) _ascii_space := [256]bool{'\t' = true, '\n' = true, '\v' = true, '\f' = true, '\r' = true, ' ' = true}
|
||||
|
||||
@@ -2291,6 +2303,7 @@ index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Same as `index_proc`, but the procedure p takes a raw pointer for state
|
||||
index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) {
|
||||
for r, i in s {
|
||||
@@ -2300,6 +2313,7 @@ index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: r
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Finds the index of the *last* rune in the string s for which the procedure p returns the same value as truth
|
||||
last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int) {
|
||||
// TODO(bill): Probably use Rabin-Karp Search
|
||||
@@ -2312,6 +2326,7 @@ last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Same as `index_proc_with_state`, runs through the string in reverse
|
||||
last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) {
|
||||
// TODO(bill): Probably use Rabin-Karp Search
|
||||
@@ -2324,6 +2339,7 @@ last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the input string `s` from the left until the procedure `p` returns false
|
||||
|
||||
@@ -2358,6 +2374,7 @@ trim_left_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) {
|
||||
}
|
||||
return s[i:]
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the input string `s` from the left until the procedure `p` with state returns false
|
||||
|
||||
@@ -2376,6 +2393,7 @@ trim_left_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, stat
|
||||
}
|
||||
return s[i:]
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the input string `s` from the right until the procedure `p` returns `false`
|
||||
|
||||
@@ -2413,6 +2431,7 @@ trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) {
|
||||
}
|
||||
return s[0:i]
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the input string `s` from the right until the procedure `p` with state returns `false`
|
||||
|
||||
@@ -2434,6 +2453,7 @@ trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta
|
||||
}
|
||||
return s[0:i]
|
||||
}
|
||||
|
||||
// Procedure for `trim_*_proc` variants, which has a string rawptr cast + rune comparison
|
||||
is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) {
|
||||
cutset := (^string)(state)^
|
||||
@@ -2444,6 +2464,7 @@ is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the cutset string from the `s` string
|
||||
|
||||
@@ -2461,6 +2482,7 @@ trim_left :: proc(s: string, cutset: string) -> (res: string) {
|
||||
state := cutset
|
||||
return trim_left_proc_with_state(s, is_in_cutset, &state)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the cutset string from the `s` string from the right
|
||||
|
||||
@@ -2478,6 +2500,7 @@ trim_right :: proc(s: string, cutset: string) -> (res: string) {
|
||||
state := cutset
|
||||
return trim_right_proc_with_state(s, is_in_cutset, &state)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims the cutset string from the `s` string, both from left and right
|
||||
|
||||
@@ -2491,6 +2514,7 @@ Returns:
|
||||
trim :: proc(s: string, cutset: string) -> (res: string) {
|
||||
return trim_right(trim_left(s, cutset), cutset)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims until a valid non-space rune from the left, "\t\txyz\t\t" -> "xyz\t\t"
|
||||
|
||||
@@ -2503,6 +2527,7 @@ Returns:
|
||||
trim_left_space :: proc(s: string) -> (res: string) {
|
||||
return trim_left_proc(s, is_space)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims from the right until a valid non-space rune, "\t\txyz\t\t" -> "\t\txyz"
|
||||
|
||||
@@ -2515,6 +2540,7 @@ Returns:
|
||||
trim_right_space :: proc(s: string) -> (res: string) {
|
||||
return trim_right_proc(s, is_space)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims from both sides until a valid non-space rune, "\t\txyz\t\t" -> "xyz"
|
||||
|
||||
@@ -2527,6 +2553,7 @@ Returns:
|
||||
trim_space :: proc(s: string) -> (res: string) {
|
||||
return trim_right_space(trim_left_space(s))
|
||||
}
|
||||
|
||||
/*
|
||||
Trims null runes from the left, "\x00\x00testing\x00\x00" -> "testing\x00\x00"
|
||||
|
||||
@@ -2539,6 +2566,7 @@ Returns:
|
||||
trim_left_null :: proc(s: string) -> (res: string) {
|
||||
return trim_left_proc(s, is_null)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims null runes from the right, "\x00\x00testing\x00\x00" -> "\x00\x00testing"
|
||||
|
||||
@@ -2551,6 +2579,7 @@ Returns:
|
||||
trim_right_null :: proc(s: string) -> (res: string) {
|
||||
return trim_right_proc(s, is_null)
|
||||
}
|
||||
|
||||
/*
|
||||
Trims null runes from both sides, "\x00\x00testing\x00\x00" -> "testing"
|
||||
|
||||
@@ -2562,6 +2591,7 @@ Returns:
|
||||
trim_null :: proc(s: string) -> (res: string) {
|
||||
return trim_right_null(trim_left_null(s))
|
||||
}
|
||||
|
||||
/*
|
||||
Trims a `prefix` string from the start of the `s` string and returns the trimmed string
|
||||
|
||||
@@ -2594,6 +2624,7 @@ trim_prefix :: proc(s, prefix: string) -> (res: string) {
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
/*
|
||||
Trims a `suffix` string from the end of the `s` string and returns the trimmed string
|
||||
|
||||
@@ -2626,6 +2657,7 @@ trim_suffix :: proc(s, suffix: string) -> (res: string) {
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string `s` by all possible `substrs` and returns an allocated array of strings
|
||||
|
||||
@@ -2698,6 +2730,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
|
||||
assert(len(results) == n)
|
||||
return results[:], nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string `s` by all possible `substrs` in an iterator fashion. The full string is returned if no match.
|
||||
|
||||
@@ -2757,6 +2790,7 @@ split_multi_iterate :: proc(it: ^string, substrs: []string) -> (res: string, ok:
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Replaces invalid UTF-8 characters in the input string with a specified replacement string. Adjacent invalid bytes are only replaced once.
|
||||
|
||||
@@ -2817,6 +2851,7 @@ scrub :: proc(s: string, replacement: string, allocator := context.allocator) ->
|
||||
|
||||
return to_string(b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Reverses the input string `s`
|
||||
|
||||
@@ -2860,6 +2895,7 @@ reverse :: proc(s: string, allocator := context.allocator, loc := #caller_locati
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Expands the input string by replacing tab characters with spaces to align to a specified tab size
|
||||
|
||||
@@ -2891,6 +2927,7 @@ Output:
|
||||
abc1 abc2 abc3
|
||||
|
||||
*/
|
||||
|
||||
expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
if tab_size <= 0 {
|
||||
panic("tab size must be positive")
|
||||
@@ -2932,6 +2969,7 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
|
||||
|
||||
return to_string(b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the input string `str` by the separator `sep` string and returns 3 parts. The values are slices of the original string.
|
||||
|
||||
@@ -2982,8 +3020,10 @@ partition :: proc(str, sep: string) -> (head, match, tail: string) {
|
||||
tail = str[i+len(sep):]
|
||||
return
|
||||
}
|
||||
|
||||
// Alias for centre_justify
|
||||
center_justify :: centre_justify // NOTE(bill): Because Americans exist
|
||||
|
||||
/*
|
||||
Centers the input string within a field of specified length by adding pad string on both sides, if its length is less than the target length.
|
||||
|
||||
@@ -3019,6 +3059,7 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
|
||||
|
||||
return to_string(b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Left-justifies the input string within a field of specified length by adding pad string on the right side, if its length is less than the target length.
|
||||
|
||||
@@ -3053,6 +3094,7 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
|
||||
|
||||
return to_string(b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Right-justifies the input string within a field of specified length by adding pad string on the left side, if its length is less than the target length.
|
||||
|
||||
@@ -3087,6 +3129,7 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
|
||||
|
||||
return to_string(b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Writes a given pad string a specified number of times to an `io.Writer`
|
||||
|
||||
@@ -3113,6 +3156,7 @@ write_pad_string :: proc(w: io.Writer, pad: string, pad_len, remains: int) {
|
||||
p = p[width:]
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into a slice of substrings at each instance of one or more consecutive white space characters, as defined by `unicode.is_space`
|
||||
|
||||
@@ -3174,6 +3218,7 @@ fields :: proc(s: string, allocator := context.allocator, loc := #caller_locatio
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Splits a string into a slice of substrings at each run of unicode code points `r` satisfying the predicate `f(r)`
|
||||
|
||||
@@ -3216,6 +3261,7 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc
|
||||
|
||||
return substrings[:], nil
|
||||
}
|
||||
|
||||
/*
|
||||
Retrieves the first non-space substring from a mutable string reference and advances the reference. `s` is advanced from any space after the substring, or be an empty string if the substring was the remaining characters
|
||||
|
||||
@@ -3254,6 +3300,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) {
|
||||
s^ = s[len(s):]
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Computes the Levenshtein edit distance between two strings
|
||||
|
||||
@@ -3431,4 +3478,4 @@ substring_to :: proc(s: string, rune_end: int) -> (sub: string, ok: bool) {
|
||||
}
|
||||
|
||||
return internal_substring(s, -1, rune_end)
|
||||
}
|
||||
}
|
||||
@@ -95,20 +95,16 @@ atomic_mutex_guard :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
|
||||
|
||||
|
||||
Atomic_RW_Mutex_State :: distinct uint
|
||||
Atomic_RW_Mutex_State_Half_Width :: size_of(Atomic_RW_Mutex_State)*8/2
|
||||
Atomic_RW_Mutex_State_Is_Writing :: Atomic_RW_Mutex_State(1)
|
||||
Atomic_RW_Mutex_State_Writer :: Atomic_RW_Mutex_State(1)<<1
|
||||
Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State(1)<<Atomic_RW_Mutex_State_Half_Width
|
||||
|
||||
Atomic_RW_Mutex_State_Writer_Mask :: Atomic_RW_Mutex_State(1<<(Atomic_RW_Mutex_State_Half_Width-1) - 1) << 1
|
||||
Atomic_RW_Mutex_State_Reader_Mask :: Atomic_RW_Mutex_State(1<<(Atomic_RW_Mutex_State_Half_Width-1) - 1) << Atomic_RW_Mutex_State_Half_Width
|
||||
Atomic_RW_Mutex_State_Is_Writing :: Atomic_RW_Mutex_State(1) << (size_of(Atomic_RW_Mutex_State)*8-1)
|
||||
Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State(1)
|
||||
Atomic_RW_Mutex_State_Reader_Mask :: ~Atomic_RW_Mutex_State_Is_Writing
|
||||
|
||||
|
||||
// An Atomic_RW_Mutex is a reader/writer mutual exclusion lock
|
||||
// The lock can be held by any arbitrary number of readers or a single writer
|
||||
// The zero value for an Atomic_RW_Mutex is an unlocked mutex
|
||||
// An Atomic_RW_Mutex is a reader/writer mutual exclusion lock.
|
||||
// The lock can be held by any arbitrary number of readers or a single writer.
|
||||
// The zero value for an Atomic_RW_Mutex is an unlocked mutex.
|
||||
//
|
||||
// An Atomic_RW_Mutex must not be copied after first use
|
||||
// An Atomic_RW_Mutex must not be copied after first use.
|
||||
Atomic_RW_Mutex :: struct #no_copy {
|
||||
state: Atomic_RW_Mutex_State,
|
||||
mutex: Atomic_Mutex,
|
||||
@@ -118,11 +114,17 @@ Atomic_RW_Mutex :: struct #no_copy {
|
||||
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
|
||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||
atomic_rw_mutex_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||
atomic_mutex_lock(&rw.mutex)
|
||||
|
||||
state := atomic_or(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||
state := atomic_or(&rw.state, Atomic_RW_Mutex_State_Is_Writing)
|
||||
if state & Atomic_RW_Mutex_State_Reader_Mask != 0 {
|
||||
// There's at least one reader, so wait for the last one to post the semaphore.
|
||||
//
|
||||
// Because we hold the exclusive lock, no more readers can come in
|
||||
// during this time, which will prevent any situations where the last
|
||||
// reader is pre-empted around the count turning zero, which would
|
||||
// result in the potential for another reader to run amok after the
|
||||
// other posts.
|
||||
atomic_sema_wait(&rw.sema)
|
||||
}
|
||||
}
|
||||
@@ -138,10 +140,15 @@ atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||
if atomic_mutex_try_lock(&rw.mutex) {
|
||||
state := atomic_load(&rw.state)
|
||||
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
|
||||
_ = atomic_or(&rw.state, Atomic_RW_Mutex_State_Is_Writing)
|
||||
return true
|
||||
// Compare-and-exchange for absolute certainty that no one has come in to read.
|
||||
_, ok := atomic_compare_exchange_strong(&rw.state, state, state | Atomic_RW_Mutex_State_Is_Writing)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// A reader is active or came in while we have the lock, so we need to
|
||||
// back out.
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
}
|
||||
return false
|
||||
@@ -150,16 +157,22 @@ atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
state := atomic_load(&rw.state)
|
||||
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||
for state & Atomic_RW_Mutex_State_Is_Writing == 0 {
|
||||
ok: bool
|
||||
state, ok = atomic_compare_exchange_weak(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||
if ok {
|
||||
// We succesfully took the shared reader lock without any writers intervening.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// A writer is active or came in while we were trying to get a shared
|
||||
// reader lock, so now we must take the full lock in order to wait for the
|
||||
// writer to give it up.
|
||||
atomic_mutex_lock(&rw.mutex)
|
||||
// At this point, we have the lock, so we can add to the reader count.
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||
// Then we give up the lock to let other readers (or writers) come through.
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
}
|
||||
|
||||
@@ -169,6 +182,8 @@ atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
|
||||
if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
|
||||
(state & Atomic_RW_Mutex_State_Is_Writing != 0) {
|
||||
// We were the last reader, so post to the writer with the lock who's
|
||||
// waiting to continue.
|
||||
atomic_sema_post(&rw.sema)
|
||||
}
|
||||
}
|
||||
@@ -176,12 +191,21 @@ atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||
state := atomic_load(&rw.state)
|
||||
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||
// NOTE: We need to check this in a for loop, because it is possible for
|
||||
// another reader to change the underlying state which would cause our
|
||||
// compare-and-exchange to fail.
|
||||
for state & (Atomic_RW_Mutex_State_Is_Writing) == 0 {
|
||||
ok: bool
|
||||
state, ok = atomic_compare_exchange_weak(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// A writer is active or came in during our lock attempt.
|
||||
|
||||
// We try to take the full lock, and if that succeeds (perhaps because the
|
||||
// writer finished during the time since we failed our CAS), we increment
|
||||
// the reader count and head on.
|
||||
if atomic_mutex_try_lock(&rw.mutex) {
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
|
||||
@@ -82,7 +82,6 @@ Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolic
|
||||
// NOTE: this is technically deprecated but still actively used (Sokol, glfw, SDL, etc.)
|
||||
// and has no clear alternative although `activate` is what Apple tells you to use,
|
||||
// that does not work the same way.
|
||||
// @(deprecated="Use NSApplication method activate instead.")
|
||||
@(objc_type=Application, objc_name="activateIgnoringOtherApps")
|
||||
Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) {
|
||||
msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
|
||||
@@ -99,7 +98,7 @@ Application_setTitle :: proc "c" (self: ^Application, title: ^String) {
|
||||
}
|
||||
|
||||
@(objc_type=Application, objc_name="mainMenu")
|
||||
Window_mainMenu :: proc "c" (self: ^Application) -> ^Menu {
|
||||
Application_mainMenu :: proc "c" (self: ^Application) -> ^Menu {
|
||||
return msgSend(^Menu, self, "mainMenu")
|
||||
}
|
||||
|
||||
@@ -256,7 +255,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
return nil
|
||||
}
|
||||
if template.applicationWillFinishLaunching != nil {
|
||||
applicationWillFinishLaunching :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillFinishLaunching :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillFinishLaunching(notification)
|
||||
@@ -264,7 +263,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillFinishLaunching:"), auto_cast applicationWillFinishLaunching, "v@:@")
|
||||
}
|
||||
if template.applicationDidFinishLaunching != nil {
|
||||
applicationDidFinishLaunching :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidFinishLaunching :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidFinishLaunching(notification)
|
||||
@@ -272,7 +271,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidFinishLaunching:"), auto_cast applicationDidFinishLaunching, "v@:@")
|
||||
}
|
||||
if template.applicationWillBecomeActive != nil {
|
||||
applicationWillBecomeActive :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillBecomeActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillBecomeActive(notification)
|
||||
@@ -280,7 +279,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillBecomeActive:"), auto_cast applicationWillBecomeActive, "v@:@")
|
||||
}
|
||||
if template.applicationDidBecomeActive != nil {
|
||||
applicationDidBecomeActive :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidBecomeActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidBecomeActive(notification)
|
||||
@@ -288,7 +287,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidBecomeActive:"), auto_cast applicationDidBecomeActive, "v@:@")
|
||||
}
|
||||
if template.applicationWillResignActive != nil {
|
||||
applicationWillResignActive :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillResignActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillResignActive(notification)
|
||||
@@ -296,7 +295,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillResignActive:"), auto_cast applicationWillResignActive, "v@:@")
|
||||
}
|
||||
if template.applicationDidResignActive != nil {
|
||||
applicationDidResignActive :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidResignActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidResignActive(notification)
|
||||
@@ -304,7 +303,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidResignActive:"), auto_cast applicationDidResignActive, "v@:@")
|
||||
}
|
||||
if template.applicationShouldTerminate != nil {
|
||||
applicationShouldTerminate :: proc "c" (self: id, sender: ^Application) -> ApplicationTerminateReply {
|
||||
applicationShouldTerminate :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> ApplicationTerminateReply {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationShouldTerminate(sender)
|
||||
@@ -312,7 +311,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldTerminate:"), auto_cast applicationShouldTerminate, _UINTEGER_ENCODING+"@:@")
|
||||
}
|
||||
if template.applicationShouldTerminateAfterLastWindowClosed != nil {
|
||||
applicationShouldTerminateAfterLastWindowClosed :: proc "c" (self: id, sender: ^Application) -> BOOL {
|
||||
applicationShouldTerminateAfterLastWindowClosed :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationShouldTerminateAfterLastWindowClosed(sender)
|
||||
@@ -320,7 +319,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldTerminateAfterLastWindowClosed:"), auto_cast applicationShouldTerminateAfterLastWindowClosed, "B@:@")
|
||||
}
|
||||
if template.applicationWillTerminate != nil {
|
||||
applicationWillTerminate :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillTerminate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillTerminate(notification)
|
||||
@@ -328,7 +327,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillTerminate:"), auto_cast applicationWillTerminate, "v@:@")
|
||||
}
|
||||
if template.applicationWillHide != nil {
|
||||
applicationWillHide :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillHide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillHide(notification)
|
||||
@@ -336,7 +335,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillHide:"), auto_cast applicationWillHide, "v@:@")
|
||||
}
|
||||
if template.applicationDidHide != nil {
|
||||
applicationDidHide :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidHide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidHide(notification)
|
||||
@@ -344,7 +343,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidHide:"), auto_cast applicationDidHide, "v@:@")
|
||||
}
|
||||
if template.applicationWillUnhide != nil {
|
||||
applicationWillUnhide :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillUnhide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillUnhide(notification)
|
||||
@@ -352,7 +351,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillUnhide:"), auto_cast applicationWillUnhide, "v@:@")
|
||||
}
|
||||
if template.applicationDidUnhide != nil {
|
||||
applicationDidUnhide :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidUnhide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidUnhide(notification)
|
||||
@@ -360,7 +359,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidUnhide:"), auto_cast applicationDidUnhide, "v@:@")
|
||||
}
|
||||
if template.applicationWillUpdate != nil {
|
||||
applicationWillUpdate :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationWillUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillUpdate(notification)
|
||||
@@ -368,7 +367,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationWillUpdate:"), auto_cast applicationWillUpdate, "v@:@")
|
||||
}
|
||||
if template.applicationDidUpdate != nil {
|
||||
applicationDidUpdate :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidUpdate(notification)
|
||||
@@ -376,7 +375,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidUpdate:"), auto_cast applicationDidUpdate, "v@:@")
|
||||
}
|
||||
if template.applicationShouldHandleReopenHasVisibleWindows != nil {
|
||||
applicationShouldHandleReopenHasVisibleWindows :: proc "c" (self: id, sender: ^Application, flag: BOOL) -> BOOL {
|
||||
applicationShouldHandleReopenHasVisibleWindows :: proc "c" (self: id, cmd: SEL, sender: ^Application, flag: BOOL) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationShouldHandleReopenHasVisibleWindows(sender, flag)
|
||||
@@ -384,7 +383,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldHandleReopen:hasVisibleWindows:"), auto_cast applicationShouldHandleReopenHasVisibleWindows, "B@:@B")
|
||||
}
|
||||
if template.applicationDockMenu != nil {
|
||||
applicationDockMenu :: proc "c" (self: id, sender: ^Application) -> ^Menu {
|
||||
applicationDockMenu :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> ^Menu {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationDockMenu(sender)
|
||||
@@ -392,7 +391,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDockMenu:"), auto_cast applicationDockMenu, "@@:@")
|
||||
}
|
||||
if template.applicationShouldAutomaticallyLocalizeKeyEquivalents != nil {
|
||||
applicationShouldAutomaticallyLocalizeKeyEquivalents :: proc "c" (self: id, application: ^Application) -> BOOL {
|
||||
applicationShouldAutomaticallyLocalizeKeyEquivalents :: proc "c" (self: id, cmd: SEL, application: ^Application) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationShouldAutomaticallyLocalizeKeyEquivalents(application)
|
||||
@@ -400,7 +399,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldAutomaticallyLocalizeKeyEquivalents:"), auto_cast applicationShouldAutomaticallyLocalizeKeyEquivalents, "B@:@")
|
||||
}
|
||||
if template.applicationWillPresentError != nil {
|
||||
applicationWillPresentError :: proc "c" (self: id, application: ^Application, error: ^Error) -> ^Error {
|
||||
applicationWillPresentError :: proc "c" (self: id, cmd: SEL, application: ^Application, error: ^Error) -> ^Error {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationWillPresentError(application, error)
|
||||
@@ -408,7 +407,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:willPresentError:"), auto_cast applicationWillPresentError, "@@:@@")
|
||||
}
|
||||
if template.applicationDidChangeScreenParameters != nil {
|
||||
applicationDidChangeScreenParameters :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidChangeScreenParameters :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidChangeScreenParameters(notification)
|
||||
@@ -416,7 +415,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidChangeScreenParameters:"), auto_cast applicationDidChangeScreenParameters, "v@:@")
|
||||
}
|
||||
if template.applicationWillContinueUserActivityWithType != nil {
|
||||
applicationWillContinueUserActivityWithType :: proc "c" (self: id, application: ^Application, userActivityType: ^String) -> BOOL {
|
||||
applicationWillContinueUserActivityWithType :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivityType: ^String) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationWillContinueUserActivityWithType(application, userActivityType)
|
||||
@@ -424,7 +423,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:willContinueUserActivityWithType:"), auto_cast applicationWillContinueUserActivityWithType, "B@:@@")
|
||||
}
|
||||
if template.applicationContinueUserActivityRestorationHandler != nil {
|
||||
applicationContinueUserActivityRestorationHandler :: proc "c" (self: id, application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL {
|
||||
applicationContinueUserActivityRestorationHandler :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationContinueUserActivityRestorationHandler(application, userActivity, restorationHandler)
|
||||
@@ -432,7 +431,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:continueUserActivity:restorationHandler:"), auto_cast applicationContinueUserActivityRestorationHandler, "B@:@@?")
|
||||
}
|
||||
if template.applicationDidFailToContinueUserActivityWithTypeError != nil {
|
||||
applicationDidFailToContinueUserActivityWithTypeError :: proc "c" (self: id, application: ^Application, userActivityType: ^String, error: ^Error) {
|
||||
applicationDidFailToContinueUserActivityWithTypeError :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivityType: ^String, error: ^Error) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidFailToContinueUserActivityWithTypeError(application, userActivityType, error)
|
||||
@@ -440,7 +439,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:didFailToContinueUserActivityWithType:error:"), auto_cast applicationDidFailToContinueUserActivityWithTypeError, "v@:@@@")
|
||||
}
|
||||
if template.applicationDidUpdateUserActivity != nil {
|
||||
applicationDidUpdateUserActivity :: proc "c" (self: id, application: ^Application, userActivity: ^UserActivity) {
|
||||
applicationDidUpdateUserActivity :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivity: ^UserActivity) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidUpdateUserActivity(application, userActivity)
|
||||
@@ -448,7 +447,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:didUpdateUserActivity:"), auto_cast applicationDidUpdateUserActivity, "v@:@@")
|
||||
}
|
||||
if template.applicationDidRegisterForRemoteNotificationsWithDeviceToken != nil {
|
||||
applicationDidRegisterForRemoteNotificationsWithDeviceToken :: proc "c" (self: id, application: ^Application, deviceToken: ^Data) {
|
||||
applicationDidRegisterForRemoteNotificationsWithDeviceToken :: proc "c" (self: id, cmd: SEL, application: ^Application, deviceToken: ^Data) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidRegisterForRemoteNotificationsWithDeviceToken(application, deviceToken)
|
||||
@@ -456,7 +455,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:didRegisterForRemoteNotificationsWithDeviceToken:"), auto_cast applicationDidRegisterForRemoteNotificationsWithDeviceToken, "v@:@@")
|
||||
}
|
||||
if template.applicationDidFailToRegisterForRemoteNotificationsWithError != nil {
|
||||
applicationDidFailToRegisterForRemoteNotificationsWithError :: proc "c" (self: id, application: ^Application, error: ^Error) {
|
||||
applicationDidFailToRegisterForRemoteNotificationsWithError :: proc "c" (self: id, cmd: SEL, application: ^Application, error: ^Error) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidFailToRegisterForRemoteNotificationsWithError(application, error)
|
||||
@@ -464,7 +463,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:didFailToRegisterForRemoteNotificationsWithError:"), auto_cast applicationDidFailToRegisterForRemoteNotificationsWithError, "v@:@@")
|
||||
}
|
||||
if template.applicationDidReceiveRemoteNotification != nil {
|
||||
applicationDidReceiveRemoteNotification :: proc "c" (self: id, application: ^Application, userInfo: ^Dictionary) {
|
||||
applicationDidReceiveRemoteNotification :: proc "c" (self: id, cmd: SEL, application: ^Application, userInfo: ^Dictionary) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidReceiveRemoteNotification(application, userInfo)
|
||||
@@ -472,7 +471,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:didReceiveRemoteNotification:"), auto_cast applicationDidReceiveRemoteNotification, "v@:@@")
|
||||
}
|
||||
// if template.applicationUserDidAcceptCloudKitShareWithMetadata != nil {
|
||||
// applicationUserDidAcceptCloudKitShareWithMetadata :: proc "c" (self: id, application: ^Application, metadata: ^CKShareMetadata) {
|
||||
// applicationUserDidAcceptCloudKitShareWithMetadata :: proc "c" (self: id, cmd: SEL, application: ^Application, metadata: ^CKShareMetadata) {
|
||||
// del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
// context = del._context
|
||||
// del.applicationUserDidAcceptCloudKitShareWithMetadata(application, metadata)
|
||||
@@ -480,7 +479,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
// class_addMethod(class, intrinsics.objc_find_selector("application:userDidAcceptCloudKitShareWithMetadata:"), auto_cast applicationUserDidAcceptCloudKitShareWithMetadata, "v@:@@")
|
||||
// }
|
||||
// if template.applicationHandlerForIntent != nil {
|
||||
// applicationHandlerForIntent :: proc "c" (self: id, application: ^Application, intent: ^INIntent) -> id {
|
||||
// applicationHandlerForIntent :: proc "c" (self: id, cmd: SEL, application: ^Application, intent: ^INIntent) -> id {
|
||||
// del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
// context = del._context
|
||||
// return del.applicationHandlerForIntent(application, intent)
|
||||
@@ -488,7 +487,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
// class_addMethod(class, intrinsics.objc_find_selector("application:handlerForIntent:"), auto_cast applicationHandlerForIntent, "@@:@@")
|
||||
// }
|
||||
if template.applicationOpenURLs != nil {
|
||||
applicationOpenURLs :: proc "c" (self: id, application: ^Application, urls: ^Array) {
|
||||
applicationOpenURLs :: proc "c" (self: id, cmd: SEL, application: ^Application, urls: ^Array) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationOpenURLs(application, urls)
|
||||
@@ -496,7 +495,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:openURLs:"), auto_cast applicationOpenURLs, "v@:@@")
|
||||
}
|
||||
if template.applicationOpenFile != nil {
|
||||
applicationOpenFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL {
|
||||
applicationOpenFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationOpenFile(sender, filename)
|
||||
@@ -504,7 +503,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:openFile:"), auto_cast applicationOpenFile, "B@:@@")
|
||||
}
|
||||
if template.applicationOpenFileWithoutUI != nil {
|
||||
applicationOpenFileWithoutUI :: proc "c" (self: id, sender: id, filename: ^String) -> BOOL {
|
||||
applicationOpenFileWithoutUI :: proc "c" (self: id, cmd: SEL, sender: id, filename: ^String) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationOpenFileWithoutUI(sender, filename)
|
||||
@@ -512,7 +511,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:openFileWithoutUI:"), auto_cast applicationOpenFileWithoutUI, "B@:@@")
|
||||
}
|
||||
if template.applicationOpenTempFile != nil {
|
||||
applicationOpenTempFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL {
|
||||
applicationOpenTempFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationOpenTempFile(sender, filename)
|
||||
@@ -520,7 +519,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:openTempFile:"), auto_cast applicationOpenTempFile, "B@:@@")
|
||||
}
|
||||
if template.applicationOpenFiles != nil {
|
||||
applicationOpenFiles :: proc "c" (self: id, sender: ^Application, filenames: ^Array) {
|
||||
applicationOpenFiles :: proc "c" (self: id, cmd: SEL, sender: ^Application, filenames: ^Array) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationOpenFiles(sender, filenames)
|
||||
@@ -528,7 +527,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:openFiles:"), auto_cast applicationOpenFiles, "v@:@@")
|
||||
}
|
||||
if template.applicationShouldOpenUntitledFile != nil {
|
||||
applicationShouldOpenUntitledFile :: proc "c" (self: id, sender: ^Application) -> BOOL {
|
||||
applicationShouldOpenUntitledFile :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationShouldOpenUntitledFile(sender)
|
||||
@@ -536,7 +535,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationShouldOpenUntitledFile:"), auto_cast applicationShouldOpenUntitledFile, "B@:@")
|
||||
}
|
||||
if template.applicationOpenUntitledFile != nil {
|
||||
applicationOpenUntitledFile :: proc "c" (self: id, sender: ^Application) -> BOOL {
|
||||
applicationOpenUntitledFile :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationOpenUntitledFile(sender)
|
||||
@@ -544,7 +543,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationOpenUntitledFile:"), auto_cast applicationOpenUntitledFile, "B@:@")
|
||||
}
|
||||
if template.applicationPrintFile != nil {
|
||||
applicationPrintFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL {
|
||||
applicationPrintFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationPrintFile(sender, filename)
|
||||
@@ -552,7 +551,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:printFile:"), auto_cast applicationPrintFile, "B@:@@")
|
||||
}
|
||||
if template.applicationPrintFilesWithSettingsShowPrintPanels != nil {
|
||||
applicationPrintFilesWithSettingsShowPrintPanels :: proc "c" (self: id, application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply {
|
||||
applicationPrintFilesWithSettingsShowPrintPanels :: proc "c" (self: id, cmd: SEL, application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationPrintFilesWithSettingsShowPrintPanels(application, fileNames, printSettings, showPrintPanels)
|
||||
@@ -560,7 +559,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:printFiles:withSettings:showPrintPanels:"), auto_cast applicationPrintFilesWithSettingsShowPrintPanels, _UINTEGER_ENCODING+"@:@@@B")
|
||||
}
|
||||
if template.applicationSupportsSecureRestorableState != nil {
|
||||
applicationSupportsSecureRestorableState :: proc "c" (self: id, app: ^Application) -> BOOL {
|
||||
applicationSupportsSecureRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationSupportsSecureRestorableState(app)
|
||||
@@ -568,7 +567,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationSupportsSecureRestorableState:"), auto_cast applicationSupportsSecureRestorableState, "B@:@")
|
||||
}
|
||||
if template.applicationProtectedDataDidBecomeAvailable != nil {
|
||||
applicationProtectedDataDidBecomeAvailable :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationProtectedDataDidBecomeAvailable :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationProtectedDataDidBecomeAvailable(notification)
|
||||
@@ -576,7 +575,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationProtectedDataDidBecomeAvailable:"), auto_cast applicationProtectedDataDidBecomeAvailable, "v@:@")
|
||||
}
|
||||
if template.applicationProtectedDataWillBecomeUnavailable != nil {
|
||||
applicationProtectedDataWillBecomeUnavailable :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationProtectedDataWillBecomeUnavailable :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationProtectedDataWillBecomeUnavailable(notification)
|
||||
@@ -584,7 +583,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationProtectedDataWillBecomeUnavailable:"), auto_cast applicationProtectedDataWillBecomeUnavailable, "v@:@")
|
||||
}
|
||||
if template.applicationWillEncodeRestorableState != nil {
|
||||
applicationWillEncodeRestorableState :: proc "c" (self: id, app: ^Application, coder: ^Coder) {
|
||||
applicationWillEncodeRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application, coder: ^Coder) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationWillEncodeRestorableState(app, coder)
|
||||
@@ -592,7 +591,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:willEncodeRestorableState:"), auto_cast applicationWillEncodeRestorableState, "v@:@@")
|
||||
}
|
||||
if template.applicationDidDecodeRestorableState != nil {
|
||||
applicationDidDecodeRestorableState :: proc "c" (self: id, app: ^Application, coder: ^Coder) {
|
||||
applicationDidDecodeRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application, coder: ^Coder) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidDecodeRestorableState(app, coder)
|
||||
@@ -600,7 +599,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("application:didDecodeRestorableState:"), auto_cast applicationDidDecodeRestorableState, "v@:@@")
|
||||
}
|
||||
if template.applicationDidChangeOcclusionState != nil {
|
||||
applicationDidChangeOcclusionState :: proc "c" (self: id, notification: ^Notification) {
|
||||
applicationDidChangeOcclusionState :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.applicationDidChangeOcclusionState(notification)
|
||||
@@ -608,7 +607,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem
|
||||
class_addMethod(class, intrinsics.objc_find_selector("applicationDidChangeOcclusionState:"), auto_cast applicationDidChangeOcclusionState, "v@:@")
|
||||
}
|
||||
if template.applicationDelegateHandlesKey != nil {
|
||||
applicationDelegateHandlesKey :: proc "c" (self: id, sender: ^Application, key: ^String) -> BOOL {
|
||||
applicationDelegateHandlesKey :: proc "c" (self: id, cmd: SEL, sender: ^Application, key: ^String) -> BOOL {
|
||||
del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.applicationDelegateHandlesKey(sender, key)
|
||||
|
||||
@@ -40,3 +40,49 @@ Array_objectAs :: proc "c" (self: ^Array, index: UInteger, $T: typeid) -> T wher
|
||||
Array_count :: proc "c" (self: ^Array) -> UInteger {
|
||||
return msgSend(UInteger, self, "count")
|
||||
}
|
||||
|
||||
|
||||
@(objc_class="NSMutableArray")
|
||||
MutableArray :: struct {
|
||||
using _: Copying(MutableArray),
|
||||
}
|
||||
|
||||
@(objc_type=MutableArray, objc_name="alloc", objc_is_class_method=true)
|
||||
MutableArray_alloc :: proc "c" () -> ^MutableArray {
|
||||
return msgSend(^MutableArray, MutableArray, "alloc")
|
||||
}
|
||||
|
||||
@(objc_type=MutableArray, objc_name="init")
|
||||
MutableArray_init :: proc "c" (self: ^MutableArray) -> ^MutableArray {
|
||||
return msgSend(^MutableArray, self, "init")
|
||||
}
|
||||
|
||||
@(objc_type=MutableArray, objc_name="initWithObjects")
|
||||
MutableArray_initWithObjects :: proc "c" (self: ^MutableArray, objects: [^]^Object, count: UInteger) -> ^MutableArray {
|
||||
return msgSend(^MutableArray, self, "initWithObjects:count:", objects, count)
|
||||
}
|
||||
|
||||
@(objc_type=MutableArray, objc_name="initWithCoder")
|
||||
MutableArray_initWithCoder :: proc "c" (self: ^MutableArray, coder: ^Coder) -> ^MutableArray {
|
||||
return msgSend(^MutableArray, self, "initWithCoder:", coder)
|
||||
}
|
||||
|
||||
@(objc_type=MutableArray, objc_name="object")
|
||||
MutableArray_object :: proc "c" (self: ^MutableArray, index: UInteger) -> ^Object {
|
||||
return msgSend(^Object, self, "objectAtIndex:", index)
|
||||
}
|
||||
@(objc_type=MutableArray, objc_name="objectAs")
|
||||
MutableArray_objectAs :: proc "c" (self: ^MutableArray, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {
|
||||
return (T)(MutableArray_object(self, index))
|
||||
}
|
||||
|
||||
@(objc_type=MutableArray, objc_name="count")
|
||||
MutableArray_count :: proc "c" (self: ^MutableArray) -> UInteger {
|
||||
return msgSend(UInteger, self, "count")
|
||||
}
|
||||
|
||||
|
||||
@(objc_type=MutableArray, objc_name="exchangeObjectAtIndex")
|
||||
MutableArray_exchangeObjectAtIndex :: proc "c" (self: ^MutableArray, idx1, idx2: UInteger) {
|
||||
msgSend(nil, self, "exchangeObjectAtIndex:withObjectAtIndex:", idx1, idx2)
|
||||
}
|
||||
|
||||
@@ -2,127 +2,562 @@ package objc_Foundation
|
||||
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
|
||||
KeyEquivalentModifierFlag :: enum UInteger {
|
||||
CapsLock = 16, // Set if Caps Lock key is pressed.
|
||||
Shift = 17, // Set if Shift key is pressed.
|
||||
Control = 18, // Set if Control key is pressed.
|
||||
Option = 19, // Set if Option or Alternate key is pressed.
|
||||
Command = 20, // Set if Command key is pressed.
|
||||
NumericPad = 21, // Set if any key in the numeric keypad is pressed.
|
||||
Help = 22, // Set if the Help key is pressed.
|
||||
Function = 23, // Set if any function key is pressed.
|
||||
}
|
||||
KeyEquivalentModifierMask :: distinct bit_set[KeyEquivalentModifierFlag; UInteger]
|
||||
|
||||
// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information.
|
||||
KeyEventModifierFlagDeviceIndependentFlagsMask := transmute(KeyEquivalentModifierMask)_KeyEventModifierFlagDeviceIndependentFlagsMask
|
||||
@(private) _KeyEventModifierFlagDeviceIndependentFlagsMask := UInteger(0xffff0000)
|
||||
import "core:c"
|
||||
|
||||
|
||||
MenuItemCallback :: proc "c" (unused: rawptr, name: SEL, sender: ^Object)
|
||||
|
||||
|
||||
@(objc_class="NSMenuItem")
|
||||
MenuItem :: struct {using _: Object}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="alloc", objc_is_class_method=true)
|
||||
MenuItem_alloc :: proc "c" () -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "alloc")
|
||||
MenuSelectionMode :: enum c.long {
|
||||
Automatic = 0,
|
||||
SelectOne = 1,
|
||||
SelectAny = 2,
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="registerActionCallback", objc_is_class_method=true)
|
||||
MenuItem_registerActionCallback :: proc "c" (name: cstring, callback: MenuItemCallback) -> SEL {
|
||||
s := string(name)
|
||||
n := len(s)
|
||||
sel: SEL
|
||||
if n > 0 && s[n-1] != ':' {
|
||||
col_name := intrinsics.alloca(n+2, 1)
|
||||
builtin.copy(col_name[:n], s)
|
||||
col_name[n] = ':'
|
||||
col_name[n+1] = 0
|
||||
sel = sel_registerName(cstring(col_name))
|
||||
} else {
|
||||
sel = sel_registerName(name)
|
||||
}
|
||||
if callback != nil {
|
||||
class_addMethod(intrinsics.objc_find_class("NSObject"), sel, auto_cast callback, "v@:@")
|
||||
}
|
||||
return sel
|
||||
MenuPresentationStyle :: enum c.long {
|
||||
Regular = 0,
|
||||
Palette = 1,
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="separatorItem", objc_is_class_method=true)
|
||||
MenuItem_separatorItem :: proc "c" () -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "separatorItem")
|
||||
UserInterfaceLayoutDirection :: enum c.long {
|
||||
LeftToRight = 0,
|
||||
RightToLeft = 1,
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="init")
|
||||
MenuItem_init :: proc "c" (self: ^MenuItem) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "init")
|
||||
MenuPropertyItem :: enum c.ulong {
|
||||
Title = 0,
|
||||
AttributedTitle = 1,
|
||||
KeyEquivalent = 2,
|
||||
Image = 3,
|
||||
Enabled = 4,
|
||||
AccessibilityDescription = 5,
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="initWithTitle")
|
||||
MenuItem_initWithTitle :: proc "c" (self: ^MenuItem, title: ^String, action: SEL, keyEquivalent: ^String) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "initWithTitle:action:keyEquivalent:", title, action, keyEquivalent)
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="setKeyEquivalentModifierMask")
|
||||
MenuItem_setKeyEquivalentModifierMask :: proc "c" (self: ^MenuItem, modifierMask: KeyEquivalentModifierMask) {
|
||||
msgSend(nil, self, "setKeyEquivalentModifierMask:", modifierMask)
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="keyEquivalentModifierMask")
|
||||
MenuItem_keyEquivalentModifierMask :: proc "c" (self: ^MenuItem) -> KeyEquivalentModifierMask {
|
||||
return msgSend(KeyEquivalentModifierMask, self, "keyEquivalentModifierMask")
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="setSubmenu")
|
||||
MenuItem_setSubmenu :: proc "c" (self: ^MenuItem, submenu: ^Menu) {
|
||||
msgSend(nil, self, "setSubmenu:", submenu)
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="title")
|
||||
MenuItem_title :: proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "title")
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="setTitle")
|
||||
MenuItem_setTitle :: proc "c" (self: ^MenuItem, title: ^String) -> ^String {
|
||||
return msgSend(^String, self, "title:", title)
|
||||
}
|
||||
|
||||
MenuProperties :: distinct bit_set[MenuPropertyItem; c.ulong]
|
||||
|
||||
|
||||
@(objc_class="NSMenu")
|
||||
Menu :: struct {using _: Object}
|
||||
|
||||
@(objc_type=Menu, objc_name="alloc", objc_is_class_method=true)
|
||||
Menu_alloc :: proc "c" () -> ^Menu {
|
||||
return msgSend(^Menu, Menu, "alloc")
|
||||
}
|
||||
|
||||
@(objc_type=Menu, objc_name="init")
|
||||
Menu_init :: proc "c" (self: ^Menu) -> ^Menu {
|
||||
return msgSend(^Menu, self, "init")
|
||||
}
|
||||
|
||||
|
||||
@(objc_type=Menu, objc_name="initWithTitle")
|
||||
Menu_initWithTitle :: proc "c" (self: ^Menu, title: ^String) -> ^Menu {
|
||||
Menu_initWithTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) -> ^Menu {
|
||||
return msgSend(^Menu, self, "initWithTitle:", title)
|
||||
}
|
||||
|
||||
|
||||
@(objc_type=Menu, objc_name="initWithCoder")
|
||||
Menu_initWithCoder :: #force_inline proc "c" (self: ^Menu, coder: ^Coder) -> ^Menu {
|
||||
return msgSend(^Menu, self, "initWithCoder:", coder)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="popUpContextMenu_withEvent_forView", objc_is_class_method=true)
|
||||
Menu_popUpContextMenu_withEvent_forView :: #force_inline proc "c" (menu: ^Menu, event: ^Event, view: ^View) {
|
||||
msgSend(nil, Menu, "popUpContextMenu:withEvent:forView:", menu, event, view)
|
||||
}
|
||||
// @(objc_type=Menu, objc_name="popUpContextMenu_withEvent_forView_withFont", objc_is_class_method=true)
|
||||
// Menu_popUpContextMenu_withEvent_forView_withFont :: #force_inline proc "c" (menu: ^Menu, event: ^Event, view: ^View, font: ^Font) {
|
||||
// msgSend(nil, Menu, "popUpContextMenu:withEvent:forView:withFont:", menu, event, view, font)
|
||||
// }
|
||||
@(objc_type=Menu, objc_name="popUpMenuPositioningItem")
|
||||
Menu_popUpMenuPositioningItem :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem, location: Point, view: ^View) -> bool {
|
||||
return msgSend(bool, self, "popUpMenuPositioningItem:atLocation:inView:", item, location, view)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setMenuBarVisible", objc_is_class_method=true)
|
||||
Menu_setMenuBarVisible :: #force_inline proc "c" (visible: bool) {
|
||||
msgSend(nil, Menu, "setMenuBarVisible:", visible)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="menuBarVisible", objc_is_class_method=true)
|
||||
Menu_menuBarVisible :: #force_inline proc "c" () -> bool {
|
||||
return msgSend(bool, Menu, "menuBarVisible")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="insertItem")
|
||||
Menu_insertItem :: #force_inline proc "c" (self: ^Menu, newItem: ^MenuItem, index: Integer) {
|
||||
msgSend(nil, self, "insertItem:atIndex:", newItem, index)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="addItem")
|
||||
Menu_addItem :: proc "c" (self: ^Menu, item: ^MenuItem) {
|
||||
msgSend(nil, self, "addItem:", item)
|
||||
Menu_addItem :: #force_inline proc "c" (self: ^Menu, newItem: ^MenuItem) {
|
||||
msgSend(nil, self, "addItem:", newItem)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="insertItemWithTitle")
|
||||
Menu_insertItemWithTitle :: #force_inline proc "c" (self: ^Menu, string: ^String, selector: SEL, charCode: ^String, index: Integer) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "insertItemWithTitle:action:keyEquivalent:atIndex:", string, selector, charCode, index)
|
||||
}
|
||||
|
||||
@(objc_type=Menu, objc_name="addItemWithTitle")
|
||||
Menu_addItemWithTitle :: proc "c" (self: ^Menu, title: ^String, selector: SEL, keyEquivalent: ^String) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "addItemWithTitle:action:keyEquivalent:", title, selector, keyEquivalent)
|
||||
Menu_addItemWithTitle :: #force_inline proc "c" (self: ^Menu, string: ^String, selector: SEL, charCode: ^String) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "addItemWithTitle:action:keyEquivalent:", string, selector, charCode)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="removeItemAtIndex")
|
||||
Menu_removeItemAtIndex :: #force_inline proc "c" (self: ^Menu, index: Integer) {
|
||||
msgSend(nil, self, "removeItemAtIndex:", index)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="removeItem")
|
||||
Menu_removeItem :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem) {
|
||||
msgSend(nil, self, "removeItem:", item)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setSubmenu")
|
||||
Menu_setSubmenu :: #force_inline proc "c" (self: ^Menu, menu: ^Menu, item: ^MenuItem) {
|
||||
msgSend(nil, self, "setSubmenu:forItem:", menu, item)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="removeAllItems")
|
||||
Menu_removeAllItems :: #force_inline proc "c" (self: ^Menu) {
|
||||
msgSend(nil, self, "removeAllItems")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="itemAtIndex")
|
||||
Menu_itemAtIndex :: #force_inline proc "c" (self: ^Menu, index: Integer) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "itemAtIndex:", index)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="indexOfItem")
|
||||
Menu_indexOfItem :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem) -> Integer {
|
||||
return msgSend(Integer, self, "indexOfItem:", item)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="indexOfItemWithTitle")
|
||||
Menu_indexOfItemWithTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) -> Integer {
|
||||
return msgSend(Integer, self, "indexOfItemWithTitle:", title)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="indexOfItemWithTag")
|
||||
Menu_indexOfItemWithTag :: #force_inline proc "c" (self: ^Menu, tag: Integer) -> Integer {
|
||||
return msgSend(Integer, self, "indexOfItemWithTag:", tag)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="indexOfItemWithRepresentedObject")
|
||||
Menu_indexOfItemWithRepresentedObject :: #force_inline proc "c" (self: ^Menu, object: id) -> Integer {
|
||||
return msgSend(Integer, self, "indexOfItemWithRepresentedObject:", object)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="indexOfItemWithSubmenu")
|
||||
Menu_indexOfItemWithSubmenu :: #force_inline proc "c" (self: ^Menu, submenu: ^Menu) -> Integer {
|
||||
return msgSend(Integer, self, "indexOfItemWithSubmenu:", submenu)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="indexOfItemWithTarget")
|
||||
Menu_indexOfItemWithTarget :: #force_inline proc "c" (self: ^Menu, target: id, actionSelector: SEL) -> Integer {
|
||||
return msgSend(Integer, self, "indexOfItemWithTarget:andAction:", target, actionSelector)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="itemWithTitle")
|
||||
Menu_itemWithTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "itemWithTitle:", title)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="itemWithTag")
|
||||
Menu_itemWithTag :: #force_inline proc "c" (self: ^Menu, tag: Integer) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "itemWithTag:", tag)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="update")
|
||||
Menu_update :: #force_inline proc "c" (self: ^Menu) {
|
||||
msgSend(nil, self, "update")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="performKeyEquivalent")
|
||||
Menu_performKeyEquivalent :: #force_inline proc "c" (self: ^Menu, event: ^Event) -> bool {
|
||||
return msgSend(bool, self, "performKeyEquivalent:", event)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="itemChanged")
|
||||
Menu_itemChanged :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem) {
|
||||
msgSend(nil, self, "itemChanged:", item)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="performActionForItemAtIndex")
|
||||
Menu_performActionForItemAtIndex :: #force_inline proc "c" (self: ^Menu, index: Integer) {
|
||||
msgSend(nil, self, "performActionForItemAtIndex:", index)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="cancelTracking")
|
||||
Menu_cancelTracking :: #force_inline proc "c" (self: ^Menu) {
|
||||
msgSend(nil, self, "cancelTracking")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="cancelTrackingWithoutAnimation")
|
||||
Menu_cancelTrackingWithoutAnimation :: #force_inline proc "c" (self: ^Menu) {
|
||||
msgSend(nil, self, "cancelTrackingWithoutAnimation")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="title")
|
||||
Menu_title :: #force_inline proc "c" (self: ^Menu) -> ^String {
|
||||
return msgSend(^String, self, "title")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setTitle")
|
||||
Menu_setTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) {
|
||||
msgSend(nil, self, "setTitle:", title)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="supermenu")
|
||||
Menu_supermenu :: #force_inline proc "c" (self: ^Menu) -> ^Menu {
|
||||
return msgSend(^Menu, self, "supermenu")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setSupermenu")
|
||||
Menu_setSupermenu :: #force_inline proc "c" (self: ^Menu, supermenu: ^Menu) {
|
||||
msgSend(nil, self, "setSupermenu:", supermenu)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="itemArray")
|
||||
Menu_itemArray :: #force_inline proc "c" (self: ^Menu) -> ^Array {
|
||||
return msgSend(^Array, self, "itemArray")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setItemArray")
|
||||
Menu_setItemArray :: #force_inline proc "c" (self: ^Menu, itemArray: ^Array) {
|
||||
msgSend(nil, self, "setItemArray:", itemArray)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="numberOfItems")
|
||||
Menu_numberOfItems :: #force_inline proc "c" (self: ^Menu) -> Integer {
|
||||
return msgSend(Integer, self, "numberOfItems")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="autoenablesItems")
|
||||
Menu_autoenablesItems :: #force_inline proc "c" (self: ^Menu) -> bool {
|
||||
return msgSend(bool, self, "autoenablesItems")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setAutoenablesItems")
|
||||
Menu_setAutoenablesItems :: #force_inline proc "c" (self: ^Menu, autoenablesItems: bool) {
|
||||
msgSend(nil, self, "setAutoenablesItems:", autoenablesItems)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="delegate")
|
||||
Menu_delegate :: #force_inline proc "c" (self: ^Menu) -> ^MenuDelegate {
|
||||
return msgSend(^MenuDelegate, self, "delegate")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setDelegate")
|
||||
Menu_setDelegate :: #force_inline proc "c" (self: ^Menu, delegate: ^MenuDelegate) {
|
||||
msgSend(nil, self, "setDelegate:", delegate)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="menuBarHeight")
|
||||
Menu_menuBarHeight :: #force_inline proc "c" (self: ^Menu) -> Float {
|
||||
return msgSend(Float, self, "menuBarHeight")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="highlightedItem")
|
||||
Menu_highlightedItem :: #force_inline proc "c" (self: ^Menu) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "highlightedItem")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="minimumWidth")
|
||||
Menu_minimumWidth :: #force_inline proc "c" (self: ^Menu) -> Float {
|
||||
return msgSend(Float, self, "minimumWidth")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setMinimumWidth")
|
||||
Menu_setMinimumWidth :: #force_inline proc "c" (self: ^Menu, minimumWidth: Float) {
|
||||
msgSend(nil, self, "setMinimumWidth:", minimumWidth)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="size")
|
||||
Menu_size :: #force_inline proc "c" (self: ^Menu) -> Size {
|
||||
return msgSend(Size, self, "size")
|
||||
}
|
||||
// @(objc_type=Menu, objc_name="font")
|
||||
// Menu_font :: #force_inline proc "c" (self: ^Menu) -> ^Font {
|
||||
// return msgSend(^Font, self, "font")
|
||||
// }
|
||||
// @(objc_type=Menu, objc_name="setFont")
|
||||
// Menu_setFont :: #force_inline proc "c" (self: ^Menu, font: ^Font) {
|
||||
// msgSend(nil, self, "setFont:", font)
|
||||
// }
|
||||
@(objc_type=Menu, objc_name="allowsContextMenuPlugIns")
|
||||
Menu_allowsContextMenuPlugIns :: #force_inline proc "c" (self: ^Menu) -> bool {
|
||||
return msgSend(bool, self, "allowsContextMenuPlugIns")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setAllowsContextMenuPlugIns")
|
||||
Menu_setAllowsContextMenuPlugIns :: #force_inline proc "c" (self: ^Menu, allowsContextMenuPlugIns: bool) {
|
||||
msgSend(nil, self, "setAllowsContextMenuPlugIns:", allowsContextMenuPlugIns)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="showsStateColumn")
|
||||
Menu_showsStateColumn :: #force_inline proc "c" (self: ^Menu) -> bool {
|
||||
return msgSend(bool, self, "showsStateColumn")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setShowsStateColumn")
|
||||
Menu_setShowsStateColumn :: #force_inline proc "c" (self: ^Menu, showsStateColumn: bool) {
|
||||
msgSend(nil, self, "setShowsStateColumn:", showsStateColumn)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="userInterfaceLayoutDirection")
|
||||
Menu_userInterfaceLayoutDirection :: #force_inline proc "c" (self: ^Menu) -> UserInterfaceLayoutDirection {
|
||||
return msgSend(UserInterfaceLayoutDirection, self, "userInterfaceLayoutDirection")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setUserInterfaceLayoutDirection")
|
||||
Menu_setUserInterfaceLayoutDirection :: #force_inline proc "c" (self: ^Menu, userInterfaceLayoutDirection: UserInterfaceLayoutDirection) {
|
||||
msgSend(nil, self, "setUserInterfaceLayoutDirection:", userInterfaceLayoutDirection)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="paletteMenuWithColors_titles_selectionHandler", objc_is_class_method=true)
|
||||
Menu_paletteMenuWithColors_titles_selectionHandler :: #force_inline proc "c" (colors: ^Array, itemTitles: ^Array, onSelectionChange: proc "c" (_arg_0: ^Menu)) -> ^Menu {
|
||||
return msgSend(^Menu, Menu, "paletteMenuWithColors:titles:selectionHandler:", colors, itemTitles, onSelectionChange)
|
||||
}
|
||||
// @(objc_type=Menu, objc_name="paletteMenuWithColors_titles_templateImage_selectionHandler", objc_is_class_method=true)
|
||||
// Menu_paletteMenuWithColors_titles_templateImage_selectionHandler :: #force_inline proc "c" (colors: ^Array, itemTitles: ^Array, image: ^Image, onSelectionChange: proc "c" (_arg_0: ^Menu)) -> ^Menu {
|
||||
// return msgSend(^Menu, Menu, "paletteMenuWithColors:titles:templateImage:selectionHandler:", colors, itemTitles, image, onSelectionChange)
|
||||
// }
|
||||
@(objc_type=Menu, objc_name="presentationStyle")
|
||||
Menu_presentationStyle :: #force_inline proc "c" (self: ^Menu) -> MenuPresentationStyle {
|
||||
return msgSend(MenuPresentationStyle, self, "presentationStyle")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setPresentationStyle")
|
||||
Menu_setPresentationStyle :: #force_inline proc "c" (self: ^Menu, presentationStyle: MenuPresentationStyle) {
|
||||
msgSend(nil, self, "setPresentationStyle:", presentationStyle)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="selectionMode")
|
||||
Menu_selectionMode :: #force_inline proc "c" (self: ^Menu) -> MenuSelectionMode {
|
||||
return msgSend(MenuSelectionMode, self, "selectionMode")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setSelectionMode")
|
||||
Menu_setSelectionMode :: #force_inline proc "c" (self: ^Menu, selectionMode: MenuSelectionMode) {
|
||||
msgSend(nil, self, "setSelectionMode:", selectionMode)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="selectedItems")
|
||||
Menu_selectedItems :: #force_inline proc "c" (self: ^Menu) -> ^Array {
|
||||
return msgSend(^Array, self, "selectedItems")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setSelectedItems")
|
||||
Menu_setSelectedItems :: #force_inline proc "c" (self: ^Menu, selectedItems: ^Array) {
|
||||
msgSend(nil, self, "setSelectedItems:", selectedItems)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="submenuAction")
|
||||
Menu_submenuAction :: #force_inline proc "c" (self: ^Menu, sender: id) {
|
||||
msgSend(nil, self, "submenuAction:", sender)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="propertiesToUpdate")
|
||||
Menu_propertiesToUpdate :: #force_inline proc "c" (self: ^Menu) -> MenuProperties {
|
||||
return msgSend(MenuProperties, self, "propertiesToUpdate")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setMenuRepresentation")
|
||||
Menu_setMenuRepresentation :: #force_inline proc "c" (self: ^Menu, menuRep: id) {
|
||||
msgSend(nil, self, "setMenuRepresentation:", menuRep)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="menuRepresentation")
|
||||
Menu_menuRepresentation :: #force_inline proc "c" (self: ^Menu) -> id {
|
||||
return msgSend(id, self, "menuRepresentation")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setContextMenuRepresentation")
|
||||
Menu_setContextMenuRepresentation :: #force_inline proc "c" (self: ^Menu, menuRep: id) {
|
||||
msgSend(nil, self, "setContextMenuRepresentation:", menuRep)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="contextMenuRepresentation")
|
||||
Menu_contextMenuRepresentation :: #force_inline proc "c" (self: ^Menu) -> id {
|
||||
return msgSend(id, self, "contextMenuRepresentation")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setTearOffMenuRepresentation")
|
||||
Menu_setTearOffMenuRepresentation :: #force_inline proc "c" (self: ^Menu, menuRep: id) {
|
||||
msgSend(nil, self, "setTearOffMenuRepresentation:", menuRep)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="tearOffMenuRepresentation")
|
||||
Menu_tearOffMenuRepresentation :: #force_inline proc "c" (self: ^Menu) -> id {
|
||||
return msgSend(id, self, "tearOffMenuRepresentation")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="menuZone", objc_is_class_method=true)
|
||||
Menu_menuZone :: #force_inline proc "c" () -> ^Zone {
|
||||
return msgSend(^Zone, Menu, "menuZone")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setMenuZone", objc_is_class_method=true)
|
||||
Menu_setMenuZone :: #force_inline proc "c" (zone: ^Zone) {
|
||||
msgSend(nil, Menu, "setMenuZone:", zone)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="attachedMenu")
|
||||
Menu_attachedMenu :: #force_inline proc "c" (self: ^Menu) -> ^Menu {
|
||||
return msgSend(^Menu, self, "attachedMenu")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="isAttached")
|
||||
Menu_isAttached :: #force_inline proc "c" (self: ^Menu) -> bool {
|
||||
return msgSend(bool, self, "isAttached")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="sizeToFit")
|
||||
Menu_sizeToFit :: #force_inline proc "c" (self: ^Menu) {
|
||||
msgSend(nil, self, "sizeToFit")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="locationForSubmenu")
|
||||
Menu_locationForSubmenu :: #force_inline proc "c" (self: ^Menu, submenu: ^Menu) -> Point {
|
||||
return msgSend(Point, self, "locationForSubmenu:", submenu)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="helpRequested")
|
||||
Menu_helpRequested :: #force_inline proc "c" (self: ^Menu, eventPtr: ^Event) {
|
||||
msgSend(nil, self, "helpRequested:", eventPtr)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="menuChangedMessagesEnabled")
|
||||
Menu_menuChangedMessagesEnabled :: #force_inline proc "c" (self: ^Menu) -> bool {
|
||||
return msgSend(bool, self, "menuChangedMessagesEnabled")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setMenuChangedMessagesEnabled")
|
||||
Menu_setMenuChangedMessagesEnabled :: #force_inline proc "c" (self: ^Menu, menuChangedMessagesEnabled: bool) {
|
||||
msgSend(nil, self, "setMenuChangedMessagesEnabled:", menuChangedMessagesEnabled)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="isTornOff")
|
||||
Menu_isTornOff :: #force_inline proc "c" (self: ^Menu) -> bool {
|
||||
return msgSend(bool, self, "isTornOff")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="load", objc_is_class_method=true)
|
||||
Menu_load :: #force_inline proc "c" () {
|
||||
msgSend(nil, Menu, "load")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="initialize", objc_is_class_method=true)
|
||||
Menu_initialize :: #force_inline proc "c" () {
|
||||
msgSend(nil, Menu, "initialize")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="new", objc_is_class_method=true)
|
||||
Menu_new :: #force_inline proc "c" () -> ^Menu {
|
||||
return msgSend(^Menu, Menu, "new")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="allocWithZone", objc_is_class_method=true)
|
||||
Menu_allocWithZone :: #force_inline proc "c" (zone: ^Zone) -> ^Menu {
|
||||
return msgSend(^Menu, Menu, "allocWithZone:", zone)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="alloc", objc_is_class_method=true)
|
||||
Menu_alloc :: #force_inline proc "c" () -> ^Menu {
|
||||
return msgSend(^Menu, Menu, "alloc")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="copyWithZone", objc_is_class_method=true)
|
||||
Menu_copyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id {
|
||||
return msgSend(id, Menu, "copyWithZone:", zone)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="mutableCopyWithZone", objc_is_class_method=true)
|
||||
Menu_mutableCopyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id {
|
||||
return msgSend(id, Menu, "mutableCopyWithZone:", zone)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="instancesRespondToSelector", objc_is_class_method=true)
|
||||
Menu_instancesRespondToSelector :: #force_inline proc "c" (aSelector: SEL) -> bool {
|
||||
return msgSend(bool, Menu, "instancesRespondToSelector:", aSelector)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="conformsToProtocol", objc_is_class_method=true)
|
||||
Menu_conformsToProtocol :: #force_inline proc "c" (protocol: ^Protocol) -> bool {
|
||||
return msgSend(bool, Menu, "conformsToProtocol:", protocol)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="instanceMethodForSelector", objc_is_class_method=true)
|
||||
Menu_instanceMethodForSelector :: #force_inline proc "c" (aSelector: SEL) -> IMP {
|
||||
return msgSend(IMP, Menu, "instanceMethodForSelector:", aSelector)
|
||||
}
|
||||
// @(objc_type=Menu, objc_name="instanceMethodSignatureForSelector", objc_is_class_method=true)
|
||||
// Menu_instanceMethodSignatureForSelector :: #force_inline proc "c" (aSelector: SEL) -> ^MethodSignature {
|
||||
// return msgSend(^MethodSignature, Menu, "instanceMethodSignatureForSelector:", aSelector)
|
||||
// }
|
||||
@(objc_type=Menu, objc_name="isSubclassOfClass", objc_is_class_method=true)
|
||||
Menu_isSubclassOfClass :: #force_inline proc "c" (aClass: Class) -> bool {
|
||||
return msgSend(bool, Menu, "isSubclassOfClass:", aClass)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="resolveClassMethod", objc_is_class_method=true)
|
||||
Menu_resolveClassMethod :: #force_inline proc "c" (sel: SEL) -> bool {
|
||||
return msgSend(bool, Menu, "resolveClassMethod:", sel)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="resolveInstanceMethod", objc_is_class_method=true)
|
||||
Menu_resolveInstanceMethod :: #force_inline proc "c" (sel: SEL) -> bool {
|
||||
return msgSend(bool, Menu, "resolveInstanceMethod:", sel)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="hash", objc_is_class_method=true)
|
||||
Menu_hash :: #force_inline proc "c" () -> UInteger {
|
||||
return msgSend(UInteger, Menu, "hash")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="superclass", objc_is_class_method=true)
|
||||
Menu_superclass :: #force_inline proc "c" () -> Class {
|
||||
return msgSend(Class, Menu, "superclass")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="class", objc_is_class_method=true)
|
||||
Menu_class :: #force_inline proc "c" () -> Class {
|
||||
return msgSend(Class, Menu, "class")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="description", objc_is_class_method=true)
|
||||
Menu_description :: #force_inline proc "c" () -> ^String {
|
||||
return msgSend(^String, Menu, "description")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="debugDescription", objc_is_class_method=true)
|
||||
Menu_debugDescription :: #force_inline proc "c" () -> ^String {
|
||||
return msgSend(^String, Menu, "debugDescription")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="version", objc_is_class_method=true)
|
||||
Menu_version :: #force_inline proc "c" () -> Integer {
|
||||
return msgSend(Integer, Menu, "version")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setVersion", objc_is_class_method=true)
|
||||
Menu_setVersion :: #force_inline proc "c" (aVersion: Integer) {
|
||||
msgSend(nil, Menu, "setVersion:", aVersion)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="poseAsClass", objc_is_class_method=true)
|
||||
Menu_poseAsClass :: #force_inline proc "c" (aClass: Class) {
|
||||
msgSend(nil, Menu, "poseAsClass:", aClass)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="cancelPreviousPerformRequestsWithTarget_selector_object", objc_is_class_method=true)
|
||||
Menu_cancelPreviousPerformRequestsWithTarget_selector_object :: #force_inline proc "c" (aTarget: id, aSelector: SEL, anArgument: id) {
|
||||
msgSend(nil, Menu, "cancelPreviousPerformRequestsWithTarget:selector:object:", aTarget, aSelector, anArgument)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="cancelPreviousPerformRequestsWithTarget_", objc_is_class_method=true)
|
||||
Menu_cancelPreviousPerformRequestsWithTarget_ :: #force_inline proc "c" (aTarget: id) {
|
||||
msgSend(nil, Menu, "cancelPreviousPerformRequestsWithTarget:", aTarget)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="accessInstanceVariablesDirectly", objc_is_class_method=true)
|
||||
Menu_accessInstanceVariablesDirectly :: #force_inline proc "c" () -> bool {
|
||||
return msgSend(bool, Menu, "accessInstanceVariablesDirectly")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="useStoredAccessor", objc_is_class_method=true)
|
||||
Menu_useStoredAccessor :: #force_inline proc "c" () -> bool {
|
||||
return msgSend(bool, Menu, "useStoredAccessor")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="keyPathsForValuesAffectingValueForKey", objc_is_class_method=true)
|
||||
Menu_keyPathsForValuesAffectingValueForKey :: #force_inline proc "c" (key: ^String) -> ^Set {
|
||||
return msgSend(^Set, Menu, "keyPathsForValuesAffectingValueForKey:", key)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="automaticallyNotifiesObserversForKey", objc_is_class_method=true)
|
||||
Menu_automaticallyNotifiesObserversForKey :: #force_inline proc "c" (key: ^String) -> bool {
|
||||
return msgSend(bool, Menu, "automaticallyNotifiesObserversForKey:", key)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setKeys", objc_is_class_method=true)
|
||||
Menu_setKeys :: #force_inline proc "c" (keys: ^Array, dependentKey: ^String) {
|
||||
msgSend(nil, Menu, "setKeys:triggerChangeNotificationsForDependentKey:", keys, dependentKey)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="classFallbacksForKeyedArchiver", objc_is_class_method=true)
|
||||
Menu_classFallbacksForKeyedArchiver :: #force_inline proc "c" () -> ^Array {
|
||||
return msgSend(^Array, Menu, "classFallbacksForKeyedArchiver")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="classForKeyedUnarchiver", objc_is_class_method=true)
|
||||
Menu_classForKeyedUnarchiver :: #force_inline proc "c" () -> Class {
|
||||
return msgSend(Class, Menu, "classForKeyedUnarchiver")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="exposeBinding", objc_is_class_method=true)
|
||||
Menu_exposeBinding :: #force_inline proc "c" (binding: ^String) {
|
||||
msgSend(nil, Menu, "exposeBinding:", binding)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="setDefaultPlaceholder", objc_is_class_method=true)
|
||||
Menu_setDefaultPlaceholder :: #force_inline proc "c" (placeholder: id, marker: id, binding: ^String) {
|
||||
msgSend(nil, Menu, "setDefaultPlaceholder:forMarker:withBinding:", placeholder, marker, binding)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="defaultPlaceholderForMarker", objc_is_class_method=true)
|
||||
Menu_defaultPlaceholderForMarker :: #force_inline proc "c" (marker: id, binding: ^String) -> id {
|
||||
return msgSend(id, Menu, "defaultPlaceholderForMarker:withBinding:", marker, binding)
|
||||
}
|
||||
@(objc_type=Menu, objc_name="popUpContextMenu")
|
||||
Menu_popUpContextMenu :: proc {
|
||||
Menu_popUpContextMenu_withEvent_forView,
|
||||
// Menu_popUpContextMenu_withEvent_forView_withFont,
|
||||
}
|
||||
|
||||
@(objc_type=Menu, objc_name="itemArray")
|
||||
Menu_itemArray :: proc "c" (self: ^Menu) -> ^Array {
|
||||
return msgSend(^Array, self, "itemArray")
|
||||
}
|
||||
@(objc_type=Menu, objc_name="paletteMenuWithColors")
|
||||
Menu_paletteMenuWithColors :: proc {
|
||||
Menu_paletteMenuWithColors_titles_selectionHandler,
|
||||
// Menu_paletteMenuWithColors_titles_templateImage_selectionHandler,
|
||||
}
|
||||
|
||||
@(objc_type=Menu, objc_name="cancelPreviousPerformRequestsWithTarget")
|
||||
Menu_cancelPreviousPerformRequestsWithTarget :: proc {
|
||||
Menu_cancelPreviousPerformRequestsWithTarget_selector_object,
|
||||
Menu_cancelPreviousPerformRequestsWithTarget_,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@(objc_class="NSMenuDelegate")
|
||||
MenuDelegate :: struct {using _: Object, using _: ObjectProtocol}
|
||||
|
||||
@(objc_type=MenuDelegate, objc_name="menuNeedsUpdate")
|
||||
MenuDelegate_menuNeedsUpdate :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) {
|
||||
msgSend(nil, self, "menuNeedsUpdate:", menu)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="numberOfItemsInMenu")
|
||||
MenuDelegate_numberOfItemsInMenu :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) -> Integer {
|
||||
return msgSend(Integer, self, "numberOfItemsInMenu:", menu)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="menu_updateItem_atIndex_shouldCancel")
|
||||
MenuDelegate_menu_updateItem_atIndex_shouldCancel :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, item: ^MenuItem, index: Integer, shouldCancel: bool) -> bool {
|
||||
return msgSend(bool, self, "menu:updateItem:atIndex:shouldCancel:", menu, item, index, shouldCancel)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="menuHasKeyEquivalent")
|
||||
MenuDelegate_menuHasKeyEquivalent :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, event: ^Event, target: ^id, action: ^SEL) -> bool {
|
||||
return msgSend(bool, self, "menuHasKeyEquivalent:forEvent:target:action:", menu, event, target, action)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="menuWillOpen")
|
||||
MenuDelegate_menuWillOpen :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) {
|
||||
msgSend(nil, self, "menuWillOpen:", menu)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="menuDidClose")
|
||||
MenuDelegate_menuDidClose :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) {
|
||||
msgSend(nil, self, "menuDidClose:", menu)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="menu_willHighlightItem")
|
||||
MenuDelegate_menu_willHighlightItem :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, item: ^MenuItem) {
|
||||
msgSend(nil, self, "menu:willHighlightItem:", menu, item)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="confinementRectForMenu")
|
||||
MenuDelegate_confinementRectForMenu :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, screen: ^Screen) -> Rect {
|
||||
return msgSend(Rect, self, "confinementRectForMenu:onScreen:", menu, screen)
|
||||
}
|
||||
@(objc_type=MenuDelegate, objc_name="menu")
|
||||
MenuDelegate_menu :: proc {
|
||||
MenuDelegate_menu_updateItem_atIndex_shouldCancel,
|
||||
MenuDelegate_menu_willHighlightItem,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
package objc_Foundation
|
||||
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
|
||||
KeyEquivalentModifierFlag :: EventModifierFlag
|
||||
KeyEquivalentModifierMask :: EventModifierFlags
|
||||
|
||||
// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information.
|
||||
KeyEventModifierFlagDeviceIndependentFlagsMask := transmute(KeyEquivalentModifierMask)_KeyEventModifierFlagDeviceIndependentFlagsMask
|
||||
@(private) _KeyEventModifierFlagDeviceIndependentFlagsMask := UInteger(0xffff0000)
|
||||
|
||||
MenuItemCallback :: proc "c" (unused: rawptr, name: SEL, sender: ^Object)
|
||||
|
||||
@(objc_class="NSMenuItem")
|
||||
MenuItem :: struct {using _: Object}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="registerActionCallback", objc_is_class_method=true)
|
||||
MenuItem_registerActionCallback :: proc "c" (name: cstring, callback: MenuItemCallback) -> SEL {
|
||||
s := string(name)
|
||||
n := len(s)
|
||||
sel: SEL
|
||||
if n > 0 && s[n-1] != ':' {
|
||||
col_name := intrinsics.alloca(n+2, 1)
|
||||
builtin.copy(col_name[:n], s)
|
||||
col_name[n] = ':'
|
||||
col_name[n+1] = 0
|
||||
sel = sel_registerName(cstring(col_name))
|
||||
} else {
|
||||
sel = sel_registerName(name)
|
||||
}
|
||||
if callback != nil {
|
||||
class_addMethod(intrinsics.objc_find_class("NSObject"), sel, auto_cast callback, "v@:@")
|
||||
}
|
||||
return sel
|
||||
}
|
||||
|
||||
@(objc_type=MenuItem, objc_name="init")
|
||||
MenuItem_init :: proc "c" (self: ^MenuItem) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "init")
|
||||
}
|
||||
|
||||
|
||||
@(objc_type=MenuItem, objc_name="separatorItem", objc_is_class_method=true)
|
||||
MenuItem_separatorItem :: #force_inline proc "c" () -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "separatorItem")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="sectionHeaderWithTitle", objc_is_class_method=true)
|
||||
MenuItem_sectionHeaderWithTitle :: #force_inline proc "c" (title: ^String) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "sectionHeaderWithTitle:", title)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="initWithTitle")
|
||||
MenuItem_initWithTitle :: #force_inline proc "c" (self: ^MenuItem, string: ^String, selector: SEL, charCode: ^String) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "initWithTitle:action:keyEquivalent:", string, selector, charCode)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="initWithCoder")
|
||||
MenuItem_initWithCoder :: #force_inline proc "c" (self: ^MenuItem, coder: ^Coder) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "initWithCoder:", coder)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="usesUserKeyEquivalents", objc_is_class_method=true)
|
||||
MenuItem_usesUserKeyEquivalents :: #force_inline proc "c" () -> bool {
|
||||
return msgSend(bool, MenuItem, "usesUserKeyEquivalents")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setUsesUserKeyEquivalents", objc_is_class_method=true)
|
||||
MenuItem_setUsesUserKeyEquivalents :: #force_inline proc "c" (usesUserKeyEquivalents: bool) {
|
||||
msgSend(nil, MenuItem, "setUsesUserKeyEquivalents:", usesUserKeyEquivalents)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="menu")
|
||||
MenuItem_menu :: #force_inline proc "c" (self: ^MenuItem) -> ^Menu {
|
||||
return msgSend(^Menu, self, "menu")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setMenu")
|
||||
MenuItem_setMenu :: #force_inline proc "c" (self: ^MenuItem, menu: ^Menu) {
|
||||
msgSend(nil, self, "setMenu:", menu)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="hasSubmenu")
|
||||
MenuItem_hasSubmenu :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "hasSubmenu")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="submenu")
|
||||
MenuItem_submenu :: #force_inline proc "c" (self: ^MenuItem) -> ^Menu {
|
||||
return msgSend(^Menu, self, "submenu")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setSubmenu")
|
||||
MenuItem_setSubmenu :: #force_inline proc "c" (self: ^MenuItem, submenu: ^Menu) {
|
||||
msgSend(nil, self, "setSubmenu:", submenu)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="parentItem")
|
||||
MenuItem_parentItem :: #force_inline proc "c" (self: ^MenuItem) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, self, "parentItem")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="title")
|
||||
MenuItem_title :: #force_inline proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "title")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setTitle")
|
||||
MenuItem_setTitle :: #force_inline proc "c" (self: ^MenuItem, title: ^String) {
|
||||
msgSend(nil, self, "setTitle:", title)
|
||||
}
|
||||
// @(objc_type=MenuItem, objc_name="attributedTitle")
|
||||
// MenuItem_attributedTitle :: #force_inline proc "c" (self: ^MenuItem) -> ^AttributedString {
|
||||
// return msgSend(^AttributedString, self, "attributedTitle")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setAttributedTitle")
|
||||
// MenuItem_setAttributedTitle :: #force_inline proc "c" (self: ^MenuItem, attributedTitle: ^AttributedString) {
|
||||
// msgSend(nil, self, "setAttributedTitle:", attributedTitle)
|
||||
// }
|
||||
@(objc_type=MenuItem, objc_name="subtitle")
|
||||
MenuItem_subtitle :: #force_inline proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "subtitle")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setSubtitle")
|
||||
MenuItem_setSubtitle :: #force_inline proc "c" (self: ^MenuItem, subtitle: ^String) {
|
||||
msgSend(nil, self, "setSubtitle:", subtitle)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="isSeparatorItem")
|
||||
MenuItem_isSeparatorItem :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isSeparatorItem")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="isSectionHeader")
|
||||
MenuItem_isSectionHeader :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isSectionHeader")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="keyEquivalent")
|
||||
MenuItem_keyEquivalent :: #force_inline proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "keyEquivalent")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setKeyEquivalent")
|
||||
MenuItem_setKeyEquivalent :: #force_inline proc "c" (self: ^MenuItem, keyEquivalent: ^String) {
|
||||
msgSend(nil, self, "setKeyEquivalent:", keyEquivalent)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="keyEquivalentModifierMask")
|
||||
MenuItem_keyEquivalentModifierMask :: #force_inline proc "c" (self: ^MenuItem) -> EventModifierFlags {
|
||||
return msgSend(EventModifierFlags, self, "keyEquivalentModifierMask")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setKeyEquivalentModifierMask")
|
||||
MenuItem_setKeyEquivalentModifierMask :: #force_inline proc "c" (self: ^MenuItem, keyEquivalentModifierMask: EventModifierFlags) {
|
||||
msgSend(nil, self, "setKeyEquivalentModifierMask:", keyEquivalentModifierMask)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="userKeyEquivalent")
|
||||
MenuItem_userKeyEquivalent :: #force_inline proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "userKeyEquivalent")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="allowsKeyEquivalentWhenHidden")
|
||||
MenuItem_allowsKeyEquivalentWhenHidden :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "allowsKeyEquivalentWhenHidden")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setAllowsKeyEquivalentWhenHidden")
|
||||
MenuItem_setAllowsKeyEquivalentWhenHidden :: #force_inline proc "c" (self: ^MenuItem, allowsKeyEquivalentWhenHidden: bool) {
|
||||
msgSend(nil, self, "setAllowsKeyEquivalentWhenHidden:", allowsKeyEquivalentWhenHidden)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="allowsAutomaticKeyEquivalentLocalization")
|
||||
MenuItem_allowsAutomaticKeyEquivalentLocalization :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "allowsAutomaticKeyEquivalentLocalization")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setAllowsAutomaticKeyEquivalentLocalization")
|
||||
MenuItem_setAllowsAutomaticKeyEquivalentLocalization :: #force_inline proc "c" (self: ^MenuItem, allowsAutomaticKeyEquivalentLocalization: bool) {
|
||||
msgSend(nil, self, "setAllowsAutomaticKeyEquivalentLocalization:", allowsAutomaticKeyEquivalentLocalization)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="allowsAutomaticKeyEquivalentMirroring")
|
||||
MenuItem_allowsAutomaticKeyEquivalentMirroring :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "allowsAutomaticKeyEquivalentMirroring")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setAllowsAutomaticKeyEquivalentMirroring")
|
||||
MenuItem_setAllowsAutomaticKeyEquivalentMirroring :: #force_inline proc "c" (self: ^MenuItem, allowsAutomaticKeyEquivalentMirroring: bool) {
|
||||
msgSend(nil, self, "setAllowsAutomaticKeyEquivalentMirroring:", allowsAutomaticKeyEquivalentMirroring)
|
||||
}
|
||||
// @(objc_type=MenuItem, objc_name="image")
|
||||
// MenuItem_image :: #force_inline proc "c" (self: ^MenuItem) -> ^Image {
|
||||
// return msgSend(^Image, self, "image")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setImage")
|
||||
// MenuItem_setImage :: #force_inline proc "c" (self: ^MenuItem, image: ^Image) {
|
||||
// msgSend(nil, self, "setImage:", image)
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="state")
|
||||
// MenuItem_state :: #force_inline proc "c" (self: ^MenuItem) -> ControlStateValue {
|
||||
// return msgSend(ControlStateValue, self, "state")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setState")
|
||||
// MenuItem_setState :: #force_inline proc "c" (self: ^MenuItem, state: ControlStateValue) {
|
||||
// msgSend(nil, self, "setState:", state)
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="onStateImage")
|
||||
// MenuItem_onStateImage :: #force_inline proc "c" (self: ^MenuItem) -> ^Image {
|
||||
// return msgSend(^Image, self, "onStateImage")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setOnStateImage")
|
||||
// MenuItem_setOnStateImage :: #force_inline proc "c" (self: ^MenuItem, onStateImage: ^Image) {
|
||||
// msgSend(nil, self, "setOnStateImage:", onStateImage)
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="offStateImage")
|
||||
// MenuItem_offStateImage :: #force_inline proc "c" (self: ^MenuItem) -> ^Image {
|
||||
// return msgSend(^Image, self, "offStateImage")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setOffStateImage")
|
||||
// MenuItem_setOffStateImage :: #force_inline proc "c" (self: ^MenuItem, offStateImage: ^Image) {
|
||||
// msgSend(nil, self, "setOffStateImage:", offStateImage)
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="mixedStateImage")
|
||||
// MenuItem_mixedStateImage :: #force_inline proc "c" (self: ^MenuItem) -> ^Image {
|
||||
// return msgSend(^Image, self, "mixedStateImage")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setMixedStateImage")
|
||||
// MenuItem_setMixedStateImage :: #force_inline proc "c" (self: ^MenuItem, mixedStateImage: ^Image) {
|
||||
// msgSend(nil, self, "setMixedStateImage:", mixedStateImage)
|
||||
// }
|
||||
@(objc_type=MenuItem, objc_name="isEnabled")
|
||||
MenuItem_isEnabled :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isEnabled")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setEnabled")
|
||||
MenuItem_setEnabled :: #force_inline proc "c" (self: ^MenuItem, enabled: bool) {
|
||||
msgSend(nil, self, "setEnabled:", enabled)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="isAlternate")
|
||||
MenuItem_isAlternate :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isAlternate")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setAlternate")
|
||||
MenuItem_setAlternate :: #force_inline proc "c" (self: ^MenuItem, alternate: bool) {
|
||||
msgSend(nil, self, "setAlternate:", alternate)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="indentationLevel")
|
||||
MenuItem_indentationLevel :: #force_inline proc "c" (self: ^MenuItem) -> Integer {
|
||||
return msgSend(Integer, self, "indentationLevel")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setIndentationLevel")
|
||||
MenuItem_setIndentationLevel :: #force_inline proc "c" (self: ^MenuItem, indentationLevel: Integer) {
|
||||
msgSend(nil, self, "setIndentationLevel:", indentationLevel)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="target")
|
||||
MenuItem_target :: #force_inline proc "c" (self: ^MenuItem) -> id {
|
||||
return msgSend(id, self, "target")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setTarget")
|
||||
MenuItem_setTarget :: #force_inline proc "c" (self: ^MenuItem, target: id) {
|
||||
msgSend(nil, self, "setTarget:", target)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="action")
|
||||
MenuItem_action :: #force_inline proc "c" (self: ^MenuItem) -> SEL {
|
||||
return msgSend(SEL, self, "action")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setAction")
|
||||
MenuItem_setAction :: #force_inline proc "c" (self: ^MenuItem, action: SEL) {
|
||||
msgSend(nil, self, "setAction:", action)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="tag")
|
||||
MenuItem_tag :: #force_inline proc "c" (self: ^MenuItem) -> Integer {
|
||||
return msgSend(Integer, self, "tag")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setTag")
|
||||
MenuItem_setTag :: #force_inline proc "c" (self: ^MenuItem, tag: Integer) {
|
||||
msgSend(nil, self, "setTag:", tag)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="representedObject")
|
||||
MenuItem_representedObject :: #force_inline proc "c" (self: ^MenuItem) -> id {
|
||||
return msgSend(id, self, "representedObject")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setRepresentedObject")
|
||||
MenuItem_setRepresentedObject :: #force_inline proc "c" (self: ^MenuItem, representedObject: id) {
|
||||
msgSend(nil, self, "setRepresentedObject:", representedObject)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="view")
|
||||
MenuItem_view :: #force_inline proc "c" (self: ^MenuItem) -> ^View {
|
||||
return msgSend(^View, self, "view")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setView")
|
||||
MenuItem_setView :: #force_inline proc "c" (self: ^MenuItem, view: ^View) {
|
||||
msgSend(nil, self, "setView:", view)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="isHighlighted")
|
||||
MenuItem_isHighlighted :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isHighlighted")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="isHidden")
|
||||
MenuItem_isHidden :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isHidden")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setHidden")
|
||||
MenuItem_setHidden :: #force_inline proc "c" (self: ^MenuItem, hidden: bool) {
|
||||
msgSend(nil, self, "setHidden:", hidden)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="isHiddenOrHasHiddenAncestor")
|
||||
MenuItem_isHiddenOrHasHiddenAncestor :: #force_inline proc "c" (self: ^MenuItem) -> bool {
|
||||
return msgSend(bool, self, "isHiddenOrHasHiddenAncestor")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="toolTip")
|
||||
MenuItem_toolTip :: #force_inline proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "toolTip")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setToolTip")
|
||||
MenuItem_setToolTip :: #force_inline proc "c" (self: ^MenuItem, toolTip: ^String) {
|
||||
msgSend(nil, self, "setToolTip:", toolTip)
|
||||
}
|
||||
// @(objc_type=MenuItem, objc_name="badge")
|
||||
// MenuItem_badge :: #force_inline proc "c" (self: ^MenuItem) -> ^MenuItemBadge {
|
||||
// return msgSend(^MenuItemBadge, self, "badge")
|
||||
// }
|
||||
// @(objc_type=MenuItem, objc_name="setBadge")
|
||||
// MenuItem_setBadge :: #force_inline proc "c" (self: ^MenuItem, badge: ^MenuItemBadge) {
|
||||
// msgSend(nil, self, "setBadge:", badge)
|
||||
// }
|
||||
@(objc_type=MenuItem, objc_name="setMnemonicLocation")
|
||||
MenuItem_setMnemonicLocation :: #force_inline proc "c" (self: ^MenuItem, location: UInteger) {
|
||||
msgSend(nil, self, "setMnemonicLocation:", location)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="mnemonicLocation")
|
||||
MenuItem_mnemonicLocation :: #force_inline proc "c" (self: ^MenuItem) -> UInteger {
|
||||
return msgSend(UInteger, self, "mnemonicLocation")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="mnemonic")
|
||||
MenuItem_mnemonic :: #force_inline proc "c" (self: ^MenuItem) -> ^String {
|
||||
return msgSend(^String, self, "mnemonic")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setTitleWithMnemonic")
|
||||
MenuItem_setTitleWithMnemonic :: #force_inline proc "c" (self: ^MenuItem, stringWithAmpersand: ^String) {
|
||||
msgSend(nil, self, "setTitleWithMnemonic:", stringWithAmpersand)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="load", objc_is_class_method=true)
|
||||
MenuItem_load :: #force_inline proc "c" () {
|
||||
msgSend(nil, MenuItem, "load")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="initialize", objc_is_class_method=true)
|
||||
MenuItem_initialize :: #force_inline proc "c" () {
|
||||
msgSend(nil, MenuItem, "initialize")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="new", objc_is_class_method=true)
|
||||
MenuItem_new :: #force_inline proc "c" () -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "new")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="allocWithZone", objc_is_class_method=true)
|
||||
MenuItem_allocWithZone :: #force_inline proc "c" (zone: ^Zone) -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "allocWithZone:", zone)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="alloc", objc_is_class_method=true)
|
||||
MenuItem_alloc :: #force_inline proc "c" () -> ^MenuItem {
|
||||
return msgSend(^MenuItem, MenuItem, "alloc")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="copyWithZone", objc_is_class_method=true)
|
||||
MenuItem_copyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id {
|
||||
return msgSend(id, MenuItem, "copyWithZone:", zone)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="mutableCopyWithZone", objc_is_class_method=true)
|
||||
MenuItem_mutableCopyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id {
|
||||
return msgSend(id, MenuItem, "mutableCopyWithZone:", zone)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="instancesRespondToSelector", objc_is_class_method=true)
|
||||
MenuItem_instancesRespondToSelector :: #force_inline proc "c" (aSelector: SEL) -> bool {
|
||||
return msgSend(bool, MenuItem, "instancesRespondToSelector:", aSelector)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="conformsToProtocol", objc_is_class_method=true)
|
||||
MenuItem_conformsToProtocol :: #force_inline proc "c" (protocol: ^Protocol) -> bool {
|
||||
return msgSend(bool, MenuItem, "conformsToProtocol:", protocol)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="instanceMethodForSelector", objc_is_class_method=true)
|
||||
MenuItem_instanceMethodForSelector :: #force_inline proc "c" (aSelector: SEL) -> IMP {
|
||||
return msgSend(IMP, MenuItem, "instanceMethodForSelector:", aSelector)
|
||||
}
|
||||
// @(objc_type=MenuItem, objc_name="instanceMethodSignatureForSelector", objc_is_class_method=true)
|
||||
// MenuItem_instanceMethodSignatureForSelector :: #force_inline proc "c" (aSelector: SEL) -> ^MethodSignature {
|
||||
// return msgSend(^MethodSignature, MenuItem, "instanceMethodSignatureForSelector:", aSelector)
|
||||
// }
|
||||
@(objc_type=MenuItem, objc_name="isSubclassOfClass", objc_is_class_method=true)
|
||||
MenuItem_isSubclassOfClass :: #force_inline proc "c" (aClass: Class) -> bool {
|
||||
return msgSend(bool, MenuItem, "isSubclassOfClass:", aClass)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="resolveClassMethod", objc_is_class_method=true)
|
||||
MenuItem_resolveClassMethod :: #force_inline proc "c" (sel: SEL) -> bool {
|
||||
return msgSend(bool, MenuItem, "resolveClassMethod:", sel)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="resolveInstanceMethod", objc_is_class_method=true)
|
||||
MenuItem_resolveInstanceMethod :: #force_inline proc "c" (sel: SEL) -> bool {
|
||||
return msgSend(bool, MenuItem, "resolveInstanceMethod:", sel)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="hash", objc_is_class_method=true)
|
||||
MenuItem_hash :: #force_inline proc "c" () -> UInteger {
|
||||
return msgSend(UInteger, MenuItem, "hash")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="superclass", objc_is_class_method=true)
|
||||
MenuItem_superclass :: #force_inline proc "c" () -> Class {
|
||||
return msgSend(Class, MenuItem, "superclass")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="class", objc_is_class_method=true)
|
||||
MenuItem_class :: #force_inline proc "c" () -> Class {
|
||||
return msgSend(Class, MenuItem, "class")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="description", objc_is_class_method=true)
|
||||
MenuItem_description :: #force_inline proc "c" () -> ^String {
|
||||
return msgSend(^String, MenuItem, "description")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="debugDescription", objc_is_class_method=true)
|
||||
MenuItem_debugDescription :: #force_inline proc "c" () -> ^String {
|
||||
return msgSend(^String, MenuItem, "debugDescription")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="version", objc_is_class_method=true)
|
||||
MenuItem_version :: #force_inline proc "c" () -> Integer {
|
||||
return msgSend(Integer, MenuItem, "version")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setVersion", objc_is_class_method=true)
|
||||
MenuItem_setVersion :: #force_inline proc "c" (aVersion: Integer) {
|
||||
msgSend(nil, MenuItem, "setVersion:", aVersion)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="poseAsClass", objc_is_class_method=true)
|
||||
MenuItem_poseAsClass :: #force_inline proc "c" (aClass: Class) {
|
||||
msgSend(nil, MenuItem, "poseAsClass:", aClass)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="cancelPreviousPerformRequestsWithTarget_selector_object", objc_is_class_method=true)
|
||||
MenuItem_cancelPreviousPerformRequestsWithTarget_selector_object :: #force_inline proc "c" (aTarget: id, aSelector: SEL, anArgument: id) {
|
||||
msgSend(nil, MenuItem, "cancelPreviousPerformRequestsWithTarget:selector:object:", aTarget, aSelector, anArgument)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="cancelPreviousPerformRequestsWithTarget_", objc_is_class_method=true)
|
||||
MenuItem_cancelPreviousPerformRequestsWithTarget_ :: #force_inline proc "c" (aTarget: id) {
|
||||
msgSend(nil, MenuItem, "cancelPreviousPerformRequestsWithTarget:", aTarget)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="accessInstanceVariablesDirectly", objc_is_class_method=true)
|
||||
MenuItem_accessInstanceVariablesDirectly :: #force_inline proc "c" () -> bool {
|
||||
return msgSend(bool, MenuItem, "accessInstanceVariablesDirectly")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="useStoredAccessor", objc_is_class_method=true)
|
||||
MenuItem_useStoredAccessor :: #force_inline proc "c" () -> bool {
|
||||
return msgSend(bool, MenuItem, "useStoredAccessor")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="keyPathsForValuesAffectingValueForKey", objc_is_class_method=true)
|
||||
MenuItem_keyPathsForValuesAffectingValueForKey :: #force_inline proc "c" (key: ^String) -> ^Set {
|
||||
return msgSend(^Set, MenuItem, "keyPathsForValuesAffectingValueForKey:", key)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="automaticallyNotifiesObserversForKey", objc_is_class_method=true)
|
||||
MenuItem_automaticallyNotifiesObserversForKey :: #force_inline proc "c" (key: ^String) -> bool {
|
||||
return msgSend(bool, MenuItem, "automaticallyNotifiesObserversForKey:", key)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setKeys", objc_is_class_method=true)
|
||||
MenuItem_setKeys :: #force_inline proc "c" (keys: ^Array, dependentKey: ^String) {
|
||||
msgSend(nil, MenuItem, "setKeys:triggerChangeNotificationsForDependentKey:", keys, dependentKey)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="classFallbacksForKeyedArchiver", objc_is_class_method=true)
|
||||
MenuItem_classFallbacksForKeyedArchiver :: #force_inline proc "c" () -> ^Array {
|
||||
return msgSend(^Array, MenuItem, "classFallbacksForKeyedArchiver")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="classForKeyedUnarchiver", objc_is_class_method=true)
|
||||
MenuItem_classForKeyedUnarchiver :: #force_inline proc "c" () -> Class {
|
||||
return msgSend(Class, MenuItem, "classForKeyedUnarchiver")
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="exposeBinding", objc_is_class_method=true)
|
||||
MenuItem_exposeBinding :: #force_inline proc "c" (binding: ^String) {
|
||||
msgSend(nil, MenuItem, "exposeBinding:", binding)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="setDefaultPlaceholder", objc_is_class_method=true)
|
||||
MenuItem_setDefaultPlaceholder :: #force_inline proc "c" (placeholder: id, marker: id, binding: ^String) {
|
||||
msgSend(nil, MenuItem, "setDefaultPlaceholder:forMarker:withBinding:", placeholder, marker, binding)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="defaultPlaceholderForMarker", objc_is_class_method=true)
|
||||
MenuItem_defaultPlaceholderForMarker :: #force_inline proc "c" (marker: id, binding: ^String) -> id {
|
||||
return msgSend(id, MenuItem, "defaultPlaceholderForMarker:withBinding:", marker, binding)
|
||||
}
|
||||
@(objc_type=MenuItem, objc_name="cancelPreviousPerformRequestsWithTarget")
|
||||
MenuItem_cancelPreviousPerformRequestsWithTarget :: proc {
|
||||
MenuItem_cancelPreviousPerformRequestsWithTarget_selector_object,
|
||||
MenuItem_cancelPreviousPerformRequestsWithTarget_,
|
||||
}
|
||||
@@ -146,7 +146,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
return nil
|
||||
}
|
||||
if template.windowWillPositionSheetUsingRect != nil {
|
||||
windowWillPositionSheetUsingRect :: proc "c" (self: id, window: ^Window, sheet: ^Window, rect: Rect) -> Rect {
|
||||
windowWillPositionSheetUsingRect :: proc "c" (self: id, cmd: SEL, window: ^Window, sheet: ^Window, rect: Rect) -> Rect {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillPositionSheetUsingRect(window, sheet, rect)
|
||||
@@ -154,7 +154,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:willPositionSheet:usingRect:"), auto_cast windowWillPositionSheetUsingRect, _RECT_ENCODING+"@:@@"+_RECT_ENCODING)
|
||||
}
|
||||
if template.windowWillBeginSheet != nil {
|
||||
windowWillBeginSheet :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillBeginSheet :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillBeginSheet(notification)
|
||||
@@ -162,7 +162,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillBeginSheet:"), auto_cast windowWillBeginSheet, "v@:@")
|
||||
}
|
||||
if template.windowDidEndSheet != nil {
|
||||
windowDidEndSheet :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidEndSheet :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidEndSheet(notification)
|
||||
@@ -170,7 +170,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidEndSheet:"), auto_cast windowDidEndSheet, "v@:@")
|
||||
}
|
||||
if template.windowWillResizeToSize != nil {
|
||||
windowWillResizeToSize :: proc "c" (self: id, sender: ^Window, frameSize: Size) -> Size {
|
||||
windowWillResizeToSize :: proc "c" (self: id, cmd: SEL, sender: ^Window, frameSize: Size) -> Size {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillResizeToSize(sender, frameSize)
|
||||
@@ -178,7 +178,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillResize:toSize:"), auto_cast windowWillResizeToSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING)
|
||||
}
|
||||
if template.windowDidResize != nil {
|
||||
windowDidResize :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidResize(notification)
|
||||
@@ -186,7 +186,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidResize:"), auto_cast windowDidResize, "v@:@")
|
||||
}
|
||||
if template.windowWillStartLiveResize != nil {
|
||||
windowWillStartLiveResize :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillStartLiveResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillStartLiveResize(notification)
|
||||
@@ -194,7 +194,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillStartLiveResize:"), auto_cast windowWillStartLiveResize, "v@:@")
|
||||
}
|
||||
if template.windowDidEndLiveResize != nil {
|
||||
windowDidEndLiveResize :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidEndLiveResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidEndLiveResize(notification)
|
||||
@@ -202,7 +202,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidEndLiveResize:"), auto_cast windowDidEndLiveResize, "v@:@")
|
||||
}
|
||||
if template.windowWillMiniaturize != nil {
|
||||
windowWillMiniaturize :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillMiniaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillMiniaturize(notification)
|
||||
@@ -210,7 +210,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillMiniaturize:"), auto_cast windowWillMiniaturize, "v@:@")
|
||||
}
|
||||
if template.windowDidMiniaturize != nil {
|
||||
windowDidMiniaturize :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidMiniaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidMiniaturize(notification)
|
||||
@@ -218,7 +218,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidMiniaturize:"), auto_cast windowDidMiniaturize, "v@:@")
|
||||
}
|
||||
if template.windowDidDeminiaturize != nil {
|
||||
windowDidDeminiaturize :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidDeminiaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidDeminiaturize(notification)
|
||||
@@ -226,7 +226,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidDeminiaturize:"), auto_cast windowDidDeminiaturize, "v@:@")
|
||||
}
|
||||
if template.windowWillUseStandardFrameDefaultFrame != nil {
|
||||
windowWillUseStandardFrameDefaultFrame :: proc(self: id, window: ^Window, newFrame: Rect) -> Rect {
|
||||
windowWillUseStandardFrameDefaultFrame :: proc(self: id, cmd: SEL, window: ^Window, newFrame: Rect) -> Rect {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillUseStandardFrameDefaultFrame(window, newFrame)
|
||||
@@ -234,7 +234,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillUseStandardFrame:defaultFrame:"), auto_cast windowWillUseStandardFrameDefaultFrame, _RECT_ENCODING+"@:@"+_RECT_ENCODING)
|
||||
}
|
||||
if template.windowShouldZoomToFrame != nil {
|
||||
windowShouldZoomToFrame :: proc "c" (self: id, window: ^Window, newFrame: Rect) -> BOOL {
|
||||
windowShouldZoomToFrame :: proc "c" (self: id, cmd: SEL, window: ^Window, newFrame: Rect) -> BOOL {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowShouldZoomToFrame(window, newFrame)
|
||||
@@ -242,7 +242,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowShouldZoom:toFrame:"), auto_cast windowShouldZoomToFrame, "B@:@"+_RECT_ENCODING)
|
||||
}
|
||||
if template.windowWillUseFullScreenContentSize != nil {
|
||||
windowWillUseFullScreenContentSize :: proc "c" (self: id, window: ^Window, proposedSize: Size) -> Size {
|
||||
windowWillUseFullScreenContentSize :: proc "c" (self: id, cmd: SEL, window: ^Window, proposedSize: Size) -> Size {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillUseFullScreenContentSize(window, proposedSize)
|
||||
@@ -250,7 +250,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:willUseFullScreenContentSize:"), auto_cast windowWillUseFullScreenContentSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING)
|
||||
}
|
||||
if template.windowWillUseFullScreenPresentationOptions != nil {
|
||||
windowWillUseFullScreenPresentationOptions :: proc(self: id, window: ^Window, proposedOptions: ApplicationPresentationOptions) -> ApplicationPresentationOptions {
|
||||
windowWillUseFullScreenPresentationOptions :: proc(self: id, cmd: SEL, window: ^Window, proposedOptions: ApplicationPresentationOptions) -> ApplicationPresentationOptions {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillUseFullScreenPresentationOptions(window, proposedOptions)
|
||||
@@ -258,7 +258,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:willUseFullScreenPresentationOptions:"), auto_cast windowWillUseFullScreenPresentationOptions, _UINTEGER_ENCODING+"@:@"+_UINTEGER_ENCODING)
|
||||
}
|
||||
if template.windowWillEnterFullScreen != nil {
|
||||
windowWillEnterFullScreen :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillEnterFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillEnterFullScreen(notification)
|
||||
@@ -266,7 +266,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillEnterFullScreen:"), auto_cast windowWillEnterFullScreen, "v@:@")
|
||||
}
|
||||
if template.windowDidEnterFullScreen != nil {
|
||||
windowDidEnterFullScreen :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidEnterFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidEnterFullScreen(notification)
|
||||
@@ -274,7 +274,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidEnterFullScreen:"), auto_cast windowDidEnterFullScreen, "v@:@")
|
||||
}
|
||||
if template.windowWillExitFullScreen != nil {
|
||||
windowWillExitFullScreen :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillExitFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillExitFullScreen(notification)
|
||||
@@ -282,7 +282,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillExitFullScreen:"), auto_cast windowWillExitFullScreen, "v@:@")
|
||||
}
|
||||
if template.windowDidExitFullScreen != nil {
|
||||
windowDidExitFullScreen :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidExitFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidExitFullScreen(notification)
|
||||
@@ -290,7 +290,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidExitFullScreen:"), auto_cast windowDidExitFullScreen, "v@:@")
|
||||
}
|
||||
if template.customWindowsToEnterFullScreenForWindow != nil {
|
||||
customWindowsToEnterFullScreenForWindow :: proc "c" (self: id, window: ^Window) -> ^Array {
|
||||
customWindowsToEnterFullScreenForWindow :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^Array {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.customWindowsToEnterFullScreenForWindow(window)
|
||||
@@ -298,7 +298,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("customWindowsToEnterFullScreenForWindow:"), auto_cast customWindowsToEnterFullScreenForWindow, "@@:@")
|
||||
}
|
||||
if template.customWindowsToEnterFullScreenForWindowOnScreen != nil {
|
||||
customWindowsToEnterFullScreenForWindowOnScreen :: proc(self: id, window: ^Window, screen: ^Screen) -> ^Array {
|
||||
customWindowsToEnterFullScreenForWindowOnScreen :: proc(self: id, cmd: SEL, window: ^Window, screen: ^Screen) -> ^Array {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.customWindowsToEnterFullScreenForWindowOnScreen(window, screen)
|
||||
@@ -306,7 +306,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("customWindowsToEnterFullScreenForWindow:onScreen:"), auto_cast customWindowsToEnterFullScreenForWindowOnScreen, "@@:@@")
|
||||
}
|
||||
if template.windowStartCustomAnimationToEnterFullScreenWithDuration != nil {
|
||||
windowStartCustomAnimationToEnterFullScreenWithDuration :: proc "c" (self: id, window: ^Window, duration: TimeInterval) {
|
||||
windowStartCustomAnimationToEnterFullScreenWithDuration :: proc "c" (self: id, cmd: SEL, window: ^Window, duration: TimeInterval) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowStartCustomAnimationToEnterFullScreenWithDuration(window, duration)
|
||||
@@ -314,7 +314,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToEnterFullScreenWithDuration:"), auto_cast windowStartCustomAnimationToEnterFullScreenWithDuration, "v@:@@")
|
||||
}
|
||||
if template.windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration != nil {
|
||||
windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration :: proc(self: id, window: ^Window, screen: ^Screen, duration: TimeInterval) {
|
||||
windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration :: proc(self: id, cmd: SEL, window: ^Window, screen: ^Screen, duration: TimeInterval) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration(window, screen, duration)
|
||||
@@ -322,7 +322,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToEnterFullScreenOnScreen:withDuration:"), auto_cast windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration, "v@:@@d")
|
||||
}
|
||||
if template.windowDidFailToEnterFullScreen != nil {
|
||||
windowDidFailToEnterFullScreen :: proc "c" (self: id, window: ^Window) {
|
||||
windowDidFailToEnterFullScreen :: proc "c" (self: id, cmd: SEL, window: ^Window) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidFailToEnterFullScreen(window)
|
||||
@@ -330,7 +330,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidFailToEnterFullScreen:"), auto_cast windowDidFailToEnterFullScreen, "v@:@")
|
||||
}
|
||||
if template.customWindowsToExitFullScreenForWindow != nil {
|
||||
customWindowsToExitFullScreenForWindow :: proc "c" (self: id, window: ^Window) -> ^Array {
|
||||
customWindowsToExitFullScreenForWindow :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^Array {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.customWindowsToExitFullScreenForWindow(window)
|
||||
@@ -338,7 +338,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("customWindowsToExitFullScreenForWindow:"), auto_cast customWindowsToExitFullScreenForWindow, "@@:@")
|
||||
}
|
||||
if template.windowStartCustomAnimationToExitFullScreenWithDuration != nil {
|
||||
windowStartCustomAnimationToExitFullScreenWithDuration :: proc "c" (self: id, window: ^Window, duration: TimeInterval) {
|
||||
windowStartCustomAnimationToExitFullScreenWithDuration :: proc "c" (self: id, cmd: SEL, window: ^Window, duration: TimeInterval) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowStartCustomAnimationToExitFullScreenWithDuration(window, duration)
|
||||
@@ -346,7 +346,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToExitFullScreenWithDuration:"), auto_cast windowStartCustomAnimationToExitFullScreenWithDuration, "v@:@d")
|
||||
}
|
||||
if template.windowDidFailToExitFullScreen != nil {
|
||||
windowDidFailToExitFullScreen :: proc "c" (self: id, window: ^Window) {
|
||||
windowDidFailToExitFullScreen :: proc "c" (self: id, cmd: SEL, window: ^Window) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidFailToExitFullScreen(window)
|
||||
@@ -354,7 +354,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidFailToExitFullScreen:"), auto_cast windowDidFailToExitFullScreen, "v@:@")
|
||||
}
|
||||
if template.windowWillMove != nil {
|
||||
windowWillMove :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillMove :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillMove(notification)
|
||||
@@ -362,7 +362,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillMove:"), auto_cast windowWillMove, "v@:@")
|
||||
}
|
||||
if template.windowDidMove != nil {
|
||||
windowDidMove :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidMove :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidMove(notification)
|
||||
@@ -370,7 +370,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidMove:"), auto_cast windowDidMove, "v@:@")
|
||||
}
|
||||
if template.windowDidChangeScreen != nil {
|
||||
windowDidChangeScreen :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidChangeScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidChangeScreen(notification)
|
||||
@@ -378,7 +378,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeScreen:"), auto_cast windowDidChangeScreen, "v@:@")
|
||||
}
|
||||
if template.windowDidChangeScreenProfile != nil {
|
||||
windowDidChangeScreenProfile :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidChangeScreenProfile :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidChangeScreenProfile(notification)
|
||||
@@ -386,7 +386,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeScreenProfile:"), auto_cast windowDidChangeScreenProfile, "v@:@")
|
||||
}
|
||||
if template.windowDidChangeBackingProperties != nil {
|
||||
windowDidChangeBackingProperties :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidChangeBackingProperties :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidChangeBackingProperties(notification)
|
||||
@@ -394,7 +394,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeBackingProperties:"), auto_cast windowDidChangeBackingProperties, "v@:@")
|
||||
}
|
||||
if template.windowShouldClose != nil {
|
||||
windowShouldClose :: proc "c" (self:id, sender: ^Window) -> BOOL {
|
||||
windowShouldClose :: proc "c" (self:id, cmd: SEL, sender: ^Window) -> BOOL {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowShouldClose(sender)
|
||||
@@ -402,7 +402,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowShouldClose:"), auto_cast windowShouldClose, "B@:@")
|
||||
}
|
||||
if template.windowWillClose != nil {
|
||||
windowWillClose :: proc "c" (self:id, notification: ^Notification) {
|
||||
windowWillClose :: proc "c" (self:id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillClose(notification)
|
||||
@@ -410,7 +410,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillClose:"), auto_cast windowWillClose, "v@:@")
|
||||
}
|
||||
if template.windowDidBecomeKey != nil {
|
||||
windowDidBecomeKey :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidBecomeKey :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidBecomeKey(notification)
|
||||
@@ -418,7 +418,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidBecomeKey:"), auto_cast windowDidBecomeKey, "v@:@")
|
||||
}
|
||||
if template.windowDidResignKey != nil {
|
||||
windowDidResignKey :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidResignKey :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidResignKey(notification)
|
||||
@@ -426,7 +426,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidResignKey:"), auto_cast windowDidResignKey, "v@:@")
|
||||
}
|
||||
if template.windowDidBecomeMain != nil {
|
||||
windowDidBecomeMain :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidBecomeMain :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidBecomeMain(notification)
|
||||
@@ -434,7 +434,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidBecomeMain:"), auto_cast windowDidBecomeMain, "v@:@")
|
||||
}
|
||||
if template.windowDidResignMain != nil {
|
||||
windowDidResignMain :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidResignMain :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidResignMain(notification)
|
||||
@@ -442,7 +442,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidResignMain:"), auto_cast windowDidResignMain, "v@:@")
|
||||
}
|
||||
if template.windowWillReturnFieldEditorToObject != nil {
|
||||
windowWillReturnFieldEditorToObject :: proc "c" (self:id, sender: ^Window, client: id) -> id {
|
||||
windowWillReturnFieldEditorToObject :: proc "c" (self:id, cmd: SEL, sender: ^Window, client: id) -> id {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillReturnFieldEditorToObject(sender, client)
|
||||
@@ -450,7 +450,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillReturnFieldEditor:toObject:"), auto_cast windowWillReturnFieldEditorToObject, "@@:@@")
|
||||
}
|
||||
if template.windowDidUpdate != nil {
|
||||
windowDidUpdate :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidUpdate(notification)
|
||||
@@ -458,7 +458,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidUpdate:"), auto_cast windowDidUpdate, "v@:@")
|
||||
}
|
||||
if template.windowDidExpose != nil {
|
||||
windowDidExpose :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidExpose :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidExpose(notification)
|
||||
@@ -466,7 +466,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidExpose:"), auto_cast windowDidExpose, "v@:@")
|
||||
}
|
||||
if template.windowDidChangeOcclusionState != nil {
|
||||
windowDidChangeOcclusionState :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidChangeOcclusionState :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidChangeOcclusionState(notification)
|
||||
@@ -474,7 +474,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeOcclusionState:"), auto_cast windowDidChangeOcclusionState, "v@:@")
|
||||
}
|
||||
if template.windowShouldDragDocumentWithEventFromWithPasteboard != nil {
|
||||
windowShouldDragDocumentWithEventFromWithPasteboard :: proc "c" (self: id, window: ^Window, event: ^Event, dragImageLocation: Point, pasteboard: ^Pasteboard) -> BOOL {
|
||||
windowShouldDragDocumentWithEventFromWithPasteboard :: proc "c" (self: id, cmd: SEL, window: ^Window, event: ^Event, dragImageLocation: Point, pasteboard: ^Pasteboard) -> BOOL {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowShouldDragDocumentWithEventFromWithPasteboard(window, event, dragImageLocation, pasteboard)
|
||||
@@ -482,7 +482,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:shouldDragDocumentWithEvent:from:withPasteboard:"), auto_cast windowShouldDragDocumentWithEventFromWithPasteboard, "B@:@@"+_POINT_ENCODING+"@")
|
||||
}
|
||||
if template.windowWillReturnUndoManager != nil {
|
||||
windowWillReturnUndoManager :: proc "c" (self: id, window: ^Window) -> ^UndoManager {
|
||||
windowWillReturnUndoManager :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^UndoManager {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillReturnUndoManager(window)
|
||||
@@ -490,7 +490,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillReturnUndoManager:"), auto_cast windowWillReturnUndoManager, "@@:@")
|
||||
}
|
||||
if template.windowShouldPopUpDocumentPathMenu != nil {
|
||||
windowShouldPopUpDocumentPathMenu :: proc "c" (self: id, window: ^Window, menu: ^Menu) -> BOOL {
|
||||
windowShouldPopUpDocumentPathMenu :: proc "c" (self: id, cmd: SEL, window: ^Window, menu: ^Menu) -> BOOL {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowShouldPopUpDocumentPathMenu(window, menu)
|
||||
@@ -498,7 +498,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:shouldPopUpDocumentPathMenu:"), auto_cast windowShouldPopUpDocumentPathMenu, "B@:@@")
|
||||
}
|
||||
if template.windowWillEncodeRestorableState != nil {
|
||||
windowWillEncodeRestorableState :: proc "c" (self: id, window: ^Window, state: ^Coder) {
|
||||
windowWillEncodeRestorableState :: proc "c" (self: id, cmd: SEL, window: ^Window, state: ^Coder) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillEncodeRestorableState(window, state)
|
||||
@@ -506,7 +506,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:willEncodeRestorableState:"), auto_cast windowWillEncodeRestorableState, "v@:@@")
|
||||
}
|
||||
if template.windowDidEncodeRestorableState != nil {
|
||||
windowDidEncodeRestorableState :: proc "c" (self: id, window: ^Window, state: ^Coder) {
|
||||
windowDidEncodeRestorableState :: proc "c" (self: id, cmd: SEL, window: ^Window, state: ^Coder) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidEncodeRestorableState(window, state)
|
||||
@@ -514,7 +514,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:didDecodeRestorableState:"), auto_cast windowDidEncodeRestorableState, "v@:@@")
|
||||
}
|
||||
if template.windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize != nil {
|
||||
windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize :: proc "c" (self: id, window: ^Window, maxPreferredFrameSize: Size, maxAllowedFrameSize: Size) -> Size {
|
||||
windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize :: proc "c" (self: id, cmd: SEL, window: ^Window, maxPreferredFrameSize: Size, maxAllowedFrameSize: Size) -> Size {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
return del.windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize(window, maxPreferredFrameSize, maxPreferredFrameSize)
|
||||
@@ -522,7 +522,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("window:willResizeForVersionBrowserWithMaxPreferredSize:maxAllowedSize:"), auto_cast windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING+_SIZE_ENCODING)
|
||||
}
|
||||
if template.windowWillEnterVersionBrowser != nil {
|
||||
windowWillEnterVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillEnterVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillEnterVersionBrowser(notification)
|
||||
@@ -530,7 +530,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillEnterVersionBrowser:"), auto_cast windowWillEnterVersionBrowser, "v@:@")
|
||||
}
|
||||
if template.windowDidEnterVersionBrowser != nil {
|
||||
windowDidEnterVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidEnterVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidEnterVersionBrowser(notification)
|
||||
@@ -538,7 +538,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowDidEnterVersionBrowser:"), auto_cast windowDidEnterVersionBrowser, "v@:@")
|
||||
}
|
||||
if template.windowWillExitVersionBrowser != nil {
|
||||
windowWillExitVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowWillExitVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowWillExitVersionBrowser(notification)
|
||||
@@ -546,7 +546,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
|
||||
class_addMethod(class, intrinsics.objc_find_selector("windowWillExitVersionBrowser:"), auto_cast windowWillExitVersionBrowser, "v@:@")
|
||||
}
|
||||
if template.windowDidExitVersionBrowser != nil {
|
||||
windowDidExitVersionBrowser :: proc "c" (self: id, notification: ^Notification) {
|
||||
windowDidExitVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) {
|
||||
del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self)
|
||||
context = del._context
|
||||
del.windowDidExitVersionBrowser(notification)
|
||||
@@ -780,4 +780,4 @@ Window_performWindowDragWithEvent :: proc "c" (self: ^Window, event: ^Event) {
|
||||
@(objc_type=Window, objc_name="setToolbar")
|
||||
Window_setToolbar :: proc "c" (self: ^Window, toolbar: ^Toolbar) {
|
||||
msgSend(nil, self, "setToolbar:", toolbar)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package objc_Foundation
|
||||
|
||||
import "base:runtime"
|
||||
import "base:intrinsics"
|
||||
|
||||
Subclasser_Proc :: proc(cls: Class, vtable: rawptr)
|
||||
|
||||
Object_VTable_Info :: struct {
|
||||
vtable: rawptr,
|
||||
size: uint,
|
||||
impl: Subclasser_Proc,
|
||||
}
|
||||
|
||||
Class_VTable_Info :: struct {
|
||||
_context: runtime.Context,
|
||||
super_vtable: rawptr,
|
||||
protocol_vtable: rawptr,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
class_get_metaclass :: #force_inline proc "contextless" (cls: Class) -> Class {
|
||||
return (^Class)(cls)^
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
object_get_vtable_info :: proc "contextless" (obj: id) -> ^Class_VTable_Info {
|
||||
return (^Class_VTable_Info)(object_getIndexedIvars(obj))
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
make_subclasser :: #force_inline proc(vtable: ^$T, impl: proc(cls: Class, vt: ^T)) -> Object_VTable_Info {
|
||||
return Object_VTable_Info{
|
||||
vtable = vtable,
|
||||
size = size_of(T),
|
||||
impl = (Subclasser_Proc)(impl),
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
register_subclass :: proc(
|
||||
class_name: cstring,
|
||||
superclass: Class,
|
||||
superclass_overrides: Maybe(Object_VTable_Info) = nil,
|
||||
protocol: Maybe(Object_VTable_Info) = nil,
|
||||
_context: Maybe(runtime.Context) = nil,
|
||||
) -> Class {
|
||||
assert(superclass != nil)
|
||||
|
||||
super_size: uint
|
||||
proto_size: uint
|
||||
|
||||
if superclass_overrides != nil {
|
||||
// Align to 8-byte boundary
|
||||
super_size = (superclass_overrides.?.size + 7)/8 * 8
|
||||
}
|
||||
|
||||
if protocol != nil {
|
||||
// Align to 8-byte boundary
|
||||
proto_size = (protocol.?.size + 7)/8 * 8
|
||||
}
|
||||
|
||||
cls := objc_lookUpClass(class_name)
|
||||
if cls != nil {
|
||||
return cls
|
||||
}
|
||||
|
||||
extra_size := uint(size_of(Class_VTable_Info)) + 8 + super_size + proto_size
|
||||
|
||||
cls = objc_allocateClassPair(superclass, class_name, extra_size)
|
||||
assert(cls != nil)
|
||||
|
||||
if s, ok := superclass_overrides.?; ok {
|
||||
s.impl(cls, s.vtable)
|
||||
}
|
||||
|
||||
if p, ok := protocol.?; ok {
|
||||
p.impl(cls, p.vtable)
|
||||
}
|
||||
|
||||
objc_registerClassPair(cls)
|
||||
meta_cls := class_get_metaclass(cls)
|
||||
meta_size := uint(class_getInstanceSize(meta_cls))
|
||||
|
||||
// Offsets are always aligned to 8-byte boundary
|
||||
info_offset := (meta_size + 7) / 8 * 8
|
||||
super_vtable_offset := (info_offset + size_of(Class_VTable_Info) + 7) / 8 * 8
|
||||
ptoto_vtable_offset := super_vtable_offset + super_size
|
||||
|
||||
|
||||
p_info := (^Class_VTable_Info)(([^]u8)(cls)[info_offset:])
|
||||
p_super_vtable := ([^]u8)(cls)[super_vtable_offset:]
|
||||
p_proto_vtable := ([^]u8)(cls)[ptoto_vtable_offset:]
|
||||
|
||||
intrinsics.mem_zero(p_info, size_of(Class_VTable_Info))
|
||||
|
||||
// Assign the context
|
||||
p_info._context = _context.? or_else context
|
||||
|
||||
if s, ok := superclass_overrides.?; ok {
|
||||
p_info.super_vtable = p_super_vtable
|
||||
intrinsics.mem_copy(p_super_vtable, s.vtable, super_size)
|
||||
}
|
||||
if p, ok := protocol.?; ok {
|
||||
p_info.protocol_vtable = p_proto_vtable
|
||||
intrinsics.mem_copy(p_proto_vtable, p.vtable, p.size)
|
||||
}
|
||||
|
||||
return cls
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
class_get_vtable_info :: proc "contextless" (cls: Class) -> ^Class_VTable_Info {
|
||||
meta_cls := class_get_metaclass(cls)
|
||||
meta_size := uint(class_getInstanceSize(meta_cls))
|
||||
|
||||
// Align to 8-byte boundary
|
||||
info_offset := (meta_size+7) / 8 * 8
|
||||
|
||||
p_cls := ([^]u8)(cls)[info_offset:]
|
||||
ctx := (^Class_VTable_Info)(p_cls)
|
||||
return ctx
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
alloc_user_object :: proc "contextless" (cls: Class, _context: Maybe(runtime.Context) = nil) -> id {
|
||||
info := class_get_vtable_info(cls)
|
||||
|
||||
obj := class_createInstance(cls, size_of(Class_VTable_Info))
|
||||
obj_info := (^Class_VTable_Info)(object_getIndexedIvars(obj))
|
||||
obj_info^ = info^
|
||||
|
||||
if _context != nil {
|
||||
obj_info._context = _context.?
|
||||
}
|
||||
return obj
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package darwin
|
||||
|
||||
import "core:sys/posix"
|
||||
|
||||
copyfile_state_t :: distinct rawptr
|
||||
|
||||
copyfile_flags :: bit_set[enum {
|
||||
ACL,
|
||||
STAT,
|
||||
XATTR,
|
||||
DATA,
|
||||
|
||||
RECURSIVE = 15,
|
||||
|
||||
CHECK,
|
||||
EXCL,
|
||||
NOFOLLOW_SRC,
|
||||
NOFOLLOW_DST,
|
||||
MOVE,
|
||||
UNLINK,
|
||||
PACK,
|
||||
UNPACK,
|
||||
|
||||
CLONE,
|
||||
CLONE_FORCE,
|
||||
RUN_IN_PLACE,
|
||||
DATA_SPARSE,
|
||||
PRESERVE_DST_TRACKED,
|
||||
VERBOSE = 30,
|
||||
}; u32]
|
||||
|
||||
COPYFILE_SECURITY :: copyfile_flags{.STAT, .ACL}
|
||||
COPYFILE_METADATA :: COPYFILE_SECURITY + copyfile_flags{.XATTR}
|
||||
COPYFILE_ALL :: COPYFILE_METADATA + copyfile_flags{.DATA}
|
||||
|
||||
COPYFILE_NOFOLLOW :: copyfile_flags{.NOFOLLOW_SRC, .NOFOLLOW_DST}
|
||||
|
||||
copyfile_state_flag :: enum u32 {
|
||||
SRC_FD = 1,
|
||||
SRC_FILENAME,
|
||||
DST_FD,
|
||||
DST_FILENAME,
|
||||
QUARANTINE,
|
||||
STATUS_CB,
|
||||
STATUS_CTX,
|
||||
COPIED,
|
||||
XATTRNAME,
|
||||
WAS_CLONED,
|
||||
SRC_BSIZE,
|
||||
DST_BSIZE,
|
||||
BSIZE,
|
||||
FORBID_CROSS_MOUNT,
|
||||
NOCPROTECT,
|
||||
PRESERVE_SUID,
|
||||
RECURSIVE_SRC_FTSENT,
|
||||
FORBID_DST_EXISTING_SYMLINKS,
|
||||
}
|
||||
|
||||
foreign system {
|
||||
copyfile :: proc(from, to: cstring, state: copyfile_state_t, flags: copyfile_flags) -> i32 ---
|
||||
fcopyfile :: proc(from, to: posix.FD, state: copyfile_state_t, flags: copyfile_flags) -> i32 ---
|
||||
|
||||
copyfile_state_alloc :: proc() -> copyfile_state_t ---
|
||||
copyfile_state_free :: proc(state: copyfile_state_t) -> posix.result ---
|
||||
copyfile_state_get :: proc(state: copyfile_state_t, flag: copyfile_state_flag, dst: rawptr) -> posix.result ---
|
||||
copyfile_state_set :: proc(state: copyfile_state_t, flag: copyfile_state_flag, src: rawptr) -> posix.result ---
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user