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