rltty.c revision 26497
1/* rltty.c -- functions to prepare and restore the terminal for readline's
2   use. */
3
4/* Copyright (C) 1992 Free Software Foundation, Inc.
5
6   This file is part of the GNU Readline Library, a library for
7   reading lines of text with interactive input and history editing.
8
9   The GNU Readline Library is free software; you can redistribute it
10   and/or modify it under the terms of the GNU General Public License
11   as published by the Free Software Foundation; either version 1, or
12   (at your option) any later version.
13
14   The GNU Readline Library is distributed in the hope that it will be
15   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   The GNU General Public License is often shipped with GNU software, and
20   is generally kept in a file called COPYING or LICENSE.  If you do not
21   have a copy of the license, write to the Free Software Foundation,
22   675 Mass Ave, Cambridge, MA 02139, USA. */
23#define READLINE_LIBRARY
24
25#if defined (HAVE_CONFIG_H)
26#  include <config.h>
27#endif
28
29#include <sys/types.h>
30#include <signal.h>
31#include <errno.h>
32#include <stdio.h>
33
34#if defined (HAVE_UNISTD_H)
35#  include <unistd.h>
36#endif /* HAVE_UNISTD_H */
37
38#include "rldefs.h"
39
40#if !defined (SHELL) && defined (GWINSZ_IN_SYS_IOCTL)
41#  include <sys/ioctl.h>
42#endif /* !SHELL && GWINSZ_IN_SYS_IOCTL */
43
44#include "rltty.h"
45#include "readline.h"
46
47#if !defined (errno)
48extern int errno;
49#endif /* !errno */
50
51extern int readline_echoing_p;
52extern int _rl_eof_char;
53
54extern int _rl_enable_keypad, _rl_enable_meta;
55
56extern void _rl_control_keypad ();
57
58#if defined (__GO32__)
59#  include <pc.h>
60#  undef HANDLE_SIGNALS
61#endif /* __GO32__ */
62
63/* Indirect functions to allow apps control over terminal management. */
64extern void rl_prep_terminal (), rl_deprep_terminal ();
65
66VFunction *rl_prep_term_function = rl_prep_terminal;
67VFunction *rl_deprep_term_function = rl_deprep_terminal;
68
69/* **************************************************************** */
70/*								    */
71/*			   Signal Management			    */
72/*								    */
73/* **************************************************************** */
74
75#if defined (HAVE_POSIX_SIGNALS)
76static sigset_t sigint_set, sigint_oset;
77#else /* !HAVE_POSIX_SIGNALS */
78#  if defined (HAVE_BSD_SIGNALS)
79static int sigint_oldmask;
80#  endif /* HAVE_BSD_SIGNALS */
81#endif /* !HAVE_POSIX_SIGNALS */
82
83static int sigint_blocked;
84
85/* Cause SIGINT to not be delivered until the corresponding call to
86   release_sigint(). */
87static void
88block_sigint ()
89{
90  if (sigint_blocked)
91    return;
92
93#if defined (HAVE_POSIX_SIGNALS)
94  sigemptyset (&sigint_set);
95  sigemptyset (&sigint_oset);
96  sigaddset (&sigint_set, SIGINT);
97  sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset);
98#else /* !HAVE_POSIX_SIGNALS */
99#  if defined (HAVE_BSD_SIGNALS)
100  sigint_oldmask = sigblock (sigmask (SIGINT));
101#  else /* !HAVE_BSD_SIGNALS */
102#    if defined (HAVE_USG_SIGHOLD)
103  sighold (SIGINT);
104#    endif /* HAVE_USG_SIGHOLD */
105#  endif /* !HAVE_BSD_SIGNALS */
106#endif /* !HAVE_POSIX_SIGNALS */
107  sigint_blocked = 1;
108}
109
110/* Allow SIGINT to be delivered. */
111static void
112release_sigint ()
113{
114  if (!sigint_blocked)
115    return;
116
117#if defined (HAVE_POSIX_SIGNALS)
118  sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL);
119#else
120#  if defined (HAVE_BSD_SIGNALS)
121  sigsetmask (sigint_oldmask);
122#  else /* !HAVE_BSD_SIGNALS */
123#    if defined (HAVE_USG_SIGHOLD)
124  sigrelse (SIGINT);
125#    endif /* HAVE_USG_SIGHOLD */
126#  endif /* !HAVE_BSD_SIGNALS */
127#endif /* !HAVE_POSIX_SIGNALS */
128
129  sigint_blocked = 0;
130}
131
132/* **************************************************************** */
133/*								    */
134/*		      Saving and Restoring the TTY	    	    */
135/*								    */
136/* **************************************************************** */
137
138/* Non-zero means that the terminal is in a prepped state. */
139static int terminal_prepped;
140
141/* If non-zero, means that this process has called tcflow(fd, TCOOFF)
142   and output is suspended. */
143#if defined (__ksr1__)
144static int ksrflow;
145#endif
146
147#if !defined (SHELL) && defined (TIOCGWINSZ)
148/* Dummy call to force a backgrounded readline to stop before it tries
149   to get the tty settings. */
150static void
151set_winsize (tty)
152     int tty;
153{
154  struct winsize w;
155
156  if (ioctl (tty, TIOCGWINSZ, &w) == 0)
157      (void) ioctl (tty, TIOCSWINSZ, &w);
158}
159#else /* SHELL || !TIOCGWINSZ */
160#  define set_winsize(tty)
161#endif /* SHELL || !TIOCGWINSZ */
162
163#if defined (NEW_TTY_DRIVER)
164
165/* Values for the `flags' field of a struct bsdtty.  This tells which
166   elements of the struct bsdtty have been fetched from the system and
167   are valid. */
168#define SGTTY_SET	0x01
169#define LFLAG_SET	0x02
170#define TCHARS_SET	0x04
171#define LTCHARS_SET	0x08
172
173struct bsdtty {
174  struct sgttyb sgttyb;	/* Basic BSD tty driver information. */
175  int lflag;		/* Local mode flags, like LPASS8. */
176#if defined (TIOCGETC)
177  struct tchars tchars;	/* Terminal special characters, including ^S and ^Q. */
178#endif
179#if defined (TIOCGLTC)
180  struct ltchars ltchars; /* 4.2 BSD editing characters */
181#endif
182  int flags;		/* Bitmap saying which parts of the struct are valid. */
183};
184
185#define TIOTYPE struct bsdtty
186
187static TIOTYPE otio;
188
189static int
190get_tty_settings (tty, tiop)
191     int tty;
192     TIOTYPE *tiop;
193{
194  set_winsize (tty);
195
196  tiop->flags = tiop->lflag = 0;
197
198  ioctl (tty, TIOCGETP, &(tiop->sgttyb));
199  tiop->flags |= SGTTY_SET;
200
201#if defined (TIOCLGET)
202  ioctl (tty, TIOCLGET, &(tiop->lflag));
203  tiop->flags |= LFLAG_SET;
204#endif
205
206#if defined (TIOCGETC)
207  ioctl (tty, TIOCGETC, &(tiop->tchars));
208  tiop->flags |= TCHARS_SET;
209#endif
210
211#if defined (TIOCGLTC)
212  ioctl (tty, TIOCGLTC, &(tiop->ltchars));
213  tiop->flags |= LTCHARS_SET;
214#endif
215
216  return 0;
217}
218
219static int
220set_tty_settings (tty, tiop)
221     int tty;
222     TIOTYPE *tiop;
223{
224  if (tiop->flags & SGTTY_SET)
225    {
226      ioctl (tty, TIOCSETN, &(tiop->sgttyb));
227      tiop->flags &= ~SGTTY_SET;
228    }
229  readline_echoing_p = 1;
230
231#if defined (TIOCLSET)
232  if (tiop->flags & LFLAG_SET)
233    {
234      ioctl (tty, TIOCLSET, &(tiop->lflag));
235      tiop->flags &= ~LFLAG_SET;
236    }
237#endif
238
239#if defined (TIOCSETC)
240  if (tiop->flags & TCHARS_SET)
241    {
242      ioctl (tty, TIOCSETC, &(tiop->tchars));
243      tiop->flags &= ~TCHARS_SET;
244    }
245#endif
246
247#if defined (TIOCSLTC)
248  if (tiop->flags & LTCHARS_SET)
249    {
250      ioctl (tty, TIOCSLTC, &(tiop->ltchars));
251      tiop->flags &= ~LTCHARS_SET;
252    }
253#endif
254
255  return 0;
256}
257
258static void
259prepare_terminal_settings (meta_flag, otio, tiop)
260     int meta_flag;
261     TIOTYPE otio, *tiop;
262{
263#if !defined (__GO32__)
264  readline_echoing_p = (otio.sgttyb.sg_flags & ECHO);
265
266  /* Copy the original settings to the structure we're going to use for
267     our settings. */
268  tiop->sgttyb = otio.sgttyb;
269  tiop->lflag = otio.lflag;
270#if defined (TIOCGETC)
271  tiop->tchars = otio.tchars;
272#endif
273#if defined (TIOCGLTC)
274  tiop->ltchars = otio.ltchars;
275#endif
276  tiop->flags = otio.flags;
277
278  /* First, the basic settings to put us into character-at-a-time, no-echo
279     input mode. */
280  tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
281  tiop->sgttyb.sg_flags |= CBREAK;
282
283  /* If this terminal doesn't care how the 8th bit is used, then we can
284     use it for the meta-key.  If only one of even or odd parity is
285     specified, then the terminal is using parity, and we cannot. */
286#if !defined (ANYP)
287#  define ANYP (EVENP | ODDP)
288#endif
289  if (((otio.sgttyb.sg_flags & ANYP) == ANYP) ||
290      ((otio.sgttyb.sg_flags & ANYP) == 0))
291    {
292      tiop->sgttyb.sg_flags |= ANYP;
293
294      /* Hack on local mode flags if we can. */
295#if defined (TIOCLGET)
296#  if defined (LPASS8)
297      tiop->lflag |= LPASS8;
298#  endif /* LPASS8 */
299#endif /* TIOCLGET */
300    }
301
302#if defined (TIOCGETC)
303#  if defined (USE_XON_XOFF)
304  /* Get rid of terminal output start and stop characters. */
305  tiop->tchars.t_stopc = -1; /* C-s */
306  tiop->tchars.t_startc = -1; /* C-q */
307
308  /* If there is an XON character, bind it to restart the output. */
309  if (otio.tchars.t_startc != -1)
310    rl_bind_key (otio.tchars.t_startc, rl_restart_output);
311#  endif /* USE_XON_XOFF */
312
313  /* If there is an EOF char, bind _rl_eof_char to it. */
314  if (otio.tchars.t_eofc != -1)
315    _rl_eof_char = otio.tchars.t_eofc;
316
317#  if defined (NO_KILL_INTR)
318  /* Get rid of terminal-generated SIGQUIT and SIGINT. */
319  tiop->tchars.t_quitc = -1; /* C-\ */
320  tiop->tchars.t_intrc = -1; /* C-c */
321#  endif /* NO_KILL_INTR */
322#endif /* TIOCGETC */
323
324#if defined (TIOCGLTC)
325  /* Make the interrupt keys go away.  Just enough to make people happy. */
326  tiop->ltchars.t_dsuspc = -1;	/* C-y */
327  tiop->ltchars.t_lnextc = -1;	/* C-v */
328#endif /* TIOCGLTC */
329#endif /* !__GO32__ */
330}
331
332#else  /* !defined (NEW_TTY_DRIVER) */
333
334#if !defined (VMIN)
335#  define VMIN VEOF
336#endif
337
338#if !defined (VTIME)
339#  define VTIME VEOL
340#endif
341
342#if defined (TERMIOS_TTY_DRIVER)
343#  define TIOTYPE struct termios
344#  define DRAIN_OUTPUT(fd)	tcdrain (fd)
345#  define GETATTR(tty, tiop)	(tcgetattr (tty, tiop))
346#  ifdef M_UNIX
347#    define SETATTR(tty, tiop)	(tcsetattr (tty, TCSANOW, tiop))
348#  else
349#    define SETATTR(tty, tiop)	(tcsetattr (tty, TCSADRAIN, tiop))
350#  endif /* !M_UNIX */
351#else
352#  define TIOTYPE struct termio
353#  define DRAIN_OUTPUT(fd)
354#  define GETATTR(tty, tiop)	(ioctl (tty, TCGETA, tiop))
355#  define SETATTR(tty, tiop)	(ioctl (tty, TCSETA, tiop))
356#endif /* !TERMIOS_TTY_DRIVER */
357
358static TIOTYPE otio;
359
360#if defined (FLUSHO)
361#  define OUTPUT_BEING_FLUSHED(tp)  (tp->c_lflag & FLUSHO)
362#else
363#  define OUTPUT_BEING_FLUSHED(tp)  0
364#endif
365
366static void
367rltty_warning (msg)
368     char *msg;
369{
370  fprintf (stderr, "readline: warning: %s\n", msg);
371}
372
373#if defined (_AIX)
374void
375setopost(tp)
376TIOTYPE *tp;
377{
378  if ((tp->c_oflag & OPOST) == 0)
379    {
380      rltty_warning ("turning on OPOST for terminal\r");
381      tp->c_oflag |= OPOST|ONLCR;
382    }
383}
384#endif
385
386static int
387get_tty_settings (tty, tiop)
388     int tty;
389     TIOTYPE *tiop;
390{
391  int ioctl_ret;
392  set_winsize (tty);
393
394  while (1)
395    {
396      ioctl_ret = GETATTR (tty, tiop);
397      if (ioctl_ret < 0)
398	{
399	  if (errno != EINTR)
400	    return -1;
401	  else
402	    continue;
403	}
404      if (OUTPUT_BEING_FLUSHED (tiop))
405	{
406#if defined (FLUSHO) && defined (_AIX41)
407	  rltty_warning ("turning off output flushing");
408	  tiop->c_lflag &= ~FLUSHO;
409	  break;
410#else
411	  continue;
412#endif
413	}
414      break;
415    }
416
417#if defined (_AIX)
418  setopost(tiop);
419#endif
420
421  return 0;
422}
423
424static int
425set_tty_settings (tty, tiop)
426     int tty;
427     TIOTYPE *tiop;
428{
429  while (SETATTR (tty, tiop) < 0)
430    {
431      if (errno != EINTR)
432	return -1;
433      errno = 0;
434    }
435
436#if 0
437
438#if defined (TERMIOS_TTY_DRIVER)
439#  if defined (__ksr1__)
440  if (ksrflow)
441    {
442      ksrflow = 0;
443      tcflow (tty, TCOON);
444    }
445#  else /* !ksr1 */
446  tcflow (tty, TCOON);		/* Simulate a ^Q. */
447#  endif /* !ksr1 */
448#else
449  ioctl (tty, TCXONC, 1);	/* Simulate a ^Q. */
450#endif /* !TERMIOS_TTY_DRIVER */
451
452#endif
453
454  return 0;
455}
456
457static void
458prepare_terminal_settings (meta_flag, otio, tiop)
459     int meta_flag;
460     TIOTYPE otio, *tiop;
461{
462  readline_echoing_p = (otio.c_lflag & ECHO);
463
464  tiop->c_lflag &= ~(ICANON | ECHO);
465
466  if ((unsigned char) otio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
467    _rl_eof_char = otio.c_cc[VEOF];
468
469#if defined (USE_XON_XOFF)
470#if defined (IXANY)
471  tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
472#else
473  /* `strict' Posix systems do not define IXANY. */
474  tiop->c_iflag &= ~(IXON | IXOFF);
475#endif /* IXANY */
476#endif /* USE_XON_XOFF */
477
478  /* Only turn this off if we are using all 8 bits. */
479  if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
480    tiop->c_iflag &= ~(ISTRIP | INPCK);
481
482  /* Make sure we differentiate between CR and NL on input. */
483  tiop->c_iflag &= ~(ICRNL | INLCR);
484
485#if !defined (HANDLE_SIGNALS)
486  tiop->c_lflag &= ~ISIG;
487#else
488  tiop->c_lflag |= ISIG;
489#endif
490
491  tiop->c_cc[VMIN] = 1;
492  tiop->c_cc[VTIME] = 0;
493
494#if defined (FLUSHO)
495  if (OUTPUT_BEING_FLUSHED (tiop))
496    {
497      tiop->c_lflag &= ~FLUSHO;
498      otio.c_lflag &= ~FLUSHO;
499    }
500#endif
501
502  /* Turn off characters that we need on Posix systems with job control,
503     just to be sure.  This includes ^Y and ^V.  This should not really
504     be necessary.  */
505#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
506
507#if defined (VLNEXT)
508  tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
509#endif
510
511#if defined (VDSUSP)
512  tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
513#endif
514
515#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
516}
517#endif  /* NEW_TTY_DRIVER */
518
519/* Put the terminal in CBREAK mode so that we can detect key presses. */
520void
521rl_prep_terminal (meta_flag)
522     int meta_flag;
523{
524#if !defined (__GO32__)
525  int tty;
526  TIOTYPE tio;
527
528  if (terminal_prepped)
529    return;
530
531  /* Try to keep this function from being INTerrupted. */
532  block_sigint ();
533
534  tty = fileno (rl_instream);
535
536  if (get_tty_settings (tty, &tio) < 0)
537    {
538      release_sigint ();
539      return;
540    }
541
542  otio = tio;
543
544  prepare_terminal_settings (meta_flag, otio, &tio);
545
546  if (set_tty_settings (tty, &tio) < 0)
547    {
548      release_sigint ();
549      return;
550    }
551
552  if (_rl_enable_keypad)
553    _rl_control_keypad (1);
554
555  fflush (rl_outstream);
556  terminal_prepped = 1;
557
558  release_sigint ();
559#endif /* !__GO32__ */
560}
561
562/* Restore the terminal's normal settings and modes. */
563void
564rl_deprep_terminal ()
565{
566#if !defined (__GO32__)
567  int tty;
568
569  if (!terminal_prepped)
570    return;
571
572  /* Try to keep this function from being interrupted. */
573  block_sigint ();
574
575  tty = fileno (rl_instream);
576
577  if (_rl_enable_keypad)
578    _rl_control_keypad (0);
579
580  fflush (rl_outstream);
581
582  if (set_tty_settings (tty, &otio) < 0)
583    {
584      release_sigint ();
585      return;
586    }
587
588  terminal_prepped = 0;
589
590  release_sigint ();
591#endif /* !__GO32__ */
592}
593
594/* **************************************************************** */
595/*								    */
596/*			Bogus Flow Control      		    */
597/*								    */
598/* **************************************************************** */
599
600int
601rl_restart_output (count, key)
602     int count, key;
603{
604  int fildes = fileno (rl_outstream);
605#if defined (TIOCSTART)
606#if defined (apollo)
607  ioctl (&fildes, TIOCSTART, 0);
608#else
609  ioctl (fildes, TIOCSTART, 0);
610#endif /* apollo */
611
612#else /* !TIOCSTART */
613#  if defined (TERMIOS_TTY_DRIVER)
614#    if defined (__ksr1__)
615  if (ksrflow)
616    {
617      ksrflow = 0;
618      tcflow (fildes, TCOON);
619    }
620#    else /* !ksr1 */
621  tcflow (fildes, TCOON);		/* Simulate a ^Q. */
622#    endif /* !ksr1 */
623#  else /* !TERMIOS_TTY_DRIVER */
624#    if defined (TCXONC)
625  ioctl (fildes, TCXONC, TCOON);
626#    endif /* TCXONC */
627#  endif /* !TERMIOS_TTY_DRIVER */
628#endif /* !TIOCSTART */
629
630  return 0;
631}
632
633int
634rl_stop_output (count, key)
635     int count, key;
636{
637  int fildes = fileno (rl_instream);
638
639#if defined (TIOCSTOP)
640# if defined (apollo)
641  ioctl (&fildes, TIOCSTOP, 0);
642# else
643  ioctl (fildes, TIOCSTOP, 0);
644# endif /* apollo */
645#else /* !TIOCSTOP */
646# if defined (TERMIOS_TTY_DRIVER)
647#  if defined (__ksr1__)
648  ksrflow = 1;
649#  endif /* ksr1 */
650  tcflow (fildes, TCOOFF);
651# else
652#   if defined (TCXONC)
653  ioctl (fildes, TCXONC, TCOON);
654#   endif /* TCXONC */
655# endif /* !TERMIOS_TTY_DRIVER */
656#endif /* !TIOCSTOP */
657
658  return 0;
659}
660
661/* **************************************************************** */
662/*								    */
663/*			Default Key Bindings			    */
664/*								    */
665/* **************************************************************** */
666void
667rltty_set_default_bindings (kmap)
668     Keymap kmap;
669{
670  TIOTYPE ttybuff;
671  int tty = fileno (rl_instream);
672
673#if defined (NEW_TTY_DRIVER)
674
675#define SET_SPECIAL(sc, func) \
676  do \
677    { \
678      int ic; \
679      ic = sc; \
680      if (ic != -1 && kmap[ic].type == ISFUNC) \
681	kmap[ic].function = func; \
682    } \
683  while (0)
684
685  if (get_tty_settings (tty, &ttybuff) == 0)
686    {
687      if (ttybuff.flags & SGTTY_SET)
688	{
689	  SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout);
690	  SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard);
691	}
692
693#  if defined (TIOCGLTC)
694      if (ttybuff.flags & LTCHARS_SET)
695	{
696	  SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout);
697	  SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert);
698	}
699#  endif /* TIOCGLTC */
700    }
701
702#else /* !NEW_TTY_DRIVER */
703
704#define SET_SPECIAL(sc, func) \
705  do \
706    { \
707      unsigned char uc; \
708      uc = ttybuff.c_cc[sc]; \
709      if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \
710	kmap[uc].function = func; \
711    } \
712  while (0)
713
714  if (get_tty_settings (tty, &ttybuff) == 0)
715    {
716      SET_SPECIAL (VERASE, rl_rubout);
717      SET_SPECIAL (VKILL, rl_unix_line_discard);
718
719#  if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
720      SET_SPECIAL (VLNEXT, rl_quoted_insert);
721#  endif /* VLNEXT && TERMIOS_TTY_DRIVER */
722
723#  if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
724      SET_SPECIAL (VWERASE, rl_unix_word_rubout);
725#  endif /* VWERASE && TERMIOS_TTY_DRIVER */
726    }
727#endif /* !NEW_TTY_DRIVER */
728}
729