/* TPWinCrt character output, input queue, and TextRec callbacks. */ #include "tdkpin_tpwincrt_text.h" #include "tdkpin_borland_files.h" /* 1008:1a39 -- draw [start_column,end_column) on the cursor row. */ void tpwincrt_draw_row_range(int16_t end_column, int16_t start_column) { if (start_column >= end_column) { return; } tpwincrt_begin_drawing(); int16_t x = (int16_t)(uint16_t)( (uint16_t)(start_column - (int16_t)g_tpwincrt_view_column) * g_tpwincrt_character_width); int16_t y = (int16_t)(uint16_t)( (uint16_t)((int16_t)g_tpwincrt_cursor_row - (int16_t)g_tpwincrt_view_row) * g_tpwincrt_character_height); (void)TextOut16( g_tpwincrt_paint_dc, x, y, tpwincrt_cell_pointer(g_tpwincrt_cursor_row, start_column), (int16_t)(end_column - start_column)); tpwincrt_end_drawing(); } /* * 1008:1a82 -- carriage return/line advance. The binary aliases two locals * in 1b11 through SS:BP; explicit pointers preserve the same updates without * pretending those caller-frame addresses are ordinary Pascal arguments. */ void tpwincrt_advance_line(int16_t *changed_start, int16_t *changed_end) { tpwincrt_draw_row_range(*changed_end, *changed_start); *changed_start = 0; *changed_end = 0; g_tpwincrt_cursor_column = 0; uint16_t next_row = (uint16_t)(g_tpwincrt_cursor_row + 1); if (next_row == g_tpwincrt_rows) { next_row--; g_tpwincrt_ring_row_origin++; if (g_tpwincrt_ring_row_origin == g_tpwincrt_rows) { g_tpwincrt_ring_row_origin = 0; } Win16FarPtr row = tpwincrt_cell_pointer(g_tpwincrt_cursor_row, 0); borland_fill_bytes(row, g_tpwincrt_columns, ' '); (void)ScrollWindow16( g_tpwincrt_window, 0, (INT16)(uint16_t)(0u - g_tpwincrt_character_height), 0, 0); (void)UpdateWindow16(g_tpwincrt_window); } g_tpwincrt_cursor_row = next_row; } /* 1008:1b11 -- write control/printable bytes into the circular text screen. */ void tpwincrt_write_bytes(uint16_t count, Win16FarPtr bytes) { tpwincrt_create_window(); int16_t changed_start = (int16_t)g_tpwincrt_cursor_column; int16_t changed_end = changed_start; while (count != 0) { uint8_t character = win16_read_u8(bytes); if (character >= 0x20) { win16_write_u8( tpwincrt_cell_pointer( g_tpwincrt_cursor_row, (int16_t)g_tpwincrt_cursor_column), character); g_tpwincrt_cursor_column++; if (changed_end < (int16_t)g_tpwincrt_cursor_column) { changed_end = (int16_t)g_tpwincrt_cursor_column; } if (g_tpwincrt_cursor_column == g_tpwincrt_columns) { tpwincrt_advance_line(&changed_start, &changed_end); } } else if (character == '\r') { tpwincrt_advance_line(&changed_start, &changed_end); } else if (character == '\b') { if ((int16_t)g_tpwincrt_cursor_column > 0) { g_tpwincrt_cursor_column--; win16_write_u8( tpwincrt_cell_pointer( g_tpwincrt_cursor_row, (int16_t)g_tpwincrt_cursor_column), ' '); if ((int16_t)g_tpwincrt_cursor_column < changed_start) { changed_start = (int16_t)g_tpwincrt_cursor_column; } } } else if (character == '\a') { (void)MessageBeep16(0); } bytes = win16_far_add_offset(bytes, 1); count--; } tpwincrt_draw_row_range(changed_end, changed_start); if (g_tpwincrt_auto_scroll != 0) { tpwincrt_scroll_cursor_into_view(); } } /* 1008:1be9 -- one-byte stack wrapper around the bulk writer. */ void tpwincrt_write_character(uint8_t character) { uint8_t byte = character; tpwincrt_write_bytes(1, win16_stack_pointer(&byte)); } /* 1008:1c03 -- drain all queued Win16 messages and report input availability. */ bool tpwincrt_poll_input(void) { tpwincrt_create_window(); MSG16 message; while (PeekMessage16(&message, 0, 0, 0, 1)) { if (message.message == 0x0012) { /* WM_QUIT */ tpwincrt_abort_on_ctrl_c(); } (void)TranslateMessage16(&message); (void)DispatchMessage16(&message); } return (int16_t)g_tpwincrt_input_count > 0; } /* 1008:1c5f -- block until one queued character is available, then dequeue it. */ uint8_t tpwincrt_read_character(void) { tpwincrt_scroll_cursor_into_view(); if (!tpwincrt_poll_input()) { g_tpwincrt_caret_enabled = 1; if (g_tpwincrt_has_focus != 0) { tpwincrt_create_caret(); } do { (void)WaitMessage16(); } while (!tpwincrt_poll_input()); if (g_tpwincrt_has_focus != 0) { tpwincrt_destroy_caret(); } g_tpwincrt_caret_enabled = 0; } g_tpwincrt_input_count--; uint8_t character = g_tpwincrt_input_buffer[0]; borland_move_bytes( win16_dgroup_pointer(0x4af8), win16_dgroup_pointer(0x4af9), g_tpwincrt_input_count); return character; } /* 1008:1cc6 -- edited line input with CR/LF and optional Ctrl-Z termination. */ uint16_t tpwincrt_read_line(uint16_t capacity, Win16FarPtr destination) { uint16_t length = 0; uint8_t character; do { character = tpwincrt_read_character(); if (character == '\b') { if (length != 0) { length--; tpwincrt_write_character('\b'); } } else if ( character >= 0x20 && (uint16_t)(capacity - 2) > length) { win16_write_u8( win16_far_add_offset(destination, length), character); length++; tpwincrt_write_character(character); } } while ( character != '\r' && (g_tpwincrt_ctrl_z_is_eof == 0 || character != 0x1a)); win16_write_u8(win16_far_add_offset(destination, length), character); length++; if (character == '\r') { win16_write_u8(win16_far_add_offset(destination, length), '\n'); length++; tpwincrt_write_character('\r'); } tpwincrt_scroll_cursor_into_view(); return length; } /* 1008:22fc -- TextRec output InOutFunc/FlushFunc. */ uint16_t tpwincrt_text_write_buffer(Win16FarPtr record) { uint16_t count = win16_read_u16(win16_far_add_offset(record, 8)); if (count != 0) { tpwincrt_write_bytes(count, win16_read_far_pointer(record, 0x0c)); win16_write_u16(record, 8, 0); (void)tpwincrt_poll_input(); } return 0; } /* 1008:233c -- TextRec input InOutFunc. */ uint16_t tpwincrt_text_read_buffer(Win16FarPtr record) { uint16_t count = tpwincrt_read_line( win16_read_u16(win16_far_add_offset(record, 4)), win16_read_far_pointer(record, 0x0c)); win16_write_u16(record, 0x0a, count); win16_write_u16(record, 8, 0); return 0; } static void write_text_procedure( 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)); } /* 1008:238b -- attach TPWinCrt callbacks to an input or output TextRec. */ uint16_t tpwincrt_open_text_record(Win16FarPtr record) { if (win16_read_u16(win16_far_add_offset(record, 2)) == BORLAND_FILE_INPUT) { write_text_procedure( record, 0x14, win16_relocated_code_pointer(2, 0x233c)); write_text_procedure(record, 0x18, 0); } else { win16_write_u16(record, 2, BORLAND_FILE_OUTPUT); Win16FarPtr write = win16_relocated_code_pointer(2, 0x22fc); write_text_procedure(record, 0x14, write); write_text_procedure(record, 0x18, write); } write_text_procedure( record, 0x1c, win16_relocated_code_pointer(2, 0x2374)); return 0; } /* * 1008:23fd -- initialize only the fields written by the binary. BufPos, * BufEnd, callbacks other than OpenFunc, and UserData deliberately retain * their prior bytes until Reset/Rewrite invokes 238b. */ void tpwincrt_initialize_text_record(Win16FarPtr record) { win16_write_u16(record, 0, 0xffff); win16_write_u16(record, 2, BORLAND_FILE_CLOSED); win16_write_u16(record, 4, 0x80); Win16FarPtr buffer = win16_far_add_offset(record, 0x80); write_text_procedure(record, 0x0c, buffer); write_text_procedure( record, 0x10, win16_relocated_code_pointer(2, 0x238b)); win16_write_u8(win16_far_add_offset(record, 0x30), 0); }