#include "../tdkpin_heap.h" #include #include uint16_t g_borland_heap_segment_head; uint16_t g_borland_local_heap_limit; uint16_t g_borland_heap_segment_bytes; Win16FarPtr g_borland_heap_error_handler; static uint8_t g_dgroup[0x10000]; static uint8_t g_segments[4][0x100]; static unsigned g_segment_count; static bool g_fail_segment; static bool g_fail_direct; static Win16FarPtr g_direct_pointer; static uint16_t g_handler_action; static unsigned g_handler_calls; static unsigned g_global_frees; Win16FarPtr borland_global_allocate(uint16_t bytes) { if (bytes == g_borland_heap_segment_bytes) { if (g_fail_segment) { return 0; } assert(g_segment_count < 4 && bytes <= sizeof(g_segments[0])); uint16_t selector = (uint16_t)(0x9000 + g_segment_count); memset(g_segments[g_segment_count], 0, sizeof(g_segments[0])); win16_bind_segment( selector, g_segments[g_segment_count], bytes, true); g_segment_count++; return win16_make_far_pointer(selector, 0); } return g_fail_direct ? 0 : g_direct_pointer; } HGLOBAL16 GlobalHandle16(uint16_t selector) { return selector >= 0x9000 && selector < 0x9004 ? (HGLOBAL16)(selector - 0x8f00) : 0; } BOOL16 GlobalUnlock16(HGLOBAL16 allocation) { assert(allocation >= 0x100 && allocation < 0x104); return 1; } HGLOBAL16 GlobalFree16(HGLOBAL16 allocation) { assert(allocation >= 0x100 && allocation < 0x104); g_global_frees++; return 0; } uint16_t win16_call_pascal_u16(Win16FarPtr procedure, uint16_t argument) { assert(procedure == g_borland_heap_error_handler && argument != 0); g_handler_calls++; if (g_handler_action == 2) { g_fail_segment = false; g_fail_direct = false; } return g_handler_action; } static void reset_environment(void) { win16_reset_segment_bindings(); memset(g_dgroup, 0, sizeof(g_dgroup)); win16_bind_segment(0x5000, g_dgroup, sizeof(g_dgroup), true); win16_set_dgroup_selector(0x5000); g_borland_heap_segment_head = 0; g_borland_local_heap_limit = 64; g_borland_heap_segment_bytes = 64; g_borland_heap_error_handler = 0; g_segment_count = 0; g_fail_segment = false; g_fail_direct = false; g_direct_pointer = win16_make_far_pointer(0xa000, 0); g_handler_action = 0; g_handler_calls = 0; g_global_frees = 0; } static void test_global_and_fallback_paths(void) { reset_environment(); BorlandAllocationAttempt direct = borland_try_get_mem(100); assert(!direct.failed && direct.block == g_direct_pointer); reset_environment(); g_borland_local_heap_limit = 32; g_fail_direct = true; BorlandAllocationAttempt fallback = borland_try_get_mem(40); assert(!fallback.failed); assert(fallback.block == win16_make_far_pointer(0x9000, 12)); } static void test_heap_error_actions(void) { reset_environment(); g_fail_segment = true; g_fail_direct = true; g_borland_heap_error_handler = win16_make_far_pointer(0x7000, 0x0100); g_handler_action = 1; BorlandAllocationAttempt result = borland_try_get_mem(20); assert(!result.failed && result.block == 0 && g_handler_calls == 1); g_handler_calls = 0; g_handler_action = 0; result = borland_try_get_mem(20); assert(result.failed && result.block == 0 && g_handler_calls == 1); g_handler_calls = 0; g_handler_action = 2; result = borland_try_get_mem(20); assert(!result.failed && result.block == win16_make_far_pointer(0x9000, 12)); assert(g_handler_calls == 1); } static void test_multi_segment_ring_and_release(void) { reset_environment(); BorlandAllocationAttempt first = borland_try_get_mem(20); BorlandAllocationAttempt second = borland_try_get_mem(20); BorlandAllocationAttempt third = borland_try_get_mem(20); assert(first.block == win16_make_far_pointer(0x9000, 12)); assert(second.block == win16_make_far_pointer(0x9000, 32)); assert(third.block == win16_make_far_pointer(0x9001, 12)); assert(g_borland_heap_segment_head == 0x9001); assert(win16_read_u16(win16_make_far_pointer(0x9000, 10)) == 0x9001); assert(win16_read_u16(win16_make_far_pointer(0x9001, 10)) == 0x9000); assert(!borland_try_free_mem(first.block, 20)); assert(!borland_try_free_mem(second.block, 20)); assert(g_borland_heap_segment_head == 0x9001 && g_global_frees == 1); assert(win16_read_u16(win16_make_far_pointer(0x9001, 10)) == 0x9001); assert(!borland_try_free_mem(third.block, 20)); assert(g_borland_heap_segment_head == 0 && g_global_frees == 2); } int main(void) { test_global_and_fallback_paths(); test_heap_error_actions(); test_multi_segment_ring_and_release(); return 0; }