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