Merge branch 'master' into macharena

This commit is contained in:
Colin Davidson
2025-06-08 16:17:32 -07:00
279 changed files with 18301 additions and 4272 deletions
+1 -1
View File
@@ -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
}
+2 -2
View File
@@ -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
-3
View File
@@ -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 {
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+3 -3
View File
@@ -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
+36
View File
@@ -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)
+32 -1
View File
@@ -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)
}
}
-2
View File
@@ -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)
+1 -1
View File
@@ -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) {
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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)
}
}
+14 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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,
};
*/
}
-3
View File
@@ -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
View File
@@ -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
+53 -11
View File
@@ -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
+1 -1
View File
@@ -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{}
+1 -1
View File
@@ -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]
+10 -5
View File
@@ -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)
}
+1 -1
View File
@@ -350,7 +350,7 @@ Example:
Possible Output:
6
500
13
*/
@(require_results)
+25 -5
View File
@@ -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
+31 -19
View File
@@ -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,
+1 -1
View File
@@ -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))
}
}
+51 -43
View File
@@ -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
}
}
+10 -1
View File
@@ -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
View File
@@ -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)
}
+17 -8
View File
@@ -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)
+3
View File
@@ -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
+11 -1
View File
@@ -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
View File
@@ -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)
}
+17 -17
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
}
+2 -1
View File
@@ -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)
}
+17
View File
@@ -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
}
+5 -5
View File
@@ -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] = '*'
+7 -7
View File
@@ -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
+2 -2
View File
@@ -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 {
+10 -10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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, &times) != .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
}
+28
View File
@@ -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
}
+2 -2
View File
@@ -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[:]))
+1 -1
View File
@@ -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 }
+27 -34
View File
@@ -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
}
-5
View File
@@ -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)
+4 -4
View File
@@ -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)
}
}
+29 -9
View File
@@ -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)
}
+2 -2
View File
@@ -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 {
+3 -3
View File
@@ -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
View File
@@ -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
}
-21
View File
@@ -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])
+2 -2
View File
@@ -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 {
+23 -19
View File
@@ -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())
+1 -12
View File
@@ -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 -41
View File
@@ -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
}
+9 -11
View File
@@ -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)
}
+4 -3
View File
@@ -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()
-2
View File
@@ -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
+63 -32
View File
@@ -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)
}
+4 -4
View File
@@ -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
}
+4 -4
View File
@@ -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 {
+9 -8
View File
@@ -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
}
+87 -45
View File
@@ -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)
}
+11 -9
View File
@@ -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)
}
+2 -2
View File
@@ -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"
}
+2 -2
View File
@@ -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
View File
@@ -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)
}
+183
View File
@@ -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
}
+79
View File
@@ -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
}
+4
View File
@@ -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
}
+36
View File
@@ -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
View File
@@ -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
+79
View File
@@ -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 ---
}
+46
View File
@@ -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 ---
}
-46
View File
@@ -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
+15 -15
View File
@@ -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.
+38
View File
@@ -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)
}
+7 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
+7 -7
View File
@@ -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
View File
@@ -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)
}
}
+42 -18
View File
@@ -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)
+46 -47
View File
@@ -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)
+46
View File
@@ -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)
}
+532 -97
View File
@@ -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,
}
+460
View File
@@ -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_,
}
+52 -52
View File
@@ -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)
}
}
+136
View File
@@ -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
}
+67
View File
@@ -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