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