diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin index 98ef4b542..763a19f8b 100644 --- a/core/container/bit_array/bit_array.odin +++ b/core/container/bit_array/bit_array.odin @@ -185,6 +185,33 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator return true } +/* + In: + - ba: ^Bit_Array - a pointer to the Bit Array + - index: The bit index. Can be an enum member. + + Out: + - ok: Whether or not we managed to unset requested bit. + + `unset` automatically resizes the Bit Array to accommodate the requested index if needed. +*/ +unset :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) { + + idx := int(index) - ba.bias + + if ba == nil || int(index) < ba.bias { return false } + context.allocator = allocator + + leg_index := idx >> INDEX_SHIFT + bit_index := idx & INDEX_MASK + + resize_if_needed(ba, leg_index) or_return + + ba.max_index = max(idx, ba.max_index) + ba.bits[leg_index] &= ~(1 << uint(bit_index)) + return true +} + /* A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative). */ diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin index 8ca3a85ac..ae1ca9f62 100644 --- a/core/container/queue/queue.odin +++ b/core/container/queue/queue.odin @@ -69,6 +69,16 @@ get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T { idx := (uint(i)+q.offset)%builtin.len(q.data) return q.data[idx] } + +front :: proc(q: ^$Q/Queue($T)) -> T { + return q.data[q.offset] +} + +back :: proc(q: ^$Q/Queue($T)) -> T { + idx := (q.offset+uint(q.len))%builtin.len(q.data) + return q.data[idx] +} + set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) { runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 9c54f35f0..14df4c127 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -49,7 +49,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { unreachable() case runtime.Type_Info_Integer: - buf: [21]byte + buf: [40]byte u: u128 switch i in a { case i8: u = u128(i) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 4f78cfcce..26dff8c45 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -28,11 +28,16 @@ Info :: struct { reordered: bool, good_arg_index: bool, ignore_user_formatters: bool, + in_bad: bool, writer: io.Writer, arg: any, // Temporary + indirection_level: int, record_level: int, + optional_len: Maybe(int), + use_nul_termination: bool, + n: int, // bytes written } @@ -589,6 +594,10 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) { fmt_bad_verb :: proc(using fi: ^Info, verb: rune) { + prev_in_bad := fi.in_bad + defer fi.in_bad = prev_in_bad + fi.in_bad = true + io.write_string(writer, "%!", &fi.n) io.write_rune(writer, verb, &fi.n) io.write_byte(writer, '(', &fi.n) @@ -941,6 +950,14 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { fmt_string :: proc(fi: ^Info, s: string, verb: rune) { + s, verb := s, verb + if ol, ok := fi.optional_len.?; ok { + s = s[:clamp(ol, 0, len(s))] + } + if !fi.in_bad && fi.record_level > 0 && verb == 'v' { + verb = 'q' + } + switch verb { case 's', 'v': if fi.width_set { @@ -1220,6 +1237,8 @@ fmt_write_array :: proc(fi: ^Info, array_data: rawptr, count: int, elem_size: in if count <= 0 { return } + fi.record_level += 1 + defer fi.record_level -= 1 if fi.hash { io.write_byte(fi.writer, '\n', &fi.n) @@ -1247,7 +1266,289 @@ fmt_write_array :: proc(fi: ^Info, array_data: rawptr, count: int, elem_size: in } } -fmt_value :: proc(fi: ^Info, v: any, verb: rune) { + +@(private) +handle_tag :: proc(data: rawptr, info: reflect.Type_Info_Struct, idx: int, verb: ^rune, optional_len: ^int, use_nul_termination: ^bool) -> (do_continue: bool) { + handle_optional_len :: proc(data: rawptr, info: reflect.Type_Info_Struct, field_name: string, optional_len: ^int) { + if optional_len == nil { + return + } + for f, i in info.names { + if f != field_name { + continue + } + ptr := rawptr(uintptr(data) + info.offsets[i]) + field := any{ptr, info.types[i].id} + if new_len, iok := reflect.as_int(field); iok { + optional_len^ = max(new_len, 0) + } + break + } + } + tag := info.tags[idx] + if vt, ok := reflect.struct_tag_lookup(reflect.Struct_Tag(tag), "fmt"); ok { + value := strings.trim_space(string(vt)) + switch value { + case "": return false + case "-": return true + } + r, w := utf8.decode_rune_in_string(value) + value = value[w:] + if value == "" || value[0] == ',' { + verb^ = r + if len(value) > 0 && value[0] == ',' { + field_name := value[1:] + if field_name == "0" { + if use_nul_termination != nil { + use_nul_termination^ = true + } + } else { + switch r { + case 's', 'q': + handle_optional_len(data, info, field_name, optional_len) + case 'v': + #partial switch reflect.type_kind(info.types[idx].id) { + case .String, .Multi_Pointer, .Array, .Slice, .Dynamic_Array: + handle_optional_len(data, info, field_name, optional_len) + } + } + } + } + } + } + return false +} + +fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_Struct, type_name: string) { + if the_verb != 'v' { + fmt_bad_verb(fi, the_verb) + return + } + if info.is_raw_union { + if type_name == "" { + io.write_string(fi.writer, "(raw union)", &fi.n) + } else { + io.write_string(fi.writer, type_name, &fi.n) + io.write_string(fi.writer, "{}", &fi.n) + } + return + } + + is_soa := info.soa_kind != .None + + io.write_string(fi.writer, type_name, &fi.n) + io.write_byte(fi.writer, '[' if is_soa else '{', &fi.n) + fi.record_level += 1 + defer fi.record_level -= 1 + + hash := fi.hash; defer fi.hash = hash + indent := fi.indent; defer fi.indent -= 1 + do_trailing_comma := hash + + // fi.hash = false; + fi.indent += 1 + + if hash { + io.write_byte(fi.writer, '\n', &fi.n) + } + defer { + if hash { + for in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + field_count := -1 + + if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } + + io.write_string(fi.writer, base_type_name, &fi.n) + io.write_byte(fi.writer, '{', &fi.n) + defer io.write_byte(fi.writer, '}', &fi.n) + fi.record_level += 1 + defer fi.record_level -= 1 + + for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + if hash { + fmt_write_indent(fi) + } + + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) + + if info.soa_kind == .Fixed { + t := info.types[i].variant.(runtime.Type_Info_Array).elem + t_size := uintptr(t.size) + if reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) + fmt_arg(fi, any{data, t.id}, verb) + } + } else { + t := info.types[i].variant.(runtime.Type_Info_Pointer).elem + t_size := uintptr(t.size) + if reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ + data := rawptr(uintptr(field_ptr) + index*t_size) + fmt_arg(fi, any{data, t.id}, verb) + } + } + + if hash { io.write_string(fi.writer, ",\n", &fi.n) } + } + } + } else { + field_count := -1 + for name, i in info.names { + optional_len: int = -1 + use_nul_termination: bool = false + verb := 'v' + if handle_tag(v.data, info, i, &verb, &optional_len, &use_nul_termination) { + continue + } + field_count += 1 + + if optional_len >= 0 { + fi.optional_len = optional_len + } + defer if optional_len >= 0 { + fi.optional_len = nil + } + fi.use_nul_termination = use_nul_termination + defer fi.use_nul_termination = false + + if !do_trailing_comma && field_count > 0 { io.write_string(fi.writer, ", ") } + if hash { + fmt_write_indent(fi) + } + + io.write_string(fi.writer, name, &fi.n) + io.write_string(fi.writer, " = ", &fi.n) + + if t := info.types[i]; reflect.is_any(t) { + io.write_string(fi.writer, "any{}", &fi.n) + } else { + data := rawptr(uintptr(v.data) + info.offsets[i]) + fmt_arg(fi, any{data, t.id}, verb) + } + + if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) } + } + } +} + +@(private) +search_nul_termination :: proc(ptr: rawptr, elem_size: int, max_n: int) -> (n: int) { + for p := uintptr(ptr); max_n < 0 || n < max_n; p += uintptr(elem_size) { + if mem.check_zero_ptr(rawptr(p), elem_size) { + break + } + n += 1 + } + return n +} + +fmt_array_nul_terminated :: proc(fi: ^Info, data: rawptr, max_n: int, elem_size: int, elem: ^reflect.Type_Info, verb: rune) { + if data == nil { + io.write_string(fi.writer, "", &fi.n) + return + } + n := search_nul_termination(data, elem_size, max_n) + fmt_array(fi, data, n, elem_size, elem, verb) +} + +fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflect.Type_Info, verb: rune) { + if data == nil && n > 0 { + io.write_string(fi.writer, "nil") + return + } + if verb == 's' || verb == 'q' { + print_utf16 :: proc(fi: ^Info, s: []$T) where size_of(T) == 2, intrinsics.type_is_integer(T) { + REPLACEMENT_CHAR :: '\ufffd' + _surr1 :: 0xd800 + _surr2 :: 0xdc00 + _surr3 :: 0xe000 + _surr_self :: 0x10000 + + for i := 0; i < len(s); i += 1 { + r := rune(REPLACEMENT_CHAR) + + switch c := s[i]; { + case c < _surr1, _surr3 <= c: + r = rune(c) + case _surr1 <= c && c < _surr2 && i+1 < len(s) && + _surr2 <= s[i+1] && s[i+1] < _surr3: + r1, r2 := rune(c), rune(s[i+1]) + if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 { + r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self + } + i += 1 + } + io.write_rune(fi.writer, r, &fi.n) + } + } + + print_utf32 :: proc(fi: ^Info, s: []$T) where size_of(T) == 4 { + for r in s { + io.write_rune(fi.writer, rune(r), &fi.n) + } + } + + switch reflect.type_info_base(elem).id { + case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return + case u16: print_utf16(fi, ([^]u16)(data)[:n]); return + case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return + case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return + case u32: print_utf32(fi, ([^]u32)(data)[:n]); return + case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return + case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return + case rune: print_utf32(fi, ([^]rune)(data)[:n]); return + } + } + if verb == 'p' { + fmt_pointer(fi, data, 'p') + } else { + fmt_write_array(fi, data, n, elem_size, elem.id, verb) + } +} + +fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named) { write_padded_number :: proc(fi: ^Info, i: i64, width: int) { n := width-1 for x := i; x >= 10; x /= 10 { @@ -1259,7 +1560,233 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { io.write_i64(fi.writer, i, 10, &fi.n) } + // Built-in Custom Formatters for core library types + switch a in v { + case runtime.Source_Code_Location: + io.write_string(fi.writer, a.file_path, &fi.n) + io.write_byte(fi.writer, '(', &fi.n) + io.write_int(fi.writer, int(a.line), 10, &fi.n) + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.column), 10, &fi.n) + io.write_byte(fi.writer, ')', &fi.n) + return + case time.Duration: + ffrac :: proc(buf: []byte, v: u64, prec: int) -> (nw: int, nv: u64) { + v := v + w := len(buf) + print := false + for in 0.. int { + v := v + w := len(buf) + if v == 0 { + w -= 1 + buf[w] = '0' + } else { + for v > 0 { + w -= 1 + buf[w] = byte(v%10) + '0' + v /= 10 + } + } + return w + } + + buf: [32]byte + w := len(buf) + u := u64(a) + neg := a < 0 + if neg { + u = -u + } + + if u < u64(time.Second) { + prec: int + w -= 1 + buf[w] = 's' + w -= 1 + switch { + case u == 0: + io.write_string(fi.writer, "0s", &fi.n) + return + case u < u64(time.Microsecond): + prec = 0 + buf[w] = 'n' + case u < u64(time.Millisecond): + prec = 3 + // U+00B5 'µ' micro sign == 0xC2 0xB5 + w -= 1 // Need room for two bytes + copy(buf[w:], "µ") + case: + prec = 6 + buf[w] = 'm' + } + w, u = ffrac(buf[:w], u, prec) + w = fint(buf[:w], u) + } else { + w -= 1 + buf[w] = 's' + w, u = ffrac(buf[:w], u, 9) + w = fint(buf[:w], u%60) + u /= 60 + if u > 0 { + w -= 1 + buf[w] = 'm' + w = fint(buf[:w], u%60) + u /= 60 + if u > 0 { + w -= 1 + buf[w] = 'h' + w = fint(buf[:w], u) + } + } + } + + if neg { + w -= 1 + buf[w] = '-' + } + io.write_string(fi.writer, string(buf[w:]), &fi.n) + return + + case time.Time: + t := a + y, mon, d := time.date(t) + h, min, s := time.clock(t) + ns := (t._nsec - (t._nsec/1e9 + time.UNIX_TO_ABSOLUTE)*1e9) % 1e9 + write_padded_number(fi, i64(y), 4) + io.write_byte(fi.writer, '-', &fi.n) + write_padded_number(fi, i64(mon), 2) + io.write_byte(fi.writer, '-', &fi.n) + write_padded_number(fi, i64(d), 2) + io.write_byte(fi.writer, ' ', &fi.n) + + write_padded_number(fi, i64(h), 2) + io.write_byte(fi.writer, ':', &fi.n) + write_padded_number(fi, i64(min), 2) + io.write_byte(fi.writer, ':', &fi.n) + write_padded_number(fi, i64(s), 2) + io.write_byte(fi.writer, '.', &fi.n) + write_padded_number(fi, (ns), 9) + io.write_string(fi.writer, " +0000 UTC", &fi.n) + return + } + + #partial switch b in info.base.variant { + case runtime.Type_Info_Struct: + fmt_struct(fi, v, verb, b, info.name) + case runtime.Type_Info_Bit_Set: + fmt_bit_set(fi, v) + case: + fmt_value(fi, any{v.data, info.base.id}, verb) + } +} + +fmt_union :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Union, type_size: int) { + if type_size == 0 { + io.write_string(fi.writer, "nil", &fi.n) + return + } + + if reflect.type_info_union_is_pure_maybe(info) { + if v.data == nil { + io.write_string(fi.writer, "nil", &fi.n) + } else { + id := info.variants[0].id + fmt_arg(fi, any{v.data, id}, verb) + } + return + } + + tag: i64 = -1 + tag_ptr := uintptr(v.data) + info.tag_offset + tag_any := any{rawptr(tag_ptr), info.tag_type.id} + + switch i in tag_any { + case u8: tag = i64(i) + case i8: tag = i64(i) + case u16: tag = i64(i) + case i16: tag = i64(i) + case u32: tag = i64(i) + case i32: tag = i64(i) + case u64: tag = i64(i) + case i64: tag = i + case: panic("Invalid union tag type") + } + assert(tag >= 0) + + if v.data == nil { + io.write_string(fi.writer, "nil", &fi.n) + } else if info.no_nil { + id := info.variants[tag].id + fmt_arg(fi, any{v.data, id}, verb) + } else if tag == 0 { + io.write_string(fi.writer, "nil", &fi.n) + } else { + id := info.variants[tag-1].id + fmt_arg(fi, any{v.data, id}, verb) + } +} + +fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix) { + io.write_string(fi.writer, "matrix[", &fi.n) + defer io.write_byte(fi.writer, ']', &fi.n) + + fi.indent += 1 + + if fi.hash { + // Printed as it is written + io.write_byte(fi.writer, '\n', &fi.n) + for row in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + offset := (row + col*info.elem_stride)*info.elem_size + + data := uintptr(v.data) + uintptr(offset) + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) + } + io.write_string(fi.writer, ",\n", &fi.n) + } + } else { + // Printed in Row-Major layout to match text layout + for row in 0.. 0 { io.write_string(fi.writer, "; ", &fi.n) } + for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } + + offset := (row + col*info.elem_stride)*info.elem_size + + data := uintptr(v.data) + uintptr(offset) + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) + } + } + } + + fi.indent -= 1 + + if fi.hash { + fmt_write_indent(fi) + } +} + +fmt_value :: proc(fi: ^Info, v: any, verb: rune) { if v.data == nil || v.id == nil { io.write_string(fi.writer, "", &fi.n) return @@ -1284,238 +1811,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Tuple: // Ignore case runtime.Type_Info_Named: - // Built-in Custom Formatters for core library types - switch a in v { - case runtime.Source_Code_Location: - io.write_string(fi.writer, a.file_path, &fi.n) - io.write_byte(fi.writer, '(', &fi.n) - io.write_int(fi.writer, int(a.line), 10, &fi.n) - io.write_byte(fi.writer, ':', &fi.n) - io.write_int(fi.writer, int(a.column), 10, &fi.n) - io.write_byte(fi.writer, ')', &fi.n) - return - - case time.Duration: - ffrac :: proc(buf: []byte, v: u64, prec: int) -> (nw: int, nv: u64) { - v := v - w := len(buf) - print := false - for in 0.. int { - v := v - w := len(buf) - if v == 0 { - w -= 1 - buf[w] = '0' - } else { - for v > 0 { - w -= 1 - buf[w] = byte(v%10) + '0' - v /= 10 - } - } - return w - } - - buf: [32]byte - w := len(buf) - u := u64(a) - neg := a < 0 - if neg { - u = -u - } - - if u < u64(time.Second) { - prec: int - w -= 1 - buf[w] = 's' - w -= 1 - switch { - case u == 0: - io.write_string(fi.writer, "0s", &fi.n) - return - case u < u64(time.Microsecond): - prec = 0 - buf[w] = 'n' - case u < u64(time.Millisecond): - prec = 3 - // U+00B5 'µ' micro sign == 0xC2 0xB5 - w -= 1 // Need room for two bytes - copy(buf[w:], "µ") - case: - prec = 6 - buf[w] = 'm' - } - w, u = ffrac(buf[:w], u, prec) - w = fint(buf[:w], u) - } else { - w -= 1 - buf[w] = 's' - w, u = ffrac(buf[:w], u, 9) - w = fint(buf[:w], u%60) - u /= 60 - if u > 0 { - w -= 1 - buf[w] = 'm' - w = fint(buf[:w], u%60) - u /= 60 - if u > 0 { - w -= 1 - buf[w] = 'h' - w = fint(buf[:w], u) - } - } - } - - if neg { - w -= 1 - buf[w] = '-' - } - io.write_string(fi.writer, string(buf[w:]), &fi.n) - return - - case time.Time: - t := a - y, mon, d := time.date(t) - h, min, s := time.clock(t) - ns := (t._nsec - (t._nsec/1e9 + time.UNIX_TO_ABSOLUTE)*1e9) % 1e9 - write_padded_number(fi, i64(y), 4) - io.write_byte(fi.writer, '-', &fi.n) - write_padded_number(fi, i64(mon), 2) - io.write_byte(fi.writer, '-', &fi.n) - write_padded_number(fi, i64(d), 2) - io.write_byte(fi.writer, ' ', &fi.n) - - write_padded_number(fi, i64(h), 2) - io.write_byte(fi.writer, ':', &fi.n) - write_padded_number(fi, i64(min), 2) - io.write_byte(fi.writer, ':', &fi.n) - write_padded_number(fi, i64(s), 2) - io.write_byte(fi.writer, '.', &fi.n) - write_padded_number(fi, (ns), 9) - io.write_string(fi.writer, " +0000 UTC", &fi.n) - return - } - - #partial switch b in info.base.variant { - case runtime.Type_Info_Struct: - if verb != 'v' { - fmt_bad_verb(fi, verb) - return - } - if b.is_raw_union { - io.write_string(fi.writer, info.name, &fi.n) - io.write_string(fi.writer, "{}", &fi.n) - return - } - - is_soa := b.soa_kind != .None - - io.write_string(fi.writer, info.name, &fi.n) - io.write_byte(fi.writer, '[' if is_soa else '{', &fi.n) - - hash := fi.hash; defer fi.hash = hash - indent := fi.indent; defer fi.indent -= 1 - - // fi.hash = false; - fi.indent += 1 - - if hash { - io.write_byte(fi.writer, '\n', &fi.n) - } - defer { - if hash { - for in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - field_count := -1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - - io.write_string(fi.writer, base_type_name, &fi.n) - io.write_byte(fi.writer, '{', &fi.n) - defer io.write_byte(fi.writer, '}', &fi.n) - - for name, i in b.names { - field_count += 1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - if hash { - fmt_write_indent(fi) - } - - io.write_string(fi.writer, name, &fi.n) - io.write_string(fi.writer, " = ", &fi.n) - - t := b.types[i].variant.(runtime.Type_Info_Array).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - data := rawptr(uintptr(v.data) + b.offsets[i] + index*t_size) - fmt_arg(fi, any{data, t.id}, 'v') - } - - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - } else { - field_count := -1 - for name, i in b.names { - field_count += 1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ") } - if hash { - fmt_write_indent(fi) - } - - io.write_string(fi.writer, name, &fi.n) - io.write_string(fi.writer, " = ", &fi.n) - - if t := b.types[i]; reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - data := rawptr(uintptr(v.data) + b.offsets[i]) - fmt_arg(fi, any{data, t.id}, 'v') - } - - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - - case runtime.Type_Info_Bit_Set: - fmt_bit_set(fi, v) - case: - fmt_value(fi, any{v.data, info.base.id}, verb) - } + fmt_named(fi, v, verb, info) case runtime.Type_Info_Boolean: fmt_arg(fi, v, verb) case runtime.Type_Info_Integer: fmt_arg(fi, v, verb) @@ -1544,9 +1840,9 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { io.write_string(fi.writer, "", &fi.n) return } - if fi.record_level < 1 { - fi.record_level += 1 - defer fi.record_level -= 1 + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 io.write_byte(fi.writer, '&') fmt_value(fi, a, verb) return @@ -1558,9 +1854,9 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { io.write_string(fi.writer, "", &fi.n) return } - if fi.record_level < 1 { - fi.record_level += 1 - defer fi.record_level -= 1 + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 io.write_byte(fi.writer, '&', &fi.n) fmt_value(fi, a, verb) return @@ -1573,23 +1869,45 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Multi_Pointer: ptr := (^rawptr)(v.data)^ + if ptr == nil { + io.write_string(fi.writer, "", &fi.n) + return + } if verb != 'p' && info.elem != nil { a := any{ptr, info.elem.id} elem := runtime.type_info_base(info.elem) if elem != nil { + if n, ok := fi.optional_len.?; ok { + fmt_array(fi, ptr, n, elem.size, elem, verb) + return + } else if fi.use_nul_termination { + fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb) + return + } + #partial switch e in elem.variant { + case runtime.Type_Info_Integer: + switch verb { + case 's', 'q': + switch elem.id { + case u8: + fmt_cstring(fi, cstring(ptr), verb) + return + case u16, u32, rune: + n := search_nul_termination(ptr, elem.size, -1) + fmt_array(fi, ptr, n, elem.size, elem, verb) + return + } + } + case runtime.Type_Info_Array, runtime.Type_Info_Slice, runtime.Type_Info_Dynamic_Array, runtime.Type_Info_Map: - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if fi.record_level < 1 { - fi.record_level += 1 - defer fi.record_level -= 1 + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 io.write_byte(fi.writer, '&', &fi.n) fmt_value(fi, a, verb) return @@ -1597,13 +1915,9 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Struct, runtime.Type_Info_Union: - if ptr == nil { - io.write_string(fi.writer, "", &fi.n) - return - } - if fi.record_level < 1 { - fi.record_level += 1 - defer fi.record_level -= 1 + if fi.indirection_level < 1 { + fi.indirection_level += 1 + defer fi.indirection_level -= 1 io.write_byte(fi.writer, '&', &fi.n) fmt_value(fi, a, verb) return @@ -1613,15 +1927,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } fmt_pointer(fi, ptr, verb) - case runtime.Type_Info_Array: - if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { - s := strings.string_from_ptr((^byte)(v.data), info.count) - fmt_string(fi, s, verb) - } else { - fmt_write_array(fi, v.data, info.count, info.elem_size, info.elem.id, verb) - } - case runtime.Type_Info_Enumerated_Array: + fi.record_level += 1 + defer fi.record_level -= 1 + if fi.hash { io.write_string(fi.writer, "[\n", &fi.n) defer { @@ -1670,16 +1979,40 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } } + case runtime.Type_Info_Array: + n := info.count + ptr := v.data + if ol, ok := fi.optional_len.?; ok { + n = min(n, ol) + } else if fi.use_nul_termination { + fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) + return + } + fmt_array(fi, ptr, n, info.elem_size, info.elem, verb) + + case runtime.Type_Info_Slice: + slice := cast(^mem.Raw_Slice)v.data + n := slice.len + ptr := slice.data + if ol, ok := fi.optional_len.?; ok { + n = min(n, ol) + } else if fi.use_nul_termination { + fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) + return + } + fmt_array(fi, ptr, n, info.elem_size, info.elem, verb) + case runtime.Type_Info_Dynamic_Array: array := cast(^mem.Raw_Dynamic_Array)v.data - if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { - s := strings.string_from_ptr((^byte)(array.data), array.len) - fmt_string(fi, s, verb) - } else if verb == 'p' { - fmt_pointer(fi, array.data, 'p') - } else { - fmt_write_array(fi, array.data, array.len, info.elem_size, info.elem.id, verb) + n := array.len + ptr := array.data + if ol, ok := fi.optional_len.?; ok { + n = min(n, ol) + } else if fi.use_nul_termination { + fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb) + return } + fmt_array(fi, ptr, n, info.elem_size, info.elem, verb) case runtime.Type_Info_Simd_Vector: io.write_byte(fi.writer, '<', &fi.n) @@ -1692,16 +2025,6 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } - case runtime.Type_Info_Slice: - slice := cast(^mem.Raw_Slice)v.data - if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { - s := strings.string_from_ptr((^byte)(slice.data), slice.len) - fmt_string(fi, s, verb) - } else if verb == 'p' { - fmt_pointer(fi, slice.data, 'p') - } else { - fmt_write_array(fi, slice.data, slice.len, info.elem_size, info.elem.id, verb) - } case runtime.Type_Info_Map: if verb != 'v' { fmt_bad_verb(fi, verb) @@ -1738,168 +2061,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Struct: - if info.is_raw_union { - io.write_string(fi.writer, "(raw_union)", &fi.n) - return - } - - is_soa := info.soa_kind != .None - - io.write_byte(fi.writer, '[' if is_soa else '{', &fi.n) - defer io.write_byte(fi.writer, ']' if is_soa else '}', &fi.n) - - fi.indent += 1; defer fi.indent -= 1 - hash := fi.hash; defer fi.hash = hash - // fi.hash = false; - - - if hash { io.write_byte(fi.writer, '\n', &fi.n) } - - if is_soa { - fi.indent += 1 - defer fi.indent -= 1 - - base_type_name: string - if v, ok := info.soa_base_type.variant.(runtime.Type_Info_Named); ok { - base_type_name = v.name - } - - actual_field_count := len(info.names) - - n := uintptr(info.soa_len) - - if info.soa_kind == .Slice { - actual_field_count = len(info.names)-1 // len - - n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) - - } else if info.soa_kind == .Dynamic { - actual_field_count = len(info.names)-3 // len, cap, allocator - - n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^) - } - - - - for index in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - field_count := -1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - - io.write_string(fi.writer, base_type_name, &fi.n) - io.write_byte(fi.writer, '{', &fi.n) - defer io.write_byte(fi.writer, '}', &fi.n) - - for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - if hash { - fmt_write_indent(fi) - } - - io.write_string(fi.writer, name, &fi.n) - io.write_string(fi.writer, " = ", &fi.n) - - if info.soa_kind == .Fixed { - t := info.types[i].variant.(runtime.Type_Info_Array).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size) - fmt_arg(fi, any{data, t.id}, 'v') - } - } else { - t := info.types[i].variant.(runtime.Type_Info_Pointer).elem - t_size := uintptr(t.size) - if reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - field_ptr := (^^byte)(uintptr(v.data) + info.offsets[i])^ - data := rawptr(uintptr(field_ptr) + index*t_size) - fmt_arg(fi, any{data, t.id}, 'v') - } - } - - if hash { io.write_string(fi.writer, ",\n", &fi.n) } - } - } - } else { - field_count := -1 - for name, i in info.names { - field_count += 1 - - if !hash && field_count > 0 { io.write_string(fi.writer, ", ", &fi.n) } - if hash { - fmt_write_indent(fi) - } - - io.write_string(fi.writer, name, &fi.n) - io.write_string(fi.writer, " = ", &fi.n) - - if t := info.types[i]; reflect.is_any(t) { - io.write_string(fi.writer, "any{}", &fi.n) - } else { - data := rawptr(uintptr(v.data) + info.offsets[i]) - fmt_arg(fi, any{data, t.id}, 'v') - } - - if hash { - io.write_string(fi.writer, ",\n", &fi.n) - } - } - } - + fmt_struct(fi, v, verb, info, "") case runtime.Type_Info_Union: - if type_info.size == 0 { - io.write_string(fi.writer, "nil", &fi.n) - return - } - - - if reflect.type_info_union_is_pure_maybe(info) { - if v.data == nil { - io.write_string(fi.writer, "nil", &fi.n) - } else { - id := info.variants[0].id - fmt_arg(fi, any{v.data, id}, verb) - } - return - } - - tag: i64 = -1 - tag_ptr := uintptr(v.data) + info.tag_offset - tag_any := any{rawptr(tag_ptr), info.tag_type.id} - - switch i in tag_any { - case u8: tag = i64(i) - case i8: tag = i64(i) - case u16: tag = i64(i) - case i16: tag = i64(i) - case u32: tag = i64(i) - case i32: tag = i64(i) - case u64: tag = i64(i) - case i64: tag = i - case: panic("Invalid union tag type") - } - assert(tag >= 0) - - if v.data == nil { - io.write_string(fi.writer, "nil", &fi.n) - } else if info.no_nil { - id := info.variants[tag].id - fmt_arg(fi, any{v.data, id}, verb) - } else if tag == 0 { - io.write_string(fi.writer, "nil", &fi.n) - } else { - id := info.variants[tag-1].id - fmt_arg(fi, any{v.data, id}, verb) - } + fmt_union(fi, v, verb, info, type_info.size) case runtime.Type_Info_Enum: fmt_enum(fi, v, verb) @@ -1940,6 +2105,9 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { len, _ := reflect.as_int(len_any) slice_type := reflect.type_info_base(info.slice).variant.(runtime.Type_Info_Slice) + fi.record_level += 1 + defer fi.record_level -= 1 + io.write_byte(fi.writer, '[', &fi.n) defer io.write_byte(fi.writer, ']', &fi.n) @@ -1952,46 +2120,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Matrix: - io.write_string(fi.writer, "matrix[", &fi.n) - defer io.write_byte(fi.writer, ']', &fi.n) - - fi.indent += 1 - - if fi.hash { - // Printed as it is written - io.write_byte(fi.writer, '\n', &fi.n) - for row in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - offset := (row + col*info.elem_stride)*info.elem_size - - data := uintptr(v.data) + uintptr(offset) - fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) - } - io.write_string(fi.writer, ",\n", &fi.n) - } - } else { - // Printed in Row-Major layout to match text layout - for row in 0.. 0 { io.write_string(fi.writer, "; ", &fi.n) } - for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - offset := (row + col*info.elem_stride)*info.elem_size - - data := uintptr(v.data) + uintptr(offset) - fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) - } - } - } - - fi.indent -= 1 - - if fi.hash { - fmt_write_indent(fi) - } + fmt_matrix(fi, v, verb, info) } } diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 6bedbf691..e2a0cc0fc 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -887,6 +887,10 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, } case .Free: delete_key(&data.allocation_map, old_memory) + case .Free_All: + if data.clear_on_free_all { + clear_map(&data.allocation_map) + } case .Resize: if old_memory != result_ptr { delete_key(&data.allocation_map, old_memory) @@ -899,11 +903,6 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, location = loc, } - case .Free_All: - if data.clear_on_free_all { - clear_map(&data.allocation_map) - } - case .Query_Features: set := (^Allocator_Mode_Set)(old_memory) if set != nil { diff --git a/core/mem/mem.odin b/core/mem/mem.odin index fd91a6c97..7295a2afa 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -109,6 +109,12 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool { case ptr == nil: return true } + switch len { + case 1: return (^u8)(ptr)^ == 0 + case 2: return intrinsics.unaligned_load((^u16)(ptr)) == 0 + case 4: return intrinsics.unaligned_load((^u32)(ptr)) == 0 + case 8: return intrinsics.unaligned_load((^u64)(ptr)) == 0 + } start := uintptr(ptr) start_aligned := align_forward_uintptr(start, align_of(uintptr)) diff --git a/core/os/os2/heap_windows.odin b/core/os/os2/heap_windows.odin index 85ea2c56f..90f0ae110 100644 --- a/core/os/os2/heap_windows.odin +++ b/core/os/os2/heap_windows.odin @@ -99,7 +99,7 @@ _heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, return nil, nil case .Query_Info: - return nil, nil + return nil, .Mode_Not_Implemented } return nil, nil diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 7cb5287c0..cebb91987 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -129,6 +129,9 @@ reserve :: proc{reserve_dynamic_array, reserve_map} @builtin resize :: proc{resize_dynamic_array} +// Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity. +@builtin +shrink :: proc{shrink_dynamic_array, shrink_map} @builtin free :: proc{mem_free} @@ -284,12 +287,30 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) { } @builtin -reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) { +reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) { if m != nil { - __dynamic_map_reserve(__get_map_header(m), capacity) + __dynamic_map_reserve(__get_map_header(m), capacity, loc) } } +/* + Shrinks the capacity of a map down to the current length, or the given capacity. + + If `new_cap` is negative, then `len(m)` is used. + + Returns false if `cap(m) < new_cap`, or the allocator report failure. + + If `len(m) < new_cap`, then `len(m)` will be left unchanged. +*/ +@builtin +shrink_map :: proc(m: ^$T/map[$K]$V, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) { + if m != nil { + new_cap := new_cap if new_cap >= 0 else len(m) + return __dynamic_map_shrink(__get_map_header(m), new_cap, loc) + } + return +} + // The delete_key built-in procedure deletes the element with the specified key (m[key]) from the map. // If m is nil, or there is no such element, this procedure is a no-op @builtin @@ -536,6 +557,54 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller return true } +/* + Shrinks the capacity of a dynamic array down to the current length, or the given capacity. + + If `new_cap` is negative, then `len(array)` is used. + + Returns false if `cap(array) < new_cap`, or the allocator report failure. + + If `len(array) < new_cap`, then `len(array)` will be left unchanged. +*/ +shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool) { + if array == nil { + return + } + a := (^Raw_Dynamic_Array)(array) + + new_cap := new_cap if new_cap >= 0 else a.len + + if new_cap > a.cap { + return + } + + if a.allocator.procedure == nil { + a.allocator = context.allocator + } + assert(a.allocator.procedure != nil) + + old_size := a.cap * size_of(E) + new_size := new_cap * size_of(E) + + new_data, err := a.allocator.procedure( + a.allocator.data, + .Resize, + new_size, + align_of(E), + a.data, + old_size, + loc, + ) + if err != nil { + return + } + + a.data = raw_data(new_data) + a.len = min(new_cap, a.len) + a.cap = new_cap + return true +} + @builtin map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) { key, value := key, value diff --git a/core/runtime/default_allocators_windows.odin b/core/runtime/default_allocators_windows.odin index 9cabbcce8..45d4d3e6a 100644 --- a/core/runtime/default_allocators_windows.odin +++ b/core/runtime/default_allocators_windows.odin @@ -17,7 +17,7 @@ when ODIN_DEFAULT_TO_NIL_ALLOCATOR { _windows_default_free(old_memory) case .Free_All: - // NOTE(tetra): Do nothing. + return nil, .Mode_Not_Implemented case .Resize: data, err = _windows_default_resize(old_memory, old_size, size, alignment) @@ -29,7 +29,7 @@ when ODIN_DEFAULT_TO_NIL_ALLOCATOR { } case .Query_Info: - // Do nothing + return nil, .Mode_Not_Implemented } return diff --git a/core/runtime/default_temporary_allocator.odin b/core/runtime/default_temporary_allocator.odin index 4337e555b..52f781980 100644 --- a/core/runtime/default_temporary_allocator.odin +++ b/core/runtime/default_temporary_allocator.odin @@ -185,7 +185,7 @@ when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR } case .Query_Info: - // Nothing to give + return nil, .Mode_Not_Implemented } return diff --git a/core/runtime/dynamic_array_internal.odin b/core/runtime/dynamic_array_internal.odin index 6f800de7a..04e2236a9 100644 --- a/core/runtime/dynamic_array_internal.odin +++ b/core/runtime/dynamic_array_internal.odin @@ -41,6 +41,35 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: return false } +__dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_cap: int, loc := #caller_location) -> (did_shrink: bool) { + array := (^Raw_Dynamic_Array)(array_) + + // NOTE(tetra, 2020-01-26): We set the allocator before earlying-out below, because user code is usually written + // assuming that appending/reserving will set the allocator, if it is not already set. + if array.allocator.procedure == nil { + array.allocator = context.allocator + } + assert(array.allocator.procedure != nil) + + if new_cap > array.cap { + return + } + + old_size := array.cap * elem_size + new_size := new_cap * elem_size + allocator := array.allocator + + new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc) + if err != nil { + return + } + + array.data = raw_data(new_data) + array.len = min(new_cap, array.len) + array.cap = new_cap + return true +} + __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool { array := (^Raw_Dynamic_Array)(array_) diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 4d4c51d6a..fee0f570f 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -239,6 +239,16 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller } } +__dynamic_map_shrink :: proc(using header: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) { + c := context + if m.entries.allocator.procedure != nil { + c.allocator = m.entries.allocator + } + context = c + + return __dynamic_array_shrink(&m.entries, entry_size, entry_align, cap, loc) +} + __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) { #force_inline __dynamic_map_reserve(header, new_count, loc) } diff --git a/core/slice/sort.odin b/core/slice/sort.odin index 8a2dec039..b6e455056 100644 --- a/core/slice/sort.odin +++ b/core/slice/sort.odin @@ -103,7 +103,7 @@ is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool { is_sorted_by_cmp :: is_sorted_cmp is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool { for i := len(array)-1; i > 0; i -= 1 { - if cmp(array[i], array[i-1]) == .Equal { + if cmp(array[i], array[i-1]) == .Less { return false } } diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin index 20badb5da..ab2c6737f 100644 --- a/core/sys/windows/advapi32.odin +++ b/core/sys/windows/advapi32.odin @@ -70,4 +70,53 @@ foreign advapi32 { lpStartupInfo: LPSTARTUPINFO, lpProcessInformation: LPPROCESS_INFORMATION, ) -> BOOL --- -} \ No newline at end of file + + RegCreateKeyExW :: proc( + hKey: HKEY, + lpSubKey: LPCWSTR, + Reserved: DWORD, + lpClass: LPWSTR, + dwOptions: DWORD, + samDesired: REGSAM, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + phkResult: PHKEY, + lpdwDisposition: LPDWORD, + ) -> LSTATUS --- + + RegOpenKeyW :: proc( + hKey: HKEY, + lpSubKey: LPCWSTR, + phkResult: PHKEY, + ) -> LSTATUS --- + + RegOpenKeyExW :: proc( + hKey: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LSTATUS --- + + RegCloseKey :: proc( + hKey: HKEY, + ) -> LSTATUS --- + + RegGetValueW :: proc( + hkey: HKEY, + lpSubKey: LPCWSTR, + lpValue: LPCWSTR, + dwFlags: DWORD, + pdwType: LPDWORD, + pvData: PVOID, + pcbData: LPDWORD, + ) -> LSTATUS --- + + RegSetValueExW :: proc( + hKey: HKEY, + lpValueName: LPCWSTR, + Reserved: DWORD, + dwType: DWORD, + lpData: ^BYTE, + cbData: DWORD, + ) -> LSTATUS --- +} diff --git a/core/sys/windows/comdlg32.odin b/core/sys/windows/comdlg32.odin index 42a1fd60f..8284050f1 100644 --- a/core/sys/windows/comdlg32.odin +++ b/core/sys/windows/comdlg32.odin @@ -26,8 +26,6 @@ OPENFILENAMEW :: struct { lCustData: LPARAM, lpfnHook: LPOFNHOOKPROC, lpTemplateName: wstring, - lpEditInfo: rawptr, // LPEDITMENU, - lpstrPrompt: wstring, pvReserved: rawptr, dwReserved: DWORD, FlagsEx: DWORD, diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 898766361..4403a5dc3 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -7,6 +7,8 @@ foreign import gdi32 "system:Gdi32.lib" foreign gdi32 { GetStockObject :: proc(i: c_int) -> HGDIOBJ --- SelectObject :: proc(hdc: HDC, h: HGDIOBJ) -> HGDIOBJ --- + DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- + SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- @@ -65,6 +67,16 @@ foreign gdi32 { SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- GetDCBrushColor :: proc(hdc: HDC) -> COLORREF --- PatBlt :: proc(hdc: HDC, x, y, w, h: c_int, rop: DWORD) -> BOOL --- + Rectangle :: proc(hdc: HDC, left, top, right, bottom: c_int) -> BOOL --- + + CreateFontW :: proc( + cHeight, cWidth, cEscapement, cOrientation, cWeight: c_int, + bItalic, bUnderline, bStrikeOut, iCharSet, iOutPrecision: DWORD, + iClipPrecision, iQuality, iPitchAndFamily: DWORD, + pszFaceName: LPCWSTR, + ) -> HFONT --- + TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL --- + GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL --- } RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 98b93ffb9..8f6c63e42 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -329,7 +329,6 @@ foreign kernel32 { } -STANDARD_RIGHTS_REQUIRED :: DWORD(0x000F0000) SECTION_QUERY :: DWORD(0x0001) SECTION_MAP_WRITE :: DWORD(0x0002) SECTION_MAP_READ :: DWORD(0x0004) diff --git a/core/sys/windows/ole32.odin b/core/sys/windows/ole32.odin index 23fe888d2..4a4b470ea 100644 --- a/core/sys/windows/ole32.odin +++ b/core/sys/windows/ole32.odin @@ -11,8 +11,29 @@ COINIT :: enum DWORD { SPEED_OVER_MEMORY = 0x8, } +IUnknown :: struct { + using Vtbl: ^IUnknownVtbl, +} +IUnknownVtbl :: struct { + QueryInterface: proc "stdcall" (This: ^IUnknown, riid: REFIID, ppvObject: ^rawptr) -> HRESULT, + AddRef: proc "stdcall" (This: ^IUnknown) -> ULONG, + Release: proc "stdcall" (This: ^IUnknown) -> ULONG, +} + +LPUNKNOWN :: ^IUnknown + @(default_calling_convention="stdcall") foreign Ole32 { CoInitializeEx :: proc(reserved: rawptr, co_init: COINIT) -> HRESULT --- CoUninitialize :: proc() --- + + CoCreateInstance :: proc( + rclsid: REFCLSID, + pUnkOuter: LPUNKNOWN, + dwClsContext: DWORD, + riid: REFIID, + ppv: ^LPVOID, + ) -> HRESULT --- + + CoTaskMemFree :: proc(pv: rawptr) --- } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index a0649c5f3..d79197532 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -33,11 +33,15 @@ HGDIOBJ :: distinct HANDLE HBITMAP :: distinct HANDLE HGLOBAL :: distinct HANDLE HHOOK :: distinct HANDLE +HKEY :: distinct HANDLE +HDESK :: distinct HANDLE +HFONT :: distinct HANDLE BOOL :: distinct b32 BYTE :: distinct u8 BOOLEAN :: distinct b8 GROUP :: distinct c_uint LARGE_INTEGER :: distinct c_longlong +ULARGE_INTEGER :: distinct c_ulonglong LONG :: c_long UINT :: c_uint INT :: c_int @@ -55,6 +59,7 @@ DWORD_PTR :: ULONG_PTR LONG_PTR :: int UINT_PTR :: uintptr ULONG :: c_ulong +ULONGLONG :: c_ulonglong UCHAR :: BYTE NTSTATUS :: c.long COLORREF :: DWORD @@ -64,6 +69,8 @@ WPARAM :: UINT_PTR LRESULT :: LONG_PTR LPRECT :: ^RECT LPPOINT :: ^POINT +LSTATUS :: LONG +PHKEY :: ^HKEY UINT8 :: u8 UINT16 :: u16 @@ -117,6 +124,8 @@ LPWSADATA :: ^WSADATA LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO LPSTR :: ^CHAR LPWSTR :: ^WCHAR +OLECHAR :: WCHAR +LPOLESTR :: ^OLECHAR LPFILETIME :: ^FILETIME LPWSABUF :: ^WSABUF LPWSAOVERLAPPED :: distinct rawptr @@ -194,11 +203,8 @@ FILE_APPEND_DATA: DWORD : 0x00000004 FILE_WRITE_EA: DWORD : 0x00000010 FILE_WRITE_ATTRIBUTES: DWORD : 0x00000100 FILE_READ_ATTRIBUTES: DWORD : 0x000000080 -READ_CONTROL: DWORD : 0x00020000 -SYNCHRONIZE: DWORD : 0x00100000 GENERIC_READ: DWORD : 0x80000000 GENERIC_WRITE: DWORD : 0x40000000 -STANDARD_RIGHTS_WRITE: DWORD : READ_CONTROL FILE_GENERIC_WRITE: DWORD : STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | @@ -266,6 +272,385 @@ REASON_CONTEXT :: struct { } PREASON_CONTEXT :: ^REASON_CONTEXT +// RRF - Registry Routine Flags (for RegGetValue) +RRF_RT_REG_NONE :: 0x00000001 +RRF_RT_REG_SZ :: 0x00000002 +RRF_RT_REG_EXPAND_SZ :: 0x00000004 +RRF_RT_REG_BINARY :: 0x00000008 +RRF_RT_REG_DWORD :: 0x00000010 +RRF_RT_REG_MULTI_SZ :: 0x00000020 +RRF_RT_REG_QWORD :: 0x00000040 +RRF_RT_DWORD :: (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD) +RRF_RT_QWORD :: (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD) +RRF_RT_ANY :: 0x0000ffff +RRF_NOEXPAND :: 0x10000000 +RRF_ZEROONFAILURE :: 0x20000000 + +ACCESS_MASK :: DWORD +PACCESS_MASK :: ^ACCESS_MASK +REGSAM :: ACCESS_MASK + +// Reserved Key Handles. +HKEY_CLASSES_ROOT :: HKEY(uintptr(0x80000000)) +HKEY_CURRENT_USER :: HKEY(uintptr(0x80000001)) +HKEY_LOCAL_MACHINE :: HKEY(uintptr(0x80000002)) +HKEY_USERS :: HKEY(uintptr(0x80000003)) +HKEY_PERFORMANCE_DATA :: HKEY(uintptr(0x80000004)) +HKEY_PERFORMANCE_TEXT :: HKEY(uintptr(0x80000050)) +HKEY_PERFORMANCE_NLSTEXT :: HKEY(uintptr(0x80000060)) +HKEY_CURRENT_CONFIG :: HKEY(uintptr(0x80000005)) +HKEY_DYN_DATA :: HKEY(uintptr(0x80000006)) +HKEY_CURRENT_USER_LOCAL_SETTINGS :: HKEY(uintptr(0x80000007)) + +// The following are masks for the predefined standard access types +DELETE : DWORD : 0x00010000 +READ_CONTROL : DWORD : 0x00020000 +WRITE_DAC : DWORD : 0x00040000 +WRITE_OWNER : DWORD : 0x00080000 +SYNCHRONIZE : DWORD : 0x00100000 + +STANDARD_RIGHTS_REQUIRED : DWORD : 0x000F0000 +STANDARD_RIGHTS_READ : DWORD : READ_CONTROL +STANDARD_RIGHTS_WRITE : DWORD : READ_CONTROL +STANDARD_RIGHTS_EXECUTE : DWORD : READ_CONTROL +STANDARD_RIGHTS_ALL : DWORD : 0x001F0000 +SPECIFIC_RIGHTS_ALL : DWORD : 0x0000FFFF + +// Registry Specific Access Rights. +KEY_QUERY_VALUE :: 0x0001 +KEY_SET_VALUE :: 0x0002 +KEY_CREATE_SUB_KEY :: 0x0004 +KEY_ENUMERATE_SUB_KEYS :: 0x0008 +KEY_NOTIFY :: 0x0010 +KEY_CREATE_LINK :: 0x0020 +KEY_WOW64_32KEY :: 0x0200 +KEY_WOW64_64KEY :: 0x0100 +KEY_WOW64_RES :: 0x0300 + +KEY_READ :: (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE) +KEY_WRITE :: (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE) +KEY_EXECUTE :: (KEY_READ) & (~SYNCHRONIZE) +KEY_ALL_ACCESS :: (STANDARD_RIGHTS_ALL | + KEY_QUERY_VALUE | + KEY_SET_VALUE | + KEY_CREATE_SUB_KEY | + KEY_ENUMERATE_SUB_KEYS | + KEY_NOTIFY | + KEY_CREATE_LINK) & (~SYNCHRONIZE) + +// Open/Create Options +REG_OPTION_RESERVED :: 0x00000000 +REG_OPTION_NON_VOLATILE :: 0x00000000 +REG_OPTION_VOLATILE :: 0x00000001 +REG_OPTION_CREATE_LINK :: 0x00000002 +REG_OPTION_BACKUP_RESTORE :: 0x00000004 +REG_OPTION_OPEN_LINK :: 0x00000008 +REG_OPTION_DONT_VIRTUALIZE :: 0x00000010 + +REG_LEGAL_OPTION :: REG_OPTION_RESERVED | + REG_OPTION_NON_VOLATILE | + REG_OPTION_VOLATILE | + REG_OPTION_CREATE_LINK | + REG_OPTION_BACKUP_RESTORE | + REG_OPTION_OPEN_LINK | + REG_OPTION_DONT_VIRTUALIZE + +REG_OPEN_LEGAL_OPTION :: REG_OPTION_RESERVED | + REG_OPTION_BACKUP_RESTORE | + REG_OPTION_OPEN_LINK | + REG_OPTION_DONT_VIRTUALIZE + +// Key creation/open disposition +REG_CREATED_NEW_KEY :: 0x00000001 +REG_OPENED_EXISTING_KEY :: 0x00000002 + +// hive format to be used by Reg(Nt)SaveKeyEx +REG_STANDARD_FORMAT :: 1 +REG_LATEST_FORMAT :: 2 +REG_NO_COMPRESSION :: 4 + +// Key restore & hive load flags +REG_WHOLE_HIVE_VOLATILE :: 0x00000001 +REG_REFRESH_HIVE :: 0x00000002 +REG_NO_LAZY_FLUSH :: 0x00000004 +REG_FORCE_RESTORE :: 0x00000008 +REG_APP_HIVE :: 0x00000010 +REG_PROCESS_PRIVATE :: 0x00000020 +REG_START_JOURNAL :: 0x00000040 +REG_HIVE_EXACT_FILE_GROWTH :: 0x00000080 +REG_HIVE_NO_RM :: 0x00000100 +REG_HIVE_SINGLE_LOG :: 0x00000200 +REG_BOOT_HIVE :: 0x00000400 +REG_LOAD_HIVE_OPEN_HANDLE :: 0x00000800 +REG_FLUSH_HIVE_FILE_GROWTH :: 0x00001000 +REG_OPEN_READ_ONLY :: 0x00002000 +REG_IMMUTABLE :: 0x00004000 +REG_NO_IMPERSONATION_FALLBACK :: 0x00008000 +REG_APP_HIVE_OPEN_READ_ONLY :: REG_OPEN_READ_ONLY + +// Unload Flags +REG_FORCE_UNLOAD :: 1 +REG_UNLOAD_LEGAL_FLAGS :: REG_FORCE_UNLOAD + +// Notify filter values +REG_NOTIFY_CHANGE_NAME :: 0x00000001 +REG_NOTIFY_CHANGE_ATTRIBUTES :: 0x00000002 +REG_NOTIFY_CHANGE_LAST_SET :: 0x00000004 +REG_NOTIFY_CHANGE_SECURITY :: 0x00000008 +REG_NOTIFY_THREAD_AGNOSTIC :: 0x10000000 + +REG_LEGAL_CHANGE_FILTER :: REG_NOTIFY_CHANGE_NAME | + REG_NOTIFY_CHANGE_ATTRIBUTES | + REG_NOTIFY_CHANGE_LAST_SET | + REG_NOTIFY_CHANGE_SECURITY | + REG_NOTIFY_THREAD_AGNOSTIC + +// Predefined Value Types. +REG_NONE :: 0 +REG_SZ :: 1 +REG_EXPAND_SZ :: 2 +REG_BINARY :: 3 +REG_DWORD :: 4 +REG_DWORD_LITTLE_ENDIAN :: 4 +REG_DWORD_BIG_ENDIAN :: 5 +REG_LINK :: 6 +REG_MULTI_SZ :: 7 +REG_RESOURCE_LIST :: 8 +REG_FULL_RESOURCE_DESCRIPTOR :: 9 +REG_RESOURCE_REQUIREMENTS_LIST :: 10 +REG_QWORD :: 11 +REG_QWORD_LITTLE_ENDIAN :: 11 + +BSMINFO :: struct { + cbSize: UINT, + hdesk: HDESK, + hwnd: HWND, + luid: LUID, +} +PBSMINFO :: ^BSMINFO + +// Broadcast Special Message Recipient list +BSM_ALLCOMPONENTS :: 0x00000000 +BSM_VXDS :: 0x00000001 +BSM_NETDRIVER :: 0x00000002 +BSM_INSTALLABLEDRIVERS :: 0x00000004 +BSM_APPLICATIONS :: 0x00000008 +BSM_ALLDESKTOPS :: 0x00000010 + +// Broadcast Special Message Flags +BSF_QUERY :: 0x00000001 +BSF_IGNORECURRENTTASK :: 0x00000002 +BSF_FLUSHDISK :: 0x00000004 +BSF_NOHANG :: 0x00000008 +BSF_POSTMESSAGE :: 0x00000010 +BSF_FORCEIFHUNG :: 0x00000020 +BSF_NOTIMEOUTIFNOTHUNG :: 0x00000040 +BSF_ALLOWSFW :: 0x00000080 +BSF_SENDNOTIFYMESSAGE :: 0x00000100 +BSF_RETURNHDESK :: 0x00000200 +BSF_LUID :: 0x00000400 + +BROADCAST_QUERY_DENY :: 0x424D5144 + +// Special HWND value for use with PostMessage() and SendMessage() +HWND_BROADCAST :: HWND(uintptr(0xffff)) +HWND_MESSAGE :: HWND(~uintptr(0) - 2) // -3 + +// Color Types +CTLCOLOR_MSGBOX :: 0 +CTLCOLOR_EDIT :: 1 +CTLCOLOR_LISTBOX :: 2 +CTLCOLOR_BTN :: 3 +CTLCOLOR_DLG :: 4 +CTLCOLOR_SCROLLBAR :: 5 +CTLCOLOR_STATIC :: 6 +CTLCOLOR_MAX :: 7 + +COLOR_SCROLLBAR :: 0 +COLOR_BACKGROUND :: 1 +COLOR_ACTIVECAPTION :: 2 +COLOR_INACTIVECAPTION :: 3 +COLOR_MENU :: 4 +COLOR_WINDOW :: 5 +COLOR_WINDOWFRAME :: 6 +COLOR_MENUTEXT :: 7 +COLOR_WINDOWTEXT :: 8 +COLOR_CAPTIONTEXT :: 9 +COLOR_ACTIVEBORDER :: 10 +COLOR_INACTIVEBORDER :: 11 +COLOR_APPWORKSPACE :: 12 +COLOR_HIGHLIGHT :: 13 +COLOR_HIGHLIGHTTEXT :: 14 +COLOR_BTNFACE :: 15 +COLOR_BTNSHADOW :: 16 +COLOR_GRAYTEXT :: 17 +COLOR_BTNTEXT :: 18 +COLOR_INACTIVECAPTIONTEXT :: 19 +COLOR_BTNHIGHLIGHT :: 20 + +COLOR_3DDKSHADOW :: 21 +COLOR_3DLIGHT :: 22 +COLOR_INFOTEXT :: 23 +COLOR_INFOBK :: 24 +COLOR_HOTLIGHT :: 26 +COLOR_GRADIENTACTIVECAPTION :: 27 +COLOR_GRADIENTINACTIVECAPTION :: 28 +COLOR_MENUHILIGHT :: 29 +COLOR_MENUBAR :: 30 + +COLOR_DESKTOP :: COLOR_BACKGROUND +COLOR_3DFACE :: COLOR_BTNFACE +COLOR_3DSHADOW :: COLOR_BTNSHADOW +COLOR_3DHIGHLIGHT :: COLOR_BTNHIGHLIGHT +COLOR_3DHILIGHT :: COLOR_BTNHIGHLIGHT +COLOR_BTNHILIGHT :: COLOR_BTNHIGHLIGHT + +// Combo Box Notification Codes +CBN_ERRSPACE :: -1 +CBN_SELCHANGE :: 1 +CBN_DBLCLK :: 2 +CBN_SETFOCUS :: 3 +CBN_KILLFOCUS :: 4 +CBN_EDITCHANGE :: 5 +CBN_EDITUPDATE :: 6 +CBN_DROPDOWN :: 7 +CBN_CLOSEUP :: 8 +CBN_SELENDOK :: 9 +CBN_SELENDCANCEL :: 10 + +// Combo Box styles +CBS_SIMPLE :: 0x0001 +CBS_DROPDOWN :: 0x0002 +CBS_DROPDOWNLIST :: 0x0003 +CBS_OWNERDRAWFIXED :: 0x0010 +CBS_OWNERDRAWVARIABLE :: 0x0020 +CBS_AUTOHSCROLL :: 0x0040 +CBS_OEMCONVERT :: 0x0080 +CBS_SORT :: 0x0100 +CBS_HASSTRINGS :: 0x0200 +CBS_NOINTEGRALHEIGHT :: 0x0400 +CBS_DISABLENOSCROLL :: 0x0800 +CBS_UPPERCASE :: 0x2000 +CBS_LOWERCASE :: 0x4000 + +// User Button Notification Codes +BN_CLICKED :: 0 +BN_PAINT :: 1 +BN_HILITE :: 2 +BN_UNHILITE :: 3 +BN_DISABLE :: 4 +BN_DOUBLECLICKED :: 5 +BN_PUSHED :: BN_HILITE +BN_UNPUSHED :: BN_UNHILITE +BN_DBLCLK :: BN_DOUBLECLICKED +BN_SETFOCUS :: 6 +BN_KILLFOCUS :: 7 + +// Button Control Styles +BS_PUSHBUTTON :: 0x00000000 +BS_DEFPUSHBUTTON :: 0x00000001 +BS_CHECKBOX :: 0x00000002 +BS_AUTOCHECKBOX :: 0x00000003 +BS_RADIOBUTTON :: 0x00000004 +BS_3STATE :: 0x00000005 +BS_AUTO3STATE :: 0x00000006 +BS_GROUPBOX :: 0x00000007 +BS_USERBUTTON :: 0x00000008 +BS_AUTORADIOBUTTON :: 0x00000009 +BS_PUSHBOX :: 0x0000000A +BS_OWNERDRAW :: 0x0000000B +BS_TYPEMASK :: 0x0000000F +BS_LEFTTEXT :: 0x00000020 +BS_TEXT :: 0x00000000 +BS_ICON :: 0x00000040 +BS_BITMAP :: 0x00000080 +BS_LEFT :: 0x00000100 +BS_RIGHT :: 0x00000200 +BS_CENTER :: 0x00000300 +BS_TOP :: 0x00000400 +BS_BOTTOM :: 0x00000800 +BS_VCENTER :: 0x00000C00 +BS_PUSHLIKE :: 0x00001000 +BS_MULTILINE :: 0x00002000 +BS_NOTIFY :: 0x00004000 +BS_FLAT :: 0x00008000 +BS_RIGHTBUTTON :: BS_LEFTTEXT + +// Button Control Messages +BST_UNCHECKED :: 0x0000 +BST_CHECKED :: 0x0001 +BST_INDETERMINATE :: 0x0002 +BST_PUSHED :: 0x0004 +BST_FOCUS :: 0x0008 + +// Static Control Constants +SS_LEFT :: 0x00000000 +SS_CENTER :: 0x00000001 +SS_RIGHT :: 0x00000002 +SS_ICON :: 0x00000003 +SS_BLACKRECT :: 0x00000004 +SS_GRAYRECT :: 0x00000005 +SS_WHITERECT :: 0x00000006 +SS_BLACKFRAME :: 0x00000007 +SS_GRAYFRAME :: 0x00000008 +SS_WHITEFRAME :: 0x00000009 +SS_USERITEM :: 0x0000000A +SS_SIMPLE :: 0x0000000B +SS_LEFTNOWORDWRAP :: 0x0000000C +SS_OWNERDRAW :: 0x0000000D +SS_BITMAP :: 0x0000000E +SS_ENHMETAFILE :: 0x0000000F +SS_ETCHEDHORZ :: 0x00000010 +SS_ETCHEDVERT :: 0x00000011 +SS_ETCHEDFRAME :: 0x00000012 +SS_TYPEMASK :: 0x0000001F +SS_REALSIZECONTROL :: 0x00000040 +SS_NOPREFIX :: 0x00000080 +SS_NOTIFY :: 0x00000100 +SS_CENTERIMAGE :: 0x00000200 +SS_RIGHTJUST :: 0x00000400 +SS_REALSIZEIMAGE :: 0x00000800 +SS_SUNKEN :: 0x00001000 +SS_EDITCONTROL :: 0x00002000 +SS_ENDELLIPSIS :: 0x00004000 +SS_PATHELLIPSIS :: 0x00008000 +SS_WORDELLIPSIS :: 0x0000C000 +SS_ELLIPSISMASK :: 0x0000C000 + +// Edit Control Styles +ES_LEFT :: 0x0000 +ES_CENTER :: 0x0001 +ES_RIGHT :: 0x0002 +ES_MULTILINE :: 0x0004 +ES_UPPERCASE :: 0x0008 +ES_LOWERCASE :: 0x0010 +ES_PASSWORD :: 0x0020 +ES_AUTOVSCROLL :: 0x0040 +ES_AUTOHSCROLL :: 0x0080 +ES_NOHIDESEL :: 0x0100 +ES_OEMCONVERT :: 0x0400 +ES_READONLY :: 0x0800 +ES_WANTRETURN :: 0x1000 +ES_NUMBER :: 0x2000 + +// Font Weights +FW_DONTCARE :: 0 +FW_THIN :: 100 +FW_EXTRALIGHT :: 200 +FW_LIGHT :: 300 +FW_NORMAL :: 400 +FW_MEDIUM :: 500 +FW_SEMIBOLD :: 600 +FW_BOLD :: 700 +FW_EXTRABOLD :: 800 +FW_HEAVY :: 900 + +FW_ULTRALIGHT :: FW_EXTRALIGHT +FW_REGULAR :: FW_NORMAL +FW_DEMIBOLD :: FW_SEMIBOLD +FW_ULTRABOLD :: FW_EXTRABOLD +FW_BLACK :: FW_HEAVY + PTIMERAPCROUTINE :: #type proc "stdcall" (lpArgToCompletionRoutine: LPVOID, dwTimerLowValue, dwTimerHighValue: DWORD) TIMERPROC :: #type proc "stdcall" (HWND, UINT, UINT_PTR, DWORD) @@ -355,6 +740,8 @@ MSG :: struct { pt: POINT, } +LPMSG :: ^MSG + PAINTSTRUCT :: struct { hdc: HDC, fErase: BOOL, @@ -514,6 +901,9 @@ WS_TILEDWINDOW : UINT : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKF WS_VISIBLE : UINT : 0x1000_0000 WS_VSCROLL : UINT : 0x0020_0000 +PBS_SMOOTH :: 0x01 +PBS_VERTICAL :: 0x04 + QS_ALLEVENTS : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY QS_ALLINPUT : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE QS_ALLPOSTMESSAGE : UINT : 0x0100 @@ -1126,34 +1516,6 @@ STD_ERROR_HANDLE: DWORD : ~DWORD(0) -12 + 1 PROGRESS_CONTINUE: DWORD : 0 -ERROR_FILE_NOT_FOUND: DWORD : 2 -ERROR_PATH_NOT_FOUND: DWORD : 3 -ERROR_ACCESS_DENIED: DWORD : 5 -ERROR_NOT_ENOUGH_MEMORY: DWORD : 8 -ERROR_INVALID_HANDLE: DWORD : 6 -ERROR_NO_MORE_FILES: DWORD : 18 -ERROR_SHARING_VIOLATION: DWORD : 32 -ERROR_LOCK_VIOLATION: DWORD : 33 -ERROR_HANDLE_EOF: DWORD : 38 -ERROR_NOT_SUPPORTED: DWORD : 50 -ERROR_FILE_EXISTS: DWORD : 80 -ERROR_INVALID_PARAMETER: DWORD : 87 -ERROR_BROKEN_PIPE: DWORD : 109 -ERROR_CALL_NOT_IMPLEMENTED: DWORD : 120 -ERROR_INSUFFICIENT_BUFFER: DWORD : 122 -ERROR_INVALID_NAME: DWORD : 123 -ERROR_BAD_ARGUMENTS: DWORD: 160 -ERROR_LOCK_FAILED: DWORD : 167 -ERROR_ALREADY_EXISTS: DWORD : 183 -ERROR_NO_DATA: DWORD : 232 -ERROR_ENVVAR_NOT_FOUND: DWORD : 203 -ERROR_OPERATION_ABORTED: DWORD : 995 -ERROR_IO_PENDING: DWORD : 997 -ERROR_TIMEOUT: DWORD : 0x5B4 -ERROR_NO_UNICODE_TRANSLATION: DWORD : 1113 - -E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001 - INVALID_HANDLE :: HANDLE(~uintptr(0)) INVALID_HANDLE_VALUE :: INVALID_HANDLE @@ -1482,7 +1844,41 @@ PGUID :: ^GUID PCGUID :: ^GUID LPGUID :: ^GUID LPCGUID :: ^GUID +REFIID :: ^GUID +REFGUID :: GUID +IID :: GUID +CLSID :: GUID +REFCLSID :: ^CLSID + +CLSCTX_INPROC_SERVER :: 0x1 +CLSCTX_INPROC_HANDLER :: 0x2 +CLSCTX_LOCAL_SERVER :: 0x4 +CLSCTX_INPROC_SERVER16 :: 0x8 +CLSCTX_REMOTE_SERVER :: 0x10 +CLSCTX_INPROC_HANDLER16 :: 0x20 +CLSCTX_RESERVED1 :: 0x40 +CLSCTX_RESERVED2 :: 0x80 +CLSCTX_RESERVED3 :: 0x100 +CLSCTX_RESERVED4 :: 0x200 +CLSCTX_NO_CODE_DOWNLOAD :: 0x400 +CLSCTX_RESERVED5 :: 0x800 +CLSCTX_NO_CUSTOM_MARSHAL :: 0x1000 +CLSCTX_ENABLE_CODE_DOWNLOAD :: 0x2000 +CLSCTX_NO_FAILURE_LOG :: 0x4000 +CLSCTX_DISABLE_AAA :: 0x8000 +CLSCTX_ENABLE_AAA :: 0x10000 +CLSCTX_FROM_DEFAULT_CONTEXT :: 0x20000 +CLSCTX_ACTIVATE_X86_SERVER :: 0x40000 +CLSCTX_ACTIVATE_32_BIT_SERVER :: CLSCTX_ACTIVATE_X86_SERVER +CLSCTX_ACTIVATE_64_BIT_SERVER :: 0x80000 +CLSCTX_ENABLE_CLOAKING :: 0x100000 +CLSCTX_APPCONTAINER :: 0x400000 +CLSCTX_ACTIVATE_AAA_AS_IU :: 0x800000 +CLSCTX_RESERVED6 :: 0x1000000 +CLSCTX_ACTIVATE_ARM32_SERVER :: 0x2000000 +CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION :: 0x4000000 +CLSCTX_PS_DLL :: 0x80000000 WSAPROTOCOLCHAIN :: struct { ChainLen: c_int, @@ -2329,4 +2725,466 @@ IMAGE_EXPORT_DIRECTORY :: struct { AddressOfFunctions: DWORD, // RVA from base of image AddressOfNames: DWORD, // RVA from base of image AddressOfNameOrdinals: DWORD, // RVA from base of image -} \ No newline at end of file +} + +SICHINTF :: DWORD +SHCONTF :: DWORD +SFGAOF :: ULONG +FILEOPENDIALOGOPTIONS :: DWORD +REFPROPERTYKEY :: ^PROPERTYKEY +REFPROPVARIANT :: ^PROPVARIANT + +SIGDN :: enum c_int { + NORMALDISPLAY = 0, + PARENTRELATIVEPARSING = -2147385343, // 0x80018001 + DESKTOPABSOLUTEPARSING = -2147319808, // 0x80028000 + PARENTRELATIVEEDITING = -2147282943, // 0x80031001 + DESKTOPABSOLUTEEDITING = -2147172352, // 0x8004c000 + FILESYSPATH = -2147123200, // 0x80058000 + URL = -2147057664, // 0x80068000 + PARENTRELATIVEFORADDRESSBAR = -2146975743, // 0x8007c001 + PARENTRELATIVE = -2146959359, // 0x80080001 + PARENTRELATIVEFORUI = -2146877439, // 0x80094001 +} + +SIATTRIBFLAGS :: enum c_int { + AND = 0x1, + OR = 0x2, + APPCOMPAT = 0x3, + MASK = 0x3, + ALLITEMS = 0x4000, +} + +FDAP :: enum c_int { + BOTTOM = 0, + TOP = 1, +} + +FDE_SHAREVIOLATION_RESPONSE :: enum c_int { + DEFAULT = 0, + ACCEPT = 1, + REFUSE = 2, +} + +GETPROPERTYSTOREFLAGS :: enum c_int { + DEFAULT = 0, + HANDLERPROPERTIESONLY = 0x1, + READWRITE = 0x2, + TEMPORARY = 0x4, + FASTPROPERTIESONLY = 0x8, + OPENSLOWITEM = 0x10, + DELAYCREATION = 0x20, + BESTEFFORT = 0x40, + NO_OPLOCK = 0x80, + PREFERQUERYPROPERTIES = 0x100, + EXTRINSICPROPERTIES = 0x200, + EXTRINSICPROPERTIESONLY = 0x400, + VOLATILEPROPERTIES = 0x800, + VOLATILEPROPERTIESONLY = 0x1000, + MASK_VALID = 0x1fff, +} + +PROPERTYKEY :: struct { + fmtid: GUID, + pid: DWORD, +} + +BIND_OPTS :: struct { + cbStruct: DWORD, + grfFlags: DWORD, + grfMode: DWORD, + dwTickCountDeadline: DWORD, +} + +STATSTG :: struct { + pwcsName: LPOLESTR, + type: DWORD, + cbSize: ULARGE_INTEGER, + mtime: FILETIME, + ctime: FILETIME, + atime: FILETIME, + grfMode: DWORD, + grfLocksSupported: DWORD, + clsid: CLSID, + grfStateBits: DWORD, + reserved: DWORD, +} + +COMDLG_FILTERSPEC :: struct { + pszName, pszSpec: LPCWSTR, +} + +DECIMAL :: struct { + wReserved: USHORT, + _: struct #raw_union { + _: struct { + scale, sign: BYTE, + }, + signscale: USHORT, + }, + Hi32: ULONG, + _: struct #raw_union { + _: struct { + Lo32, Mid32: ULONG, + }, + Lo64: ULONGLONG, + }, +} + +// NOTE(ftphikari): bigger definition of this struct is ignored +PROPVARIANT :: struct { + decVal: DECIMAL, +} + +SICHINT_DISPLAY :: 0 +SICHINT_ALLFIELDS :: -2147483648 // 0x80000000 +SICHINT_CANONICAL :: 0x10000000 +SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL :: 0x20000000 + +FOS_OVERWRITEPROMPT :: 0x2 +FOS_STRICTFILETYPES :: 0x4 +FOS_NOCHANGEDIR :: 0x8 +FOS_PICKFOLDERS :: 0x20 +FOS_FORCEFILESYSTEM :: 0x40 +FOS_ALLNONSTORAGEITEMS :: 0x80 +FOS_NOVALIDATE :: 0x100 +FOS_ALLOWMULTISELECT :: 0x200 +FOS_PATHMUSTEXIST :: 0x800 +FOS_FILEMUSTEXIST :: 0x1000 +FOS_CREATEPROMPT :: 0x2000 +FOS_SHAREAWARE :: 0x4000 +FOS_NOREADONLYRETURN :: 0x8000 +FOS_NOTESTFILECREATE :: 0x10000 +FOS_HIDEMRUPLACES :: 0x20000 +FOS_HIDEPINNEDPLACES :: 0x40000 +FOS_NODEREFERENCELINKS :: 0x100000 +FOS_OKBUTTONNEEDSINTERACTION :: 0x200000 +FOS_DONTADDTORECENT :: 0x2000000 +FOS_FORCESHOWHIDDEN :: 0x10000000 +FOS_DEFAULTNOMINIMODE :: 0x20000000 +FOS_FORCEPREVIEWPANEON :: 0x40000000 +FOS_SUPPORTSTREAMABLEITEMS :: 0x80000000 + +SHCONTF_CHECKING_FOR_CHILDREN :: 0x10 +SHCONTF_FOLDERS :: 0x20 +SHCONTF_NONFOLDERS :: 0x40 +SHCONTF_INCLUDEHIDDEN :: 0x80 +SHCONTF_INIT_ON_FIRST_NEXT :: 0x100 +SHCONTF_NETPRINTERSRCH :: 0x200 +SHCONTF_SHAREABLE :: 0x400 +SHCONTF_STORAGE :: 0x800 +SHCONTF_NAVIGATION_ENUM :: 0x1000 +SHCONTF_FASTITEMS :: 0x2000 +SHCONTF_FLATLIST :: 0x4000 +SHCONTF_ENABLE_ASYNC :: 0x8000 +SHCONTF_INCLUDESUPERHIDDEN :: 0x10000 + +CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}} +CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}} + +IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}} +IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}} +IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}} + +IModalWindow :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IModalWindowVtbl, +} +IModalWindowVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Show: proc "stdcall" (this: ^IModalWindow, hwndOwner: HWND) -> HRESULT, +} + +ISequentialStream :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^ISequentialStreamVtbl, +} +ISequentialStreamVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Read: proc "stdcall" (this: ^ISequentialStream, pv: rawptr, cb: ULONG, pcbRead: ^ULONG) -> HRESULT, + Write: proc "stdcall" (this: ^ISequentialStream, pv: rawptr, cb: ULONG, pcbWritten: ^ULONG) -> HRESULT, +} + +IStream :: struct #raw_union { + #subtype ISequentialStream: ISequentialStream, + using Vtbl: ^IStreamVtbl, +} +IStreamVtbl :: struct { + using ISequentialStreamVtbl: ISequentialStreamVtbl, + Seek: proc "stdcall" (this: ^IStream, dlibMove: LARGE_INTEGER, dwOrigin: DWORD, plibNewPosition: ^ULARGE_INTEGER) -> HRESULT, + SetSize: proc "stdcall" (this: ^IStream, libNewSize: ULARGE_INTEGER) -> HRESULT, + CopyTo: proc "stdcall" (this: ^IStream, pstm: ^IStream, cb: ULARGE_INTEGER, pcbRead: ^ULARGE_INTEGER, pcbWritten: ^ULARGE_INTEGER) -> HRESULT, + Commit: proc "stdcall" (this: ^IStream, grfCommitFlags: DWORD) -> HRESULT, + Revert: proc "stdcall" (this: ^IStream) -> HRESULT, + LockRegion: proc "stdcall" (this: ^IStream, libOffset: ULARGE_INTEGER, cb: ULARGE_INTEGER, dwLockType: DWORD) -> HRESULT, + UnlockRegion: proc "stdcall" (this: ^IStream, libOffset: ULARGE_INTEGER, cb: ULARGE_INTEGER, dwLockType: DWORD) -> HRESULT, + Stat: proc "stdcall" (this: ^IStream, pstatstg: ^STATSTG, grfStatFlag: DWORD) -> HRESULT, + Clone: proc "stdcall" (this: ^IStream, ppstm: ^^IStream) -> HRESULT, +} + +IPersist :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IPersistVtbl, +} +IPersistVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + GetClassID: proc "stdcall" (this: ^IPersist, pClassID: ^CLSID) -> HRESULT, +} + +IPersistStream :: struct #raw_union { + #subtype IPersist: IPersist, + using Vtbl: ^IPersistStreamVtbl, +} +IPersistStreamVtbl :: struct { + using IPersistVtbl: IPersistVtbl, + IsDirty: proc "stdcall" (this: ^IPersistStream) -> HRESULT, + Load: proc "stdcall" (this: ^IPersistStream, pStm: ^IStream) -> HRESULT, + Save: proc "stdcall" (this: ^IPersistStream, pStm: ^IStream, fClearDirty: BOOL) -> HRESULT, + GetSizeMax: proc "stdcall" (this: ^IPersistStream, pcbSize: ^ULARGE_INTEGER) -> HRESULT, +} + +IMoniker :: struct #raw_union { + #subtype IPersistStream: IPersistStream, + using Vtbl: ^IMonikerVtbl, +} +IMonikerVtbl :: struct { + using IPersistStreamVtbl: IPersistStreamVtbl, + BindToObject: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, pmkToLeft: ^IMoniker, riidResult: REFIID, ppvResult: ^rawptr) -> HRESULT, + BindToStorage: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, pmkToLeft: ^IMoniker, riid: REFIID, ppvObj: ^rawptr) -> HRESULT, + Reduce: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, dwReduceHowFar: DWORD, ppmkToLeft: ^^IMoniker, ppmkReduced: ^^IMoniker) -> HRESULT, + ComposeWith: proc "stdcall" (this: ^IMoniker, pmkRight: ^IMoniker, fOnlyIfNotGeneric: BOOL, ppmkComposite: ^^IMoniker) -> HRESULT, + Enum: proc "stdcall" (this: ^IMoniker, fForward: BOOL, ppenumMoniker: ^^IEnumMoniker) -> HRESULT, + IsEqual: proc "stdcall" (this: ^IMoniker, pmkOtherMoniker: ^IMoniker) -> HRESULT, + Hash: proc "stdcall" (this: ^IMoniker, pdwHash: ^DWORD) -> HRESULT, + IsRunning: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, pmkToLeft: ^IMoniker, pmkNewlyRunning: ^IMoniker) -> HRESULT, + GetTimeOfLastChange: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, pmkToLeft: ^IMoniker, pFileTime: ^FILETIME) -> HRESULT, + Inverse: proc "stdcall" (this: ^IMoniker, ppmk: ^^IMoniker) -> HRESULT, + CommonPrefixWith: proc "stdcall" (this: ^IMoniker, pmkOther: ^IMoniker, ppmkPrefix: ^^IMoniker) -> HRESULT, + RelativePathTo: proc "stdcall" (this: ^IMoniker, pmkOther: ^IMoniker, ppmkRelPath: ^^IMoniker) -> HRESULT, + GetDisplayName: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, pmkToLeft: ^IMoniker, ppszDisplayName: ^LPOLESTR) -> HRESULT, + ParseDisplayName: proc "stdcall" (this: ^IMoniker, pbc: ^IBindCtx, pmkToLeft: ^IMoniker, pszDisplayName: LPOLESTR, pchEaten: ^ULONG, ppmkOut: ^^IMoniker) -> HRESULT, + IsSystemMoniker: proc "stdcall" (this: ^IMoniker, pdwMksys: ^DWORD) -> HRESULT, +} + +IEnumMoniker :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IEnumMonikerVtbl, +} +IEnumMonikerVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Next: proc "stdcall" (this: ^IEnumMoniker, celt: ULONG, rgelt: ^^IMoniker, pceltFetched: ^ULONG) -> HRESULT, + Skip: proc "stdcall" (this: ^IEnumMoniker, celt: ULONG) -> HRESULT, + Reset: proc "stdcall" (this: ^IEnumMoniker) -> HRESULT, + Clone: proc "stdcall" (this: ^IEnumMoniker, ppenum: ^^IEnumMoniker) -> HRESULT, +} + +IRunningObjectTable :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IRunningObjectTableVtbl, +} +IRunningObjectTableVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Register: proc "stdcall" (this: ^IRunningObjectTable, grfFlags: DWORD, punkObject: ^IUnknown, pmkObjectName: ^IMoniker, pdwRegister: ^DWORD) -> HRESULT, + Revoke: proc "stdcall" (this: ^IRunningObjectTable, dwRegister: DWORD) -> HRESULT, + IsRunning: proc "stdcall" (this: ^IRunningObjectTable, pmkObjectName: ^IMoniker) -> HRESULT, + GetObject: proc "stdcall" (this: ^IRunningObjectTable, pmkObjectName: ^IMoniker, ppunkObject: ^^IUnknown) -> HRESULT, + NoteChangeTime: proc "stdcall" (this: ^IRunningObjectTable, dwRegister: DWORD, pfiletime: ^FILETIME) -> HRESULT, + GetTimeOfLastChange: proc "stdcall" (this: ^IRunningObjectTable, pmkObjectName: ^IMoniker, pfiletime: ^FILETIME) -> HRESULT, + EnumRunning: proc "stdcall" (this: ^IRunningObjectTable, ppenumMoniker: ^^IEnumMoniker) -> HRESULT, +} + +IEnumString :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IEnumStringVtbl, +} +IEnumStringVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Next: proc "stdcall" (this: ^IEnumString, celt: ULONG, rgelt: ^LPOLESTR, pceltFetched: ^ULONG) -> HRESULT, + Skip: proc "stdcall" (this: ^IEnumString, celt: ULONG) -> HRESULT, + Reset: proc "stdcall" (this: ^IEnumString) -> HRESULT, + Clone: proc "stdcall" (this: ^IEnumString, ppenum: ^^IEnumString) -> HRESULT, +} + +IBindCtx :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IBindCtxVtbl, +} +IBindCtxVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + RegisterObjectBound: proc "stdcall" (this: ^IBindCtx, punk: ^IUnknown) -> HRESULT, + RevokeObjectBound: proc "stdcall" (this: ^IBindCtx, punk: ^IUnknown) -> HRESULT, + ReleaseBoundObjects: proc "stdcall" (this: ^IBindCtx) -> HRESULT, + SetBindOptions: proc "stdcall" (this: ^IBindCtx, pbindopts: ^BIND_OPTS) -> HRESULT, + GetBindOptions: proc "stdcall" (this: ^IBindCtx, pbindopts: ^BIND_OPTS) -> HRESULT, + GetRunningObjectTable: proc "stdcall" (this: ^IBindCtx, pprot: ^^IRunningObjectTable) -> HRESULT, + RegisterObjectParam: proc "stdcall" (this: ^IBindCtx, pszKey: LPOLESTR, punk: ^IUnknown) -> HRESULT, + GetObjectParam: proc "stdcall" (this: ^IBindCtx, pszKey: LPOLESTR, ppunk: ^^IUnknown) -> HRESULT, + EnumObjectParam: proc "stdcall" (this: ^IBindCtx, ppenum: ^^IEnumString) -> HRESULT, + RevokeObjectParam: proc "stdcall" (this: ^IBindCtx, pszKey: LPOLESTR) -> HRESULT, +} + +IEnumShellItems :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IEnumShellItemsVtbl, +} +IEnumShellItemsVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + Next: proc "stdcall" (this: ^IEnumShellItems, celt: ULONG, rgelt: ^^IShellItem, pceltFetched: ^ULONG) -> HRESULT, + Skip: proc "stdcall" (this: ^IEnumShellItems, celt: ULONG) -> HRESULT, + Reset: proc "stdcall" (this: ^IEnumShellItems) -> HRESULT, + Clone: proc "stdcall" (this: ^IEnumShellItems, ppenum: ^^IEnumShellItems) -> HRESULT, +} + +IShellItem :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IShellItemVtbl, +} +IShellItemVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + BindToHandler: proc "stdcall" (this: ^IShellItem, pbc: ^IBindCtx, bhid: REFGUID, riid: REFIID, ppv: ^rawptr) -> HRESULT, + GetParent: proc "stdcall" (this: ^IShellItem, ppsiFolder: ^^IShellItem) -> HRESULT, + GetDisplayName: proc "stdcall" (this: ^IShellItem, sigdnName: SIGDN, ppszName: ^LPWSTR) -> HRESULT, + GetAttributes: proc "stdcall" (this: ^IShellItem, sfgaoMask: SFGAOF, psfgaoAttribs: ^SFGAOF) -> HRESULT, + Compare: proc "stdcall" (this: ^IShellItem, psi: ^IShellItem, hint: SICHINTF, piOrder: ^c_int) -> HRESULT, +} + +IShellItemArray :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IShellItemArrayVtbl, +} +IShellItemArrayVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + BindToHandler: proc "stdcall" (this: ^IShellItemArray, pbc: ^IBindCtx, bhid: REFGUID, riid: REFIID, ppvOut: ^rawptr) -> HRESULT, + GetPropertyStore: proc "stdcall" (this: ^IShellItemArray, flags: GETPROPERTYSTOREFLAGS, riid: REFIID, ppv: ^rawptr) -> HRESULT, + GetPropertyDescriptionList: proc "stdcall" (this: ^IShellItemArray, keyType: REFPROPERTYKEY, riid: REFIID, ppv: ^rawptr) -> HRESULT, + GetAttributes: proc "stdcall" (this: ^IShellItemArray, AttribFlags: SIATTRIBFLAGS, sfgaoMask: SFGAOF, psfgaoAttribs: ^SFGAOF) -> HRESULT, + GetCount: proc "stdcall" (this: ^IShellItemArray, pdwNumItems: ^DWORD) -> HRESULT, + GetItemAt: proc "stdcall" (this: ^IShellItemArray, dwIndex: DWORD, ppsi: ^^IShellItem) -> HRESULT, + EnumItems: proc "stdcall" (this: ^IShellItemArray, ppenumShellItems: ^^IEnumShellItems) -> HRESULT, +} + +IFileDialogEvents :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IFileDialogEventsVtbl, +} +IFileDialogEventsVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + OnFileOk: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog) -> HRESULT, + OnFolderChanging: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog, psiFolder: ^IShellItem) -> HRESULT, + OnFolderChange: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog) -> HRESULT, + OnSelectionChange: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog) -> HRESULT, + OnShareViolation: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog, psi: ^IShellItem, pResponse: ^FDE_SHAREVIOLATION_RESPONSE) -> HRESULT, + OnTypeChange: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog) -> HRESULT, + OnOverwrite: proc "stdcall" (this: ^IFileDialogEvents, pfd: ^IFileDialog, psi: ^IShellItem, pResponse: ^FDE_SHAREVIOLATION_RESPONSE) -> HRESULT, +} + +IShellItemFilter :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IShellItemFilterVtbl, +} +IShellItemFilterVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + IncludeItem: proc "stdcall" (this: ^IShellItemFilter, psi: ^IShellItem) -> HRESULT, + GetEnumFlagsForItem: proc "stdcall" (this: ^IShellItemFilter, psi: ^IShellItem, pgrfFlags: ^SHCONTF) -> HRESULT, +} + +IFileDialog :: struct #raw_union { + #subtype IModalWindow: IModalWindow, + using Vtbl: ^IFileDialogVtbl, +} +IFileDialogVtbl :: struct { + using IModalWindowVtbl: IModalWindowVtbl, + SetFileTypes: proc "stdcall" (this: ^IFileDialog, cFileTypes: UINT, rgFilterSpec: ^COMDLG_FILTERSPEC) -> HRESULT, + SetFileTypeIndex: proc "stdcall" (this: ^IFileDialog, iFileType: UINT) -> HRESULT, + GetFileTypeIndex: proc "stdcall" (this: ^IFileDialog, piFileType: ^UINT) -> HRESULT, + Advise: proc "stdcall" (this: ^IFileDialog, pfde: ^IFileDialogEvents, pdwCookie: ^DWORD) -> HRESULT, + Unadvise: proc "stdcall" (this: ^IFileDialog, dwCookie: DWORD) -> HRESULT, + SetOptions: proc "stdcall" (this: ^IFileDialog, fos: FILEOPENDIALOGOPTIONS) -> HRESULT, + GetOptions: proc "stdcall" (this: ^IFileDialog, pfos: ^FILEOPENDIALOGOPTIONS) -> HRESULT, + SetDefaultFolder: proc "stdcall" (this: ^IFileDialog, psi: ^IShellItem) -> HRESULT, + SetFolder: proc "stdcall" (this: ^IFileDialog, psi: ^IShellItem) -> HRESULT, + GetFolder: proc "stdcall" (this: ^IFileDialog, ppsi: ^^IShellItem) -> HRESULT, + GetCurrentSelection: proc "stdcall" (this: ^IFileDialog, ppsi: ^^IShellItem) -> HRESULT, + SetFileName: proc "stdcall" (this: ^IFileDialog, pszName: LPCWSTR) -> HRESULT, + GetFileName: proc "stdcall" (this: ^IFileDialog, pszName: ^LPCWSTR) -> HRESULT, + SetTitle: proc "stdcall" (this: ^IFileDialog, pszTitle: LPCWSTR) -> HRESULT, + SetOkButtonLabel: proc "stdcall" (this: ^IFileDialog, pszText: LPCWSTR) -> HRESULT, + SetFileNameLabel: proc "stdcall" (this: ^IFileDialog, pszLabel: LPCWSTR) -> HRESULT, + GetResult: proc "stdcall" (this: ^IFileDialog, ppsi: ^^IShellItem) -> HRESULT, + AddPlace: proc "stdcall" (this: ^IFileDialog, psi: ^IShellItem, fdap: FDAP) -> HRESULT, + SetDefaultExtension: proc "stdcall" (this: ^IFileDialog, pszDefaultExtension: LPCWSTR) -> HRESULT, + Close: proc "stdcall" (this: ^IFileDialog, hr: HRESULT) -> HRESULT, + SetClientGuid: proc "stdcall" (this: ^IFileDialog, guid: REFGUID) -> HRESULT, + ClearClientData: proc "stdcall" (this: ^IFileDialog) -> HRESULT, + SetFilter: proc "stdcall" (this: ^IFileDialog, pFilter: ^IShellItemFilter) -> HRESULT, +} + +IFileOpenDialog :: struct #raw_union { + #subtype IFileDialog: IFileDialog, + using Vtbl: ^IFileOpenDialogVtbl, +} +IFileOpenDialogVtbl :: struct { + using IFileDialogVtbl: IFileDialogVtbl, + GetResults: proc "stdcall" (this: ^IFileOpenDialog, ppenum: ^^IShellItemArray) -> HRESULT, + GetSelectedItems: proc "stdcall" (this: ^IFileOpenDialog, ppsai: ^^IShellItemArray) -> HRESULT, +} + +IPropertyStore :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IPropertyStoreVtbl, +} +IPropertyStoreVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + GetCount: proc "stdcall" (this: ^IPropertyStore, cProps: ^DWORD) -> HRESULT, + GetAt: proc "stdcall" (this: ^IPropertyStore, iProp: DWORD, pkey: ^PROPERTYKEY) -> HRESULT, + GetValue: proc "stdcall" (this: ^IPropertyStore, key: REFPROPERTYKEY, pv: ^PROPVARIANT) -> HRESULT, + SetValue: proc "stdcall" (this: ^IPropertyStore, key: REFPROPERTYKEY, propvar: REFPROPVARIANT) -> HRESULT, + Commit: proc "stdcall" (this: ^IPropertyStore) -> HRESULT, +} + +IPropertyDescriptionList :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IPropertyDescriptionListVtbl, +} +IPropertyDescriptionListVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + GetCount: proc "stdcall" (this: ^IPropertyDescriptionList, pcElem: ^UINT) -> HRESULT, + GetAt: proc "stdcall" (this: ^IPropertyDescriptionList, iElem: UINT, riid: REFIID, ppv: ^rawptr) -> HRESULT, +} + +IFileOperationProgressSink :: struct #raw_union { + #subtype IUnknown: IUnknown, + using Vtbl: ^IFileOperationProgressSinkVtbl, +} +IFileOperationProgressSinkVtbl :: struct { + using IUnknownVtbl: IUnknownVtbl, + StartOperations: proc "stdcall" (this: ^IFileOperationProgressSink) -> HRESULT, + FinishOperations: proc "stdcall" (this: ^IFileOperationProgressSink, hrResult: HRESULT) -> HRESULT, + PreRenameItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, pszNewName: LPCWSTR) -> HRESULT, + PostRenameItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, pszNewName: LPCWSTR, hrRename: HRESULT, psiNewlyCreated: ^IShellItem) -> HRESULT, + PreMoveItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, psiDestinationFolder: ^IShellItem, pszNewName: LPCWSTR) -> HRESULT, + PostMoveItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, psiDestinationFolder: ^IShellItem, pszNewName: LPCWSTR, hrMove: HRESULT, psiNewlyCreated: ^IShellItem) -> HRESULT, + PreCopyItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, psiDestinationFolder: ^IShellItem, pszNewName: LPCWSTR) -> HRESULT, + PostCopyItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, psiDestinationFolder: ^IShellItem, pszNewName: LPCWSTR, hrMove: HRESULT, psiNewlyCreated: ^IShellItem) -> HRESULT, + PreDeleteItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem) -> HRESULT, + PostDeleteItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiItem: ^IShellItem, hrDelete: HRESULT, psiNewlyCreated: ^IShellItem) -> HRESULT, + PreNewItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiDestinationFolder: ^IShellItem, pszNewName: LPCWSTR) -> HRESULT, + PostNewItem: proc "stdcall" (this: ^IFileOperationProgressSink, dwFlags: DWORD, psiDestinationFolder: ^IShellItem, pszNewName: LPCWSTR, pszTemplateName: LPCWSTR, dwFileAttributes: DWORD, hrNew: HRESULT, psiNewItem: ^IShellItem) -> HRESULT, + UpdateProgress: proc "stdcall" (this: ^IFileOperationProgressSink, iWorkTotal: UINT, iWorkSoFar: UINT) -> HRESULT, + ResetTimer: proc "stdcall" (this: ^IFileOperationProgressSink) -> HRESULT, + PauseTimer: proc "stdcall" (this: ^IFileOperationProgressSink) -> HRESULT, + ResumeTimer: proc "stdcall" (this: ^IFileOperationProgressSink) -> HRESULT, +} + +IFileSaveDialog :: struct #raw_union { + #subtype IFileDialog: IFileDialog, + using Vtbl: ^IFileSaveDialogVtbl, +} +IFileSaveDialogVtbl :: struct { + using IFileDialogVtbl: IFileDialogVtbl, + SetSaveAsItem: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem) -> HRESULT, + SetProperties: proc "stdcall" (this: ^IFileSaveDialog, pStore: ^IPropertyStore) -> HRESULT, + SetCollectedProperties: proc "stdcall" (this: ^IFileSaveDialog, pList: ^IPropertyDescriptionList, fAppendDefault: BOOL) -> HRESULT, + GetProperties: proc "stdcall" (this: ^IFileSaveDialog, ppStore: ^^IPropertyStore) -> HRESULT, + ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT, +} diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 1b6d23ba4..9fe64a92c 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -134,6 +134,45 @@ foreign user32 { GetCursorPos :: proc(lpPoint: LPPOINT) -> BOOL --- SetCursorPos :: proc(X: c_int, Y: c_int) -> BOOL --- SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR --- + + BroadcastSystemMessageW :: proc( + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> c_long --- + + BroadcastSystemMessageExW :: proc( + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + pbsmInfo: PBSMINFO, + ) -> c_long --- + + SendMessageTimeoutW :: proc( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + fuFlags: UINT, + uTimeout: UINT, + lpdwResult: PDWORD_PTR, + ) -> LRESULT --- + + GetSysColor :: proc(nIndex: c_int) -> DWORD --- + GetSysColorBrush :: proc(nIndex: c_int) -> HBRUSH --- + SetSysColors :: proc(cElements: c_int, lpaElements: ^INT, lpaRgbValues: ^COLORREF) -> BOOL --- + MessageBeep :: proc(uType: UINT) -> BOOL --- + + IsDialogMessageW :: proc(hDlg: HWND, lpMsg: LPMSG) -> BOOL --- + GetWindowTextLengthW :: proc(hWnd: HWND) -> c_int --- + GetWindowTextW :: proc(hWnd: HWND, lpString: LPWSTR, nMaxCount: c_int) -> c_int --- + SetWindowTextW :: proc(hWnd: HWND, lpString: LPCWSTR) -> BOOL --- + CallWindowProcW :: proc(lpPrevWndFunc: WNDPROC, hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT --- + EnableWindow :: proc(hWnd: HWND, bEnable: BOOL) -> BOOL --- } CreateWindowW :: #force_inline proc "stdcall" ( diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin index 9c3a30088..d6b883916 100644 --- a/core/sys/windows/window_messages.odin +++ b/core/sys/windows/window_messages.odin @@ -25,6 +25,7 @@ WM_ENDSESSION :: 0x0016 WM_SHOWWINDOW :: 0x0018 WM_CTLCOLOR :: 0x0019 WM_WININICHANGE :: 0x001a +WM_SETTINGCHANGE :: WM_WININICHANGE WM_DEVMODECHANGE :: 0x001b WM_ACTIVATEAPP :: 0x001c WM_FONTCHANGE :: 0x001d diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin new file mode 100644 index 000000000..b7652d1f4 --- /dev/null +++ b/core/sys/windows/winerror.odin @@ -0,0 +1,48 @@ +// +build windows +package sys_windows + +ERROR_SUCCESS : DWORD : 0 +NO_ERROR :: 0 +SEC_E_OK : HRESULT : 0x00000000 + +ERROR_INVALID_FUNCTION : DWORD : 1 +ERROR_FILE_NOT_FOUND : DWORD : 2 +ERROR_PATH_NOT_FOUND : DWORD : 3 +ERROR_ACCESS_DENIED : DWORD : 5 +ERROR_INVALID_HANDLE : DWORD : 6 +ERROR_NOT_ENOUGH_MEMORY : DWORD : 8 +ERROR_INVALID_BLOCK : DWORD : 9 +ERROR_BAD_ENVIRONMENT : DWORD : 10 +ERROR_BAD_FORMAT : DWORD : 11 +ERROR_INVALID_ACCESS : DWORD : 12 +ERROR_INVALID_DATA : DWORD : 13 +ERROR_OUTOFMEMORY : DWORD : 14 +ERROR_INVALID_DRIVE : DWORD : 15 +ERROR_CURRENT_DIRECTORY : DWORD : 16 +ERROR_NO_MORE_FILES : DWORD : 18 +ERROR_SHARING_VIOLATION : DWORD : 32 +ERROR_LOCK_VIOLATION : DWORD : 33 +ERROR_HANDLE_EOF : DWORD : 38 +ERROR_NOT_SUPPORTED : DWORD : 50 +ERROR_FILE_EXISTS : DWORD : 80 +ERROR_INVALID_PARAMETER : DWORD : 87 +ERROR_BROKEN_PIPE : DWORD : 109 +ERROR_CALL_NOT_IMPLEMENTED : DWORD : 120 +ERROR_INSUFFICIENT_BUFFER : DWORD : 122 +ERROR_INVALID_NAME : DWORD : 123 +ERROR_BAD_ARGUMENTS : DWORD : 160 +ERROR_LOCK_FAILED : DWORD : 167 +ERROR_ALREADY_EXISTS : DWORD : 183 +ERROR_NO_DATA : DWORD : 232 +ERROR_ENVVAR_NOT_FOUND : DWORD : 203 +ERROR_OPERATION_ABORTED : DWORD : 995 +ERROR_IO_PENDING : DWORD : 997 +ERROR_NO_UNICODE_TRANSLATION : DWORD : 1113 +ERROR_TIMEOUT : DWORD : 1460 +ERROR_DATATYPE_MISMATCH : DWORD : 1629 +ERROR_UNSUPPORTED_TYPE : DWORD : 1630 +ERROR_NOT_SAME_OBJECT : DWORD : 1656 + +E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001 + +SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool do return result >= 0 diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin index e812c410a..525eae685 100644 --- a/core/testing/runner_windows.odin +++ b/core/testing/runner_windows.odin @@ -203,7 +203,7 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) { thread.it.p(t) sema_post(&global_fail_timeout_semaphore) - thread_join_and_destroy(global_fail_timeout_thread) + if global_fail_timeout_thread != nil do thread_join_and_destroy(global_fail_timeout_thread) thread.success = true sema_post(&global_threaded_runner_semaphore) diff --git a/src/parser.cpp b/src/parser.cpp index b58e3c320..30b9455c1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1461,7 +1461,11 @@ Token expect_closing_brace_of_field_list(AstFile *f) { if (allow_token(f, Token_CloseBrace)) { return token; } - if (allow_token(f, Token_Semicolon)) { + bool ok = true; + if (!build_context.strict_style) { + ok = !skip_possible_newline(f); + } + if (ok && allow_token(f, Token_Semicolon)) { String p = token_to_string(token); syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p)); } @@ -2065,6 +2069,20 @@ Ast *parse_check_directive_for_statement(Ast *s, Token const &tag_token, u16 sta return s; } +Array parse_union_variant_list(AstFile *f) { + auto variants = array_make(heap_allocator()); + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { + Ast *type = parse_type(f); + if (type->kind != Ast_BadExpr) { + array_add(&variants, type); + } + if (!allow_token(f, Token_Comma)) { + break; + } + } + return variants; +} Ast *parse_operand(AstFile *f, bool lhs) { Ast *operand = nullptr; // Operand @@ -2418,7 +2436,9 @@ Ast *parse_operand(AstFile *f, bool lhs) { check_polymorphic_params_for_type(f, polymorphic_params, token); } - isize prev_level = f->expr_level; + isize prev_level; + + prev_level = f->expr_level; f->expr_level = -1; while (allow_token(f, Token_Hash)) { @@ -2457,7 +2477,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { if (f->curr_token.kind == Token_where) { where_token = expect_token(f, Token_where); - isize prev_level = f->expr_level; + prev_level = f->expr_level; f->expr_level = -1; where_clauses = parse_rhs_expr_list(f); f->expr_level = prev_level; @@ -2481,7 +2501,6 @@ Ast *parse_operand(AstFile *f, bool lhs) { case Token_union: { Token token = expect_token(f, Token_union); - auto variants = array_make(heap_allocator()); Ast *polymorphic_params = nullptr; Ast *align = nullptr; bool no_nil = false; @@ -2565,18 +2584,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { skip_possible_newline_for_literal(f); Token open = expect_token_after(f, Token_OpenBrace, "union"); - - while (f->curr_token.kind != Token_CloseBrace && - f->curr_token.kind != Token_EOF) { - Ast *type = parse_type(f); - if (type->kind != Ast_BadExpr) { - array_add(&variants, type); - } - if (!allow_token(f, Token_Comma)) { - break; - } - } - + auto variants = parse_union_variant_list(f); Token close = expect_closing_brace_of_field_list(f); return ast_union_type(f, token, variants, polymorphic_params, align, union_kind, where_token, where_clauses); @@ -2734,7 +2742,7 @@ Ast *parse_call_expr(AstFile *f, Ast *operand) { isize prev_expr_level = f->expr_level; bool prev_allow_newline = f->allow_newline; f->expr_level = 0; - f->allow_newline = true; + f->allow_newline = build_context.strict_style; open_paren = expect_token(f, Token_OpenParen); @@ -3775,6 +3783,10 @@ bool check_procedure_name_list(Array const &names) { } Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_typeid_token) { + bool prev_allow_newline = f->allow_newline; + defer (f->allow_newline = prev_allow_newline); + f->allow_newline = build_context.strict_style; + Token start_token = f->curr_token; CommentGroup *docs = f->lead_comment; diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 9c9831199..171e4674d 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -20,6 +20,7 @@ import "core:image/qoi" import "core:bytes" import "core:hash" import "core:fmt" +import "core:strings" import "core:mem" import "core:os" @@ -1463,7 +1464,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { context = runtime.default_context() for file in suite { - test_file := fmt.tprintf("%v/%v.png", TEST_SUITE_PATH, file.file) + test_file := strings.concatenate({TEST_SUITE_PATH, "/", file.file, ".png"}, context.temp_allocator) img: ^png.Image err: png.Error diff --git a/vendor/darwin/Foundation/NSTypes.odin b/vendor/darwin/Foundation/NSTypes.odin index ef895d449..0c1239710 100644 --- a/vendor/darwin/Foundation/NSTypes.odin +++ b/vendor/darwin/Foundation/NSTypes.odin @@ -36,7 +36,12 @@ NotFound :: IntegerMax Float :: distinct (f32 when size_of(uint) == 4 else f64) +Point :: struct { + x: Float, + y: Float, +} + Size :: struct { width: Float, height: Float, -} \ No newline at end of file +} diff --git a/vendor/darwin/Foundation/NSWindow.odin b/vendor/darwin/Foundation/NSWindow.odin index 3c7c17023..330af6012 100644 --- a/vendor/darwin/Foundation/NSWindow.odin +++ b/vendor/darwin/Foundation/NSWindow.odin @@ -3,8 +3,8 @@ package objc_Foundation import NS "vendor:darwin/Foundation" Rect :: struct { - x, y: f64, - width, height: f64, + using origin: Point, + using size: Size, } WindowStyleFlag :: enum NS.UInteger { @@ -102,8 +102,19 @@ Window_alloc :: proc() -> ^Window { } @(objc_type=Window, objc_name="initWithContentRect") -Window_initWithContentRect :: proc(self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: bool) -> ^Window { - return msgSend(^Window, self, "initWithContentRect:styleMask:backing:defer:", contentRect, styleMask, backing, doDefer) +Window_initWithContentRect :: proc (self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: bool) -> ^Window { + self := self + // HACK: due to a compiler bug, the generated calling code does not + // currently work for this message. Has to do with passing a struct along + // with other parameters, so we don't send the rect here. + // Omiting the rect argument here actually works, because of how the C + // calling conventions are defined. + self = msgSend(^Window, self, "initWithContentRect:styleMask:backing:defer:", styleMask, backing, doDefer) + + // apply the contentRect now, since we did not pass it to the init call + msgSend(nil, self, "setContentSize:", contentRect.size) + msgSend(nil, self, "setFrameOrigin:", contentRect.origin) + return self } @(objc_type=Window, objc_name="contentView") Window_contentView :: proc(self: ^Window) -> ^View { @@ -148,4 +159,4 @@ Window_setTitle :: proc(self: ^Window, title: ^NS.String) { @(objc_type=Window, objc_name="close") Window_close :: proc(self: ^Window) { msgSend(nil, self, "close") -} \ No newline at end of file +}