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