#include "../tdkpin_tpwincrt_text.h" #include "../tdkpin_borland_files.h" #include #include #include HWND16 g_tpwincrt_window; uint16_t g_tpwincrt_columns; uint16_t g_tpwincrt_rows; uint16_t g_tpwincrt_cursor_column; uint16_t g_tpwincrt_cursor_row; uint16_t g_tpwincrt_view_column; uint16_t g_tpwincrt_view_row; uint8_t g_tpwincrt_break_check_enabled; uint8_t g_tpwincrt_auto_scroll; uint8_t g_tpwincrt_ctrl_z_is_eof; uint16_t g_tpwincrt_input_count; uint16_t g_tpwincrt_ring_row_origin; uint8_t g_tpwincrt_window_created; uint8_t g_tpwincrt_has_focus; uint8_t g_tpwincrt_caret_enabled; uint8_t g_tpwincrt_paint_message_active; Win16FarPtr g_tpwincrt_screen_buffer; uint16_t g_tpwincrt_character_width; uint16_t g_tpwincrt_character_height; uint16_t g_tpwincrt_caret_y_offset; HDC16 g_tpwincrt_paint_dc; PAINTSTRUCT16 g_tpwincrt_paint; HGDIOBJ16 g_tpwincrt_previous_font; uint16_t g_tpwincrt_visible_columns; uint16_t g_tpwincrt_visible_rows; uint16_t g_tpwincrt_max_view_column; uint16_t g_tpwincrt_max_view_row; uint8_t g_tpwincrt_input_buffer[64]; _Atomic uint16_t g_borland_io_result; uint8_t g_borland_file_mode; static unsigned g_begin_calls; static unsigned g_end_calls; static unsigned g_draw_calls; static INT16 g_last_x; static INT16 g_last_y; static INT16 g_last_draw_count; static unsigned g_scroll_cursor_calls; static unsigned g_create_window_calls; static unsigned g_beep_calls; static unsigned g_scroll_window_calls; static INT16 g_scroll_delta_y; static unsigned g_update_calls; static unsigned g_create_caret_calls; static unsigned g_destroy_caret_calls; static unsigned g_wait_calls; static MSG16 g_messages[4]; static unsigned g_message_count; static unsigned g_message_index; static unsigned g_translate_calls; static unsigned g_dispatch_calls; Win16FarPtr tpwincrt_cell_pointer(int16_t row, int16_t column) { uint16_t physical = (uint16_t)(row + g_tpwincrt_ring_row_origin); if ((int16_t)physical >= (int16_t)g_tpwincrt_rows) { physical = (uint16_t)(physical - g_tpwincrt_rows); } uint16_t offset = (uint16_t)( win16_far_offset(g_tpwincrt_screen_buffer) + physical * g_tpwincrt_columns + (uint16_t)column); return win16_make_far_pointer( win16_far_selector(g_tpwincrt_screen_buffer), offset); } void tpwincrt_begin_drawing(void) { g_begin_calls++; g_tpwincrt_paint_dc = 0x3333; } void tpwincrt_end_drawing(void) { g_end_calls++; } void tpwincrt_scroll_cursor_into_view(void) { g_scroll_cursor_calls++; } void tpwincrt_create_window(void) { g_create_window_calls++; } void tpwincrt_create_caret(void) { g_create_caret_calls++; } void tpwincrt_destroy_caret(void) { g_destroy_caret_calls++; } _Noreturn void tpwincrt_abort_on_ctrl_c(void) { assert(false); __builtin_unreachable(); } BOOL16 TextOut16( HDC16 dc, INT16 x, INT16 y, Win16FarPtr text, INT16 count) { assert(dc == 0x3333); (void)text; g_draw_calls++; g_last_x = x; g_last_y = y; g_last_draw_count = count; return 1; } BOOL16 ScrollWindow16( HWND16 window, INT16 delta_x, INT16 delta_y, Win16FarPtr scroll_rect, Win16FarPtr clip_rect) { assert(window == g_tpwincrt_window && delta_x == 0); assert(scroll_rect == 0 && clip_rect == 0); g_scroll_window_calls++; g_scroll_delta_y = delta_y; return 1; } BOOL16 UpdateWindow16(HWND16 window) { assert(window == g_tpwincrt_window); g_update_calls++; return 1; } BOOL16 MessageBeep16(UINT16 type) { assert(type == 0); g_beep_calls++; return 1; } BOOL16 PeekMessage16( MSG16 *message, HWND16 window, UINT16 minimum_message, UINT16 maximum_message, UINT16 remove_message) { assert(window == 0 && minimum_message == 0 && maximum_message == 0); assert(remove_message == 1); if (g_message_index == g_message_count) { return 0; } *message = g_messages[g_message_index++]; return 1; } BOOL16 TranslateMessage16(const MSG16 *message) { assert(message->message == g_messages[g_translate_calls].message); g_translate_calls++; return 1; } LRESULT16 DispatchMessage16(const MSG16 *message) { assert(message->message == g_messages[g_dispatch_calls].message); g_dispatch_calls++; return 0; } BOOL16 WaitMessage16(void) { g_wait_calls++; g_tpwincrt_input_buffer[0] = 'Z'; g_tpwincrt_input_count = 1; return 1; } void borland_fill_bytes( Win16FarPtr destination, uint16_t count, uint8_t value) { for (uint16_t index = 0; index != count; index++) { win16_write_u8(win16_far_add_offset(destination, index), value); } } void borland_move_bytes( Win16FarPtr destination, Win16FarPtr source, uint16_t count) { assert(win16_far_offset(destination) == 0x4af8); assert(win16_far_offset(source) == 0x4af9); memmove(g_tpwincrt_input_buffer, g_tpwincrt_input_buffer + 1, count); } static void reset_observations(void) { g_begin_calls = 0; g_end_calls = 0; g_draw_calls = 0; g_scroll_cursor_calls = 0; g_create_window_calls = 0; g_beep_calls = 0; g_scroll_window_calls = 0; g_update_calls = 0; g_create_caret_calls = 0; g_destroy_caret_calls = 0; g_wait_calls = 0; g_message_count = 0; g_message_index = 0; g_translate_calls = 0; g_dispatch_calls = 0; } int main(void) { static uint8_t dgroup[0x6000]; static uint8_t screen[0x100]; static uint8_t code[0x3000]; uint8_t stack_anchor = 0; uintptr_t stack_base = (uintptr_t)&stack_anchor - 0x8000; win16_reset_segment_bindings(); win16_bind_segment(0x7000, dgroup, sizeof(dgroup), true); win16_set_dgroup_selector(0x7000); win16_bind_segment(0x7100, screen, sizeof(screen), true); win16_bind_ne_segment(2, 0x6000, code, sizeof(code), false); win16_bind_segment(0x7200, (void *)stack_base, 0x10000, true); g_tpwincrt_window = 0x2222; g_tpwincrt_columns = 5; g_tpwincrt_rows = 3; g_tpwincrt_character_width = 8; g_tpwincrt_character_height = 12; g_tpwincrt_screen_buffer = win16_make_far_pointer(0x7100, 0); memset(screen, ' ', sizeof(screen)); Win16FarPtr record = win16_make_far_pointer(0x7000, 0x100); memset(dgroup + 0x100, 0xa5, 0x100); tpwincrt_initialize_text_record(record); assert(win16_read_u16(record) == 0xffff); assert(win16_read_u16(win16_far_add_offset(record, 2)) == BORLAND_FILE_CLOSED); assert(win16_read_u16(win16_far_add_offset(record, 4)) == 0x80); assert(win16_read_u16(win16_far_add_offset(record, 6)) == 0xa5a5); assert(win16_read_far_pointer(record, 0x0c) == win16_far_add_offset(record, 0x80)); assert(win16_read_far_pointer(record, 0x10) == win16_make_far_pointer(0x6000, 0x238b)); assert(win16_read_u8(win16_far_add_offset(record, 0x30)) == 0); win16_write_u16(record, 2, BORLAND_FILE_INPUT); assert(tpwincrt_open_text_record(record) == 0); assert(win16_read_far_pointer(record, 0x14) == win16_make_far_pointer(0x6000, 0x233c)); assert(win16_read_far_pointer(record, 0x18) == 0); assert(win16_read_far_pointer(record, 0x1c) == win16_make_far_pointer(0x6000, 0x2374)); win16_write_u16(record, 2, BORLAND_TEXT_APPEND); assert(tpwincrt_open_text_record(record) == 0); assert(win16_read_u16(win16_far_add_offset(record, 2)) == BORLAND_FILE_OUTPUT); assert(win16_read_far_pointer(record, 0x14) == win16_make_far_pointer(0x6000, 0x22fc)); assert(win16_read_far_pointer(record, 0x18) == win16_make_far_pointer(0x6000, 0x22fc)); reset_observations(); g_tpwincrt_auto_scroll = 1; uint8_t output[] = {'A', 'B', '\b', 'C', '\r', 'D', '\a'}; Win16FarPtr output_far = win16_make_far_pointer(0x7000, 0x300); memcpy(dgroup + 0x300, output, sizeof(output)); tpwincrt_write_bytes(sizeof(output), output_far); assert(memcmp(screen, "AC D", 6) == 0); assert(g_tpwincrt_cursor_column == 1 && g_tpwincrt_cursor_row == 1); assert(g_beep_calls == 1 && g_create_window_calls == 1); assert(g_scroll_cursor_calls == 1 && g_draw_calls >= 2); reset_observations(); g_tpwincrt_cursor_column = 0; g_tpwincrt_cursor_row = 2; g_tpwincrt_ring_row_origin = 2; int16_t changed_start = 0; int16_t changed_end = 0; memset(screen, 'Q', 15); tpwincrt_advance_line(&changed_start, &changed_end); assert(g_tpwincrt_cursor_row == 2 && g_tpwincrt_ring_row_origin == 0); assert(memcmp(screen + 10, " ", 5) == 0); assert(g_scroll_window_calls == 1 && g_scroll_delta_y == -12); assert(g_update_calls == 1); reset_observations(); g_messages[0].message = WIN16_WM_PAINT; g_messages[1].message = WIN16_WM_SIZE; g_message_count = 2; g_tpwincrt_input_count = 1; assert(tpwincrt_poll_input()); assert(g_translate_calls == 2 && g_dispatch_calls == 2); reset_observations(); memcpy(g_tpwincrt_input_buffer, "XY", 2); g_tpwincrt_input_count = 2; assert(tpwincrt_read_character() == 'X'); assert(g_tpwincrt_input_count == 1 && g_tpwincrt_input_buffer[0] == 'Y'); assert(g_wait_calls == 0); reset_observations(); g_tpwincrt_input_count = 0; g_tpwincrt_has_focus = 1; assert(tpwincrt_read_character() == 'Z'); assert(g_wait_calls == 1); assert(g_create_caret_calls == 1 && g_destroy_caret_calls == 1); assert(g_tpwincrt_caret_enabled == 0); reset_observations(); g_tpwincrt_cursor_column = 0; g_tpwincrt_cursor_row = 0; g_tpwincrt_ring_row_origin = 0; g_tpwincrt_has_focus = 0; g_tpwincrt_ctrl_z_is_eof = 0; const uint8_t line_input[] = {'A', 'B', '\b', 'C', '\r'}; memcpy(g_tpwincrt_input_buffer, line_input, sizeof(line_input)); g_tpwincrt_input_count = sizeof(line_input); Win16FarPtr line = win16_make_far_pointer(0x7000, 0x400); assert(tpwincrt_read_line(10, line) == 4); assert(memcmp(dgroup + 0x400, "AC\r\n", 4) == 0); reset_observations(); const uint8_t eof_input[] = {'X', 0x1a}; memcpy(g_tpwincrt_input_buffer, eof_input, sizeof(eof_input)); g_tpwincrt_input_count = sizeof(eof_input); g_tpwincrt_ctrl_z_is_eof = 1; assert(tpwincrt_read_line(10, line) == 2); assert(dgroup[0x400] == 'X' && dgroup[0x401] == 0x1a); reset_observations(); Win16FarPtr record_buffer = win16_make_far_pointer(0x7000, 0x500); memcpy(dgroup + 0x500, "OK", 2); win16_write_u16(record, 8, 2); win16_write_u16(record, 0x0c, win16_far_offset(record_buffer)); win16_write_u16(record, 0x0e, win16_far_selector(record_buffer)); assert(tpwincrt_text_write_buffer(record) == 0); assert(win16_read_u16(win16_far_add_offset(record, 8)) == 0); return 0; }