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