home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / posix / termios / tminit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-15  |  22.5 KB  |  1,006 lines

  1. /*
  2.  * tminit.c - initializer and main part of termios emulation.
  3.  *   designed for DJGPP by Daisuke Aoyama <jack@st.rim.or.jp>
  4.  *   special thanks to Ryo Shimizu
  5.  */
  6.  
  7. #include <libc/stubs.h>
  8. #include <fcntl.h>
  9. #include <go32.h>
  10. #include <io.h>
  11. #include <limits.h>
  12. #include <signal.h>
  13. #include <stddef.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <termios.h>
  17. #include <unistd.h>
  18. #include <libc/bss.h>
  19. #include <libc/file.h>
  20. #include <libc/dosio.h>
  21. #include <libc/ttyprvt.h>
  22.  
  23. #define _DEV_STDIN  0x0001
  24. #define _DEV_STDOUT 0x0002
  25. #define _DEV_NUL    0x0004
  26. #define _DEV_CLOCK  0x0008
  27. #define _DEV_RAW    0x0020
  28. #define _DEV_CDEV   0x0080
  29. #define _DEV_IOCTRL 0x4000
  30.  
  31. #define CPMEOF 0x1a /* Ctrl+Z */
  32.  
  33. /* tty buffers */
  34. unsigned char __libc_tty_queue_buffer[_TTY_QUEUE_SIZE];
  35. struct tty __libc_tty_internal = TTYDEFAULT;
  36. struct tty *__libc_tty_p = &__libc_tty_internal;
  37. struct tty_editline __libc_tty_editline = { 0, { 0 }, { 0 }, };
  38.  
  39. /* global only in the termios functions */
  40. int __libc_termios_hook_common_count = -1;
  41.  
  42. /* static functions */
  43. static void __libc_termios_fflushall (void);
  44. static ssize_t __libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv);
  45. static ssize_t __libc_termios_read_cooked_tty (int handle, void *buffer, size_t count);
  46. static ssize_t __libc_termios_read_raw_tty (int handle, void *buffer, size_t count);
  47. static ssize_t __libc_termios_write (int handle, const void *buffer, size_t count, ssize_t *rv);
  48. static ssize_t __libc_termios_write_cooked_tty (int handle, const void *buffer, size_t count);
  49. static ssize_t __libc_termios_write_raw_tty (int handle, const void *buffer, size_t count);
  50. static void __libc_termios_echo_ctrl (unsigned char ch);
  51. static void __libc_termios_maybe_echo_ctrl (unsigned char ch);
  52. static void __libc_termios_maybe_echo (unsigned char ch);
  53. static void __libc_termios_maybe_erase1 (void);
  54. static void __libc_termios_erase_editline (void);
  55. static void __libc_termios_kill_editline (void);
  56. static void __libc_termios_insert_editline (unsigned char ch);
  57. static int __libc_termios_exist_queue (void);
  58. static void __libc_termios_clear_queue (void);
  59. static int __libc_termios_get_queue (void);
  60. static int __libc_termios_put_queue (unsigned char ch);
  61. static void __libc_termios_fill_queue (void);
  62.  
  63. /* direct I/O functions */
  64. static inline int __direct_keysense (void);
  65. static inline unsigned char __direct_keyinput (void);
  66. static inline int __direct_ctrlsense (void);
  67. static inline void __direct_output (unsigned char ch);
  68. static inline void __direct_outputs (const unsigned char *s);
  69.  
  70. /******************************************************************************/
  71. /* initialize function ********************************************************/
  72.  
  73. static void
  74. __libc_termios_fflushall (void)
  75. {
  76. #if 0 /* don't work on djgpp */
  77.   fflush (NULL);
  78. #else
  79.   _fwalk ((void (*) (FILE*)) fflush);
  80. #endif
  81. }
  82.  
  83. void
  84. __libc_termios_init (void)
  85. {
  86.   if (__libc_termios_hook_common_count != __bss_count)
  87.     {
  88.       __libc_termios_hook_common_count = __bss_count;
  89.  
  90.       /* flush all buffered streams */
  91.       __libc_termios_fflushall ();
  92.  
  93.       /* set special hooks */
  94.       __libc_read_termios_hook = __libc_termios_read;
  95.       __libc_write_termios_hook = __libc_termios_write;
  96.  
  97.       /* import parameters */
  98.       /* __libc_tty_p = ...; */
  99.     }
  100. }
  101.  
  102. /******************************************************************************/
  103. /* direct I/O function (inlined) **********************************************/
  104.  
  105. #define _REG_STATUS_ZF 0x40
  106.  
  107. static inline int
  108. __direct_keysense (void)
  109. {
  110.   __dpmi_regs r;
  111.  
  112.   r.h.ah = 0x01;
  113.   __dpmi_int (0x16, &r);
  114.   if (r.x.flags & _REG_STATUS_ZF)
  115.     return 0;
  116.  
  117.   return 1;
  118. }
  119.  
  120. static inline unsigned char
  121. __direct_keyinput (void)
  122. {
  123.   __dpmi_regs r;
  124.  
  125.   r.h.ah = 0x00;
  126.   __dpmi_int (0x16, &r);
  127.  
  128.   return r.h.al;
  129. }
  130.  
  131. #define _KEY_INS  0x80
  132. #define _KEY_CAPS 0x40
  133. #define _KEY_NUM  0x20
  134. #define _KEY_SCRL 0x10
  135. #define _KEY_ALT  0x08
  136. #define _KEY_CTRL 0x04
  137. #define _KEY_LSFT 0x02
  138. #define _KEY_RSFT 0x01
  139.  
  140. static inline int
  141. __direct_ctrlsense (void)
  142. {
  143.   __dpmi_regs r;
  144.  
  145.   r.h.ah = 0x02;
  146.   __dpmi_int (0x16, &r);
  147.   if (r.h.al & _KEY_CTRL)
  148.     return 1;
  149.  
  150.   return 0;
  151. }
  152.  
  153. static inline void
  154. __direct_output (unsigned char ch)
  155. {
  156.   __dpmi_regs r;
  157.  
  158.   if (ch == 0xff)
  159.     return;
  160.  
  161.   r.h.al = ch;
  162.   __dpmi_int (0x29, &r);
  163. }
  164.  
  165. static inline void
  166. __direct_outputs (const unsigned char *s)
  167. {
  168.   while (*s)
  169.     __direct_output (*s++);
  170. }
  171.  
  172. /******************************************************************************/
  173. /* special read function ******************************************************/
  174.  
  175. static ssize_t
  176. __libc_termios_read (int handle, void *buffer, size_t count, ssize_t *rv)
  177. {
  178.   short devmod;
  179.   ssize_t bytes;
  180.  
  181.   /* check handle whether valid or not */
  182.   devmod = _get_dev_info (handle);
  183.   if (devmod == -1)
  184.     {
  185.       *rv = -1;
  186.       return 1;
  187.     }
  188.  
  189.   /* special case */
  190.   if (count == 0)
  191.     {
  192.       *rv = 0;
  193.       return 1;
  194.     }
  195.  
  196.   /* console only... */
  197.   if ((devmod & _DEV_CDEV) && (devmod & (_DEV_STDIN|_DEV_STDOUT)))
  198.     {
  199.       /* character device */
  200.       if (devmod & _DEV_RAW)
  201.     *rv = __libc_termios_read_raw_tty (handle, buffer, count);
  202.       else
  203.     *rv = __libc_termios_read_cooked_tty (handle, buffer, count);
  204.       return 1;
  205.     }
  206.  
  207.   if (__file_handle_modes[handle] & O_BINARY)
  208.     {
  209.       bytes = _read (handle, buffer, count);
  210.       if (bytes < 0)
  211.     {
  212.       *rv = -1;
  213.       return 1;
  214.     }
  215.     }
  216.   else
  217.     {
  218.       unsigned char *rp, *wp;
  219.       ssize_t n;
  220.  
  221.       bytes = _read (handle, buffer, count);
  222.       if (bytes < 0)
  223.     {
  224.       *rv = -1;
  225.       return 1;
  226.     }
  227.  
  228.       rp = wp = buffer;
  229.       n = bytes;
  230.       while (--n >= 0)
  231.     {
  232.       unsigned char ch;
  233.  
  234.       ch = *rp++;
  235.       if (ch == CPMEOF)
  236.         {
  237.           ++n;
  238.           (void) lseek (handle, -n, SEEK_CUR);
  239.           break;
  240.         }
  241.       else if (ch == '\r')
  242.         {
  243.           if (n > 0)
  244.         {
  245.           /* peek next character */
  246.           if (*rp == '\n')
  247.             {
  248.               /* if found '\n', delete '\r' */
  249.               ch = *rp++;
  250.               --n;
  251.             }
  252.         }
  253.           else
  254.         {
  255.           unsigned char tmpch;
  256.  
  257.           /* read a character to peek */
  258.           if (_read (handle, &tmpch, 1) == 1)
  259.             {
  260.               if (tmpch == '\n')
  261.             ch = tmpch;
  262.               else
  263.             (void) lseek (handle, -1, SEEK_CUR);
  264.             }
  265.         }
  266.         }
  267.       *wp++ = ch;
  268.     }
  269.       bytes = wp - (unsigned char *) buffer;
  270.     }
  271.  
  272.   /* result of read() */
  273.   *rv =  bytes;
  274.   return 1;
  275. }
  276.  
  277. static ssize_t
  278. __libc_termios_read_cooked_tty (int handle, void *buffer, size_t count)
  279. {
  280.   unsigned char *wp;
  281.   ssize_t n;
  282.  
  283.   wp = buffer;
  284.   n = count;
  285.  
  286. #if 0
  287.   /* clear cooked queue */
  288.   if (__libc_termios_exist_queue ())
  289.     __libc_termios_clear_queue ();
  290. #endif
  291.  
  292.   if (__libc_tty_p->t_lflag & ICANON)
  293.     {
  294.       /* get inputs (wait for NL or EOT) */
  295.       if (! __libc_termios_exist_queue ())
  296.     __libc_termios_fill_queue ();
  297.  
  298.       while (--n >= 0)
  299.     {
  300.       if (! __libc_termios_exist_queue ())
  301.         break;
  302.  
  303.       *wp++ = __libc_termios_get_queue ();
  304.     }
  305.     }
  306.   else
  307.     {
  308.       /* block until getting inputs */
  309.       while (! __libc_termios_exist_queue ())
  310.     {
  311.       __dpmi_yield ();
  312.       __libc_termios_fill_queue ();
  313.     }
  314.  
  315.       while (--n >= 0)
  316.     {
  317.       *wp++ = __libc_termios_get_queue ();
  318.  
  319.       if (! __libc_termios_exist_queue ())
  320.         {
  321.           __libc_termios_fill_queue ();
  322.           if (! __libc_termios_exist_queue ())
  323.         break;
  324.         }
  325.     }
  326.     }
  327.  
  328.   return (ssize_t) (wp - (unsigned char *) buffer);
  329. }
  330.  
  331. static ssize_t
  332. __libc_termios_read_raw_tty (int handle, void *buffer, size_t count)
  333. {
  334.   unsigned char *wp;
  335.   unsigned char ch;
  336.   ssize_t n;
  337.  
  338.   n = count;
  339.   wp = buffer;
  340.  
  341.   /* clear cooked queue */
  342.   if (__libc_termios_exist_queue ())
  343.     __libc_termios_clear_queue ();
  344.  
  345.   /* block until getting inputs */
  346.   while (! __direct_keysense ())
  347.     __dpmi_yield ();
  348.  
  349.   while (--n >= 0)
  350.     {
  351.       /* exhaust inputs ? */
  352.       if (! __direct_keysense ())
  353.     break;
  354.  
  355.       /* realy get */
  356.       ch = __direct_keyinput ();
  357.  
  358.       /* replace CTRL+SPACE with 0x00 */
  359.       if (ch == ' ' && __direct_ctrlsense ())
  360.     ch = '\0';
  361.  
  362.       /* copy a character into buffer and echo */
  363.       *wp++ = ch;
  364.       __libc_termios_maybe_echo (ch);
  365.     }
  366.  
  367.   return (ssize_t) (wp - (unsigned char *) buffer);
  368. }
  369.  
  370. /******************************************************************************/
  371. /* special write function *****************************************************/
  372.  
  373. static unsigned char __libc_termios_write_sbuf_internal[64];
  374. static unsigned char *__libc_termios_write_sbuf = NULL;
  375. static size_t __libc_termios_write_sbuflen = 0;
  376. static int __libc_termios_write_count = -1;
  377.  
  378. static ssize_t
  379. __libc_termios_write (int handle, const void *buffer, size_t count, ssize_t *rv)
  380. {
  381.   short devmod;
  382.   ssize_t bytes;
  383.  
  384.   /* check handle whether valid or not */
  385.   devmod = _get_dev_info (handle);
  386.   if (devmod == -1)
  387.     {
  388.       *rv = -1;
  389.       return 1;
  390.     }
  391.  
  392.   /* special case */
  393.   if (count == 0)
  394.     {
  395.       *rv = 0;
  396.       return 1;
  397.     }
  398.  
  399.   /* console only... */
  400.   if ((devmod & _DEV_CDEV) && (devmod & (_DEV_STDIN|_DEV_STDOUT)))
  401.     {
  402.       /* character device */
  403.       if (devmod & _DEV_RAW)
  404.     *rv = __libc_termios_write_raw_tty (handle, buffer, count);
  405.       else
  406.     *rv = __libc_termios_write_cooked_tty (handle, buffer, count);
  407.       return 1;
  408.     }
  409.  
  410.   if (__file_handle_modes[handle] & O_BINARY)
  411.     {
  412.       bytes = _write (handle, buffer, count);
  413.       if (bytes < 0)
  414.     {
  415.       *rv = -1;
  416.       return 1;
  417.     }
  418.     }
  419.   else
  420.     {
  421.       const unsigned char *rp;
  422.       unsigned char *tp, *ep;
  423.       ssize_t n;
  424.  
  425.       /* initialize local buffer */
  426.       if (__libc_termios_write_count != __bss_count)
  427.     {
  428.       __libc_termios_write_count = __bss_count;
  429.       __libc_termios_write_sbuflen = _go32_info_block.size_of_transfer_buffer;
  430.       __libc_termios_write_sbuf = malloc (__libc_termios_write_sbuflen);
  431.       if (__libc_termios_write_sbuf == NULL)
  432.         {
  433.           __libc_termios_write_sbuf = &__libc_termios_write_sbuf_internal[0];
  434.           __libc_termios_write_sbuflen = sizeof (__libc_termios_write_sbuf_internal);
  435.         }
  436.     }
  437.  
  438.       rp = buffer;
  439.       tp = __libc_termios_write_sbuf;
  440.       ep = tp + __libc_termios_write_sbuflen;
  441.       n = count;
  442.       bytes = 0;
  443.       while (n >= 0)
  444.     {
  445.       unsigned char *wp;
  446.       unsigned char ch;
  447.       ssize_t ncr, wbytes;
  448.  
  449.       /* fill local buffer */
  450.       wp = tp;
  451.       ncr = 0;
  452.       while ((wp < ep) && (--n >= 0))
  453.         {
  454.           /* get character */
  455.           ch = *rp++;
  456.  
  457.           /* LF conversion */
  458.           if (ch == '\n')
  459.         {
  460.           if (wp == (ep - 1))
  461.             {
  462.               n++;
  463.               rp--;
  464.               break;
  465.             }
  466.           *wp++ = '\r';
  467.           ncr++;
  468.         }
  469.  
  470.           /* put character */
  471.           *wp++ = ch;
  472.         }
  473.  
  474.       /* write on handle */
  475.       wbytes = _write (handle, tp, (size_t) (wp - tp));
  476.       if (wbytes < 0)
  477.         {
  478.           *rv = -1;
  479.           return 1;
  480.         }
  481.       if (wbytes < (ssize_t) (wp - tp))
  482.         {
  483.           /* detected disk full, but the result is not reality */
  484.           *rv = bytes + (wbytes > ncr ? wbytes - ncr : 0);
  485.           return 1;
  486.         }
  487.  
  488.       /* don't count CR */
  489.       bytes += wbytes - ncr;
  490.     }
  491.     }
  492.  
  493.   /* result of write() */
  494.   *rv =  bytes;
  495.   return 1;
  496. }
  497.  
  498. static ssize_t
  499. __libc_termios_write_cooked_tty (int handle, const void *buffer, size_t count)
  500. {
  501.   ssize_t bytes;
  502.  
  503.   /* output process if need */
  504.   if (__libc_tty_p->t_oflag & OPOST)
  505.     {
  506.       const unsigned char *rp;
  507.       unsigned char ch;
  508.       ssize_t n;
  509.  
  510.       rp = buffer;
  511.       n = count;
  512.       while (--n >= 0)
  513.     {
  514.       /* get character */
  515.       ch = *rp++;
  516.  
  517.       /* NOTE: multibyte character don't contain control character */
  518.       /* map NL to CRNL */
  519.       if (ch == '\n' && (__libc_tty_p->t_oflag & ONLCR))
  520.         __direct_output ('\r');
  521.       /* map CR to NL */
  522.       else if (ch == '\r' && (__libc_tty_p->t_oflag & OCRNL))
  523.         ch = '\n';
  524.  
  525.       __direct_output (ch);
  526.     }
  527.  
  528.       /* don't count CR */
  529.       bytes = count;
  530.     }
  531.   else
  532.     {
  533.       /* output with no effect */
  534.       bytes = __libc_termios_write_raw_tty (handle, buffer, count);
  535.     }
  536.  
  537.   return bytes;
  538. }
  539.  
  540. static ssize_t
  541. __libc_termios_write_raw_tty (int handle, const void *buffer, size_t count)
  542. {
  543.   const unsigned char *rp;
  544.   ssize_t n;
  545.  
  546.   rp = buffer;
  547.   n = count;
  548.   while (--n >= 0)
  549.     __direct_output (*rp++);
  550.  
  551.   return count;
  552. }
  553.  
  554. /******************************************************************************/
  555. /* echo routines **************************************************************/
  556.  
  557. static void
  558. __libc_termios_echo_ctrl (unsigned char ch)
  559. {
  560.   ch ^= 0x40;
  561.   __direct_output ('^');
  562.   __direct_output (ch);
  563. }
  564.  
  565. static void
  566. __libc_termios_maybe_echo_ctrl (unsigned char ch)
  567. {
  568.   if (__libc_tty_p->t_lflag & ECHOCTL)
  569.     __libc_termios_echo_ctrl (ch);
  570. }
  571.  
  572. static void
  573. __libc_termios_maybe_echo (unsigned char ch)
  574. {
  575.   if (! (__libc_tty_p->t_lflag & ECHO))
  576.     {
  577.       /* don't echo but newline is required ? */
  578.       if (ch == '\n' && (__libc_tty_p->t_lflag & ECHONL))
  579.     {
  580.       if (__libc_tty_p->t_oflag & ONLCR)
  581.         __direct_output ('\r');
  582.       __direct_output ('\n');
  583.     }
  584.       return;
  585.     }
  586.  
  587.   /* check literal flag */
  588.   if ((__libc_tty_p->t_status & _TS_LNCH) && (ch < 0x20))
  589.     {
  590.       __libc_termios_echo_ctrl (ch);
  591.       return;
  592.     }
  593.  
  594.   /* output process if need */
  595.   if (__libc_tty_p->t_oflag & OPOST)
  596.     {
  597.       /* map NL to CRNL */
  598.       if (ch == '\n' && (__libc_tty_p->t_oflag & ONLCR))
  599.     {
  600.       __direct_output ('\r');
  601.       __direct_output ('\n');
  602.       return;
  603.     }
  604.       /* map CR to NL */
  605.       else if (ch == '\r' && (__libc_tty_p->t_oflag & OCRNL))
  606.     {
  607.       __direct_output ('\n');
  608.       return;
  609.     }
  610.       /* discard EOT */
  611.       else if (_CC_EQU (VEOF, ch) && (__libc_tty_p->t_oflag & ONOEOT))
  612.     {
  613.       return;
  614.     }
  615.     }
  616.  
  617.   /* control character except newline */
  618.   if ((ch < 0x20 || ch == 0x7f) && (__libc_tty_p->t_lflag & ECHOCTL) && ch != '\n')
  619.     {
  620.       __libc_termios_echo_ctrl (ch);
  621.       return;
  622.     }
  623.  
  624.   /* no effect */
  625.   __direct_output (ch);
  626. }
  627.  
  628. /******************************************************************************/
  629. /* edit routines **************************************************************/
  630.  
  631. static void
  632. __libc_termios_maybe_erase1 (void)
  633. {
  634.   if (__libc_tty_p->t_lflag & ECHO)
  635.     {
  636.       /* eat prev. character by BS SPC BS */
  637.       __direct_output ('\010');
  638.       if (__libc_tty_p->t_lflag & ECHOE)
  639.     {
  640.       __direct_output (' ');
  641.       __direct_output ('\010');
  642.     }
  643.     }
  644. }
  645.  
  646. /* erase one prev. character of editline */
  647. static void
  648. __libc_termios_erase_editline (void)
  649. {
  650.   int col;
  651.   char pf;
  652.  
  653.   col = __libc_tty_editline.col;
  654.   if (col == 0) /* no more */
  655.     return;
  656.  
  657.   /* get position flag */
  658.   pf = __libc_tty_editline.flag[col - 1];
  659.   if (pf == _TTY_EDITLINE_INVALID || pf < 0)
  660.     {
  661.       /* erase all invalid character */
  662.       while (col > 0 && __libc_tty_editline.flag[col - 1] < 0)
  663.     {
  664.       __libc_termios_maybe_erase1 ();
  665.       --col;
  666.     }
  667.     }
  668.   else if (pf == _TTY_EDITLINE_CTRL)
  669.     {
  670.       if (__libc_tty_p->t_lflag & ECHOCTL)
  671.     {
  672.       /* erase one of "^X" */
  673.       __libc_termios_maybe_erase1 ();
  674.       --col;
  675.     }
  676.       __libc_termios_maybe_erase1 ();
  677.       --col;
  678.     }
  679.   else
  680.     {
  681.       /* erase single or multibyte charcter */
  682.       while (--pf >= 0)
  683.     {
  684.       __libc_termios_maybe_erase1 ();
  685.       --col;
  686.     }
  687.     }
  688.  
  689.   /* set next insert position */
  690.   __libc_tty_editline.col = col;
  691. }
  692.  
  693. /* erase all editline */
  694. static void
  695. __libc_termios_kill_editline (void)
  696. {
  697.   if (__libc_tty_p->t_lflag & ECHOKE)
  698.     {
  699.       while (__libc_tty_editline.col != 0)
  700.     __libc_termios_erase_editline ();
  701.     }
  702.   else
  703.     __libc_tty_editline.col = 0;
  704.  
  705.   if (__libc_tty_p->t_lflag & ECHOK)
  706.     __libc_termios_maybe_echo ('\n');
  707. }
  708.  
  709. static void
  710. __libc_termios_insert_editline (unsigned char ch)
  711. {
  712.   int mbsize;
  713.   int col;
  714.  
  715.   col = __libc_tty_editline.col;
  716.   if (col >= _TTY_EDITLINE_SIZE)
  717.     {
  718.       /* detected over flow */
  719.       if (__libc_tty_p->t_iflag & IMAXBEL)
  720.     __direct_output ('\007');
  721.       return;
  722.     }
  723.  
  724.   __libc_tty_editline.buf[col] = ch;
  725.   if (col == 0 || ((col > 0)
  726.            && __libc_tty_editline.flag[col - 1] != _TTY_EDITLINE_INVALID))
  727.     {
  728.       /* check multibyte length */
  729.       mbsize = mblen (__libc_tty_editline.buf + col, 1);
  730.       if (mbsize == 1)
  731.     {
  732.       /* single character */
  733.       if ((ch < 0x20) || ch == 0x7f)
  734.         __libc_tty_editline.flag[col] = _TTY_EDITLINE_CTRL;
  735.       else
  736.         __libc_tty_editline.flag[col] = _TTY_EDITLINE_SINGLE;
  737.       __libc_termios_maybe_echo (ch);
  738.     }
  739.       else
  740.     {
  741.       /* first of multibyte or invalid character */
  742.       __libc_tty_editline.flag[col] = _TTY_EDITLINE_INVALID;
  743.       __libc_tty_p->t_status |= _TS_LNCH;
  744.     }
  745.     }
  746.   else
  747.     {
  748.       int pcol;
  749.  
  750.       /* look for non fixed flag */
  751.       pcol = col;
  752.       while (__libc_tty_editline.flag[pcol - 1] == _TTY_EDITLINE_INVALID)
  753.     if (--pcol <= 0)
  754.       break;
  755.  
  756.       /* check whether it's multibyte sequence */
  757.       mbsize = mblen (__libc_tty_editline.buf + pcol, (col - pcol + 1));
  758.       if (mbsize > 1)
  759.     {
  760.       /* multibyte sequence is good */
  761.       while (pcol < col)
  762.         {
  763.           /* set negative size for dividing sequence */
  764.           __libc_tty_editline.flag[pcol] = -mbsize;
  765.           __libc_termios_maybe_echo (__libc_tty_editline.buf[pcol]);
  766.           pcol++;
  767.         }
  768.       /* last flag is always positive size */
  769.       __libc_tty_editline.flag[col] = mbsize;
  770.       __libc_termios_maybe_echo (ch);
  771.     }
  772.       else
  773.     {
  774.       if ((col - pcol + 1) > MB_CUR_MAX)
  775.         {
  776.           /* it's terrible... */
  777.           while (pcol <= col)
  778.         {
  779.           /* replace all with valid character */
  780.           __libc_tty_editline.flag[pcol] = _TTY_EDITLINE_SINGLE;
  781.           __libc_tty_editline.buf[pcol] = 'X';
  782.           __libc_termios_maybe_echo ('X');
  783.           pcol++;
  784.         }
  785.         }
  786.  
  787.       /* continuous multibyte character */
  788.       __libc_tty_editline.flag[col] = _TTY_EDITLINE_INVALID;
  789.       __libc_tty_p->t_status |= _TS_LNCH;
  790.     }
  791.     }
  792.  
  793.   /* set next insert position */
  794.   col++;
  795.   __libc_tty_editline.col = col;
  796. }
  797.  
  798. /******************************************************************************/
  799. /* queued input routines ******************************************************/
  800.  
  801. static int
  802. __libc_termios_exist_queue (void)
  803. {
  804.   return __libc_tty_p->t_count;
  805. }
  806.  
  807. static void
  808. __libc_termios_clear_queue (void)
  809. {
  810.   __libc_tty_p->t_count = 0;
  811.   __libc_tty_p->t_rpos = __libc_tty_p->t_top;
  812.   __libc_tty_p->t_wpos = __libc_tty_p->t_top;
  813. }
  814.  
  815. static int
  816. __libc_termios_get_queue (void)
  817. {
  818.   int ch;
  819.  
  820.   if (__libc_tty_p->t_count == 0)
  821.     return -1;
  822.  
  823.   ch = *__libc_tty_p->t_rpos++;
  824.   __libc_tty_p->t_count--;
  825.  
  826.   if (__libc_tty_p->t_rpos >= __libc_tty_p->t_bottom)
  827.     __libc_tty_p->t_rpos = __libc_tty_p->t_top;
  828.  
  829.   return ch;
  830. }
  831.  
  832. static int
  833. __libc_termios_put_queue (unsigned char ch)
  834. {
  835.   if (__libc_tty_p->t_count >= __libc_tty_p->t_size)
  836.     return -1;
  837.  
  838.   *__libc_tty_p->t_wpos++ = ch;
  839.   __libc_tty_p->t_count++;
  840.  
  841.   if (__libc_tty_p->t_wpos >= __libc_tty_p->t_bottom)
  842.     __libc_tty_p->t_wpos = __libc_tty_p->t_top;
  843.  
  844.   return 0;
  845. }
  846.  
  847. static void
  848. __libc_termios_fill_queue (void)
  849. {
  850.   unsigned char ch;
  851.  
  852.   while (1)
  853.     {
  854.       /* exhaust inputs ? */
  855.       if (! __direct_keysense ())
  856.     {
  857.       if (__libc_tty_p->t_lflag & ICANON)
  858.         {
  859.           /* wait for NL or EOT */
  860.           __dpmi_yield ();
  861.           continue;
  862.         }
  863.       return;
  864.     }
  865.  
  866.       /* realy get */
  867.       ch = __direct_keyinput ();
  868.  
  869.       /* replace CTRL+SPACE with 0x00 */
  870.       if (ch == ' ' && __direct_ctrlsense ())
  871.     ch = '\0';
  872.  
  873.       /* input process if need */
  874.       if (! (__libc_tty_p->t_status & _TS_LNCH) || ch != (unsigned char) _POSIX_VDISABLE)
  875.     {
  876.       /* software signals */
  877.       if (__libc_tty_p->t_lflag & ISIG)
  878.         {
  879.           if (! (__libc_tty_p->t_iflag & IGNBRK) && _CC_EQU (VINTR, ch))
  880.         {
  881.           if (__libc_tty_p->t_iflag & BRKINT)
  882.             {
  883.               __libc_termios_maybe_echo_ctrl (ch);
  884.               kill (getpid (), SIGINT);
  885.               continue;
  886.             }
  887.           else
  888.             {
  889.               ch = '\0';
  890.               goto proc_skip;
  891.             }
  892.         }
  893.           else if (_CC_EQU (VQUIT, ch))
  894.         {
  895.           __libc_termios_maybe_echo_ctrl (ch);
  896.           kill (getpid(), SIGQUIT);
  897.           continue;
  898.         }
  899.           else if (_CC_EQU (VSUSP, ch))
  900.         {
  901.           __libc_termios_maybe_echo_ctrl (ch);
  902. #ifdef SIGTSTP
  903.           kill (getpid(), SIGTSTP);
  904. #else /* djgpp don't have ... */
  905.           {
  906.             char oldcwd[PATH_MAX];
  907.             int fds[5] = { -1, -1, -1, -1, -1 };
  908.             int i;
  909.  
  910.             for (i = 0; i < 5; i++)
  911.               if ((fds[i] = fcntl (i, F_DUPFD, 20)) < 0)
  912.                 __direct_outputs ("Suspend: cannot save fds\r\n");
  913.  
  914.             __direct_outputs ("\r\nSuspended\r\n");
  915.             /* keep cwd on exec */
  916.             getcwd (oldcwd, sizeof (oldcwd));
  917.             system (NULL);
  918.             chdir (oldcwd);
  919.  
  920.             for (i = 0; i < 5; i++)
  921.               if (fds[i] >= 0)
  922.             {
  923.               dup2 (fds[i], i);
  924.               close (fds[i]);
  925.             }
  926.           }
  927. #endif /* !SIGTSTP */
  928.           continue;
  929.         }
  930.         }
  931.  
  932.       /* flow control... */
  933.       if (_CC_EQU (VSTART, ch) && (__libc_tty_p->t_iflag & IXOFF))
  934.         {
  935.           continue;
  936.         }
  937.       else if (_CC_EQU (VSTOP, ch) && (__libc_tty_p->t_iflag & IXOFF))
  938.         {
  939.           continue;
  940.         }
  941.  
  942.       /* CR/LF process */
  943.       if (ch == '\r')
  944.         {
  945.           if (__libc_tty_p->t_iflag & IGNCR)
  946.         continue;
  947.           if (__libc_tty_p->t_iflag & ICRNL)
  948.         ch = '\n';
  949.         }
  950.       else if ((ch == '\n') && (__libc_tty_p->t_iflag & INLCR))
  951.         ch = '\r';
  952.  
  953.       /* strip 8th-bit */
  954.       if (__libc_tty_p->t_iflag & ISTRIP)
  955.         ch &= 0x7f;
  956.     }
  957.  
  958. proc_skip:
  959.       if (__libc_tty_p->t_lflag & ICANON)
  960.     {
  961.       if (__libc_tty_p->t_status & _TS_LNCH)
  962.         {
  963.           __libc_tty_p->t_status &= ~_TS_LNCH;
  964.           __libc_termios_insert_editline (ch);
  965.         }
  966.       else
  967.         {
  968.           if (_CC_EQU (VERASE, ch))
  969.         __libc_termios_erase_editline ();
  970.           else if (_CC_EQU (VKILL, ch))
  971.         __libc_termios_kill_editline ();
  972.           else if (ch == '\n' || _CC_EQU (VEOF, ch) || _CC_EQU (VEOL, ch))
  973.         {
  974.           int col = __libc_tty_editline.col;
  975.           unsigned char *p = __libc_tty_editline.buf;
  976.  
  977.           /* clear column for next access */
  978.           __libc_tty_editline.col = 0;
  979.  
  980.           /* copy editline into tty queue */
  981.           while (--col >= 0)
  982.             __libc_termios_put_queue (*p++);
  983.  
  984.           /* echo terminate character and put it */
  985.           __libc_termios_maybe_echo (ch);
  986.           if (_CC_NEQU (VEOF, ch))
  987.             __libc_termios_put_queue (ch);
  988.  
  989.           return;
  990.         }
  991.           else
  992.         __libc_termios_insert_editline (ch);
  993.         } /* !_TS_LNCH */
  994.     }
  995.       else /* !ICANON */
  996.     {
  997.       __libc_termios_maybe_echo (ch);
  998.       __libc_tty_p->t_status &= ~_TS_LNCH;
  999.       __libc_termios_put_queue (ch);
  1000.     }
  1001.     } /* end of while (1) */
  1002. }
  1003.  
  1004. /******************************************************************************/
  1005.  
  1006.