Files
tdkpin/original/reconstructed/tests/test_tpwincrt_text.c
T
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
Replace the partial mechanics transcriptions with a separate, readable C11
reconstruction of the complete Win16 image while preserving the original raw
Ghidra export as immutable evidence. Cover all ordinary and overlapping entry
points, Borland runtime behavior, Win16 imports, segmented data, callbacks,
resources, indirect control flow, physics, rendering, persistence, and
startup/shutdown lifecycles.

Add deterministic extraction and audit tooling plus address-linked ledgers for
functions, imports, DGROUP ranges and objects, relocations, resources, and
callbacks. The final gate records zero raw, partial, restored, unknown,
blocked, or unclassified required units. Keep the semantic-fidelity boundary
explicit: the portable C is not claimed to reproduce a byte-identical Borland
NE build.

Add strict focused harnesses for every reconstructed C unit, exact resource
round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source
or Cargo metadata is changed in this phase.

Test Plan:
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed
- `git diff --cached --check` -- passed
- `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
2026-08-23 16:41:17 +02:00

357 lines
11 KiB
C

#include "../tdkpin_tpwincrt_text.h"
#include "../tdkpin_borland_files.h"
#include <assert.h>
#include <stdint.h>
#include <string.h>
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;
}