home *** CD-ROM | disk | FTP | other *** search
/ Internet MPEG Audio Archive / IMAA.mdf / util / dos / l3v100n / rsx / source / termio.c < prev    next >
C/C++ Source or Header  |  1994-01-19  |  8KB  |  373 lines

  1. /* This file is TERMIO.C
  2. **
  3. **    - ioctl() terminal functions
  4. **
  5. **    ( termio functions are modified from the Linux-kernel 0.99 )
  6. **
  7. ** Copyright (c) Rainer Schnitker 91,92,93
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <bios.h>
  13. #include "DPMI.H"
  14. #include "DPMIDOS.H"
  15. #include "SIGNALS.H"
  16. #include "PROCESS.H"
  17. #include "START32.H"
  18. #include "COPY32.H"
  19. #include "RSX.H"
  20. #include "EXCEP32.H"
  21. #include "TERMIO.H"
  22. #include "DOSERRNO.H"
  23.  
  24. static void keyboard_flush(void);
  25. static int keyboard_read(void);
  26. static void put_kbd_queue(int);
  27. static int get_kbd_queue(void);
  28. static void flush_input(void);
  29. static int copy_to_cooked(void);
  30. static int available_canon_input(void);
  31. static void wait_for_canon_input(void);
  32. static DWORD do_fionread(void);
  33.  
  34. static char control_c;
  35. static unsigned long timeout;
  36. static unsigned delay_flag;
  37.  
  38. struct termio termios =
  39. {
  40.      /* iflag */ BRKINT | ICRNL | IXON | IXANY,
  41.      /* oflag */ 0,
  42.      /* cflag */ B9600 | CS8 | CREAD | HUPCL,
  43.      /* lflag */ ISIG | ICANON | ECHO | ECHOE | ECHOK | IDEFAULT,
  44.      /* line  */ 0,
  45.      /* c_cc  */ 003, 034, 010, 025, 004, 000, 006, 001};
  46.  /* INTR, QUIT,ERASE, KILL, EOF , EOL , VMIN, VTIME */
  47.  /* C-C , C-\ , C-H , C-U , C-D , EOL , VMIN, VTIME */
  48.  
  49. #define QUEUE_BUF_SIZE    128
  50. struct queue {
  51.     int data;
  52.     int head;
  53.     int tail;
  54.     char buf[QUEUE_BUF_SIZE];
  55. } kbd_queue;
  56.  
  57. #define INC(a) (a = (a+1) & (QUEUE_BUF_SIZE-1))
  58. #define DEC(a) (a = (a-1) & (QUEUE_BUF_SIZE-1))
  59. #define EMPTY(a) (a.head == a.tail)
  60. #define LEFT(a) ((a.tail-a.head-1)&(QUEUE_BUF_SIZE-1))
  61. #define LAST(a) (a.buf[(QUEUE_BUF_SIZE-1)&(a.head-1)])
  62. #define FULL(a) (!LEFT(a))
  63. #define CHARS(a) ((a.head-a.tail)&(QUEUE_BUF_SIZE-1))
  64.  
  65. /* flush keyboard buffer */
  66. static void keyboard_flush(void)
  67. {
  68.     while (_bios_keybrd(kready))
  69.     _bios_keybrd(kread);
  70. }
  71.  
  72. /* read a key ; extended = 0,next call scan-code */
  73. static int keyboard_read()
  74. {
  75.     static int next_key = 0;
  76.     int key, scan, ascii;
  77.  
  78.     if (next_key) {
  79.     ascii = next_key;
  80.     next_key = 0;
  81.     } else {
  82.     if (!_bios_keybrd(kready)) {
  83.         if (timeout)
  84.         if (timeout <= time_tic)
  85.             timeout = 0;
  86.         return -1;
  87.     }
  88.     key = _bios_keybrd(kread);
  89.     ascii = key & 0xff;
  90.     scan = key >> 8;
  91.  
  92.     if (ascii == 0xE0)
  93.         ascii = 0;
  94.  
  95.     if (ascii == 0)
  96.         next_key = scan;
  97.     }
  98.  
  99.     return ascii;
  100. }
  101.  
  102. /* put one char into kbd_queue */
  103. static void put_kbd_queue(int c)
  104. {
  105.     int head = (kbd_queue.head + 1) & (QUEUE_BUF_SIZE - 1);
  106.  
  107.     if (head != kbd_queue.tail) {
  108.     kbd_queue.buf[kbd_queue.head] = (char) c;
  109.     kbd_queue.head = head;
  110.     }
  111. }
  112.  
  113. /* get one char from kbd_queue ; -1 = no char */
  114. static int get_kbd_queue()
  115. {
  116.     int result = -1;
  117.  
  118.     if (kbd_queue.tail != kbd_queue.head) {
  119.     result = 0xff & kbd_queue.buf[kbd_queue.tail];
  120.     kbd_queue.tail = (kbd_queue.tail + 1) & (QUEUE_BUF_SIZE - 1);
  121.     }
  122.     return result;
  123. }
  124.  
  125. static void flush_input(void)
  126. {
  127.     keyboard_flush();
  128.     kbd_queue.head = kbd_queue.tail;
  129.     kbd_queue.data = 0;
  130. }
  131.  
  132. #define TTY_READ_FLUSH    copy_to_cooked();
  133.  
  134. int copy_to_cooked(void)
  135. {
  136.     int c;
  137.  
  138.     for (;;) {
  139.     c = LEFT(kbd_queue);
  140.     if (c == 0)
  141.         return 0;
  142.     c = keyboard_read();
  143.  
  144.     if (c < 0)
  145.         return 0;
  146.     if (c == 0)        /* extended key */
  147.         if (L_CANON) {    /* CANON ignores it */
  148.         keyboard_read();/* forget scan code */
  149.         continue;
  150.         } else {
  151.         put_kbd_queue(c);    /* put char 0,scan */
  152.         c = keyboard_read();
  153.         put_kbd_queue(c);
  154.         continue;
  155.         }
  156.  
  157.     if (I_STRP)
  158.         c &= 0x7f;
  159.     if (c == 13) {
  160.         if (I_CRNL)
  161.         c = 10;
  162.         else if (I_NOCR)
  163.         continue;
  164.     } else if (c == 10 && I_NLCR)
  165.         c = 13;
  166.     if (I_UCLC)
  167.         c = tolower(c);
  168.  
  169.     if (L_CANON) {
  170.         if ((char) c == KILL_CHAR) {
  171.         while (!(EMPTY(kbd_queue) || (c = LAST(kbd_queue)) == 10 ||
  172.              c == EOF_CHAR)) {
  173.             if (L_ECHO) {
  174.             if (c < 32) {
  175.                 putchar('\b');
  176.                 putchar(' ');
  177.                 putchar('\b');
  178.             }
  179.             putchar('\b');
  180.             putchar(' ');
  181.             putchar('\b');
  182.             }
  183.             DEC(kbd_queue.head);
  184.         }
  185.         continue;
  186.         }
  187.         if (c == ERASE_CHAR) {
  188.         if (EMPTY(kbd_queue) || (c = LAST(kbd_queue)) == 10 || c == EOF_CHAR)
  189.             continue;
  190.         if (L_ECHO) {
  191.             if (c < 32) {
  192.             putchar('\b');
  193.             putchar(' ');
  194.             putchar('\b');
  195.             }
  196.             putchar('\b');
  197.             putchar(' ');
  198.             putchar('\b');
  199.         }
  200.         DEC(kbd_queue.head);
  201.         continue;
  202.         }
  203.     }            /* ICANON */
  204.     if (L_ISIG) {
  205.         if (c == INTR_CHAR) {
  206.         control_c = 1;
  207.         send_signal(npz, SIGINT);
  208.         flush_input();
  209.         return 1;
  210.         }
  211.     }
  212.     /* linefeed: new data */
  213.     if (c == 10 || c == EOF_CHAR)
  214.         kbd_queue.data++;
  215.     /* write char */
  216.     if ((c == 10) && (L_ECHO || (L_CANON && L_ECHONL))) {
  217.         putchar(10);
  218.         putchar(13);
  219.     } else if (L_ECHO)
  220.         putchar(c);
  221.  
  222.     put_kbd_queue(c);
  223.  
  224.     }
  225. }
  226.  
  227. static int available_canon_input()
  228. {
  229.     TTY_READ_FLUSH;
  230.     if (kbd_queue.data)
  231.     return 1;
  232.     else
  233.     return 0;
  234. }
  235.  
  236. static void wait_for_canon_input()
  237. {
  238.     if (!available_canon_input()) {
  239.     if (control_c)
  240.         return;
  241.     while (1) {
  242.         if (available_canon_input())
  243.         break;
  244.         if (control_c)
  245.         break;
  246.     }
  247.     }
  248. }
  249.  
  250. int termio_read(unsigned dataseg, unsigned long buf, int nr)
  251. {
  252.     int c;
  253.     unsigned long b = buf;
  254.     int minimum, time;
  255.  
  256.     control_c = 0;
  257.  
  258.     if (L_CANON) {
  259.     minimum = time = 0;
  260.     timeout = 0L;
  261.     } else {
  262.     time = termios.c_cc[VTIME] * 10;
  263.     minimum = termios.c_cc[VMIN];
  264.     if (minimum)
  265.         timeout = 0xffffffff;
  266.     else {
  267.         if (time)
  268.         timeout = (unsigned long) time / 55L + time_tic;
  269.         else
  270.         timeout = 0;
  271.         time = 0;
  272.         minimum = 1;
  273.     }
  274.     }
  275.     if (delay_flag) {
  276.     time = 0;
  277.     timeout = 0;
  278.     if (L_CANON) {
  279.         if (!available_canon_input())
  280.         return -EMX_EAGAIN;
  281.     }
  282.     } else if (L_CANON) {
  283.     wait_for_canon_input();
  284.     }
  285.     if (minimum > nr)
  286.     minimum = nr;
  287.  
  288.     while (nr > 0) {
  289.     while (nr > 0 && ((c = get_kbd_queue()) >= 0)) {
  290.         TTY_READ_FLUSH;
  291.         if (control_c)
  292.         return 0;
  293.         if (c == EOF_CHAR || c == 10)
  294.         kbd_queue.data--;
  295.         if (c == EOF_CHAR && L_CANON)
  296.         break;
  297.         cpy16_32(dataseg, b, &c, 1L);
  298.         b++;
  299.         nr--;
  300.         if (time)
  301.         timeout = (unsigned long) time / 55L + time_tic;
  302.         if (c == 10 && L_CANON)
  303.         break;
  304.     }
  305.     if ((int) (b - buf) >= minimum || !timeout)
  306.         break;
  307.     TTY_READ_FLUSH;
  308.     if (control_c)
  309.         return 0;
  310.     if (!EMPTY(kbd_queue))
  311.         continue;
  312.     }
  313.     TTY_READ_FLUSH;
  314.     timeout = 0;
  315.  
  316.     if (b - buf)
  317.     return (unsigned) (b - buf);
  318.  
  319.     if (delay_flag)
  320.     return -EMX_EAGAIN;
  321.     return 0;
  322. }
  323.  
  324. void set_fcntl_flag(unsigned flag)
  325. {
  326.     delay_flag = flag & FCNTL_NDELAY;
  327. }
  328.  
  329. static DWORD do_fionread()
  330. {
  331.     TTY_READ_FLUSH;
  332.     return (DWORD) (CHARS(kbd_queue));
  333. }
  334.  
  335. int kbd_ioctl(unsigned cmd, unsigned long termio_arg)
  336. {
  337.     switch (cmd) {
  338.     case TCGETA:
  339.     if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
  340.         return EMX_EINVAL;
  341.     cpy16_32(npz->data32sel, termio_arg,
  342.          &termios, sizeof(struct termio));
  343.     return 0;
  344.  
  345.     case TCSETAF:
  346.     flush_input();
  347.     /* fall through */
  348.     case TCSETAW:
  349.     case TCSETA:
  350.     if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
  351.         return EMX_EINVAL;
  352.     cpy32_16(npz->data32sel, termio_arg,
  353.          &termios, sizeof(struct termio));
  354.  
  355.     if (!L_IDEFAULT)    /* enable termio */
  356.         npz->p_flags |= PF_TERMIO;
  357.     return 0;
  358.  
  359.     case TCFLSH:
  360.     if (termio_arg == 0)
  361.         flush_input();
  362.     return 0;
  363.  
  364.     case FIONREAD:
  365.     if (verify_illegal(npz, termio_arg, sizeof(long)))
  366.         return EMX_EINVAL;
  367.     store32(npz->data32sel, termio_arg, do_fionread());
  368.  
  369.     default:
  370.     return EMX_EINVAL;
  371.     }
  372. }
  373.