From: "Mark E." To: djgpp-workers AT delorie DOT com Date: Thu, 26 Jul 2001 16:19:49 -0400 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: termios cursor motion support Message-ID: <3B604325.14771.32CE14@localhost> X-mailer: Pegasus Mail for Win32 (v3.12c) Reply-To: djgpp-workers AT delorie DOT com This patch adds support for acting on ecma-48 commands and support for cursor motion commands. Other commands can be supported using the current output method. But I think color support would require the direct video method ala conio. Comments? *** tminit.bak Thu Jul 26 09:52:38 2001 --- tminit.c Thu Jul 26 16:12:26 2001 *************** *** 34,39 **** --- 34,41 ---- #define SENSE_REG_KEY 1 #define SENSE_EXT_KEY 2 + #define NARGS 16 + /* tty buffers */ unsigned char __libc_tty_queue_buffer[_TTY_QUEUE_SIZE]; struct tty __libc_tty_internal = TTYDEFAULT; *************** static unsigned ah_ctrl_sense; *** 50,55 **** --- 52,65 ---- static const unsigned char *ext_key_string; + /* Console command parser */ + + enum cmd_parser_states { need_esc = 0, have_esc, have_lbracket, + have_arg, have_cmd}; + + static enum cmd_parser_states cmd_state; + + /* static functions */ static void __libc_termios_fflushall (void); static ssize_t __libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv); *************** static void __libc_termios_clear_queue ( *** 69,74 **** --- 79,86 ---- static int __libc_termios_get_queue (void); static int __libc_termios_put_queue (unsigned char ch); static void __libc_termios_fill_queue (void); + static size_t parse_console_command(const unsigned char *buf, size_t count); + static void execute_console_command(const unsigned char cmd, unsigned char argc, unsigned int args[NARGS]); /* direct I/O functions */ static inline int __direct_keysense (void); *************** __libc_termios_write_cooked_tty (int han *** 420,429 **** rp = buffer; n = count; ! while (--n >= 0) { /* get character */ ! ch = *rp++; /* NOTE: multibyte character don't contain control character */ /* map NL to CRNL */ --- 432,456 ---- rp = buffer; n = count; ! while (n > 0) { /* get character */ ! ch = *rp; ! ! /* Handle console commands */ ! if (ch == '\e' || cmd_state != need_esc) ! { ! size_t delta; ! delta = parse_console_command(rp, n); ! ! /* Skip past what was parsed. */ ! n -= delta; ! rp += delta; ! continue; ! } ! ! ++rp; ! --n; /* NOTE: multibyte character don't contain control character */ /* map NL to CRNL */ *************** proc_skip: *** 963,965 **** --- 990,1208 ---- /******************************************************************************/ + static size_t + parse_console_command(const unsigned char *buf, size_t count) + { + static unsigned int args[NARGS]; + static unsigned char arg_count; + + const unsigned char *ptr = buf; + const unsigned char *ptr_end = buf + count; + + while (ptr < ptr_end) + { + switch (cmd_state) + { + case need_esc: + /* Find an escape or bail out. */ + if (*ptr != '\e') + return (ptr - buf); + ++ptr; + cmd_state = have_esc; + if (ptr >= ptr_end) + break; + + case have_esc: + /* Find a left bracket or bail out. */ + if (*ptr != '[') + return (ptr - buf); + + cmd_state = have_lbracket; + ++ptr; + if (ptr == ptr_end) + break; + + case have_lbracket: + /* After the left bracket, either an argument + or the command follows. */ + arg_count = NARGS; + arg_count = 0; + args[0] = 0; + if (isdigit(*ptr)) + { + cmd_state = have_arg; + } + else + { + cmd_state = have_cmd; + break; + } + + case have_arg: + { + /* Parse the argument. Quit when there are no more digits. */ + if (isdigit(*ptr)) + { + do + { + args[arg_count] *= 10; + args[arg_count] += *ptr - '0'; + ++ptr; + } while (ptr < ptr_end && isdigit(*ptr)); + break; + } + else if (*ptr == ';') + { + /* Argument separator. */ + ++arg_count; + if (arg_count < NARGS) + args[arg_count] = 0; + ++ptr; + break; + } + else + { + /* End of the current argument. + Assume the command has been reached. */ + cmd_state = have_cmd; + ++arg_count; + } + } + case have_cmd: + { + /* Execute the command. */ + execute_console_command(*ptr, arg_count, args); + /* Reset the parse state. */ + cmd_state = need_esc; + ++ptr; + return ptr - buf; + } + } + } + return ptr - buf; + } + + static inline void + get_cursor(unsigned char *col, unsigned char *row) + { + unsigned char cur_page; + unsigned short rowcol; + + cur_page = _farnspeekb(0x462); + + rowcol = _farnspeekw(0x450 + cur_page); + *row = rowcol >> 8; + *col = rowcol & 0xff; + } + + + static void + move_cursor(int x_delta, int y_delta) + { + unsigned char row, col; + unsigned char max_row, max_col; + unsigned char cur_page; + unsigned short rowcol; + __dpmi_regs r; + + _farsetsel(_dos_ds); + cur_page = _farnspeekb(0x462); + + rowcol = _farnspeekw(0x450 + cur_page); + row = rowcol >> 8; + col = rowcol & 0xff; + + max_row = _farnspeekb(0x484) + 1; + max_col = _farnspeekb(0x44a); + + if ((int)row + y_delta < 0) + row = 0; + else if (row + y_delta > max_row) + row = max_row; + + if ((int)col + x_delta < 0) + col = 0; + else if (col + x_delta > max_row) + col = max_col; + + r.h.ah = 2; + r.h.bh = cur_page; + r.h.dh = row + y_delta; + r.h.dl = col + x_delta; + __dpmi_int(0x10, &r); + } + + static void + set_cursor(unsigned char col, unsigned char row) + { + unsigned char max_row, max_col; + unsigned char cur_page; + unsigned short rowcol; + __dpmi_regs r; + + _farsetsel(_dos_ds); + cur_page = _farnspeekb(0x462); + + max_row = _farnspeekb(0x484) + 1; + max_col = _farnspeekb(0x44a); + + if (row + y_delta > max_row) + row = max_row; + + if (col + x_delta > max_row) + col = max_col; + + r.h.ah = 2; + r.h.bh = cur_page; + r.h.dh = row; + r.h.dl = col; + __dpmi_int(0x10, &r); + } + + #define GET_ARG(I, DEFVAL) ((argc > I) ? (args[I] : (DEFVAL))) + + static void + execute_console_command(const unsigned char cmd, unsigned char argc, + unsigned int args[NARGS]) + { + unsigned char row, col; + + switch (cmd) + { + /* Move up. */ + case 'A': + move_cursor(0, -GET_ARG(0, 1)); + break; + + /* Move down. */ + case 'B': + move_cursor(0, -GET_ARG(0, 1); + break; + + /* Move left. */ + case 'C': + move_cursor(-GET_ARG(0, 1), 0); + break; + + /* Move right. */ + case 'D': + move_cursor(GET_ARG(0, 1), 0); + break; + + /* Move to column. */ + case 'G': + get_cursor(&row, &col); + set_cursor(GET_ARG(0, 1) - 1, row); + break; + + /* Move to row and column. */ + case 'H': + set_cursor(GET_ARG(0, 1) - 1, GET_ARG(1, 1) - 1); + break; + + /* Move to row. */ + case 'd': + get_cursor(&row, &col); + set_cursor(row, GET_ARG(0, 1) - 1); + } + }