home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / os2conio.c < prev    next >
C/C++ Source or Header  |  1999-01-02  |  11KB  |  477 lines

  1. /* -*-C-*-
  2.  
  3. $Id: os2conio.c,v 1.10 1999/01/02 06:11:34 cph Exp $
  4.  
  5. Copyright (c) 1994-1999 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #define USE_PMCON
  23. /* #define USE_VIO */
  24. /* #define USE_PMIO */
  25.  
  26. #include "os2.h"
  27.  
  28. #ifdef USE_PMCON
  29.  
  30. extern void OS2_initialize_pm_console (void);
  31. extern int  OS2_pm_console_getch (void);
  32. extern void OS2_pm_console_write (const char *, size_t);
  33.  
  34. #else
  35. #ifdef USE_PMIO
  36.  
  37. #include <pmio.h>
  38.  
  39. #endif
  40. #endif
  41.  
  42. #ifdef USE_PMCON
  43. #define getch OS2_pm_console_getch
  44. #else
  45. #ifndef USE_PMIO
  46. static int getch (void);
  47. #endif
  48. #endif
  49.  
  50. static void console_thread (void *);
  51. static void grab_console_lock (void);
  52. static void release_console_lock (void);
  53.  
  54. static void process_input_char (char);
  55. static void do_rubout (void);
  56. static void add_to_line (char);
  57. static void do_newline (void);
  58. static void do_self_insert (char);
  59. static void add_char_to_line_buffer (char);
  60. static void finish_line (void);
  61. static void send_char (char);
  62. static void send_readahead (msg_t *);
  63. static void handle_console_interrupt (msg_t *);
  64.  
  65. static void console_operator
  66.   (Tchannel, chop_t, choparg_t, choparg_t, choparg_t);;
  67. static void flush_input (void);
  68. static void console_input_buffered (Tchannel, int, int *);
  69. static void console_output_cooked (Tchannel, int, int *);
  70.  
  71. static void write_char (char, int);
  72. static void write_output (const char *, size_t, int);
  73. static void write_output_1 (const char *, const char *);
  74. static unsigned int char_output_length (char);
  75.  
  76. static HMTX console_lock;
  77. static int input_buffered_p;
  78. static int output_cooked_p;
  79. static qid_t console_writer_qid;
  80. static channel_context_t * console_context;
  81. static void * line_buffer;
  82.  
  83. TID OS2_console_tid;
  84.  
  85. void
  86. OS2_initialize_console (void)
  87. {
  88. #ifdef USE_PMCON
  89.   OS2_initialize_pm_console ();
  90. #else
  91. #ifdef USE_PMIO
  92.   pmio_fontspec = "6.System VIO";
  93.   set_width (80);
  94.   set_height (40);
  95.   start_pmio ();
  96. #endif
  97. #endif
  98.   console_lock = (OS2_create_mutex_semaphore (0, 0));
  99.   input_buffered_p = 1;
  100.   output_cooked_p = 1;
  101.   console_context = (OS2_make_channel_context ());
  102.   OS2_open_qid ((CHANNEL_CONTEXT_READER_QID (console_context)),
  103.         OS2_scheme_tqueue);
  104.   console_writer_qid = (CHANNEL_CONTEXT_WRITER_QID (console_context));
  105.   OS2_open_qid (console_writer_qid, (OS2_make_std_tqueue ()));
  106.   (CHANNEL_CONTEXT_FIRST_READ_P (console_context)) = 0;
  107.   OS2_console_tid = (OS2_beginthread (console_thread, 0, 0x4000));
  108.   (CHANNEL_CONTEXT_TID (console_context)) = OS2_console_tid;
  109. }
  110.  
  111. static void
  112. console_thread (void * arg)
  113. {
  114.   EXCEPTIONREGISTRATIONRECORD registration;
  115.   grab_console_lock ();
  116.   line_buffer = (OS2_make_readahead_buffer ());
  117.   release_console_lock ();
  118.   (void) OS2_thread_initialize ((®istration), console_writer_qid);
  119.   while (1)
  120.     {
  121.       int c = (getch ());
  122.       if (c == EOF)
  123.     {
  124.       msg_t * message = (OS2_make_readahead ());
  125.       (SM_READAHEAD_SIZE (message)) = 0;
  126.       send_readahead (message);
  127.       break;
  128.     }
  129.       {
  130.     int code = (OS2_keyboard_interrupt_handler (c));
  131.     if (code == '\0')
  132.       process_input_char (c);
  133.     else
  134.       {
  135.         msg_t * message = (OS2_create_message (mt_console_interrupt));
  136.         (SM_CONSOLE_INTERRUPT_CODE (message)) = code;
  137.         OS2_send_message (OS2_interrupt_qid, message);
  138.         /* Flush buffers only for certain chars? */
  139.         flush_input ();
  140.         if (c == '\a')
  141.           write_char ('\a', 0);
  142.       }
  143.       }
  144.     }
  145.   {
  146.     tqueue_t * tqueue = (OS2_qid_tqueue (console_writer_qid));
  147.     OS2_close_qid (console_writer_qid);
  148.     OS2_close_std_tqueue (tqueue);
  149.   }
  150.   OS2_endthread ();
  151. }
  152.  
  153. #if ((!defined(USE_PMCON)) && (!defined(USE_PMIO)))
  154. static int
  155. getch (void)
  156. {
  157.   while (1)
  158.     {
  159. #ifdef USE_VIO
  160.       KBDKEYINFO info;
  161.       XTD_API_CALL
  162.     (kbd_char_in, ((&info), IO_WAIT, 0),
  163.      {
  164.        if (rc == ERROR_KBD_INVALID_HANDLE)
  165.          return (EOF);
  166.      });
  167.       if ((info . fbStatus) == 0x40)
  168.     return (info . chChar);
  169. #else
  170.       int c = (_getch ());
  171.       if (c == EOF)
  172.     return (EOF);
  173.       else if ((c == 0) || (c == 0xe0))
  174.     {
  175.       /* Discard extended keycodes. */
  176.       if ((_getch ()) == EOF)
  177.         return (EOF);
  178.     }
  179.       else
  180.     return (c);
  181. #endif
  182.     }
  183. }
  184. #endif /* not USE_PMIO */
  185.  
  186. static void
  187. grab_console_lock (void)
  188. {
  189.   OS2_request_mutex_semaphore (console_lock);
  190. }
  191.  
  192. static void
  193. release_console_lock (void)
  194. {
  195.   OS2_release_mutex_semaphore (console_lock);
  196. }
  197.  
  198. static void
  199. process_input_char (char c)
  200. {
  201.   if (!input_buffered_p)
  202.     send_char (c);
  203.   else switch (c)
  204.     {
  205.     case '\b':
  206.     case '\177':
  207.       do_rubout ();
  208.       break;
  209.     case '\r':
  210.       do_self_insert ('\r');
  211.       do_self_insert ('\n');
  212.       finish_line ();
  213.       break;
  214.     default:
  215.       do_self_insert (c);
  216.       break;
  217.     }
  218. }
  219.  
  220. static void
  221. do_self_insert (char c)
  222. {
  223.   add_char_to_line_buffer (c);
  224.   write_char (c, 1);
  225. }
  226.  
  227. static void
  228. add_char_to_line_buffer (char c)
  229. {
  230.   grab_console_lock ();
  231.   OS2_readahead_buffer_insert (line_buffer, c);
  232.   release_console_lock ();
  233. }
  234.  
  235. static void
  236. do_rubout (void)
  237. {
  238.   grab_console_lock ();
  239.   if (OS2_readahead_buffer_emptyp (line_buffer))
  240.     {
  241.       release_console_lock ();
  242.       write_char ('\a', 0);
  243.       return;
  244.     }
  245.   {
  246.     unsigned int n
  247.       = (char_output_length (OS2_readahead_buffer_rubout (line_buffer)));
  248.     unsigned int i;
  249.     release_console_lock ();
  250.     for (i = 0; (i < n); i += 1)
  251.       write_char ('\b', 0);
  252.     for (i = 0; (i < n); i += 1)
  253.       write_char (' ', 0);
  254.     for (i = 0; (i < n); i += 1)
  255.       write_char ('\b', 0);
  256.   }
  257. }
  258.  
  259. static void
  260. finish_line (void)
  261. {
  262.   msg_t ** messages;
  263.   msg_t ** scan;
  264.   grab_console_lock ();
  265.   messages = (OS2_readahead_buffer_read_all (line_buffer));
  266.   release_console_lock ();
  267.   scan = messages;
  268.   while (1)
  269.     {
  270.       msg_t * msg = (*scan++);
  271.       if (msg == 0)
  272.     break;
  273.       send_readahead (msg);
  274.     }
  275.   OS_free (messages);
  276. }
  277.  
  278. static void
  279. send_char (char c)
  280. {
  281.   msg_t * message = (OS2_make_readahead ());
  282.   (SM_READAHEAD_SIZE (message)) = 1;
  283.   ((SM_READAHEAD_DATA (message)) [0]) = c;
  284.   send_readahead (message);
  285. }
  286.  
  287. static void
  288. send_readahead (msg_t * message)
  289. {
  290.   OS2_send_message (console_writer_qid, message);
  291.   (void) OS2_wait_for_readahead_ack (console_writer_qid);
  292. }
  293.  
  294. void
  295. OS2_initialize_console_channel (Tchannel channel)
  296. {
  297.   (CHANNEL_OPERATOR_CONTEXT (channel)) = console_context;
  298.   (CHANNEL_OPERATOR (channel)) = console_operator;
  299. }
  300.  
  301. static void
  302. console_operator (Tchannel channel, chop_t operation,
  303.           choparg_t arg1, choparg_t arg2, choparg_t arg3)
  304. {
  305.   switch (operation)
  306.     {
  307.     case chop_read:
  308.       (* ((long *) arg3))
  309.     = (OS2_channel_thread_read
  310.        (channel, ((char *) arg1), ((size_t) arg2)));
  311.       break;
  312.     case chop_write:
  313.       write_output (((const char *) arg1), ((size_t) arg2), output_cooked_p);
  314.       (* ((long *) arg3)) = ((size_t) arg2);
  315.       break;
  316.     case chop_close:
  317.     case chop_output_flush:
  318.     case chop_output_drain:
  319.       break;
  320.     case chop_input_flush:
  321.       flush_input ();
  322.       break;
  323.     case chop_input_buffered:
  324.       console_input_buffered (channel, ((int) arg1), ((int *) arg2));
  325.       break;
  326.     case chop_output_cooked:
  327.       console_output_cooked (channel, ((int) arg1), ((int *) arg2));
  328.       break;
  329.     default:
  330.       OS2_logic_error ("Unknown operation for console.");
  331.       break;
  332.     }
  333. }
  334.  
  335. static void
  336. flush_input (void)
  337. {
  338.   msg_t ** messages;
  339.   msg_t ** scan;
  340.   grab_console_lock ();
  341.   messages = (OS2_readahead_buffer_read_all (line_buffer));
  342.   release_console_lock ();
  343.   scan = messages;
  344.   while (1)
  345.     {
  346.       msg_t * msg = (*scan++);
  347.       if (msg == 0)
  348.     break;
  349.       OS2_destroy_message (msg);
  350.     }
  351.   OS_free (messages);
  352. }
  353.  
  354. static void
  355. console_input_buffered (Tchannel channel, int new, int * pold)
  356. {
  357.   if (new < 0)
  358.     (* pold) = input_buffered_p;
  359.   else
  360.     {
  361.       int old = input_buffered_p;
  362.       input_buffered_p = new;
  363.       if (old && (!new))
  364.     flush_input ();
  365.     }
  366. }
  367.  
  368. static void
  369. console_output_cooked (Tchannel channel, int new, int * pold)
  370. {
  371.   if (new < 0)
  372.     (* pold) = output_cooked_p;
  373.   else
  374.     output_cooked_p = (new ? 1 : 0);
  375. }
  376.  
  377. static void
  378. write_char (char c, int cooked_p)
  379. {
  380.   write_output ((&c), 1, cooked_p);
  381. }
  382.  
  383. void
  384. OS2_console_write (const char * data, size_t size)
  385. {
  386.   write_output (data, size, 2);
  387. }
  388.  
  389. static void
  390. write_output (const char * data, size_t size, int cooked_p)
  391. {
  392.   const char * scan = data;
  393.   const char * end = (scan + size);
  394.   char output_translation [256];
  395.   char * out = output_translation;
  396.   char * out_limit = (out + ((sizeof (output_translation)) - 4));
  397.   char c;
  398.   if (cooked_p == 0)
  399.     write_output_1 (scan, end);
  400.   else
  401.     while (1)
  402.       {
  403.     if ((scan == end) || (out >= out_limit))
  404.       {
  405.         write_output_1 (output_translation, out);
  406.         if (scan == end)
  407.           break;
  408.         out = output_translation;
  409.       }
  410.     c = (*scan++);
  411.     if ((cooked_p == 2) && (c == '\n'))
  412.       {
  413.         (*out++) = '\r';
  414.         (*out++) = '\n';
  415.       }
  416.     else if ((isprint (c))
  417.          || (c == '\f')
  418.          || (c == '\a')
  419.          || (c == '\r')
  420.          || (c == '\n'))
  421.       (*out++) = c;
  422.     else if (c < 0x20)
  423.       {
  424.         (*out++) = '^';
  425.         (*out++) = ('@' + c);
  426.       }
  427.     else
  428.       {
  429.         (*out++) = '\\';
  430.         (*out++) = ('0' + ((c >> 6) & 3));
  431.         (*out++) = ('0' + ((c >> 3) & 7));
  432.         (*out++) = ('0' + (c & 7));
  433.       }
  434.       }
  435. }
  436.  
  437. static void
  438. write_output_1 (const char * scan, const char * end)
  439. {
  440. #ifdef USE_PMCON
  441.  
  442.   OS2_pm_console_write (scan, (end - scan));
  443.  
  444. #else /* not USE_PMCON */
  445. #ifdef USE_PMIO
  446.  
  447.   put_raw ((end - scan), scan);
  448.  
  449. #else /* not USE_PMIO */
  450. #ifdef USE_VIO
  451.  
  452.   STD_API_CALL (vio_wrt_tty, (((PCH) scan), (end - scan), 0));
  453.  
  454. #else /* not USE_VIO */
  455.  
  456.   while (1)
  457.     {
  458.       ULONG n;
  459.       APIRET rc = (dos_write (1, ((void *) scan), (end - scan), (& n)));
  460.       if (rc != NO_ERROR)
  461.     break;
  462.       scan += n;
  463.       if (scan == end)
  464.     break;
  465.     }
  466.  
  467. #endif /* not USE_VIO */
  468. #endif /* not USE_PMIO */
  469. #endif /* not USE_PMCON */
  470. }
  471.  
  472. static unsigned int
  473. char_output_length (char c)
  474. {
  475.   return ((isprint (c)) ? 1 : (c < 0x20) ? 2 : 4);
  476. }
  477.