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