source: trunk/third/readline/rltty.c @ 12992

Revision 12992, 16.3 KB checked in by kcr, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12991, which included commits to RCS files with non-trunk default branches.
Line 
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 (GWINSZ_IN_SYS_IOCTL)
41#  include <sys/ioctl.h>
42#endif /* 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 (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#endif /* TIOCGWINSZ */
160
161#if defined (NEW_TTY_DRIVER)
162
163/* Values for the `flags' field of a struct bsdtty.  This tells which
164   elements of the struct bsdtty have been fetched from the system and
165   are valid. */
166#define SGTTY_SET       0x01
167#define LFLAG_SET       0x02
168#define TCHARS_SET      0x04
169#define LTCHARS_SET     0x08
170
171struct bsdtty {
172  struct sgttyb sgttyb; /* Basic BSD tty driver information. */
173  int lflag;            /* Local mode flags, like LPASS8. */
174#if defined (TIOCGETC)
175  struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */
176#endif
177#if defined (TIOCGLTC)
178  struct ltchars ltchars; /* 4.2 BSD editing characters */
179#endif
180  int flags;            /* Bitmap saying which parts of the struct are valid. */
181};
182
183#define TIOTYPE struct bsdtty
184
185static TIOTYPE otio;
186
187static int
188get_tty_settings (tty, tiop)
189     int tty;
190     TIOTYPE *tiop;
191{
192  set_winsize (tty);
193
194  tiop->flags = tiop->lflag = 0;
195
196  ioctl (tty, TIOCGETP, &(tiop->sgttyb));
197  tiop->flags |= SGTTY_SET;
198
199#if defined (TIOCLGET)
200  ioctl (tty, TIOCLGET, &(tiop->lflag));
201  tiop->flags |= LFLAG_SET;
202#endif
203
204#if defined (TIOCGETC)
205  ioctl (tty, TIOCGETC, &(tiop->tchars));
206  tiop->flags |= TCHARS_SET;
207#endif
208
209#if defined (TIOCGLTC)
210  ioctl (tty, TIOCGLTC, &(tiop->ltchars));
211  tiop->flags |= LTCHARS_SET;
212#endif
213
214  return 0;
215}
216
217static int
218set_tty_settings (tty, tiop)
219     int tty;
220     TIOTYPE *tiop;
221{
222  if (tiop->flags & SGTTY_SET)
223    {
224      ioctl (tty, TIOCSETN, &(tiop->sgttyb));
225      tiop->flags &= ~SGTTY_SET;
226    }
227  readline_echoing_p = 1;
228
229#if defined (TIOCLSET)
230  if (tiop->flags & LFLAG_SET)
231    {
232      ioctl (tty, TIOCLSET, &(tiop->lflag));
233      tiop->flags &= ~LFLAG_SET;
234    }
235#endif
236
237#if defined (TIOCSETC)
238  if (tiop->flags & TCHARS_SET)
239    {
240      ioctl (tty, TIOCSETC, &(tiop->tchars));
241      tiop->flags &= ~TCHARS_SET;
242    }
243#endif
244
245#if defined (TIOCSLTC)
246  if (tiop->flags & LTCHARS_SET)
247    {
248      ioctl (tty, TIOCSLTC, &(tiop->ltchars));
249      tiop->flags &= ~LTCHARS_SET;
250    }
251#endif
252
253  return 0;
254}
255
256static void
257prepare_terminal_settings (meta_flag, otio, tiop)
258     int meta_flag;
259     TIOTYPE otio, *tiop;
260{
261#if !defined (__GO32__)
262  readline_echoing_p = (otio.sgttyb.sg_flags & ECHO);
263
264  /* Copy the original settings to the structure we're going to use for
265     our settings. */
266  tiop->sgttyb = otio.sgttyb;
267  tiop->lflag = otio.lflag;
268#if defined (TIOCGETC)
269  tiop->tchars = otio.tchars;
270#endif
271#if defined (TIOCGLTC)
272  tiop->ltchars = otio.ltchars;
273#endif
274  tiop->flags = otio.flags;
275
276  /* First, the basic settings to put us into character-at-a-time, no-echo
277     input mode. */
278  tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
279  tiop->sgttyb.sg_flags |= CBREAK;
280
281  /* If this terminal doesn't care how the 8th bit is used, then we can
282     use it for the meta-key.  If only one of even or odd parity is
283     specified, then the terminal is using parity, and we cannot. */
284#if !defined (ANYP)
285#  define ANYP (EVENP | ODDP)
286#endif
287  if (((otio.sgttyb.sg_flags & ANYP) == ANYP) ||
288      ((otio.sgttyb.sg_flags & ANYP) == 0))
289    {
290      tiop->sgttyb.sg_flags |= ANYP;
291
292      /* Hack on local mode flags if we can. */
293#if defined (TIOCLGET)
294#  if defined (LPASS8)
295      tiop->lflag |= LPASS8;
296#  endif /* LPASS8 */
297#endif /* TIOCLGET */
298    }
299
300#if defined (TIOCGETC)
301#  if defined (USE_XON_XOFF)
302  /* Get rid of terminal output start and stop characters. */
303  tiop->tchars.t_stopc = -1; /* C-s */
304  tiop->tchars.t_startc = -1; /* C-q */
305
306  /* If there is an XON character, bind it to restart the output. */
307  if (otio.tchars.t_startc != -1)
308    rl_bind_key (otio.tchars.t_startc, rl_restart_output);
309#  endif /* USE_XON_XOFF */
310
311  /* If there is an EOF char, bind _rl_eof_char to it. */
312  if (otio.tchars.t_eofc != -1)
313    _rl_eof_char = otio.tchars.t_eofc;
314
315#  if defined (NO_KILL_INTR)
316  /* Get rid of terminal-generated SIGQUIT and SIGINT. */
317  tiop->tchars.t_quitc = -1; /* C-\ */
318  tiop->tchars.t_intrc = -1; /* C-c */
319#  endif /* NO_KILL_INTR */
320#endif /* TIOCGETC */
321
322#if defined (TIOCGLTC)
323  /* Make the interrupt keys go away.  Just enough to make people happy. */
324  tiop->ltchars.t_dsuspc = -1;  /* C-y */
325  tiop->ltchars.t_lnextc = -1;  /* C-v */
326#endif /* TIOCGLTC */
327#endif /* !__GO32__ */
328}
329
330#else  /* !defined (NEW_TTY_DRIVER) */
331
332#if !defined (VMIN)
333#  define VMIN VEOF
334#endif
335
336#if !defined (VTIME)
337#  define VTIME VEOL
338#endif
339
340#if defined (TERMIOS_TTY_DRIVER)
341#  define TIOTYPE struct termios
342#  define DRAIN_OUTPUT(fd)      tcdrain (fd)
343#  define GETATTR(tty, tiop)    (tcgetattr (tty, tiop))
344#  ifdef M_UNIX
345#    define SETATTR(tty, tiop)  (tcsetattr (tty, TCSANOW, tiop))
346#  else
347#    define SETATTR(tty, tiop)  (tcsetattr (tty, TCSADRAIN, tiop))
348#  endif /* !M_UNIX */
349#else
350#  define TIOTYPE struct termio
351#  define DRAIN_OUTPUT(fd)
352#  define GETATTR(tty, tiop)    (ioctl (tty, TCGETA, tiop))
353#  define SETATTR(tty, tiop)    (ioctl (tty, TCSETA, tiop))
354#endif /* !TERMIOS_TTY_DRIVER */
355
356static TIOTYPE otio;
357
358#if defined (FLUSHO)
359#  define OUTPUT_BEING_FLUSHED(tp)  (tp->c_lflag & FLUSHO)
360#else
361#  define OUTPUT_BEING_FLUSHED(tp)  0
362#endif
363
364static void
365rltty_warning (msg)
366     char *msg;
367{
368  fprintf (stderr, "readline: warning: %s\n", msg);
369}
370
371#if defined (_AIX)
372void
373setopost(tp)
374TIOTYPE *tp;
375{
376  if ((tp->c_oflag & OPOST) == 0)
377    {
378      rltty_warning ("turning on OPOST for terminal\r");
379      tp->c_oflag |= OPOST|ONLCR;
380    }
381}
382#endif
383
384static int
385get_tty_settings (tty, tiop)
386     int tty;
387     TIOTYPE *tiop;
388{
389  int ioctl_ret;
390
391  set_winsize (tty);
392
393  while (1)
394    {
395      ioctl_ret = GETATTR (tty, tiop);
396      if (ioctl_ret < 0)
397        {
398          if (errno != EINTR)
399            return -1;
400          else
401            continue;
402        }
403      if (OUTPUT_BEING_FLUSHED (tiop))
404        {
405#if defined (FLUSHO) && defined (_AIX41)
406          rltty_warning ("turning off output flushing");
407          tiop->c_lflag &= ~FLUSHO;
408          break;
409#else
410          continue;
411#endif
412        }
413      break;
414    }
415
416#if defined (_AIX)
417  setopost(tiop);
418#endif
419
420  return 0;
421}
422
423static int
424set_tty_settings (tty, tiop)
425     int tty;
426     TIOTYPE *tiop;
427{
428  while (SETATTR (tty, tiop) < 0)
429    {
430      if (errno != EINTR)
431        return -1;
432      errno = 0;
433    }
434
435#if 0
436
437#if defined (TERMIOS_TTY_DRIVER)
438#  if defined (__ksr1__)
439  if (ksrflow)
440    {
441      ksrflow = 0;
442      tcflow (tty, TCOON);
443    }
444#  else /* !ksr1 */
445  tcflow (tty, TCOON);          /* Simulate a ^Q. */
446#  endif /* !ksr1 */
447#else
448  ioctl (tty, TCXONC, 1);       /* Simulate a ^Q. */
449#endif /* !TERMIOS_TTY_DRIVER */
450
451#endif
452
453  return 0;
454}
455
456static void
457prepare_terminal_settings (meta_flag, otio, tiop)
458     int meta_flag;
459     TIOTYPE otio, *tiop;
460{
461  readline_echoing_p = (otio.c_lflag & ECHO);
462
463  tiop->c_lflag &= ~(ICANON | ECHO);
464
465  if ((unsigned char) otio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
466    _rl_eof_char = otio.c_cc[VEOF];
467
468#if defined (USE_XON_XOFF)
469#if defined (IXANY)
470  tiop->c_iflag &= ~(IXON | IXOFF | IXANY);
471#else
472  /* `strict' Posix systems do not define IXANY. */
473  tiop->c_iflag &= ~(IXON | IXOFF);
474#endif /* IXANY */
475#endif /* USE_XON_XOFF */
476
477  /* Only turn this off if we are using all 8 bits. */
478  if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
479    tiop->c_iflag &= ~(ISTRIP | INPCK);
480
481  /* Make sure we differentiate between CR and NL on input. */
482  tiop->c_iflag &= ~(ICRNL | INLCR);
483
484#if !defined (HANDLE_SIGNALS)
485  tiop->c_lflag &= ~ISIG;
486#else
487  tiop->c_lflag |= ISIG;
488#endif
489
490  tiop->c_cc[VMIN] = 1;
491  tiop->c_cc[VTIME] = 0;
492
493#if defined (FLUSHO)
494  if (OUTPUT_BEING_FLUSHED (tiop))
495    {
496      tiop->c_lflag &= ~FLUSHO;
497      otio.c_lflag &= ~FLUSHO;
498    }
499#endif
500
501  /* Turn off characters that we need on Posix systems with job control,
502     just to be sure.  This includes ^Y and ^V.  This should not really
503     be necessary.  */
504#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
505
506#if defined (VLNEXT)
507  tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
508#endif
509
510#if defined (VDSUSP)
511  tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
512#endif
513
514#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
515}
516#endif  /* NEW_TTY_DRIVER */
517
518/* Put the terminal in CBREAK mode so that we can detect key presses. */
519void
520rl_prep_terminal (meta_flag)
521     int meta_flag;
522{
523#if !defined (__GO32__)
524  int tty;
525  TIOTYPE tio;
526
527  if (terminal_prepped)
528    return;
529
530  /* Try to keep this function from being INTerrupted. */
531  block_sigint ();
532
533  tty = fileno (rl_instream);
534
535  if (get_tty_settings (tty, &tio) < 0)
536    {
537      release_sigint ();
538      return;
539    }
540
541  otio = tio;
542
543  prepare_terminal_settings (meta_flag, otio, &tio);
544
545  if (set_tty_settings (tty, &tio) < 0)
546    {
547      release_sigint ();
548      return;
549    }
550
551  if (_rl_enable_keypad)
552    _rl_control_keypad (1);
553
554  fflush (rl_outstream);
555  terminal_prepped = 1;
556
557  release_sigint ();
558#endif /* !__GO32__ */
559}
560
561/* Restore the terminal's normal settings and modes. */
562void
563rl_deprep_terminal ()
564{
565#if !defined (__GO32__)
566  int tty;
567
568  if (!terminal_prepped)
569    return;
570
571  /* Try to keep this function from being interrupted. */
572  block_sigint ();
573
574  tty = fileno (rl_instream);
575
576  if (_rl_enable_keypad)
577    _rl_control_keypad (0);
578
579  fflush (rl_outstream);
580
581  if (set_tty_settings (tty, &otio) < 0)
582    {
583      release_sigint ();
584      return;
585    }
586
587  terminal_prepped = 0;
588
589  release_sigint ();
590#endif /* !__GO32__ */
591}
592
593/* **************************************************************** */
594/*                                                                  */
595/*                      Bogus Flow Control                          */
596/*                                                                  */
597/* **************************************************************** */
598
599int
600rl_restart_output (count, key)
601     int count, key;
602{
603  int fildes = fileno (rl_outstream);
604#if defined (TIOCSTART)
605#if defined (apollo)
606  ioctl (&fildes, TIOCSTART, 0);
607#else
608  ioctl (fildes, TIOCSTART, 0);
609#endif /* apollo */
610
611#else /* !TIOCSTART */
612#  if defined (TERMIOS_TTY_DRIVER)
613#    if defined (__ksr1__)
614  if (ksrflow)
615    {
616      ksrflow = 0;
617      tcflow (fildes, TCOON);
618    }
619#    else /* !ksr1 */
620  tcflow (fildes, TCOON);               /* Simulate a ^Q. */
621#    endif /* !ksr1 */
622#  else /* !TERMIOS_TTY_DRIVER */
623#    if defined (TCXONC)
624  ioctl (fildes, TCXONC, TCOON);
625#    endif /* TCXONC */
626#  endif /* !TERMIOS_TTY_DRIVER */
627#endif /* !TIOCSTART */
628
629  return 0;
630}
631
632int
633rl_stop_output (count, key)
634     int count, key;
635{
636  int fildes = fileno (rl_instream);
637
638#if defined (TIOCSTOP)
639# if defined (apollo)
640  ioctl (&fildes, TIOCSTOP, 0);
641# else
642  ioctl (fildes, TIOCSTOP, 0);
643# endif /* apollo */
644#else /* !TIOCSTOP */
645# if defined (TERMIOS_TTY_DRIVER)
646#  if defined (__ksr1__)
647  ksrflow = 1;
648#  endif /* ksr1 */
649  tcflow (fildes, TCOOFF);
650# else
651#   if defined (TCXONC)
652  ioctl (fildes, TCXONC, TCOON);
653#   endif /* TCXONC */
654# endif /* !TERMIOS_TTY_DRIVER */
655#endif /* !TIOCSTOP */
656
657  return 0;
658}
659
660/* **************************************************************** */
661/*                                                                  */
662/*                      Default Key Bindings                        */
663/*                                                                  */
664/* **************************************************************** */
665void
666rltty_set_default_bindings (kmap)
667     Keymap kmap;
668{
669  TIOTYPE ttybuff;
670  int tty = fileno (rl_instream);
671
672#if defined (NEW_TTY_DRIVER)
673
674#define SET_SPECIAL(sc, func) \
675  do \
676    { \
677      int ic; \
678      ic = sc; \
679      if (ic != -1 && kmap[ic].type == ISFUNC) \
680        kmap[ic].function = func; \
681    } \
682  while (0)
683
684  if (get_tty_settings (tty, &ttybuff) == 0)
685    {
686      if (ttybuff.flags & SGTTY_SET)
687        {
688          SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout);
689          SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard);
690        }
691
692#  if defined (TIOCGLTC)
693      if (ttybuff.flags & LTCHARS_SET)
694        {
695          SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout);
696          SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert);
697        }
698#  endif /* TIOCGLTC */
699    }
700
701#else /* !NEW_TTY_DRIVER */
702
703#define SET_SPECIAL(sc, func) \
704  do \
705    { \
706      unsigned char uc; \
707      uc = ttybuff.c_cc[sc]; \
708      if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \
709        kmap[uc].function = func; \
710    } \
711  while (0)
712
713  if (get_tty_settings (tty, &ttybuff) == 0)
714    {
715      SET_SPECIAL (VERASE, rl_rubout);
716      SET_SPECIAL (VKILL, rl_unix_line_discard);
717
718#  if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
719      SET_SPECIAL (VLNEXT, rl_quoted_insert);
720#  endif /* VLNEXT && TERMIOS_TTY_DRIVER */
721
722#  if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
723      SET_SPECIAL (VWERASE, rl_unix_word_rubout);
724#  endif /* VWERASE && TERMIOS_TTY_DRIVER */
725    }
726#endif /* !NEW_TTY_DRIVER */
727}
Note: See TracBrowser for help on using the repository browser.