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
540 lines
20 KiB
C
540 lines
20 KiB
C
#include "../tdkpin_borland_files.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdatomic.h>
|
|
|
|
_Atomic uint16_t g_borland_io_result;
|
|
uint8_t g_borland_file_mode = 2;
|
|
|
|
static Win16FarPtr g_open_proc;
|
|
static Win16FarPtr g_flush_proc;
|
|
static Win16FarPtr g_close_proc;
|
|
static uint16_t g_open_result;
|
|
static uint16_t g_flush_result;
|
|
static uint16_t g_close_result;
|
|
static Win16FarPtr g_call_order[8];
|
|
static unsigned g_call_count;
|
|
static Win16DosResult g_dos_read_result;
|
|
static Win16DosResult g_dos_write_result;
|
|
static Win16DosResult g_dos_close_result;
|
|
static uint16_t g_dos_handle;
|
|
static Win16FarPtr g_dos_buffer;
|
|
static uint16_t g_dos_count;
|
|
static unsigned g_dos_calls;
|
|
static Win16DosResult g_dos_seek_result;
|
|
static uint32_t g_seek_offset;
|
|
static uint8_t g_seek_origin;
|
|
static Win16DosResult g_dos_open_result;
|
|
static Win16DosResult g_dos_create_result;
|
|
static Win16DosExtendedResult g_dos_extended_seek_results[4];
|
|
static unsigned g_dos_extended_seek_count;
|
|
static unsigned g_dos_extended_seek_index;
|
|
static Win16DosExtendedResult g_dos_device_info_result;
|
|
static Win16FarPtr g_dos_name;
|
|
static uint16_t g_dos_open_argument;
|
|
static uint32_t g_extended_seek_offsets[4];
|
|
static uint8_t g_extended_seek_origins[4];
|
|
static Win16FarPtr g_last_write_buffer;
|
|
|
|
enum DosOperation {
|
|
DOS_OPERATION_READ,
|
|
DOS_OPERATION_WRITE,
|
|
DOS_OPERATION_CLOSE,
|
|
DOS_OPERATION_SEEK,
|
|
DOS_OPERATION_OPEN,
|
|
DOS_OPERATION_CREATE,
|
|
DOS_OPERATION_SEEK_EXTENDED,
|
|
DOS_OPERATION_DEVICE_INFO,
|
|
};
|
|
|
|
static enum DosOperation g_dos_operations[16];
|
|
|
|
static void record_dos_operation(enum DosOperation operation)
|
|
{
|
|
assert(g_dos_calls < sizeof(g_dos_operations) / sizeof(*g_dos_operations));
|
|
g_dos_operations[g_dos_calls++] = operation;
|
|
}
|
|
|
|
uint16_t win16_call_file_procedure(
|
|
Win16FarPtr procedure, Win16FarPtr record)
|
|
{
|
|
assert(record == win16_make_far_pointer(0x7000, 2));
|
|
g_call_order[g_call_count++] = procedure;
|
|
if (procedure == g_open_proc) return g_open_result;
|
|
if (procedure == g_flush_proc) return g_flush_result;
|
|
assert(procedure == g_close_proc);
|
|
return g_close_result;
|
|
}
|
|
|
|
static void write_far(
|
|
Win16FarPtr record, uint16_t offset, Win16FarPtr procedure)
|
|
{
|
|
win16_write_u16(record, offset, win16_far_offset(procedure));
|
|
win16_write_u16(record, (uint16_t)(offset + 2),
|
|
win16_far_selector(procedure));
|
|
}
|
|
|
|
static void reset_calls(void)
|
|
{
|
|
g_call_count = 0;
|
|
g_open_result = 0;
|
|
g_flush_result = 0;
|
|
g_close_result = 0;
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_calls = 0;
|
|
g_dos_extended_seek_count = 0;
|
|
g_dos_extended_seek_index = 0;
|
|
}
|
|
|
|
Win16DosResult win16_dos_read(
|
|
uint16_t handle, Win16FarPtr buffer, uint16_t count)
|
|
{
|
|
g_dos_handle = handle;
|
|
g_dos_buffer = buffer;
|
|
g_dos_count = count;
|
|
record_dos_operation(DOS_OPERATION_READ);
|
|
return g_dos_read_result;
|
|
}
|
|
|
|
Win16DosResult win16_dos_write(
|
|
uint16_t handle, Win16FarPtr buffer, uint16_t count)
|
|
{
|
|
g_dos_handle = handle;
|
|
g_dos_buffer = buffer;
|
|
g_last_write_buffer = buffer;
|
|
g_dos_count = count;
|
|
record_dos_operation(DOS_OPERATION_WRITE);
|
|
return g_dos_write_result;
|
|
}
|
|
|
|
Win16DosResult win16_dos_close(uint16_t handle)
|
|
{
|
|
g_dos_handle = handle;
|
|
record_dos_operation(DOS_OPERATION_CLOSE);
|
|
return g_dos_close_result;
|
|
}
|
|
|
|
Win16DosResult win16_dos_seek(
|
|
uint16_t handle, uint32_t offset, uint8_t origin)
|
|
{
|
|
g_dos_handle = handle;
|
|
g_seek_offset = offset;
|
|
g_seek_origin = origin;
|
|
record_dos_operation(DOS_OPERATION_SEEK);
|
|
return g_dos_seek_result;
|
|
}
|
|
|
|
_Noreturn void win16_integer_divide_fault(void)
|
|
{
|
|
assert(false);
|
|
__builtin_unreachable();
|
|
}
|
|
|
|
Win16DosResult win16_dos_open(Win16FarPtr name, uint8_t access_mode)
|
|
{
|
|
g_dos_name = name;
|
|
g_dos_open_argument = access_mode;
|
|
record_dos_operation(DOS_OPERATION_OPEN);
|
|
return g_dos_open_result;
|
|
}
|
|
|
|
Win16DosResult win16_dos_create(Win16FarPtr name, uint16_t attributes)
|
|
{
|
|
g_dos_name = name;
|
|
g_dos_open_argument = attributes;
|
|
record_dos_operation(DOS_OPERATION_CREATE);
|
|
return g_dos_create_result;
|
|
}
|
|
|
|
Win16DosExtendedResult win16_dos_seek_extended(
|
|
uint16_t handle, uint32_t offset, uint8_t origin)
|
|
{
|
|
assert(g_dos_extended_seek_index < g_dos_extended_seek_count);
|
|
unsigned index = g_dos_extended_seek_index++;
|
|
g_dos_handle = handle;
|
|
g_extended_seek_offsets[index] = offset;
|
|
g_extended_seek_origins[index] = origin;
|
|
record_dos_operation(DOS_OPERATION_SEEK_EXTENDED);
|
|
return g_dos_extended_seek_results[index];
|
|
}
|
|
|
|
Win16DosExtendedResult win16_dos_get_device_info(uint16_t handle)
|
|
{
|
|
g_dos_handle = handle;
|
|
record_dos_operation(DOS_OPERATION_DEVICE_INFO);
|
|
return g_dos_device_info_result;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
static uint8_t record_bytes[512];
|
|
static uint8_t code_bytes[0x700];
|
|
win16_reset_segment_bindings();
|
|
win16_bind_segment(0x7000, record_bytes, sizeof(record_bytes), true);
|
|
win16_bind_ne_segment(
|
|
5, 0x6000, code_bytes, sizeof(code_bytes), false);
|
|
Win16FarPtr record = win16_make_far_pointer(0x7000, 2);
|
|
g_open_proc = win16_make_far_pointer(0x6000, 0x1000);
|
|
g_flush_proc = win16_make_far_pointer(0x6000, 0x2000);
|
|
g_close_proc = win16_make_far_pointer(0x6000, 0x3000);
|
|
write_far(record, 0x10, g_open_proc);
|
|
write_far(record, 0x14, g_flush_proc);
|
|
write_far(record, 0x1c, g_close_proc);
|
|
|
|
reset_calls();
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
win16_write_u16(record, 8, 9);
|
|
win16_write_u16(record, 10, 10);
|
|
borland_reset_file(record);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_INPUT);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 8)) == 0);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 10)) == 0);
|
|
assert(g_call_count == 1 && g_call_order[0] == g_open_proc);
|
|
|
|
reset_calls();
|
|
g_open_result = 5;
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
borland_rewrite_file(record);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_CLOSED);
|
|
assert(atomic_load(&g_borland_io_result) == 5);
|
|
|
|
reset_calls();
|
|
win16_write_u16(record, 2, BORLAND_FILE_OUTPUT);
|
|
g_flush_result = 6;
|
|
borland_close_file(record);
|
|
assert(g_call_count == 2);
|
|
assert(g_call_order[0] == g_flush_proc && g_call_order[1] == g_close_proc);
|
|
assert(atomic_load(&g_borland_io_result) == 6);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_CLOSED);
|
|
|
|
reset_calls();
|
|
win16_write_u16(record, 2, BORLAND_FILE_INPUT);
|
|
borland_close_file(record);
|
|
assert(g_call_count == 1 && g_call_order[0] == g_close_proc);
|
|
|
|
reset_calls();
|
|
win16_write_u16(record, 2, 0x1111);
|
|
borland_close_file(record);
|
|
assert(g_call_count == 0 && atomic_load(&g_borland_io_result) == 0x67);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
borland_reset_file(record);
|
|
assert(g_call_count == 0 && atomic_load(&g_borland_io_result) == 0x66);
|
|
|
|
reset_calls();
|
|
win16_write_u16(record, 2, BORLAND_FILE_OUTPUT);
|
|
borland_reset_file(record);
|
|
assert(g_call_count == 3);
|
|
assert(g_call_order[0] == g_flush_proc);
|
|
assert(g_call_order[1] == g_close_proc);
|
|
assert(g_call_order[2] == g_open_proc);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_INPUT);
|
|
|
|
Win16FarPtr buffer = win16_make_far_pointer(0x7100, 0x0200);
|
|
win16_write_u16(record, 0, 9);
|
|
win16_write_u16(record, 4, 100);
|
|
write_far(record, 12, buffer);
|
|
win16_write_u16(record, 8, 7);
|
|
g_dos_read_result = (Win16DosResult){60, false};
|
|
reset_calls();
|
|
assert(borland_file_read_buffer(record) == 0);
|
|
assert(g_dos_handle == 9 && g_dos_buffer == buffer && g_dos_count == 100);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 8)) == 0);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 10)) == 60);
|
|
g_dos_read_result = (Win16DosResult){5, true};
|
|
assert(borland_file_read_buffer(record) == 5);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 10)) == 0);
|
|
|
|
win16_write_u16(record, 8, 20);
|
|
g_dos_write_result = (Win16DosResult){20, false};
|
|
reset_calls();
|
|
assert(borland_file_flush_buffer(record) == 0);
|
|
assert(g_dos_count == 20);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 8)) == 0);
|
|
win16_write_u16(record, 8, 20);
|
|
g_dos_write_result = (Win16DosResult){19, false};
|
|
assert(borland_file_flush_buffer(record) == 0x65);
|
|
win16_write_u16(record, 8, 20);
|
|
g_dos_write_result = (Win16DosResult){6, true};
|
|
assert(borland_file_flush_buffer(record) == 6);
|
|
|
|
win16_write_u16(record, 8, 20);
|
|
g_dos_write_result = (Win16DosResult){19, false};
|
|
assert(borland_file_write_buffer(record) == 0);
|
|
win16_write_u16(record, 8, 20);
|
|
g_dos_write_result = (Win16DosResult){7, true};
|
|
assert(borland_file_write_buffer(record) == 7);
|
|
|
|
win16_write_u16(record, 0, 4);
|
|
reset_calls();
|
|
assert(borland_file_close_handle(record) == 0 && g_dos_calls == 0);
|
|
win16_write_u16(record, 0, 9);
|
|
g_dos_close_result = (Win16DosResult){0, false};
|
|
assert(borland_file_close_handle(record) == 0 && g_dos_calls == 1);
|
|
g_dos_close_result = (Win16DosResult){8, true};
|
|
assert(borland_file_close_handle(record) == 8);
|
|
|
|
atomic_store(&g_borland_io_result, 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
assert(!borland_validate_open_file(record));
|
|
assert(atomic_load(&g_borland_io_result) == 0x67);
|
|
unsigned dos_calls = g_dos_calls;
|
|
borland_truncate_file(record);
|
|
assert(g_dos_calls == dos_calls);
|
|
|
|
atomic_store(&g_borland_io_result, 0);
|
|
win16_set_indeterminate_u16(0xbeef);
|
|
win16_write_u16(record, 0, 9);
|
|
win16_write_u16(record, 2, 0xd7b3);
|
|
g_dos_write_result = (Win16DosResult){0, false};
|
|
borland_truncate_file(record);
|
|
assert(g_dos_count == 0);
|
|
assert(g_dos_buffer == win16_make_far_pointer(0xbeef, 0xbeef));
|
|
g_dos_write_result = (Win16DosResult){9, true};
|
|
borland_truncate_file(record);
|
|
assert(atomic_load(&g_borland_io_result) == 9);
|
|
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_close_result = (Win16DosResult){10, true};
|
|
borland_close_generic_file(record);
|
|
assert(atomic_load(&g_borland_io_result) == 10);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_CLOSED);
|
|
win16_write_u16(record, 0, 4);
|
|
win16_write_u16(record, 2, 0xd7b3);
|
|
dos_calls = g_dos_calls;
|
|
borland_close_generic_file(record);
|
|
assert(g_dos_calls == dos_calls);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_CLOSED);
|
|
|
|
Win16FarPtr transfer = win16_make_far_pointer(0x7100, 0x0200);
|
|
static uint8_t transfer_bytes[0x400];
|
|
win16_bind_segment(
|
|
0x7100, transfer_bytes, sizeof(transfer_bytes), true);
|
|
win16_write_u16(record, 0, 9);
|
|
win16_write_u16(record, 2, 0xd7b3);
|
|
win16_write_u16(record, 4, 4);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_read_result = (Win16DosResult){4, false};
|
|
borland_file_read_record(transfer, record);
|
|
assert(atomic_load(&g_borland_io_result) == 0);
|
|
g_dos_read_result = (Win16DosResult){3, false};
|
|
borland_file_read_record(transfer, record);
|
|
assert(atomic_load(&g_borland_io_result) == 0x64);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_write_result = (Win16DosResult){3, false};
|
|
borland_file_write_record(transfer, record);
|
|
assert(atomic_load(&g_borland_io_result) == 0x65);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_write_result = (Win16DosResult){11, true};
|
|
borland_file_write_record(transfer, record);
|
|
assert(atomic_load(&g_borland_io_result) == 11);
|
|
|
|
Win16FarPtr result_count = win16_make_far_pointer(0x7100, 0);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_read_result = (Win16DosResult){8, false};
|
|
borland_file_block_read(result_count, 3, transfer, record);
|
|
assert(win16_read_u16(result_count) == 2);
|
|
assert(atomic_load(&g_borland_io_result) == 0);
|
|
borland_file_block_read(0, 3, transfer, record);
|
|
assert(atomic_load(&g_borland_io_result) == 0x64);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_write_result = (Win16DosResult){8, false};
|
|
borland_file_block_write(0, 3, transfer, record);
|
|
assert(atomic_load(&g_borland_io_result) == 0x65);
|
|
borland_file_block_write(result_count, 3, transfer, record);
|
|
assert(win16_read_u16(result_count) == 2);
|
|
|
|
g_dos_seek_result = (Win16DosResult){0, false};
|
|
borland_file_seek_record(0x00010002u, record);
|
|
assert(g_seek_offset == 0x00040008u && g_seek_origin == 0);
|
|
g_dos_seek_result = (Win16DosResult){12, true};
|
|
borland_file_seek_record(3, record);
|
|
assert(atomic_load(&g_borland_io_result) == 12);
|
|
|
|
Win16FarPtr name = win16_far_add_offset(record, 48);
|
|
win16_write_u8(name, 'F');
|
|
win16_write_u8(win16_far_add_offset(name, 1), 0);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
g_dos_open_result = (Win16DosResult){15, false};
|
|
reset_calls();
|
|
borland_open_generic_file(4, record);
|
|
assert(g_dos_name == name && g_dos_open_argument == 2);
|
|
assert(win16_read_u16(record) == 15);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) == 0xd7b3);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 4)) == 4);
|
|
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
g_dos_create_result = (Win16DosResult){16, false};
|
|
borland_create_generic_file(8, record);
|
|
assert(g_dos_open_argument == 0 && win16_read_u16(record) == 16);
|
|
|
|
win16_write_u8(name, 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
reset_calls();
|
|
borland_open_generic_file(4, record);
|
|
assert(g_dos_calls == 0 && win16_read_u16(record) == 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
borland_create_generic_file(4, record);
|
|
assert(g_dos_calls == 0 && win16_read_u16(record) == 1);
|
|
|
|
win16_write_u8(name, 'F');
|
|
win16_write_u16(record, 2, BORLAND_FILE_CLOSED);
|
|
atomic_store(&g_borland_io_result, 0);
|
|
g_dos_open_result = (Win16DosResult){13, true};
|
|
borland_open_generic_file(4, record);
|
|
assert(atomic_load(&g_borland_io_result) == 13);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_CLOSED);
|
|
|
|
atomic_store(&g_borland_io_result, 0);
|
|
win16_write_u16(record, 2, 0x1111);
|
|
borland_open_generic_file(4, record);
|
|
assert(atomic_load(&g_borland_io_result) == 0x66);
|
|
|
|
win16_write_u16(record, 2, 0xd7b3);
|
|
win16_write_u16(record, 0, 9);
|
|
g_dos_close_result = (Win16DosResult){0, false};
|
|
g_dos_open_result = (Win16DosResult){17, false};
|
|
reset_calls();
|
|
borland_open_generic_file(4, record);
|
|
assert(g_dos_calls == 2 && win16_read_u16(record) == 17);
|
|
assert(tdkpin_file_close_noop(record) == 0);
|
|
|
|
Win16FarPtr text_name = win16_far_add_offset(record, 0x30);
|
|
Win16FarPtr read_buffer_proc =
|
|
win16_make_far_pointer(0x6000, 0x05d8);
|
|
Win16FarPtr flush_buffer_proc =
|
|
win16_make_far_pointer(0x6000, 0x0608);
|
|
Win16FarPtr write_buffer_proc =
|
|
win16_make_far_pointer(0x6000, 0x062d);
|
|
Win16FarPtr close_handle_proc =
|
|
win16_make_far_pointer(0x6000, 0x064d);
|
|
|
|
reset_calls();
|
|
win16_write_u8(text_name, 'I');
|
|
win16_write_u8(win16_far_add_offset(text_name, 1), 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_INPUT);
|
|
g_dos_open_result = (Win16DosResult){7, false};
|
|
assert(borland_open_text_record(record) == 0);
|
|
assert(g_dos_calls == 1 && g_dos_operations[0] == DOS_OPERATION_OPEN);
|
|
assert(g_dos_open_argument == 0 && win16_read_u16(record) == 7);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_INPUT);
|
|
assert(win16_read_far_pointer(record, 0x14) == read_buffer_proc);
|
|
assert(win16_read_far_pointer(record, 0x18) == 0);
|
|
assert(win16_read_far_pointer(record, 0x1c) == close_handle_proc);
|
|
|
|
reset_calls();
|
|
win16_write_u8(text_name, 'O');
|
|
win16_write_u16(record, 2, BORLAND_FILE_OUTPUT);
|
|
g_dos_create_result = (Win16DosResult){8, false};
|
|
g_dos_device_info_result =
|
|
(Win16DosExtendedResult){0, 0, false};
|
|
assert(borland_open_text_record(record) == 0);
|
|
assert(g_dos_calls == 2);
|
|
assert(g_dos_operations[0] == DOS_OPERATION_CREATE);
|
|
assert(g_dos_operations[1] == DOS_OPERATION_DEVICE_INFO);
|
|
assert(g_dos_open_argument == 0 && win16_read_u16(record) == 8);
|
|
assert(win16_read_far_pointer(record, 0x14) == flush_buffer_proc);
|
|
assert(win16_read_far_pointer(record, 0x18) == 0);
|
|
assert(win16_read_far_pointer(record, 0x1c) == close_handle_proc);
|
|
|
|
reset_calls();
|
|
win16_write_u8(text_name, 'A');
|
|
win16_write_u16(record, 2, BORLAND_TEXT_APPEND);
|
|
g_dos_open_result = (Win16DosResult){9, false};
|
|
g_dos_device_info_result =
|
|
(Win16DosExtendedResult){5, 0x0080, true};
|
|
assert(borland_open_text_record(record) == 0);
|
|
assert(g_dos_calls == 2);
|
|
assert(g_dos_operations[0] == DOS_OPERATION_OPEN);
|
|
assert(g_dos_operations[1] == DOS_OPERATION_DEVICE_INFO);
|
|
assert(g_dos_open_argument == 2 && win16_read_u16(record) == 9);
|
|
assert(win16_read_u16(win16_far_add_offset(record, 2)) ==
|
|
BORLAND_FILE_OUTPUT);
|
|
assert(win16_read_far_pointer(record, 0x14) == write_buffer_proc);
|
|
assert(win16_read_far_pointer(record, 0x18) == write_buffer_proc);
|
|
|
|
reset_calls();
|
|
win16_write_u8(text_name, 'A');
|
|
win16_write_u16(record, 2, BORLAND_TEXT_APPEND);
|
|
g_dos_open_result = (Win16DosResult){10, false};
|
|
g_dos_device_info_result =
|
|
(Win16DosExtendedResult){0, 0, false};
|
|
g_dos_extended_seek_count = 3;
|
|
g_dos_extended_seek_results[0] =
|
|
(Win16DosExtendedResult){0x0090, 0x0001, false};
|
|
g_dos_extended_seek_results[1] =
|
|
(Win16DosExtendedResult){0, 0, false};
|
|
g_dos_extended_seek_results[2] =
|
|
(Win16DosExtendedResult){0x000c, 0x1234, false};
|
|
g_dos_read_result = (Win16DosResult){6, false};
|
|
Win16FarPtr text_buffer = win16_far_add_offset(record, 0x80);
|
|
for (uint16_t index = 0; index < 6; index++) {
|
|
win16_write_u8(win16_far_add_offset(text_buffer, index), 'x');
|
|
}
|
|
win16_write_u8(win16_far_add_offset(text_buffer, 2), 0x1a);
|
|
g_dos_write_result = (Win16DosResult){0, false};
|
|
assert(borland_open_text_record(record) == 0);
|
|
assert(g_dos_calls == 7 && g_dos_extended_seek_index == 3);
|
|
assert(g_dos_operations[0] == DOS_OPERATION_OPEN);
|
|
assert(g_dos_operations[1] == DOS_OPERATION_DEVICE_INFO);
|
|
assert(g_dos_operations[2] == DOS_OPERATION_SEEK_EXTENDED);
|
|
assert(g_dos_operations[3] == DOS_OPERATION_SEEK_EXTENDED);
|
|
assert(g_dos_operations[4] == DOS_OPERATION_READ);
|
|
assert(g_dos_operations[5] == DOS_OPERATION_SEEK_EXTENDED);
|
|
assert(g_dos_operations[6] == DOS_OPERATION_WRITE);
|
|
assert(g_extended_seek_offsets[0] == 0 &&
|
|
g_extended_seek_origins[0] == 2);
|
|
assert(g_extended_seek_offsets[1] == 0x00010010u &&
|
|
g_extended_seek_origins[1] == 0);
|
|
assert(g_extended_seek_offsets[2] == 0xfffffffcu &&
|
|
g_extended_seek_origins[2] == 2);
|
|
assert(g_dos_count == 0);
|
|
assert(g_last_write_buffer ==
|
|
win16_make_far_pointer(0x7000, 0x1234));
|
|
assert(win16_read_far_pointer(record, 0x14) == flush_buffer_proc);
|
|
assert(win16_read_far_pointer(record, 0x18) == 0);
|
|
|
|
reset_calls();
|
|
win16_write_u8(text_name, 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_INPUT);
|
|
assert(borland_open_text_record(record) == 0);
|
|
assert(g_dos_calls == 0 && win16_read_u16(record) == 0);
|
|
win16_write_u16(record, 2, BORLAND_FILE_OUTPUT);
|
|
g_dos_device_info_result =
|
|
(Win16DosExtendedResult){0, 0x0080, false};
|
|
assert(borland_open_text_record(record) == 0);
|
|
assert(g_dos_calls == 1 && win16_read_u16(record) == 1);
|
|
|
|
reset_calls();
|
|
win16_write_u8(text_name, 'E');
|
|
win16_write_u16(record, 2, BORLAND_FILE_INPUT);
|
|
write_far(record, 0x14, win16_make_far_pointer(0x1111, 0x2222));
|
|
g_dos_open_result = (Win16DosResult){13, true};
|
|
assert(borland_open_text_record(record) == 13);
|
|
assert(g_dos_calls == 1 && win16_read_u16(record) == 0);
|
|
assert(win16_read_far_pointer(record, 0x14) ==
|
|
win16_make_far_pointer(0x1111, 0x2222));
|
|
|
|
reset_calls();
|
|
win16_write_u16(record, 0, 11);
|
|
g_dos_extended_seek_count = 2;
|
|
g_dos_extended_seek_results[0] =
|
|
(Win16DosExtendedResult){4, 0, true};
|
|
g_dos_extended_seek_results[1] =
|
|
(Win16DosExtendedResult){0, 0, true};
|
|
g_dos_read_result = (Win16DosResult){5, true};
|
|
borland_text_truncate_at_ctrl_z(record);
|
|
assert(g_dos_calls == 3 && g_dos_extended_seek_index == 2);
|
|
assert(g_extended_seek_offsets[1] == 0);
|
|
assert(g_dos_operations[2] == DOS_OPERATION_READ);
|
|
return 0;
|
|
}
|