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 / uxctty.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  16KB  |  553 lines

  1. /* -*-C-*-
  2.  
  3. $Id: uxctty.c,v 1.14 2000/12/05 21:23:48 cph Exp $
  4.  
  5. Copyright (c) 1990-2000 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. #include "ux.h"
  23. #include "osctty.h"
  24. #include "ossig.h"
  25.  
  26. /* If `ctty_fildes' is nonnegative, it is an open file descriptor for
  27.    the controlling terminal of the process.
  28.  
  29.    If `ctty_fildes' is negative, Scheme should not alter the control
  30.    terminal's settings. */
  31. static int ctty_fildes;
  32.  
  33. /* This flag says whether Scheme was in the foreground when it was
  34.    last entered.  Provided that no other process forces Scheme out of
  35.    the foreground, it will remain in the foreground until it exits or
  36.    is stopped.
  37.  
  38.    If `scheme_in_foreground' is zero, Scheme should not alter the
  39.    control terminal's settings, nor should it alter the settings of
  40.    stdin, stdout, or stderr if they are terminals. */
  41. int scheme_in_foreground;
  42.  
  43. /* This flag, set during initialization, says whether we are
  44.    permitted to change the settings of the control terminal. */
  45. static int permit_ctty_control;
  46.  
  47. /* Original states of the control terminal, stdin, and stdout when
  48.    Scheme was last continued or stopped, respectively.  If the
  49.    corresponding `_recorded' flag is zero, then no information is
  50.    saved. */
  51.  
  52. struct terminal_state_recording
  53. {
  54.   int fd;
  55.   int recorded_p;
  56.   Ttty_state state;
  57.   int flags;
  58. };
  59.  
  60. static struct terminal_state_recording outside_ctty_state;
  61. static struct terminal_state_recording outside_stdin_state;
  62. static struct terminal_state_recording outside_stdout_state;
  63. static struct terminal_state_recording inside_ctty_state;
  64. static struct terminal_state_recording inside_stdin_state;
  65. static struct terminal_state_recording inside_stdout_state;
  66.  
  67. static void EXFUN (ctty_update_interrupt_chars, (void));
  68.  
  69. static int
  70. DEFUN (get_terminal_state, (fd, s), int fd AND Ttty_state * s)
  71. {
  72.   while (1)
  73.     {
  74.       int scr = (UX_terminal_get_state (fd, s));
  75.       if ((scr >= 0) || (errno != EINTR))
  76.     return (scr);
  77.     }
  78. }
  79.  
  80. static int
  81. DEFUN (set_terminal_state, (fd, s), int fd AND Ttty_state * s)
  82. {
  83.   while (1)
  84.     {
  85.       int scr = (UX_terminal_set_state (fd, s));
  86.       if ((scr >= 0) || (errno != EINTR))
  87.     return (scr);
  88.     }
  89. }
  90.  
  91.  
  92. static int
  93. DEFUN (get_flags, (fd, flags), int fd AND int * flags)
  94. {
  95. #ifdef FCNTL_NONBLOCK
  96.   while (1)
  97.     {
  98.       int scr = (UX_fcntl (fd, F_GETFL, 0));
  99.       if (scr >= 0)
  100.     {
  101.       (*flags) = scr;
  102.       return (0);
  103.     }
  104.       if (errno != EINTR)
  105.     return (-1);
  106.     }
  107. #else
  108.   return (0);
  109. #endif
  110. }
  111.  
  112. static int
  113. DEFUN (set_flags, (fd, flags), int fd AND int * flags)
  114. {
  115. #ifdef FCNTL_NONBLOCK
  116.   while (1)
  117.     {
  118.       int scr = (UX_fcntl (fd, F_SETFL, (*flags)));
  119.       if ((scr >= 0) || (errno != EINTR))
  120.     return (scr);
  121.     }
  122. #else
  123.   return (0);
  124. #endif
  125. }
  126.  
  127. static void
  128. DEFUN (save_external_state, (s), struct terminal_state_recording * s)
  129. {
  130.   (s -> recorded_p) =
  131.     (scheme_in_foreground
  132.      && (isatty (s -> fd))
  133.      && ((get_terminal_state ((s -> fd), (& (s -> state)))) >= 0)
  134.      && ((get_flags ((s -> fd), (& (s -> flags)))) >= 0));
  135. }
  136.  
  137. static void
  138. DEFUN (restore_external_state, (s), struct terminal_state_recording * s)
  139. {
  140.   if (s -> recorded_p)
  141.     {
  142.       set_terminal_state ((s -> fd), (& (s -> state)));
  143.       set_flags ((s -> fd), (& (s -> flags)));
  144.       (s -> recorded_p) = 0;
  145.     }
  146. }
  147.  
  148. void
  149. DEFUN (save_internal_state, (s, es),
  150.        struct terminal_state_recording * s AND
  151.        struct terminal_state_recording * es)
  152. {
  153.   /* Don't do anything unless we have a recording of the external
  154.      state.  Otherwise, we should preserve the previous recording of
  155.      the internal state, if any. */
  156.   if (es -> recorded_p)
  157.     (s -> recorded_p) =
  158.       (((get_terminal_state ((s -> fd), (& (s -> state)))) >= 0)
  159.        && ((get_flags ((s -> fd), (& (s -> flags)))) >= 0));
  160. }
  161.  
  162. static void
  163. DEFUN (restore_internal_state, (s, es),
  164.        struct terminal_state_recording * s AND
  165.        struct terminal_state_recording * es)
  166. {
  167.   /* When we recorded the internal state, we had a recording of the
  168.      external state.  But since we've stopped Scheme and restarted it,
  169.      we may no longer have a current recording of the external state.
  170.      If we don't, then we can't restore the internal state.
  171.  
  172.      The usual reason that we don't have a recording is that Scheme is
  173.      in the background.  In that case it would be nice to preserve the
  174.      previous internal state until we go back to the foreground.  But
  175.      doing that transparently would also require tracking all
  176.      attempted state changes in the recording, which is a pain.  So if
  177.      we can't restore the internal state, we just thrown it away. */
  178.   if (s -> recorded_p)
  179.     {
  180.       if (es -> recorded_p)
  181.     {
  182.       set_terminal_state ((s -> fd), (& (s -> state)));
  183.       set_flags ((s -> fd), (& (s -> flags)));
  184.     }
  185.       (s -> recorded_p) = 0;
  186.     }
  187. }
  188.  
  189. void
  190. DEFUN_VOID (UX_ctty_save_external_state)
  191. {
  192.   if (permit_ctty_control && (ctty_fildes >= 0))
  193.     {
  194.       pid_t pgrp_id = (UX_tcgetpgrp (ctty_fildes));
  195.       scheme_in_foreground =
  196.     ((pgrp_id < 0)
  197.      /* If no job control, assume we're in foreground. */
  198.      ? (errno == ENOSYS)
  199.      : ((UX_getpgrp ()) == pgrp_id));
  200.     }
  201.   else
  202.     scheme_in_foreground = 0;
  203.   save_external_state (&outside_ctty_state);
  204.   save_external_state (&outside_stdin_state);
  205.   save_external_state (&outside_stdout_state);
  206. }
  207.  
  208. void
  209. DEFUN_VOID (UX_ctty_restore_external_state)
  210. {
  211.   restore_external_state (&outside_ctty_state);
  212.   restore_external_state (&outside_stdin_state);
  213.   restore_external_state (&outside_stdout_state);
  214. }
  215.  
  216. void
  217. DEFUN_VOID (UX_ctty_save_internal_state)
  218. {
  219.   save_internal_state ((&inside_ctty_state), (&outside_ctty_state));
  220.   save_internal_state ((&inside_stdin_state), (&outside_stdin_state));
  221.   save_internal_state ((&inside_stdout_state), (&outside_stdout_state));
  222. }
  223.  
  224. void
  225. DEFUN_VOID (UX_ctty_restore_internal_state)
  226. {
  227.   int do_update =
  228.     ((inside_ctty_state . recorded_p)
  229.      && (outside_ctty_state . recorded_p));
  230.   restore_internal_state ((&inside_ctty_state), (&outside_ctty_state));
  231.   restore_internal_state ((&inside_stdin_state), (&outside_stdin_state));
  232.   restore_internal_state ((&inside_stdout_state), (&outside_stdout_state));
  233.   if (do_update)
  234.     ctty_update_interrupt_chars ();
  235. }
  236.  
  237. int
  238. DEFUN_VOID (OS_ctty_interrupt_control)
  239. {
  240.   return (outside_ctty_state . recorded_p);
  241. }
  242.  
  243. int
  244. DEFUN (UX_terminal_control_ok, (fd), int fd)
  245. {
  246.   return
  247.     ((fd == STDIN_FILENO)
  248.      ? (outside_stdin_state . recorded_p)
  249.      : (fd == STDOUT_FILENO)
  250.      ? (outside_stdout_state . recorded_p)
  251.      : 1);
  252. }
  253.  
  254. /* Keyboard Interrupt Characters */
  255.  
  256. typedef struct
  257. {
  258.   cc_t quit;
  259.   cc_t intrpt;
  260.   cc_t tstp;
  261.   cc_t dtstp;
  262. } Tinterrupt_chars;
  263.  
  264. static Tinterrupt_enables current_interrupt_enables;
  265. static Tinterrupt_chars current_interrupt_chars;
  266.  
  267. #define DEFAULT_SIGQUIT_CHAR    ((cc_t) '\003') /* ^C */
  268. #define DEFAULT_SIGINT_CHAR    ((cc_t) '\007') /* ^G */
  269. #define DEFAULT_SIGTSTP_CHAR    ((cc_t) '\032') /* ^Z */
  270.  
  271. #define KEYBOARD_QUIT_INTERRUPT        0x1
  272. #define KEYBOARD_INTRPT_INTERRUPT    0x2
  273. #define KEYBOARD_TSTP_INTERRUPT        0x4
  274. #define KEYBOARD_ALL_INTERRUPTS        0x7
  275.  
  276. cc_t
  277. DEFUN_VOID (OS_ctty_quit_char)
  278. {
  279.   return (current_interrupt_chars . quit);
  280. }
  281.  
  282. cc_t
  283. DEFUN_VOID (OS_ctty_int_char)
  284. {
  285.   return (current_interrupt_chars . intrpt);
  286. }
  287.  
  288. cc_t
  289. DEFUN_VOID (OS_ctty_tstp_char)
  290. {
  291.   return (current_interrupt_chars . tstp);
  292. }
  293.  
  294. cc_t
  295. DEFUN_VOID (OS_ctty_disabled_char)
  296. {
  297.   return ((ctty_fildes >= 0) ? (UX_PC_VDISABLE (ctty_fildes)) : '\377');
  298. }
  299.  
  300. int
  301. DEFUN_VOID (OS_ctty_fd)
  302. {
  303.   return (ctty_fildes);
  304. }
  305.  
  306. #if 0
  307.  
  308. /* not currently used */
  309. static void
  310. DEFUN (ctty_get_interrupt_chars, (ic), Tinterrupt_chars * ic)
  311. {
  312.   Ttty_state s;
  313.   if ((get_terminal_state (ctty_fildes, (&s))) == 0)
  314.     {
  315. #ifdef HAVE_TERMIOS_H
  316.       (ic -> quit) = ((s . tio . c_cc) [VQUIT]);
  317.       (ic -> intrpt) = ((s . tio . c_cc) [VINTR]);
  318.       (ic -> tstp) = ((s . tio . c_cc) [VSUSP]);
  319.  
  320. #ifdef VDSUSP
  321.       (ic -> dtstp) = ((s . tio . c_cc) [VDSUSP]);
  322. #else /* not VDSUSP */
  323. #ifdef __HPUX__
  324.       (ic -> dtstp) = (s . ltc . t_dsuspc);
  325. #endif /* __HPUX__ */
  326. #endif /* not VDSUSP */
  327.  
  328. #else /* not HAVE_TERMIOS_H */
  329. #ifdef HAVE_TERMIO_H
  330.  
  331.       (ic -> quit) = ((s . tio . c_cc) [VQUIT]);
  332.       (ic -> intrpt) = ((s . tio . c_cc) [VINTR]);
  333. #ifdef HAVE_STRUCT_LTCHARS
  334.       (ic -> tstp) = (s . ltc . t_suspc);
  335.       (ic -> dtstp) = (s . ltc . t_dsuspc);
  336. #else /* not HAVE_STRUCT_LTCHARS */
  337.       {
  338.     cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  339.     (ic -> tstp) = disabled_char;
  340.     (ic -> dtstp) = disabled_char;
  341.       }
  342. #endif /* not HAVE_STRUCT_LTCHARS */
  343.  
  344. #else /* not HAVE_TERMIO_H */
  345. #ifdef HAVE_SGTTY_H
  346.  
  347.       (ic -> quit) = (s . tc . t_quitc);
  348.       (ic -> intrpt) = (s . tc . t_intrc);
  349. #ifdef HAVE_STRUCT_LTCHARS
  350.       (ic -> tstp) = (s . ltc . t_suspc);
  351.       (ic -> dtstp) = (s . ltc . t_dsuspc);
  352. #else /* not HAVE_STRUCT_LTCHARS */
  353.       {
  354.     cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  355.     (ic -> tstp) = disabled_char;
  356.     (ic -> dtstp) = disabled_char;
  357.       }
  358. #endif /* not HAVE_STRUCT_LTCHARS */
  359.  
  360. #endif /* HAVE_SGTTY_H */
  361. #endif /* HAVE_TERMIO_H */
  362. #endif /* HAVE_TERMIOS_H */
  363.     }
  364.   else
  365.     {
  366.       cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  367.       (ic -> quit) = disabled_char;
  368.       (ic -> intrpt) = disabled_char;
  369.       (ic -> tstp) = disabled_char;
  370.       (ic -> dtstp) = disabled_char;
  371.     }
  372. }
  373. #endif /* 0 */
  374.  
  375. static void
  376. DEFUN (ctty_set_interrupt_chars, (ic), Tinterrupt_chars * ic)
  377. {
  378.   Ttty_state s;
  379.   if ((get_terminal_state (ctty_fildes, (&s))) == 0)
  380.     {
  381. #ifdef HAVE_TERMIOS_H
  382.       ((s . tio . c_cc) [VQUIT]) = (ic -> quit);
  383.       ((s . tio . c_cc) [VINTR]) = (ic -> intrpt);
  384.       ((s . tio . c_cc) [VSUSP]) = (ic -> tstp);
  385. #ifdef VDSUSP
  386.       ((s . tio . c_cc) [VDSUSP]) = (ic -> dtstp);
  387. #else /* not VDSUSP */
  388. #ifdef __HPUX__
  389.       (s . ltc . t_suspc) = (ic -> tstp);
  390.       (s . ltc . t_dsuspc) = (ic -> dtstp);
  391. #endif /* __HPUX__ */
  392. #endif /* not VDSUSP */
  393.  
  394. #else /* not HAVE_TERMIOS_H */
  395. #ifdef HAVE_TERMIO_H
  396.  
  397.       ((s . tio . c_cc) [VQUIT]) = (ic -> quit);
  398.       ((s . tio . c_cc) [VINTR]) = (ic -> intrpt);
  399. #ifdef HAVE_STRUCT_LTCHARS
  400.       (s . ltc . t_suspc) = (ic -> tstp);
  401.       (s . ltc . t_dsuspc) = (ic -> dtstp);
  402. #endif
  403.  
  404. #else /* not HAVE_TERMIO_H */
  405. #ifdef HAVE_SGTTY_H
  406.  
  407.       (s . tc . t_quitc) = (ic -> quit);
  408.       (s . tc . t_intrc) = (ic -> intrpt);
  409. #ifdef HAVE_STRUCT_LTCHARS
  410.       (s . ltc . t_suspc) = (ic -> tstp);
  411.       (s . ltc . t_dsuspc) = (ic -> dtstp);
  412. #endif
  413.  
  414. #endif /* HAVE_SGTTY_H */
  415. #endif /* HAVE_TERMIO_H */
  416. #endif /* HAVE_TERMIOS_H */
  417.       set_terminal_state (ctty_fildes, (&s));
  418.     }
  419. }
  420.  
  421. static void
  422. DEFUN_VOID (ctty_update_interrupt_chars)
  423. {
  424.   if (outside_ctty_state . recorded_p)
  425.     {
  426.       cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  427.       /* Must split declaration and assignment because some compilers
  428.      do not permit aggregate initializers. */
  429.       Tinterrupt_chars active_interrupt_chars;
  430.       active_interrupt_chars = current_interrupt_chars;
  431.       if ((current_interrupt_enables & KEYBOARD_QUIT_INTERRUPT) == 0)
  432.     (active_interrupt_chars . quit) = disabled_char;
  433.       if ((current_interrupt_enables & KEYBOARD_INTRPT_INTERRUPT) == 0)
  434.     (active_interrupt_chars . intrpt) = disabled_char;
  435.       if ((current_interrupt_enables & KEYBOARD_TSTP_INTERRUPT) == 0)
  436.     (active_interrupt_chars . tstp) = disabled_char;
  437.       (active_interrupt_chars . dtstp) = disabled_char;
  438.       ctty_set_interrupt_chars (&active_interrupt_chars);
  439.     }
  440. }
  441.  
  442. void
  443. DEFUN (OS_ctty_get_interrupt_enables, (mask), Tinterrupt_enables * mask)
  444. {
  445.   (*mask) = current_interrupt_enables;
  446. }
  447.  
  448. void
  449. DEFUN (OS_ctty_set_interrupt_enables, (mask), Tinterrupt_enables * mask)
  450. {
  451.   current_interrupt_enables = (*mask);
  452.   ctty_update_interrupt_chars ();
  453. }
  454.  
  455. #if 0
  456.  
  457. void
  458. DEFUN (OS_ctty_set_interrupt_chars, (quit_char, int_char, tstp_char),
  459.        cc_t quit_char AND
  460.        cc_t int_char AND
  461.        cc_t tstp_char)
  462. {
  463.   (current_interrupt_chars . quit) = quit_char;
  464.   (current_interrupt_chars . intrpt) = int_char;
  465.   (current_interrupt_chars . tstp) = tstp_char;
  466.   ctty_update_interrupt_chars ();
  467. }
  468. #endif
  469.  
  470. unsigned int
  471. DEFUN_VOID (OS_ctty_num_int_chars)
  472. {
  473.   return (3);
  474. }
  475.  
  476. cc_t *
  477. DEFUN_VOID (OS_ctty_get_int_chars)
  478. {
  479.   static cc_t int_chars [3];
  480.  
  481.   int_chars[0] = current_interrupt_chars.quit;
  482.   int_chars[1] = current_interrupt_chars.intrpt;
  483.   int_chars[2] = current_interrupt_chars.tstp;
  484.   return (& int_chars [0]);
  485. }
  486.  
  487. void
  488. DEFUN (OS_ctty_set_int_chars, (int_chars), cc_t * int_chars)
  489. {
  490.   current_interrupt_chars.quit   = int_chars[0];
  491.   current_interrupt_chars.intrpt = int_chars[1];
  492.   current_interrupt_chars.tstp   = int_chars[2];
  493.   ctty_update_interrupt_chars ();
  494.   return;
  495. }
  496.  
  497. extern enum interrupt_handler EXFUN (OS_signal_quit_handler, (void));
  498. extern enum interrupt_handler EXFUN (OS_signal_int_handler, (void));
  499. extern enum interrupt_handler EXFUN (OS_signal_tstp_handler, (void));
  500. extern void EXFUN
  501.   (OS_signal_set_interrupt_handlers,
  502.    (enum interrupt_handler quit_handler,
  503.     enum interrupt_handler int_handler,
  504.     enum interrupt_handler tstp_handler));
  505.  
  506. cc_t *
  507. DEFUN_VOID (OS_ctty_get_int_char_handlers)
  508. {
  509.   static cc_t int_handlers [3];
  510.  
  511.   int_handlers[0] = ((cc_t) (OS_signal_quit_handler ()));
  512.   int_handlers[1] = ((cc_t) (OS_signal_int_handler ()));
  513.   int_handlers[2] = ((cc_t) (OS_signal_tstp_handler ()));
  514.   return (& int_handlers [0]);
  515. }
  516.  
  517. void
  518. DEFUN (OS_ctty_set_int_char_handlers, (int_handlers), cc_t * int_handlers)
  519. {
  520.   OS_signal_set_interrupt_handlers
  521.     (((enum interrupt_handler) (int_handlers [0])),
  522.      ((enum interrupt_handler) (int_handlers [1])),
  523.      ((enum interrupt_handler) (int_handlers [2])));
  524.   return;
  525. }
  526.  
  527. void
  528. DEFUN (UX_initialize_ctty, (interactive), int interactive)
  529. {
  530.   {
  531.     char * tty = (UX_ctermid (0));
  532.     ctty_fildes =
  533.       (((tty == 0) || ((tty[0]) == 0))
  534.        ? (-1)
  535.        : (UX_open (tty, O_RDWR, 0)));
  536.   }
  537.   permit_ctty_control = interactive;
  538.   (inside_ctty_state . fd) = (outside_ctty_state . fd) = ctty_fildes;
  539.   (inside_stdin_state . fd) = (outside_stdin_state . fd) = STDIN_FILENO;
  540.   (inside_stdout_state . fd) = (outside_stdout_state . fd) = STDOUT_FILENO;
  541.   UX_ctty_save_external_state ();
  542.   (inside_ctty_state . recorded_p) = 0;
  543.   (inside_stdin_state . recorded_p) = 0;
  544.   (inside_stdout_state . recorded_p) = 0;
  545.   (current_interrupt_chars . quit) = DEFAULT_SIGQUIT_CHAR;
  546.   (current_interrupt_chars . intrpt) = DEFAULT_SIGINT_CHAR;
  547.   (current_interrupt_chars . tstp) = DEFAULT_SIGTSTP_CHAR;
  548.   (current_interrupt_chars . dtstp) = (UX_PC_VDISABLE (ctty_fildes));
  549.   current_interrupt_enables = KEYBOARD_ALL_INTERRUPTS;
  550.   if (outside_ctty_state . recorded_p)
  551.     ctty_set_interrupt_chars (¤t_interrupt_chars);
  552. }
  553.