/* * tminit.c - initializer and main part of termios emulation. * designed for DJGPP by Daisuke Aoyama * special thanks to Ryo Shimizu */ #if defined (__DJGPP__) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __DJGPP_MINOR__ < 4 # define _DEV_STDIN 0x0001 # define _DEV_STDOUT 0x0002 # define _DEV_NUL 0x0004 # define _DEV_CLOCK 0x0008 # define _DEV_RAW 0x0020 # define _DEV_CDEV 0x0080 # define _DEV_IOCTRL 0x4000 #else # include #endif #define CPMEOF 0x1a /* Ctrl+Z */ #define _REG_STATUS_CF 0x01 #define _REG_STATUS_ZF 0x40 #define _KEY_INS 0x80 #define _KEY_CAPS 0x40 #define _KEY_NUM 0x20 #define _KEY_SCRL 0x10 #define _KEY_ALT 0x08 #define _KEY_CTRL 0x04 #define _KEY_LSFT 0x02 #define _KEY_RSFT 0x01 #define _KEYE_SYSRQ 0x80 #define _KEYE_CAPS 0x40 #define _KEYE_NUM 0x20 #define _KEYE_SCRL 0x10 #define _KEYE_RALT 0x08 #define _KEYE_RCTRL 0x04 #define _KEYE_LALT 0x02 #define _KEYE_LCTRL 0x01 #define CHECKBYTES 32 /* tty buffers */ unsigned char __libc_tty_queue_buffer[_TTY_QUEUE_SIZE]; struct tty __libc_tty_internal = TTYDEFAULT; struct tty *__libc_tty_p = &__libc_tty_internal; struct tty_editline __libc_tty_editline = { 0, { 0 }, { 0 }, }; /* global only in the termios functions */ int __libc_termios_hook_common_count = -1; /* static variables */ static int __libc_use_function_and_arrow_keys = 0; static int __libc_has_enhanced_keyboard = 0; static int __libc_has_extended_keystroke = 0; static unsigned char __libc_extended_keystroke[16] = { 0, }; static ssize_t __libc_termios_check_bytes = CHECKBYTES; /* static functions */ static void __libc_termios_fflushall (void); static void __libc_termios_init_direct_functions (void); static ssize_t __libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv); static ssize_t __libc_termios_read_cooked_tty (int handle, void *buffer, size_t count); static ssize_t __libc_termios_read_raw_tty (int handle, void *buffer, size_t count); static ssize_t __libc_termios_write (int handle, const void *buffer, size_t count, ssize_t *rv); static ssize_t __libc_termios_write_cooked_tty (int handle, const void *buffer, size_t count); static ssize_t __libc_termios_write_raw_tty (int handle, const void *buffer, size_t count); static int __libc_termios_fsext (__FSEXT_Fnumber n, int *rv, va_list ap); static void __libc_termios_echo_ctrl (unsigned char ch); static void __libc_termios_maybe_echo_ctrl (unsigned char ch); static void __libc_termios_maybe_echo (unsigned char ch); static void __libc_termios_maybe_erase1 (void); static void __libc_termios_erase_editline (void); static void __libc_termios_kill_editline (void); static void __libc_termios_insert_editline (unsigned char ch); #if __DJGPP_MINOR__ < 4 static int __libc_termios_exist_queue (void); #endif static void __libc_termios_clear_queue (void); static int __libc_termios_get_queue (void); static int __libc_termios_put_queue (unsigned char ch); static void __libc_termios_raise_signal (unsigned char ch, int sig); static void __libc_termios_fill_queue (void); /* direct I/O functions */ static void __direct_add_keystroke (int c); static void __direct_add_keystrokes (char *s); static void __direct_check_extened_keystroke_at (int scan); /* AT keyboard */ static int __direct_keysense_at (void); static unsigned char __direct_keyinput_at (void); static int __direct_ctrlsense_at (void); /* AT enhanced keyboard */ static int __direct_keysense_ate (void); static unsigned char __direct_keyinput_ate (void); static int __direct_ctrlsense_ate (void); /* Output functions */ static void __direct_output_tab_at (void); static void __direct_output_at (unsigned char ch); static void __direct_outputns_at (int n, const unsigned char *s); static void __direct_outputs_at (const unsigned char *s); /* function pointers */ static int (*__direct_keysense) (void) = __direct_keysense_at; static unsigned char (*__direct_keyinput) (void) = __direct_keyinput_at; static int (*__direct_ctrlsense) (void) = __direct_ctrlsense_at; static void (*__direct_output) (unsigned char ch) = __direct_output_at; static void (*__direct_outputns) (int n, const unsigned char *s) = __direct_outputns_at; static void (*__direct_outputs) (const unsigned char *s) = __direct_outputs_at; /******************************************************************************/ /* initialize function ********************************************************/ static void __libc_termios_fflushall(void) { #if 0 /* don't work on djgpp */ fflush(NULL); #else _fwalk((void (*) (FILE*)) fflush); #endif } static void __libc_termios_init_direct_functions(void) { __libc_has_enhanced_keyboard = 0; __libc_has_extended_keystroke = 0; if (_farpeekb(_dos_ds, 0x496) & 0x10) __libc_has_enhanced_keyboard = 1; if (__libc_has_enhanced_keyboard) { __direct_keysense = __direct_keysense_ate; __direct_keyinput = __direct_keyinput_ate; __direct_ctrlsense = __direct_ctrlsense_ate; } else { __direct_keysense = __direct_keysense_at; __direct_keyinput = __direct_keyinput_at; __direct_ctrlsense = __direct_ctrlsense_at; } __direct_output = __direct_output_at; __direct_outputs = __direct_outputs_at; } void __libc_termios_init(void) { if (__libc_termios_hook_common_count != __bss_count) { __libc_termios_hook_common_count = __bss_count; /* flush all buffered streams */ __libc_termios_fflushall(); /* check enhanced keyboard, etc */ __libc_termios_init_direct_functions(); /* set special hooks */ __libc_read_termios_hook = __libc_termios_read; __libc_write_termios_hook = __libc_termios_write; /* import parameters */ /* __libc_tty_p = ...; */ /* fsext */ (void) __FSEXT_set_function(0, __libc_termios_fsext); (void) __FSEXT_set_function(1, __libc_termios_fsext); (void) __FSEXT_set_function(2, __libc_termios_fsext); __libc_termios_check_bytes = CHECKBYTES; } } int __libc_termios_disable_function_and_arrow_keys(void) { int old_value; old_value = __libc_use_function_and_arrow_keys; __libc_use_function_and_arrow_keys = 0; return old_value; } int __libc_termios_enable_function_and_arrow_keys(void) { int old_value; old_value = __libc_use_function_and_arrow_keys; __libc_use_function_and_arrow_keys = 1; return old_value; } /******************************************************************************/ /* direct I/O function ********************************************************/ /* function key trans function */ static void __direct_add_keystroke(int c) { if (__libc_has_extended_keystroke + 1 > sizeof (__libc_extended_keystroke)) return; __libc_extended_keystroke[__libc_has_extended_keystroke++] = (unsigned char) c; } static void __direct_add_keystrokes(char *s) { int len; len = strlen(s); if (__libc_has_extended_keystroke + len > sizeof (__libc_extended_keystroke)) return; while (--len >= 0) __libc_extended_keystroke[__libc_has_extended_keystroke++] = (unsigned char) s[len]; } #define _NDUMMY (0xffU) #define _N(c) (0x00U|(c)) /* no shift */ #define _S(c) (0x40U|(c)) /* w/shift */ #define _C(c) (0x80U|(c)) /* w/ctrl */ #define _A(c) (0xc0U|(c)) /* w/alt */ #define _TRANS_NOSHIFT "\x1b[0" #define _TRANS_SHIFT "\x1b[1" #define _TRANS_CTRL "\x1b[2" #define _TRANS_ALT "\x1b[3" static unsigned char trans_alphabet_chars[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456ABCDEFGHIJKLMNOPQRSTUVWXYZ123456"; static unsigned char trans_mapping_chars_at[] = { /* 000-037: A-Z, 040-077: XA-XZ */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 00-07 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 08-0F */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 10-17 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 18-1F */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 20-27 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 28-2F */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 30-37 */ _NDUMMY, _NDUMMY, _NDUMMY, _N(040), _N(041), _N(042), _N(043), _N(044), /* 38-3F */ _N(045), _N(046), _N(047), _N(050), _N(051), _NDUMMY, _NDUMMY, _N(006), /* 40-47 */ _N(000), _N(010), _NDUMMY, _N(001), _NDUMMY, _N(002), _NDUMMY, _N(007), /* 48-4F */ _N(003), _N(011), _N(004), _N(005), _S(040), _S(041), _S(042), _S(043), /* 50-57 */ _S(044), _S(045), _S(046), _S(047), _S(050), _S(051), _C(040), _C(041), /* 58-5F */ _C(042), _C(043), _C(044), _C(045), _C(046), _C(047), _C(050), _C(051), /* 60-67 */ _A(040), _A(041), _A(042), _A(043), _A(044), _A(045), _A(046), _A(047), /* 68-6F */ _A(050), _A(051), _NDUMMY, _C(001), _C(002), _C(007), _C(011), _C(006), /* 70-77 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* 78-7F */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _C(010), _N(052), _N(053), _S(052), /* 80-87 */ _S(053), _C(052), _C(053), _A(052), _A(053), _C(000), _NDUMMY, _NDUMMY, /* 88-8F */ _NDUMMY, _C(003), _C(004), _C(005), _NDUMMY, _NDUMMY, _NDUMMY, _A(006), /* 90-97 */ _A(000), _A(010), _NDUMMY, _A(001), _NDUMMY, _A(002), _NDUMMY, _A(007), /* 98-9F */ _A(003), _A(011), _A(004), _A(005), _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* A0-A7 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* A8-AF */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* B0-B7 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* B8-BF */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* C0-C7 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* C8-CF */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* D0-D7 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* D8-DF */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* E0-E7 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* E8-EF */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* F0-F7 */ _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, _NDUMMY, /* F8-FF */ }; static void __direct_check_extened_keystroke_at(int scan) { int c, shift; if (!__libc_use_function_and_arrow_keys || scan < 0 || scan > 0xff) return; c = (int) trans_mapping_chars_at[scan]; if (c == (int) _NDUMMY) return; shift = c & 0xc0; c &= ~0xc0; __direct_add_keystroke(trans_alphabet_chars[c]); if (c >= 040) __direct_add_keystroke ('X'); if (shift == 0x00) __direct_add_keystrokes(_TRANS_NOSHIFT); else if (shift == 0x40) __direct_add_keystrokes(_TRANS_SHIFT); else if (shift == 0x80) __direct_add_keystrokes(_TRANS_CTRL); else if (shift == 0xc0) __direct_add_keystrokes(_TRANS_ALT); } /* Input form AT keyboard */ static int __direct_keysense_at (void) { __dpmi_regs r; if (__libc_has_extended_keystroke) return 1; r.h.ah = 0x01; __dpmi_int(0x16, &r); if (r.x.flags & _REG_STATUS_ZF) return 0; return 1; } static unsigned char __direct_keyinput_at(void) { __dpmi_regs r; if (__libc_has_extended_keystroke) return __libc_extended_keystroke[--__libc_has_extended_keystroke]; r.h.ah = 0x00; __dpmi_int (0x16, &r); if (r.h.al != 0x00) return r.h.al; __direct_check_extened_keystroke_at(r.h.ah); if (__libc_has_extended_keystroke) return __libc_extended_keystroke[--__libc_has_extended_keystroke]; return 0; } static int __direct_ctrlsense_at(void) { __dpmi_regs r; if (__libc_has_extended_keystroke) return 0; r.h.ah = 0x02; __dpmi_int (0x16, &r); if (r.h.al & _KEY_CTRL) return 1; return 0; } /* Input from AT enhanced keyboard */ static int __direct_keysense_ate(void) { __dpmi_regs r; if (__libc_has_extended_keystroke) return 1; r.h.ah = 0x11; __dpmi_int (0x16, &r); if (r.x.flags & _REG_STATUS_ZF) return 0; return 1; } static unsigned char __direct_keyinput_ate (void) { __dpmi_regs r; if (__libc_has_extended_keystroke) return __libc_extended_keystroke[--__libc_has_extended_keystroke]; r.h.ah = 0x10; __dpmi_int (0x16, &r); if (r.h.al != 0x00 && (r.h.al < 0xe0U || (r.h.al != 0xe0 && r.h.al != 0xf0))) return r.h.al; __direct_check_extened_keystroke_at(r.h.ah); if (__libc_has_extended_keystroke) return __libc_extended_keystroke[--__libc_has_extended_keystroke]; return 0; } static int __direct_ctrlsense_ate(void) { __dpmi_regs r; if (__libc_has_extended_keystroke) return 0; r.h.ah = 0x12; __dpmi_int(0x16, &r); if (r.h.al & _KEY_CTRL) /* either CTRL */ return 1; return 0; } /* output to Screen */ static void __direct_output_tab_at (void) { __dpmi_regs r; int page, col; int x, y; page = _farpeekb(_dos_ds, 0x462); col = _farpeekw(_dos_ds, 0x44a); r.h.ah = 3; r.h.bh = page; __dpmi_int(0x10, &r); x = r.h.dl; y = r.h.dh; x += 8; x &= ~7; if (x > col) { #if 1 r.h.al = '\r'; __dpmi_int(0x29, &r); r.h.al = '\n'; __dpmi_int(0x29, &r); #else (void) putch ('\r'); (void) putch ('\n'); #endif } else { r.h.ah = 2; r.h.bh = page; r.h.dl = x; r.h.dh = y; __dpmi_int(0x10, &r); } } static void __direct_output_at(unsigned char ch) { #if 1 __dpmi_regs r; #endif if (ch == 0x09) { __direct_output_tab_at(); return; } else if (ch == 0xff) return; #if 1 r.h.al = ch; __dpmi_int(0x29, &r); #else (void) putch(ch); #endif } static void __direct_outputns_at(int n, const unsigned char *s) { #if 1 __dpmi_regs r; #endif unsigned char ch; while (--n >= 0) { ch = *s++; if (ch == 0x09) __direct_output_tab_at(); else if (ch != 0xff) { #if 1 r.h.al = ch; __dpmi_int(0x29, &r); #else (void) putch(ch); #endif } } } static void __direct_outputs_at(const unsigned char *s) { while (*s) __direct_output_at(*s++); } /******************************************************************************/ /* special read function ******************************************************/ static ssize_t __libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv) { short devmod; ssize_t bytes; /* check handle whether valid or not */ devmod = _get_dev_info (handle); if (devmod == -1) { *rv = -1; return 1; } /* special case */ if (count == 0) { *rv = 0; return 1; } /* console only... */ if ((devmod & _DEV_CDEV) && (devmod & (_DEV_STDIN|_DEV_STDOUT))) { /* character device */ if (devmod & _DEV_RAW) *rv = __libc_termios_read_raw_tty (handle, buffer, count); else *rv = __libc_termios_read_cooked_tty (handle, buffer, count); return 1; } if (__file_handle_modes[handle] & O_BINARY) { bytes = _read (handle, buffer, count); if (bytes < 0) { *rv = -1; return 1; } } else { unsigned char *rp, *wp; ssize_t n; bytes = _read (handle, buffer, count); if (bytes < 0) { *rv = -1; return 1; } rp = wp = buffer; n = bytes; while (--n >= 0) { unsigned char ch; ch = *rp++; if (ch == CPMEOF) { ++n; (void) lseek (handle, -n, SEEK_CUR); break; } else if (ch == '\r') { if (n > 0) { /* peek next character */ if (*rp == '\n') { /* if found '\n', delete '\r' */ ch = *rp++; --n; } } else { unsigned char tmpch; /* read a character to peek */ if (_read (handle, &tmpch, 1) == 1) { if (tmpch == '\n') ch = tmpch; else (void) lseek (handle, -1, SEEK_CUR); } } } *wp++ = ch; } bytes = wp - (unsigned char *) buffer; } /* result of read() */ *rv = bytes; return 1; } static ssize_t __libc_termios_read_cooked_tty (int handle, void *buffer, size_t count) { unsigned char *wp; ssize_t n; wp = buffer; n = count; #if 0 /* clear cooked queue */ if (__libc_termios_exist_queue ()) __libc_termios_clear_queue (); #endif if (__libc_tty_p->t_lflag & ICANON) { /* get inputs (wait for NL or EOT) */ if (! __libc_termios_exist_queue ()) __libc_termios_fill_queue (); while (--n >= 0) { if (! __libc_termios_exist_queue ()) break; *wp++ = __libc_termios_get_queue (); } } else { /* block until getting inputs */ while (! __libc_termios_exist_queue ()) { __dpmi_yield (); __libc_termios_fill_queue (); } while (--n >= 0) { *wp++ = __libc_termios_get_queue (); if (! __libc_termios_exist_queue ()) { __libc_termios_fill_queue (); if (! __libc_termios_exist_queue ()) break; } } } return (ssize_t) (wp - (unsigned char *) buffer); } static ssize_t __libc_termios_read_raw_tty (int handle, void *buffer, size_t count) { unsigned char *wp; unsigned char ch; ssize_t n; n = count; wp = buffer; /* clear cooked queue */ if (__libc_termios_exist_queue ()) __libc_termios_clear_queue (); /* block until getting inputs */ while (! __direct_keysense ()) __dpmi_yield (); while (--n >= 0) { /* exhaust inputs ? */ if (! __direct_keysense ()) break; /* realy get */ ch = __direct_keyinput (); /* replace CTRL+SPACE with 0x00 */ if (ch == ' ' && __direct_ctrlsense ()) ch = '\0'; /* copy a character into buffer and echo */ *wp++ = ch; __libc_termios_maybe_echo (ch); } return (ssize_t) (wp - (unsigned char *) buffer); } /******************************************************************************/ /* special write function *****************************************************/ static unsigned char __libc_termios_write_sbuf_internal[64]; static unsigned char *__libc_termios_write_sbuf = NULL; static size_t __libc_termios_write_sbuflen = 0; static int __libc_termios_write_count = -1; void __libc_termios_check_signals (void); static ssize_t __libc_termios_write (int handle, const void *buffer, size_t count, ssize_t *rv) { short devmod; ssize_t bytes; /* check handle whether valid or not */ devmod = _get_dev_info (handle); if (devmod == -1) { *rv = -1; return 1; } /* special case */ if (count == 0) { *rv = 0; return 1; } /* console only... */ if ((devmod & _DEV_CDEV) && (devmod & (_DEV_STDIN|_DEV_STDOUT))) { /* character device */ if (devmod & _DEV_RAW) *rv = __libc_termios_write_raw_tty (handle, buffer, count); else *rv = __libc_termios_write_cooked_tty (handle, buffer, count); return 1; } if (__file_handle_modes[handle] & O_BINARY) { bytes = _write (handle, buffer, count); if (bytes < 0) { *rv = -1; return 1; } } else { const unsigned char *rp; unsigned char *tp, *ep; ssize_t n; /* initialize local buffer */ if (__libc_termios_write_count != __bss_count) { __libc_termios_write_count = __bss_count; __libc_termios_write_sbuflen = _go32_info_block.size_of_transfer_buffer; __libc_termios_write_sbuf = malloc (__libc_termios_write_sbuflen); if (__libc_termios_write_sbuf == NULL) { __libc_termios_write_sbuf = &__libc_termios_write_sbuf_internal[0]; __libc_termios_write_sbuflen = sizeof (__libc_termios_write_sbuf_internal); } } rp = buffer; tp = __libc_termios_write_sbuf; ep = tp + __libc_termios_write_sbuflen; n = count; bytes = 0; while (n >= 0) { unsigned char *wp; unsigned char ch; ssize_t ncr, wbytes; /* fill local buffer */ wp = tp; ncr = 0; while ((wp < ep) && (--n >= 0)) { /* get character */ ch = *rp++; /* LF conversion */ if (ch == '\n') { if (wp == (ep - 1)) { n++; rp--; break; } *wp++ = '\r'; ncr++; } /* put character */ *wp++ = ch; } /* write on handle */ wbytes = _write (handle, tp, (size_t) (wp - tp)); if (wbytes < 0) { *rv = -1; return 1; } if (wbytes < (ssize_t) (wp - tp)) { /* detected disk full, but the result is not reality */ *rv = bytes + (wbytes > ncr ? wbytes - ncr : 0); return 1; } /* don't count CR */ bytes += wbytes - ncr; } } __libc_termios_check_bytes -= bytes; if (__libc_termios_check_bytes <= 0) { __libc_termios_check_bytes = CHECKBYTES; __libc_termios_check_signals (); } /* result of write() */ *rv = bytes; return 1; } static ssize_t __libc_termios_write_cooked_tty (int handle, const void *buffer, size_t count) { ssize_t bytes; /* output process if need */ if (__libc_tty_p->t_oflag & OPOST) { const unsigned char *rp; unsigned char ch; ssize_t n, nn; rp = buffer; n = count; while (n > 0) { nn = (n < __libc_termios_check_bytes) ? n : __libc_termios_check_bytes; n -= nn; __libc_termios_check_bytes -= nn; while (--nn >= 0) { /* get character */ ch = *rp++; /* NOTE: multibyte character don't contain control character */ /* map NL to CRNL */ if (ch == '\n' && (__libc_tty_p->t_oflag & ONLCR)) __direct_output ('\r'); /* map CR to NL */ else if (ch == '\r' && (__libc_tty_p->t_oflag & OCRNL)) ch = '\n'; __direct_output (ch); } if (__libc_termios_check_bytes <= 0) { __libc_termios_check_bytes = CHECKBYTES; __libc_termios_check_signals (); } } /* don't count CR */ bytes = count; } else { /* output with no effect */ bytes = __libc_termios_write_raw_tty (handle, buffer, count); } return bytes; } static ssize_t __libc_termios_write_raw_tty (int handle, const void *buffer, size_t count) { const unsigned char *rp; ssize_t n; rp = buffer; n = count; while (n > 0) { if (n < __libc_termios_check_bytes) { __libc_termios_check_bytes -= n; __direct_outputns (n, rp); rp += n; break; } else { n -= __libc_termios_check_bytes; __direct_outputns (__libc_termios_check_bytes, rp); rp += __libc_termios_check_bytes; __libc_termios_check_bytes = CHECKBYTES; __libc_termios_check_signals (); } } return count; } /******************************************************************************/ /* special fsext function *****************************************************/ static int __libc_termios_fsext (__FSEXT_Fnumber n, int *rv, va_list ap) { short devmod; ssize_t bytes; int handle; handle = va_arg (ap, int); devmod = _get_dev_info (handle); if (devmod == -1) return 0; if (!(devmod & _DEV_CDEV) || !(devmod & (_DEV_STDIN|_DEV_STDOUT))) return 0; /* console only... */ switch (n) { #if 0 case __FSEXT_read: { void *buffer; size_t count; buffer = va_arg (ap, void *); count = va_arg (ap, size_t); if (devmod & _DEV_RAW) bytes = __libc_termios_read_raw_tty (handle, buffer, count); else bytes = __libc_termios_read_cooked_tty (handle, buffer, count); /* result of read */ *rv = bytes; return 1; } case __FSEXT_write: { const void *buffer; size_t count; buffer = va_arg (ap, const void *); count = va_arg (ap, size_t); if (devmod & _DEV_RAW) bytes = __libc_termios_write_raw_tty (handle, buffer, count); else bytes = __libc_termios_write_cooked_tty (handle, buffer, count); /* result of write */ *rv = bytes; return 1; } #else case __FSEXT_write: { size_t count; const void *buffer; buffer = va_arg (ap, const void *); count = va_arg (ap, size_t); bytes = __libc_termios_write_raw_tty (handle, buffer, count); /* result of write */ *rv = bytes; return 1; } #endif default: break; } return 0; } /******************************************************************************/ /* echo routines **************************************************************/ static void __libc_termios_echo_ctrl (unsigned char ch) { ch ^= 0x40; __direct_output ('^'); __direct_output (ch); } static void __libc_termios_maybe_echo_ctrl (unsigned char ch) { if (__libc_tty_p->t_lflag & ECHOCTL) __libc_termios_echo_ctrl (ch); } static void __libc_termios_maybe_echo (unsigned char ch) { if (! (__libc_tty_p->t_lflag & ECHO)) { /* don't echo but newline is required ? */ if (ch == '\n' && (__libc_tty_p->t_lflag & ECHONL)) { if (__libc_tty_p->t_oflag & ONLCR) __direct_output ('\r'); __direct_output ('\n'); } return; } /* check literal flag */ if ((__libc_tty_p->t_status & _TS_LNCH) && (ch < 0x20)) { __libc_termios_echo_ctrl (ch); return; } /* output process if need */ if (__libc_tty_p->t_oflag & OPOST) { /* map NL to CRNL */ if (ch == '\n' && (__libc_tty_p->t_oflag & ONLCR)) { __direct_output ('\r'); __direct_output ('\n'); return; } /* map CR to NL */ else if (ch == '\r' && (__libc_tty_p->t_oflag & OCRNL)) { __direct_output ('\n'); return; } /* discard EOT */ else if (_CC_EQU (VEOF, ch) && (__libc_tty_p->t_oflag & ONOEOT)) { return; } } /* control character except newline */ if ((ch < 0x20 || ch == 0x7f) && (__libc_tty_p->t_lflag & ECHOCTL) && ch != '\n') { __libc_termios_echo_ctrl (ch); return; } /* no effect */ __direct_output (ch); } /******************************************************************************/ /* edit routines **************************************************************/ static void __libc_termios_maybe_erase1 (void) { if (__libc_tty_p->t_lflag & ECHO) { /* eat prev. character by BS SPC BS */ __direct_output ('\010'); if (__libc_tty_p->t_lflag & ECHOE) { __direct_output (' '); __direct_output ('\010'); } } } /* erase one prev. character of editline */ static void __libc_termios_erase_editline (void) { int col; char pf; col = __libc_tty_editline.col; if (col == 0) /* no more */ return; /* get position flag */ pf = __libc_tty_editline.flag[col - 1]; if (pf == _TTY_EDITLINE_INVALID || pf < 0) { /* erase all invalid character */ while (col > 0 && __libc_tty_editline.flag[col - 1] < 0) { __libc_termios_maybe_erase1 (); --col; } } else if (pf == _TTY_EDITLINE_CTRL) { if (__libc_tty_p->t_lflag & ECHOCTL) { /* erase one of "^X" */ __libc_termios_maybe_erase1 (); --col; } __libc_termios_maybe_erase1 (); --col; } else { /* erase single or multibyte charcter */ while (--pf >= 0) { __libc_termios_maybe_erase1 (); --col; } } /* set next insert position */ __libc_tty_editline.col = col; } /* erase all editline */ static void __libc_termios_kill_editline (void) { if (__libc_tty_p->t_lflag & ECHOKE) { while (__libc_tty_editline.col != 0) __libc_termios_erase_editline (); } else __libc_tty_editline.col = 0; if (__libc_tty_p->t_lflag & ECHOK) __libc_termios_maybe_echo ('\n'); } static void __libc_termios_insert_editline (unsigned char ch) { int mbsize; int col; col = __libc_tty_editline.col; if (col >= _TTY_EDITLINE_SIZE) { /* detected over flow */ if (__libc_tty_p->t_iflag & IMAXBEL) __direct_output ('\007'); return; } __libc_tty_editline.buf[col] = ch; if (col == 0 || ((col > 0) && __libc_tty_editline.flag[col - 1] != _TTY_EDITLINE_INVALID)) { /* check multibyte length */ mbsize = mblen (__libc_tty_editline.buf + col, 1); if (mbsize == 1) { /* single character */ if ((ch < 0x20) || ch == 0x7f) __libc_tty_editline.flag[col] = _TTY_EDITLINE_CTRL; else __libc_tty_editline.flag[col] = _TTY_EDITLINE_SINGLE; __libc_termios_maybe_echo (ch); } else { /* first of multibyte or invalid character */ __libc_tty_editline.flag[col] = _TTY_EDITLINE_INVALID; __libc_tty_p->t_status |= _TS_LNCH; } } else { int pcol; /* look for non fixed flag */ pcol = col; while (__libc_tty_editline.flag[pcol - 1] == _TTY_EDITLINE_INVALID) if (--pcol <= 0) break; /* check whether it's multibyte sequence */ mbsize = mblen (__libc_tty_editline.buf + pcol, (col - pcol + 1)); if (mbsize > 1) { /* multibyte sequence is good */ while (pcol < col) { /* set negative size for dividing sequence */ __libc_tty_editline.flag[pcol] = -mbsize; __libc_termios_maybe_echo (__libc_tty_editline.buf[pcol]); pcol++; } /* last flag is always positive size */ __libc_tty_editline.flag[col] = mbsize; __libc_termios_maybe_echo (ch); } else { if ((col - pcol + 1) > MB_CUR_MAX) { /* it's terrible... */ while (pcol <= col) { /* replace all with valid character */ __libc_tty_editline.flag[pcol] = _TTY_EDITLINE_SINGLE; __libc_tty_editline.buf[pcol] = 'X'; __libc_termios_maybe_echo ('X'); pcol++; } } /* continuous multibyte character */ __libc_tty_editline.flag[col] = _TTY_EDITLINE_INVALID; __libc_tty_p->t_status |= _TS_LNCH; } } /* set next insert position */ col++; __libc_tty_editline.col = col; } /******************************************************************************/ /* queued input routines ******************************************************/ #if __DJGPP_MINOR__ < 4 static int #else int #endif __libc_termios_exist_queue (void) { return __libc_tty_p->t_count; } static void __libc_termios_clear_queue (void) { __libc_tty_p->t_count = 0; __libc_tty_p->t_rpos = __libc_tty_p->t_top; __libc_tty_p->t_wpos = __libc_tty_p->t_top; } static int __libc_termios_get_queue (void) { int ch; if (__libc_tty_p->t_count == 0) return -1; ch = *__libc_tty_p->t_rpos++; __libc_tty_p->t_count--; if (__libc_tty_p->t_rpos >= __libc_tty_p->t_bottom) __libc_tty_p->t_rpos = __libc_tty_p->t_top; return ch; } static int __libc_termios_put_queue (unsigned char ch) { if (__libc_tty_p->t_count >= __libc_tty_p->t_size) return -1; *__libc_tty_p->t_wpos++ = ch; __libc_tty_p->t_count++; if (__libc_tty_p->t_wpos >= __libc_tty_p->t_bottom) __libc_tty_p->t_wpos = __libc_tty_p->t_top; return 0; } static void __libc_termios_raise_signal (unsigned char ch, int sig) { #if 0 struct sigaction oldact; if (sigaction (sig, NULL, &oldact) == 0) if (oldact.sa_handler == SIG_DFL) __libc_termios_maybe_echo_ctrl (ch); #else __libc_termios_maybe_echo_ctrl (ch); #endif kill (getpid(), sig); } static void __libc_termios_fill_queue (void) { unsigned char ch; while (1) { /* exhaust inputs ? */ if (! __direct_keysense ()) { __dpmi_yield (); /* wait for NL or EOT ? */ if (__libc_tty_p->t_lflag & ICANON) continue; return; } /* realy get */ ch = __direct_keyinput (); /* replace CTRL+SPACE with 0x00 */ if (ch == ' ' && __direct_ctrlsense ()) ch = '\0'; /* input process if need */ if (! (__libc_tty_p->t_status & _TS_LNCH) || ch != (unsigned char) _POSIX_VDISABLE) { /* software signals */ if (__libc_tty_p->t_lflag & ISIG) { if (! (__libc_tty_p->t_iflag & IGNBRK) && _CC_EQU (VINTR, ch)) { if (__libc_tty_p->t_iflag & BRKINT) { __libc_termios_raise_signal (ch, SIGINT); continue; } else { ch = '\0'; goto proc_skip; } } else if (_CC_EQU (VQUIT, ch)) { __libc_termios_raise_signal (ch, SIGQUIT); continue; } else if (_CC_EQU (VSUSP, ch)) { #ifdef SIGTSTP __libc_termios_raise_signal (ch, SIGTSTP); #else /* djgpp don't have ... */ { char oldcwd[PATH_MAX]; int fds[5] = { -1, -1, -1, -1, -1 }; int i; for (i = 0; i < 5; i++) if ((fds[i] = fcntl (i, F_DUPFD, 20)) < 0) __direct_outputs ("Suspend: cannot save fds\r\n"); __direct_outputs ("\r\nSuspended\r\n"); /* keep cwd on exec */ getcwd (oldcwd, sizeof (oldcwd)); system (NULL); chdir (oldcwd); for (i = 0; i < 5; i++) if (fds[i] >= 0) { dup2 (fds[i], i); close (fds[i]); } } #endif /* !SIGTSTP */ continue; } } /* flow control... */ if (_CC_EQU (VSTART, ch) && (__libc_tty_p->t_iflag & IXOFF)) { continue; } else if (_CC_EQU (VSTOP, ch) && (__libc_tty_p->t_iflag & IXOFF)) { continue; } /* CR/LF process */ if (ch == '\r') { if (__libc_tty_p->t_iflag & IGNCR) continue; if (__libc_tty_p->t_iflag & ICRNL) ch = '\n'; } else if ((ch == '\n') && (__libc_tty_p->t_iflag & INLCR)) ch = '\r'; /* strip 8th-bit */ if (__libc_tty_p->t_iflag & ISTRIP) ch &= 0x7f; } proc_skip: if (__libc_tty_p->t_lflag & ICANON) { if (__libc_tty_p->t_status & _TS_LNCH) { __libc_tty_p->t_status &= ~_TS_LNCH; __libc_termios_insert_editline (ch); } else { if (_CC_EQU (VERASE, ch)) __libc_termios_erase_editline (); else if (_CC_EQU (VKILL, ch)) __libc_termios_kill_editline (); else if (ch == '\n' || _CC_EQU (VEOF, ch) || _CC_EQU (VEOL, ch)) { int col = __libc_tty_editline.col; unsigned char *p = __libc_tty_editline.buf; /* clear column for next access */ __libc_tty_editline.col = 0; /* copy editline into tty queue */ while (--col >= 0) __libc_termios_put_queue (*p++); /* echo terminate character and put it */ __libc_termios_maybe_echo (ch); if (_CC_NEQU (VEOF, ch)) __libc_termios_put_queue (ch); return; } else __libc_termios_insert_editline (ch); } /* !_TS_LNCH */ } else /* !ICANON */ { __libc_termios_maybe_echo (ch); __libc_tty_p->t_status &= ~_TS_LNCH; __libc_termios_put_queue (ch); } } /* end of while (1) */ } /******************************************************************************/ /* software signal checker ****************************************************/ void __libc_termios_check_signals (void) { unsigned char ch; if (! __direct_keysense ()) return; /* software signals */ if (__libc_tty_p->t_lflag & ISIG) { ch = __direct_keyinput (); if (! (__libc_tty_p->t_iflag & IGNBRK) && _CC_EQU (VINTR, ch)) { if (__libc_tty_p->t_iflag & BRKINT) { __libc_termios_raise_signal (ch, SIGINT); return; } } else if (_CC_EQU (VQUIT, ch)) { __libc_termios_raise_signal (ch, SIGQUIT); return; } /* for compatiblity */ if (ch == 0x13 && !(__libc_tty_p->t_iflag & IXOFF)) { /* CTRL+S */ while (! __direct_keysense ()) __dpmi_yield (); ch = __direct_keyinput (); return; } /* push back */ __direct_add_keystroke ((int) ch); } } /******************************************************************************/ #endif /* __DJGPP__ */