Home | History | Annotate | Line # | Download | only in info
      1 /*	$NetBSD: terminal.c,v 1.2 2016/01/14 00:34:52 christos Exp $	*/
      2 
      3 /* terminal.c -- how to handle the physical terminal for Info.
      4    Id: terminal.c,v 1.3 2004/04/11 17:56:46 karl Exp
      5 
      6    Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1996, 1997, 1998,
      7    1999, 2001, 2002, 2004 Free Software Foundation, Inc.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 2, or (at your option)
     12    any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     22 
     23    Originally written by Brian Fox (bfox (at) ai.mit.edu). */
     24 
     25 #include "info.h"
     26 #include "terminal.h"
     27 #include "termdep.h"
     28 
     29 #include <sys/types.h>
     30 #include <sys/ioctl.h>
     31 #include <signal.h>
     32 
     33 /* The Unix termcap interface code. */
     34 #ifdef HAVE_NCURSES_TERMCAP_H
     35 #include <ncurses/termcap.h>
     36 #else
     37 #ifdef HAVE_TERMCAP_H
     38 #include <termcap.h>
     39 #else
     40 /* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
     41    Unfortunately, PC is a global variable used by the termcap library. */
     42 #undef PC
     43 
     44 /* Termcap requires these variables, whether we access them or not. */
     45 char *BC, *UP;
     46 char PC;      /* Pad character */
     47 short ospeed; /* Terminal output baud rate */
     48 extern int tgetnum (), tgetflag (), tgetent ();
     49 extern char *tgetstr (), *tgoto ();
     50 extern void tputs ();
     51 #endif /* not HAVE_TERMCAP_H */
     52 #endif /* not HAVE_NCURSES_TERMCAP_H */
     53 
     54 /* Function "hooks".  If you make one of these point to a function, that
     55    function is called when appropriate instead of its namesake.  Your
     56    function is called with exactly the same arguments that were passed
     57    to the namesake function. */
     58 VFunction *terminal_begin_inverse_hook = (VFunction *)NULL;
     59 VFunction *terminal_end_inverse_hook = (VFunction *)NULL;
     60 VFunction *terminal_prep_terminal_hook = (VFunction *)NULL;
     61 VFunction *terminal_unprep_terminal_hook = (VFunction *)NULL;
     62 VFunction *terminal_up_line_hook = (VFunction *)NULL;
     63 VFunction *terminal_down_line_hook = (VFunction *)NULL;
     64 VFunction *terminal_clear_screen_hook = (VFunction *)NULL;
     65 VFunction *terminal_clear_to_eol_hook = (VFunction *)NULL;
     66 VFunction *terminal_get_screen_size_hook = (VFunction *)NULL;
     67 VFunction *terminal_goto_xy_hook = (VFunction *)NULL;
     68 VFunction *terminal_initialize_terminal_hook = (VFunction *)NULL;
     69 VFunction *terminal_new_terminal_hook = (VFunction *)NULL;
     70 VFunction *terminal_put_text_hook = (VFunction *)NULL;
     71 VFunction *terminal_ring_bell_hook = (VFunction *)NULL;
     72 VFunction *terminal_write_chars_hook = (VFunction *)NULL;
     73 VFunction *terminal_scroll_terminal_hook = (VFunction *)NULL;
     74 
     75 /* **************************************************************** */
     76 /*                                                                  */
     77 /*                      Terminal and Termcap                        */
     78 /*                                                                  */
     79 /* **************************************************************** */
     80 
     81 /* A buffer which holds onto the current terminal description, and a pointer
     82    used to float within it.  And the name of the terminal.  */
     83 static char *term_buffer = NULL;
     84 static char *term_string_buffer = NULL;
     85 static char *term_name;
     86 
     87 /* Some strings to control terminal actions.  These are output by tputs (). */
     88 static char *term_goto, *term_clreol, *term_cr, *term_clrpag;
     89 static char *term_begin_use, *term_end_use;
     90 static char *term_AL, *term_DL, *term_al, *term_dl;
     91 
     92 static char *term_keypad_on, *term_keypad_off;
     93 
     94 /* How to go up a line. */
     95 static char *term_up;
     96 
     97 /* How to go down a line. */
     98 static char *term_dn;
     99 
    100 /* An audible bell, if the terminal can be made to make noise. */
    101 static char *audible_bell;
    102 
    103 /* A visible bell, if the terminal can be made to flash the screen. */
    104 static char *visible_bell;
    105 
    106 /* The string to write to turn on the meta key, if this term has one. */
    107 static char *term_mm;
    108 
    109 /* The string to turn on inverse mode, if this term has one. */
    110 static char *term_invbeg;
    111 
    112 /* The string to turn off inverse mode, if this term has one. */
    113 static char *term_invend;
    114 
    115 /* Although I can't find any documentation that says this is supposed to
    116    return its argument, all the code I've looked at (termutils, less)
    117    does so, so fine.  */
    118 static int
    119 output_character_function (int c)
    120 {
    121   putc (c, stdout);
    122   return c;
    123 }
    124 
    125 /* Macro to send STRING to the terminal. */
    126 #define send_to_terminal(string) \
    127   do { \
    128     if (string) \
    129       tputs (string, 1, output_character_function); \
    130      } while (0)
    131 
    132 /* Tell the terminal that we will be doing cursor addressable motion.  */
    133 static void
    134 terminal_begin_using_terminal (void)
    135 {
    136   RETSIGTYPE (*sigsave) (int signum);
    137 
    138   if (term_keypad_on)
    139       send_to_terminal (term_keypad_on);
    140 
    141   if (!term_begin_use || !*term_begin_use)
    142     return;
    143 
    144 #ifdef SIGWINCH
    145   sigsave = signal (SIGWINCH, SIG_IGN);
    146 #endif
    147 
    148   send_to_terminal (term_begin_use);
    149   fflush (stdout);
    150   if (STREQ (term_name, "sun-cmd"))
    151     /* Without this fflush and sleep, running info in a shelltool or
    152        cmdtool (TERM=sun-cmd) with scrollbars loses -- the scrollbars are
    153        not restored properly.
    154        From: strube (at) physik3.gwdg.de (Hans Werner Strube).  */
    155     sleep (1);
    156 
    157 #ifdef SIGWINCH
    158   signal (SIGWINCH, sigsave);
    159 #endif
    160 }
    161 
    162 /* Tell the terminal that we will not be doing any more cursor
    163    addressable motion. */
    164 static void
    165 terminal_end_using_terminal (void)
    166 {
    167   RETSIGTYPE (*sigsave) (int signum);
    168 
    169   if (term_keypad_off)
    170       send_to_terminal (term_keypad_off);
    171 
    172   if (!term_end_use || !*term_end_use)
    173     return;
    174 
    175 #ifdef SIGWINCH
    176   sigsave = signal (SIGWINCH, SIG_IGN);
    177 #endif
    178 
    179   send_to_terminal (term_end_use);
    180   fflush (stdout);
    181   if (STREQ (term_name, "sun-cmd"))
    182     /* See comments at other sleep.  */
    183     sleep (1);
    184 
    185 #ifdef SIGWINCH
    186   signal (SIGWINCH, sigsave);
    187 #endif
    188 }
    189 
    190 /* **************************************************************** */
    192 /*                                                                  */
    193 /*                   Necessary Terminal Functions                   */
    194 /*                                                                  */
    195 /* **************************************************************** */
    196 
    197 /* The functions and variables on this page implement the user visible
    198    portion of the terminal interface. */
    199 
    200 /* The width and height of the terminal. */
    201 int screenwidth, screenheight;
    202 
    203 /* Non-zero means this terminal can't really do anything. */
    204 int terminal_is_dumb_p = 0;
    205 
    206 /* Non-zero means that this terminal has a meta key. */
    207 int terminal_has_meta_p = 0;
    208 
    209 /* Non-zero means that this terminal can produce a visible bell. */
    210 int terminal_has_visible_bell_p = 0;
    211 
    212 /* Non-zero means to use that visible bell if at all possible. */
    213 int terminal_use_visible_bell_p = 0;
    214 
    215 /* Non-zero means that the terminal can do scrolling. */
    216 int terminal_can_scroll = 0;
    217 
    218 /* The key sequences output by the arrow keys, if this terminal has any. */
    219 char *term_ku = NULL;
    220 char *term_kd = NULL;
    221 char *term_kr = NULL;
    222 char *term_kl = NULL;
    223 char *term_kP = NULL;   /* page-up */
    224 char *term_kN = NULL;   /* page-down */
    225 char *term_kh = NULL;	/* home */
    226 char *term_ke = NULL;	/* end */
    227 char *term_kD = NULL;	/* delete */
    228 char *term_ki = NULL;	/* ins */
    229 char *term_kx = NULL;	/* del */
    230 
    231 /* Move the cursor to the terminal location of X and Y. */
    232 void
    233 terminal_goto_xy (int x, int y)
    234 {
    235   if (terminal_goto_xy_hook)
    236     (*terminal_goto_xy_hook) (x, y);
    237   else
    238     {
    239       if (term_goto)
    240         tputs (tgoto (term_goto, x, y), 1, output_character_function);
    241     }
    242 }
    243 
    244 /* Print STRING to the terminal at the current position. */
    245 void
    246 terminal_put_text (char *string)
    247 {
    248   if (terminal_put_text_hook)
    249     (*terminal_put_text_hook) (string);
    250   else
    251     {
    252       printf ("%s", string);
    253     }
    254 }
    255 
    256 /* Print NCHARS from STRING to the terminal at the current position. */
    257 void
    258 terminal_write_chars (char *string, int nchars)
    259 {
    260   if (terminal_write_chars_hook)
    261     (*terminal_write_chars_hook) (string, nchars);
    262   else
    263     {
    264       if (nchars)
    265         fwrite (string, 1, nchars, stdout);
    266     }
    267 }
    268 
    269 /* Clear from the current position of the cursor to the end of the line. */
    270 void
    271 terminal_clear_to_eol (void)
    272 {
    273   if (terminal_clear_to_eol_hook)
    274     (*terminal_clear_to_eol_hook) ();
    275   else
    276     {
    277       send_to_terminal (term_clreol);
    278     }
    279 }
    280 
    281 /* Clear the entire terminal screen. */
    282 void
    283 terminal_clear_screen (void)
    284 {
    285   if (terminal_clear_screen_hook)
    286     (*terminal_clear_screen_hook) ();
    287   else
    288     {
    289       send_to_terminal (term_clrpag);
    290     }
    291 }
    292 
    293 /* Move the cursor up one line. */
    294 void
    295 terminal_up_line (void)
    296 {
    297   if (terminal_up_line_hook)
    298     (*terminal_up_line_hook) ();
    299   else
    300     {
    301       send_to_terminal (term_up);
    302     }
    303 }
    304 
    305 /* Move the cursor down one line. */
    306 void
    307 terminal_down_line (void)
    308 {
    309   if (terminal_down_line_hook)
    310     (*terminal_down_line_hook) ();
    311   else
    312     {
    313       send_to_terminal (term_dn);
    314     }
    315 }
    316 
    317 /* Turn on reverse video if possible. */
    318 void
    319 terminal_begin_inverse (void)
    320 {
    321   if (terminal_begin_inverse_hook)
    322     (*terminal_begin_inverse_hook) ();
    323   else
    324     {
    325       send_to_terminal (term_invbeg);
    326     }
    327 }
    328 
    329 /* Turn off reverse video if possible. */
    330 void
    331 terminal_end_inverse (void)
    332 {
    333   if (terminal_end_inverse_hook)
    334     (*terminal_end_inverse_hook) ();
    335   else
    336     {
    337       send_to_terminal (term_invend);
    338     }
    339 }
    340 
    341 /* Ring the terminal bell.  The bell is run visibly if it both has one and
    342    terminal_use_visible_bell_p is non-zero. */
    343 void
    344 terminal_ring_bell (void)
    345 {
    346   if (terminal_ring_bell_hook)
    347     (*terminal_ring_bell_hook) ();
    348   else
    349     {
    350       if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
    351         send_to_terminal (visible_bell);
    352       else
    353         send_to_terminal (audible_bell);
    354     }
    355 }
    356 
    357 /* At the line START, delete COUNT lines from the terminal display. */
    358 static void
    359 terminal_delete_lines (int start, int count)
    360 {
    361   int lines;
    362 
    363   /* Normalize arguments. */
    364   if (start < 0)
    365     start = 0;
    366 
    367   lines = screenheight - start;
    368   terminal_goto_xy (0, start);
    369   if (term_DL)
    370     tputs (tgoto (term_DL, 0, count), lines, output_character_function);
    371   else
    372     {
    373       while (count--)
    374         tputs (term_dl, lines, output_character_function);
    375     }
    376 
    377   fflush (stdout);
    378 }
    379 
    380 /* At the line START, insert COUNT lines in the terminal display. */
    381 static void
    382 terminal_insert_lines (int start, int count)
    383 {
    384   int lines;
    385 
    386   /* Normalize arguments. */
    387   if (start < 0)
    388     start = 0;
    389 
    390   lines = screenheight - start;
    391   terminal_goto_xy (0, start);
    392 
    393   if (term_AL)
    394     tputs (tgoto (term_AL, 0, count), lines, output_character_function);
    395   else
    396     {
    397       while (count--)
    398         tputs (term_al, lines, output_character_function);
    399     }
    400 
    401   fflush (stdout);
    402 }
    403 
    404 /* Scroll an area of the terminal, starting with the region from START
    405    to END, AMOUNT lines.  If AMOUNT is negative, the lines are scrolled
    406    towards the top of the screen, else they are scrolled towards the
    407    bottom of the screen. */
    408 void
    409 terminal_scroll_terminal (int start, int end, int amount)
    410 {
    411   if (!terminal_can_scroll)
    412     return;
    413 
    414   /* Any scrolling at all? */
    415   if (amount == 0)
    416     return;
    417 
    418   if (terminal_scroll_terminal_hook)
    419     (*terminal_scroll_terminal_hook) (start, end, amount);
    420   else
    421     {
    422       /* If we are scrolling down, delete AMOUNT lines at END.  Then insert
    423          AMOUNT lines at START. */
    424       if (amount > 0)
    425         {
    426           terminal_delete_lines (end, amount);
    427           terminal_insert_lines (start, amount);
    428         }
    429 
    430       /* If we are scrolling up, delete AMOUNT lines before START.  This
    431          actually does the upwards scroll.  Then, insert AMOUNT lines
    432          after the already scrolled region (i.e., END - AMOUNT). */
    433       if (amount < 0)
    434         {
    435           int abs_amount = -amount;
    436           terminal_delete_lines (start - abs_amount, abs_amount);
    437           terminal_insert_lines (end - abs_amount, abs_amount);
    438         }
    439     }
    440 }
    441 
    442 /* Re-initialize the terminal considering that the TERM/TERMCAP variable
    443    has changed. */
    444 void
    445 terminal_new_terminal (char *terminal_name)
    446 {
    447   if (terminal_new_terminal_hook)
    448     (*terminal_new_terminal_hook) (terminal_name);
    449   else
    450     {
    451       terminal_initialize_terminal (terminal_name);
    452     }
    453 }
    454 
    455 /* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
    456 void
    457 terminal_get_screen_size (void)
    458 {
    459   if (terminal_get_screen_size_hook)
    460     (*terminal_get_screen_size_hook) ();
    461   else
    462     {
    463       screenwidth = screenheight = 0;
    464 
    465 #if defined (TIOCGWINSZ)
    466       {
    467         struct winsize window_size;
    468 
    469         if (ioctl (fileno (stdout), TIOCGWINSZ, &window_size) == 0)
    470           {
    471             screenwidth = (int) window_size.ws_col;
    472             screenheight = (int) window_size.ws_row;
    473           }
    474       }
    475 #endif                          /* TIOCGWINSZ */
    476 
    477       /* Environment variable COLUMNS overrides setting of "co". */
    478       if (screenwidth <= 0)
    479         {
    480           char *sw = getenv ("COLUMNS");
    481 
    482           if (sw)
    483             screenwidth = atoi (sw);
    484 
    485           if (screenwidth <= 0)
    486             screenwidth = tgetnum ("co");
    487         }
    488 
    489       /* Environment variable LINES overrides setting of "li". */
    490       if (screenheight <= 0)
    491         {
    492           char *sh = getenv ("LINES");
    493 
    494           if (sh)
    495             screenheight = atoi (sh);
    496 
    497           if (screenheight <= 0)
    498             screenheight = tgetnum ("li");
    499         }
    500 
    501       /* If all else fails, default to 80x24 terminal. */
    502       if (screenwidth <= 0)
    503         screenwidth = 80;
    504 
    505       if (screenheight <= 0)
    506         screenheight = 24;
    507     }
    508 }
    509 
    510 /* Initialize the terminal which is known as TERMINAL_NAME.  If this
    511    terminal doesn't have cursor addressability, `terminal_is_dumb_p'
    512    becomes nonzero.  The variables SCREENHEIGHT and SCREENWIDTH are set
    513    to the dimensions that this terminal actually has.  The variable
    514    TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta
    515    key.  Finally, the terminal screen is cleared. */
    516 void
    517 terminal_initialize_terminal (char *terminal_name)
    518 {
    519   char *buffer;
    520 
    521   terminal_is_dumb_p = 0;
    522 
    523   if (terminal_initialize_terminal_hook)
    524     {
    525       (*terminal_initialize_terminal_hook) (terminal_name);
    526       return;
    527     }
    528 
    529   term_name = terminal_name ? terminal_name : getenv ("TERM");
    530   if (!term_name)
    531     term_name = "dumb";
    532 
    533   if (!term_string_buffer)
    534     term_string_buffer = xmalloc (2048);
    535 
    536   if (!term_buffer)
    537     term_buffer = xmalloc (2048);
    538 
    539   buffer = term_string_buffer;
    540 
    541   term_clrpag = term_cr = term_clreol = NULL;
    542 
    543   /* HP-UX 11.x returns 0 for OK --jeff.hull (at) state.co.us.  */
    544   if (tgetent (term_buffer, term_name) < 0)
    545     {
    546       terminal_is_dumb_p = 1;
    547       screenwidth = 80;
    548       screenheight = 24;
    549       term_cr = "\r";
    550       term_up = term_dn = audible_bell = visible_bell = NULL;
    551       term_ku = term_kd = term_kl = term_kr = NULL;
    552       term_kP = term_kN = NULL;
    553       term_kh = term_ke = NULL;
    554       term_kD = NULL;
    555       return;
    556     }
    557 
    558   BC = tgetstr ("pc", &buffer);
    559   PC = BC ? *BC : 0;
    560 
    561 #if defined (HAVE_TERMIOS_H)
    562   {
    563     struct termios ti;
    564     if (tcgetattr (fileno(stdout), &ti) != -1)
    565       ospeed = cfgetospeed (&ti);
    566     else
    567       ospeed = B9600;
    568   }
    569 #else
    570 # if defined (TIOCGETP)
    571   {
    572     struct sgttyb sg;
    573 
    574     if (ioctl (fileno (stdout), TIOCGETP, &sg) != -1)
    575       ospeed = sg.sg_ospeed;
    576     else
    577       ospeed = B9600;
    578   }
    579 # else
    580   ospeed = B9600;
    581 # endif /* !TIOCGETP */
    582 #endif
    583 
    584   term_cr = tgetstr ("cr", &buffer);
    585   term_clreol = tgetstr ("ce", &buffer);
    586   term_clrpag = tgetstr ("cl", &buffer);
    587   term_goto = tgetstr ("cm", &buffer);
    588 
    589   /* Find out about this terminal's scrolling capability. */
    590   term_AL = tgetstr ("AL", &buffer);
    591   term_DL = tgetstr ("DL", &buffer);
    592   term_al = tgetstr ("al", &buffer);
    593   term_dl = tgetstr ("dl", &buffer);
    594 
    595   terminal_can_scroll = ((term_AL || term_al) && (term_DL || term_dl));
    596 
    597   term_invbeg = tgetstr ("mr", &buffer);
    598   if (term_invbeg)
    599     term_invend = tgetstr ("me", &buffer);
    600   else
    601     term_invend = NULL;
    602 
    603   if (!term_cr)
    604     term_cr =  "\r";
    605 
    606   terminal_get_screen_size ();
    607 
    608   term_up = tgetstr ("up", &buffer);
    609   term_dn = tgetstr ("dn", &buffer);
    610   visible_bell = tgetstr ("vb", &buffer);
    611   terminal_has_visible_bell_p = (visible_bell != NULL);
    612   audible_bell = tgetstr ("bl", &buffer);
    613   if (!audible_bell)
    614     audible_bell = "\007";
    615   term_begin_use = tgetstr ("ti", &buffer);
    616   term_end_use = tgetstr ("te", &buffer);
    617 
    618   term_keypad_on = tgetstr ("ks", &buffer);
    619   term_keypad_off = tgetstr ("ke", &buffer);
    620 
    621   /* Check to see if this terminal has a meta key. */
    622   terminal_has_meta_p = (tgetflag ("km") || tgetflag ("MT"));
    623   if (terminal_has_meta_p)
    624     {
    625       term_mm = tgetstr ("mm", &buffer);
    626     }
    627   else
    628     {
    629       term_mm = NULL;
    630     }
    631 
    632   /* Attempt to find the arrow keys.  */
    633   term_ku = tgetstr ("ku", &buffer);
    634   term_kd = tgetstr ("kd", &buffer);
    635   term_kr = tgetstr ("kr", &buffer);
    636   term_kl = tgetstr ("kl", &buffer);
    637 
    638   term_kP = tgetstr ("kP", &buffer);
    639   term_kN = tgetstr ("kN", &buffer);
    640 
    641 #if defined(INFOKEY)
    642   term_kh = tgetstr ("kh", &buffer);
    643   term_ke = tgetstr ("@7", &buffer);
    644   term_ki = tgetstr ("kI", &buffer);
    645   term_kx = tgetstr ("kD", &buffer);
    646 #endif /* defined(INFOKEY) */
    647 
    648   /* Home and end keys. */
    649   term_kh = tgetstr ("kh", &buffer);
    650   term_ke = tgetstr ("@7", &buffer);
    651 
    652   term_kD = tgetstr ("kD", &buffer);
    653 
    654   /* If this terminal is not cursor addressable, then it is really dumb. */
    655   if (!term_goto)
    656     terminal_is_dumb_p = 1;
    657 }
    658 
    659 /* How to read characters from the terminal.  */
    661 
    662 #if defined (HAVE_TERMIOS_H)
    663 struct termios original_termios, ttybuff;
    664 #else
    665 #  if defined (HAVE_TERMIO_H)
    666 /* A buffer containing the terminal mode flags upon entry to info. */
    667 struct termio original_termio, ttybuff;
    668 #  else /* !HAVE_TERMIO_H */
    669 /* Buffers containing the terminal mode flags upon entry to info. */
    670 int original_tty_flags = 0;
    671 int original_lmode;
    672 struct sgttyb ttybuff;
    673 
    674 #    if defined(TIOCGETC) && defined(M_XENIX)
    675 /* SCO 3.2v5.0.2 defines but does not support TIOCGETC.  Gak.  Maybe
    676    better fix would be to use Posix termios in preference.  --gildea,
    677    1jul99.  */
    678 #      undef TIOCGETC
    679 #    endif
    680 
    681 #    if defined (TIOCGETC)
    682 /* A buffer containing the terminal interrupt characters upon entry
    683    to Info. */
    684 struct tchars original_tchars;
    685 #    endif
    686 
    687 #    if defined (TIOCGLTC)
    688 /* A buffer containing the local terminal mode characters upon entry
    689    to Info. */
    690 struct ltchars original_ltchars;
    691 #    endif
    692 #  endif /* !HAVE_TERMIO_H */
    693 #endif /* !HAVE_TERMIOS_H */
    694 
    695 /* Prepare to start using the terminal to read characters singly. */
    696 void
    697 terminal_prep_terminal (void)
    698 {
    699   int tty;
    700 
    701   if (terminal_prep_terminal_hook)
    702     {
    703       (*terminal_prep_terminal_hook) ();
    704       return;
    705     }
    706 
    707   terminal_begin_using_terminal ();
    708 
    709   tty = fileno (stdin);
    710 
    711 #if defined (HAVE_TERMIOS_H)
    712   tcgetattr (tty, &original_termios);
    713   tcgetattr (tty, &ttybuff);
    714 #else
    715 #  if defined (HAVE_TERMIO_H)
    716   ioctl (tty, TCGETA, &original_termio);
    717   ioctl (tty, TCGETA, &ttybuff);
    718 #  endif
    719 #endif
    720 
    721 #if defined (HAVE_TERMIOS_H) || defined (HAVE_TERMIO_H)
    722   ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON);
    723 /* These output flags are not part of POSIX, so only use them if they
    724    are defined.  */
    725 #ifdef ONLCR
    726   ttybuff.c_oflag &= ~ONLCR ;
    727 #endif
    728 #ifdef OCRNL
    729   ttybuff.c_oflag &= ~OCRNL;
    730 #endif
    731   ttybuff.c_lflag &= (~ICANON & ~ECHO);
    732 
    733   ttybuff.c_cc[VMIN] = 1;
    734   ttybuff.c_cc[VTIME] = 0;
    735 
    736   if (ttybuff.c_cc[VINTR] == '\177')
    737     ttybuff.c_cc[VINTR] = -1;
    738 
    739   if (ttybuff.c_cc[VQUIT] == '\177')
    740     ttybuff.c_cc[VQUIT] = -1;
    741 
    742 #ifdef VLNEXT
    743   if (ttybuff.c_cc[VLNEXT] == '\026')
    744     ttybuff.c_cc[VLNEXT] = -1;
    745 #endif /* VLNEXT */
    746 #endif /* TERMIOS or TERMIO */
    747 
    748 /* cf. emacs/src/sysdep.c for being sure output is on. */
    749 #if defined (HAVE_TERMIOS_H)
    750   /* linux kernel 2.2.x needs a TCOFF followed by a TCOON to turn output
    751      back on if the user presses ^S at the very beginning; just a TCOON
    752      doesn't work.  --Kevin Ryde <user42 (at) zip.com.au>, 16jun2000.  */
    753   tcsetattr (tty, TCSANOW, &ttybuff);
    754 #  ifdef TCOON
    755   tcflow (tty, TCOOFF);
    756   tcflow (tty, TCOON);
    757 #  endif
    758 #else
    759 #  if defined (HAVE_TERMIO_H)
    760   ioctl (tty, TCSETA, &ttybuff);
    761 #    ifdef TCXONC
    762   ioctl (tty, TCXONC, 1);
    763 #    endif
    764 #  endif
    765 #endif
    766 
    767 #if !defined (HAVE_TERMIOS_H) && !defined (HAVE_TERMIO_H)
    768   ioctl (tty, TIOCGETP, &ttybuff);
    769 
    770   if (!original_tty_flags)
    771     original_tty_flags = ttybuff.sg_flags;
    772 
    773   /* Make this terminal pass 8 bits around while we are using it. */
    774 #  if defined (PASS8)
    775   ttybuff.sg_flags |= PASS8;
    776 #  endif /* PASS8 */
    777 
    778 #  if defined (TIOCLGET) && defined (LPASS8)
    779   {
    780     int flags;
    781     ioctl (tty, TIOCLGET, &flags);
    782     original_lmode = flags;
    783     flags |= LPASS8;
    784     ioctl (tty, TIOCLSET, &flags);
    785   }
    786 #  endif /* TIOCLGET && LPASS8 */
    787 
    788 #  if defined (TIOCGETC)
    789   {
    790     struct tchars temp;
    791 
    792     ioctl (tty, TIOCGETC, &original_tchars);
    793     temp = original_tchars;
    794 
    795     /* C-s and C-q. */
    796     temp.t_startc = temp.t_stopc = -1;
    797 
    798     /* Often set to C-d. */
    799     temp.t_eofc = -1;
    800 
    801     /* If the a quit or interrupt character conflicts with one of our
    802        commands, then make it go away. */
    803     if (temp.t_intrc == '\177')
    804       temp.t_intrc = -1;
    805 
    806     if (temp.t_quitc == '\177')
    807       temp.t_quitc = -1;
    808 
    809     ioctl (tty, TIOCSETC, &temp);
    810   }
    811 #  endif /* TIOCGETC */
    812 
    813 #  if defined (TIOCGLTC)
    814   {
    815     struct ltchars temp;
    816 
    817     ioctl (tty, TIOCGLTC, &original_ltchars);
    818     temp = original_ltchars;
    819 
    820     /* Make the interrupt keys go away.  Just enough to make people happy. */
    821     temp.t_lnextc = -1;         /* C-v. */
    822     temp.t_dsuspc = -1;         /* C-y. */
    823     temp.t_flushc = -1;         /* C-o. */
    824     ioctl (tty, TIOCSLTC, &temp);
    825   }
    826 #  endif /* TIOCGLTC */
    827 
    828   ttybuff.sg_flags &= ~ECHO;
    829   ttybuff.sg_flags |= CBREAK;
    830   ioctl (tty, TIOCSETN, &ttybuff);
    831 #endif /* !HAVE_TERMIOS_H && !HAVE_TERMIO_H */
    832 }
    833 
    834 /* Restore the tty settings back to what they were before we started using
    835    this terminal. */
    836 void
    837 terminal_unprep_terminal (void)
    838 {
    839   int tty;
    840 
    841   if (terminal_unprep_terminal_hook)
    842     {
    843       (*terminal_unprep_terminal_hook) ();
    844       return;
    845     }
    846 
    847   tty = fileno (stdin);
    848 
    849 #if defined (HAVE_TERMIOS_H)
    850   tcsetattr (tty, TCSANOW, &original_termios);
    851 #else
    852 #  if defined (HAVE_TERMIO_H)
    853   ioctl (tty, TCSETA, &original_termio);
    854 #  else /* !HAVE_TERMIO_H */
    855   ioctl (tty, TIOCGETP, &ttybuff);
    856   ttybuff.sg_flags = original_tty_flags;
    857   ioctl (tty, TIOCSETN, &ttybuff);
    858 
    859 #  if defined (TIOCGETC)
    860   ioctl (tty, TIOCSETC, &original_tchars);
    861 #  endif /* TIOCGETC */
    862 
    863 #  if defined (TIOCGLTC)
    864   ioctl (tty, TIOCSLTC, &original_ltchars);
    865 #  endif /* TIOCGLTC */
    866 
    867 #  if defined (TIOCLGET) && defined (LPASS8)
    868   ioctl (tty, TIOCLSET, &original_lmode);
    869 #  endif /* TIOCLGET && LPASS8 */
    870 
    871 #  endif /* !HAVE_TERMIO_H */
    872 #endif /* !HAVE_TERMIOS_H */
    873   terminal_end_using_terminal ();
    874 }
    875 
    876 #ifdef __MSDOS__
    877 # include "pcterm.c"
    878 #endif
    879