commit bash-20140612 snapshot

This commit is contained in:
Chet Ramey
2014-06-23 14:58:55 -04:00
parent bbea163ce4
commit 92717e1a6e
13 changed files with 14610 additions and 3 deletions
+29
View File
@@ -6310,3 +6310,32 @@ shell.c
config-top.h
- EXIT_ON_SETUID_FAILURE: new settable define, will cause the shell to
exit if setuid fails with errno == EAGAIN
6/10
----
parse.y
- time_command_acceptable: fix so time is accepted everywhere the
grammar is looking for a `compound_list'. Fixes bug reported by
Dale Worley <worley@alum.mit.edu>
6/12
----
subst.c
- clear_fifo_list: new function, clears FDs associated with open pipes
in current FIFO list without closing the file descriptors. Can
possibly be used when shell_execve fails and the shell jumps back
to top_level and we don't want the shell to close the open FIFOs
each time through the read-execute loop. Bug reported by Harald
Koenig <koenig@tat.physik.uni-tuebingen.de>
6/16
----
builtins/shopt.def
- compat42: make sure the `compat42' option sets the correct variable
for compatibility level. Fixes bug reported by Ondrej Oprala
<ooprala@redhat.com>
support/bashbug.sh
- fix typo when echoing $USAGE. Report from Shantanu Kulkarni
<djbware@shantanukulkarni.org>
+6337
View File
File diff suppressed because it is too large Load Diff
+4263
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -160,7 +160,7 @@ static struct {
{ "compat32", &shopt_compat32, set_compatibility_level },
{ "compat40", &shopt_compat40, set_compatibility_level },
{ "compat41", &shopt_compat41, set_compatibility_level },
{ "compat42", &shopt_compat41, set_compatibility_level },
{ "compat42", &shopt_compat42, set_compatibility_level },
#if defined (READLINE)
{ "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL},
{ "direxpand", &dircomplete_expand, shopt_set_complete_direxpand },
+777
View File
@@ -0,0 +1,777 @@
This file is shopt.def, from which is created shopt.c.
It implements the Bash `shopt' builtin.
Copyright (C) 1994-2012 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES shopt.c
$BUILTIN shopt
$FUNCTION shopt_builtin
$SHORT_DOC shopt [-pqsu] [-o] [optname ...]
Set and unset shell options.
Change the setting of each shell option OPTNAME. Without any option
arguments, list all shell options with an indication of whether or not each
is set.
Options:
-o restrict OPTNAMEs to those defined for use with `set -o'
-p print each shell option with an indication of its status
-q suppress output
-s enable (set) each OPTNAME
-u disable (unset) each OPTNAME
Exit Status:
Returns success if OPTNAME is enabled; fails if an invalid option is
given or OPTNAME is disabled.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "version.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../flags.h"
#include "common.h"
#include "bashgetopt.h"
#if defined (READLINE)
# include "../bashline.h"
#endif
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#define UNSETOPT 0
#define SETOPT 1
#define OPTFMT "%-15s\t%s\n"
extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
extern int cdable_vars, mail_warning, source_uses_path;
extern int no_exit_on_failed_exec, print_shift_error;
extern int check_hashed_filenames, promptvars;
extern int cdspelling, expand_aliases;
extern int extended_quote;
extern int check_window_size;
extern int glob_ignore_case, match_ignore_case;
extern int hup_on_exit;
extern int xpg_echo;
extern int gnu_error_format;
extern int check_jobs_at_exit;
extern int autocd;
extern int glob_star;
extern int glob_asciirange;
extern int lastpipe_opt;
#if defined (EXTENDED_GLOB)
extern int extended_glob;
#endif
#if defined (READLINE)
extern int hist_verify, history_reediting, perform_hostname_completion;
extern int no_empty_command_completion;
extern int force_fignore;
extern int dircomplete_spelling, dircomplete_expand;
extern int complete_fullquote;
extern int enable_hostname_completion __P((int));
#endif
#if defined (PROGRAMMABLE_COMPLETION)
extern int prog_completion_enabled;
#endif
#if defined (RESTRICTED_SHELL)
extern char *shell_name;
#endif
#if defined (DEBUGGER)
extern int debugging_mode;
#endif
static void shopt_error __P((char *));
static int set_shellopts_after_change __P((char *, int));
static int shopt_enable_hostname_completion __P((char *, int));
static int set_compatibility_level __P((char *, int));
#if defined (RESTRICTED_SHELL)
static int set_restricted_shell __P((char *, int));
#endif
#if defined (READLINE)
static int shopt_set_complete_direxpand __P((char *, int));
#endif
static int shopt_login_shell;
static int shopt_compat31;
static int shopt_compat32;
static int shopt_compat40;
static int shopt_compat41;
static int shopt_compat42;
typedef int shopt_set_func_t __P((char *, int));
static struct {
char *name;
int *value;
shopt_set_func_t *set_func;
} shopt_vars[] = {
{ "autocd", &autocd, (shopt_set_func_t *)NULL },
{ "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL },
{ "cdspell", &cdspelling, (shopt_set_func_t *)NULL },
{ "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL },
#if defined (JOB_CONTROL)
{ "checkjobs", &check_jobs_at_exit, (shopt_set_func_t *)NULL },
#endif
{ "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
{ "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
#endif
{ "compat31", &shopt_compat31, set_compatibility_level },
{ "compat32", &shopt_compat32, set_compatibility_level },
{ "compat40", &shopt_compat40, set_compatibility_level },
{ "compat41", &shopt_compat41, set_compatibility_level },
{ "compat42", &shopt_compat41, set_compatibility_level },
#if defined (READLINE)
{ "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL},
{ "direxpand", &dircomplete_expand, shopt_set_complete_direxpand },
{ "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL },
#endif
{ "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
{ "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
{ "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
#if defined (DEBUGGER)
{ "extdebug", &debugging_mode, (shopt_set_func_t *)NULL },
#endif
#if defined (EXTENDED_GLOB)
{ "extglob", &extended_glob, (shopt_set_func_t *)NULL },
#endif
{ "extquote", &extended_quote, (shopt_set_func_t *)NULL },
{ "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL },
#if defined (READLINE)
{ "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
#endif
{ "globasciiranges", &glob_asciirange, (shopt_set_func_t *)NULL },
{ "globstar", &glob_star, (shopt_set_func_t *)NULL },
{ "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
{ "histappend", &force_append_history, (shopt_set_func_t *)NULL },
#endif
#if defined (READLINE)
{ "histreedit", &history_reediting, (shopt_set_func_t *)NULL },
{ "histverify", &hist_verify, (shopt_set_func_t *)NULL },
{ "hostcomplete", &perform_hostname_completion, shopt_enable_hostname_completion },
#endif
{ "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
{ "interactive_comments", &interactive_comments, set_shellopts_after_change },
{ "lastpipe", &lastpipe_opt, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
{ "lithist", &literal_history, (shopt_set_func_t *)NULL },
#endif
{ "login_shell", &shopt_login_shell, set_login_shell },
{ "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
#if defined (READLINE)
{ "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL },
#endif
{ "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL },
{ "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL },
{ "nullglob", &allow_null_glob_expansion, (shopt_set_func_t *)NULL },
#if defined (PROGRAMMABLE_COMPLETION)
{ "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL },
#endif
{ "promptvars", &promptvars, (shopt_set_func_t *)NULL },
#if defined (RESTRICTED_SHELL)
{ "restricted_shell", &restricted_shell, set_restricted_shell },
#endif
{ "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL },
{ "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL },
{ "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL },
{ (char *)0, (int *)0, (shopt_set_func_t *)NULL }
};
#define N_SHOPT_OPTIONS (sizeof (shopt_vars) / sizeof (shopt_vars[0]))
#define GET_SHOPT_OPTION_VALUE(i) (*shopt_vars[i].value)
static const char * const on = "on";
static const char * const off = "off";
static int find_shopt __P((char *));
static int toggle_shopts __P((int, WORD_LIST *, int));
static void print_shopt __P((char *, int, int));
static int list_shopts __P((WORD_LIST *, int));
static int list_some_shopts __P((int, int));
static int list_shopt_o_options __P((WORD_LIST *, int));
static int list_some_o_options __P((int, int));
static int set_shopt_o_options __P((int, WORD_LIST *, int));
#define SFLAG 0x01
#define UFLAG 0x02
#define QFLAG 0x04
#define OFLAG 0x08
#define PFLAG 0x10
int
shopt_builtin (list)
WORD_LIST *list;
{
int opt, flags, rval;
flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "psuoq")) != -1)
{
switch (opt)
{
case 's':
flags |= SFLAG;
break;
case 'u':
flags |= UFLAG;
break;
case 'q':
flags |= QFLAG;
break;
case 'o':
flags |= OFLAG;
break;
case 'p':
flags |= PFLAG;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG))
{
builtin_error (_("cannot set and unset shell options simultaneously"));
return (EXECUTION_FAILURE);
}
rval = EXECUTION_SUCCESS;
if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */
rval = list_shopt_o_options (list, flags);
else if (list && (flags & OFLAG)) /* shopt -so args */
rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG);
else if (flags & OFLAG) /* shopt -so */
rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags);
else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */
rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG);
else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */
rval = list_shopts (list, flags);
else /* shopt -su */
rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags);
return (rval);
}
/* Reset the options managed by `shopt' to the values they would have at
shell startup. */
void
reset_shopt_options ()
{
allow_null_glob_expansion = glob_dot_filenames = 0;
cdable_vars = mail_warning = 0;
no_exit_on_failed_exec = print_shift_error = 0;
check_hashed_filenames = cdspelling = expand_aliases = 0;
source_uses_path = promptvars = 1;
check_window_size = CHECKWINSIZE_DEFAULT;
#if defined (EXTENDED_GLOB)
extended_glob = 0;
#endif
#if defined (HISTORY)
literal_history = force_append_history = 0;
command_oriented_history = 1;
#endif
#if defined (READLINE)
hist_verify = history_reediting = 0;
perform_hostname_completion = 1;
#endif
shopt_login_shell = login_shell;
}
static int
find_shopt (name)
char *name;
{
int i;
for (i = 0; shopt_vars[i].name; i++)
if (STREQ (name, shopt_vars[i].name))
return i;
return -1;
}
static void
shopt_error (s)
char *s;
{
builtin_error (_("%s: invalid shell option name"), s);
}
static int
toggle_shopts (mode, list, quiet)
int mode;
WORD_LIST *list;
int quiet;
{
WORD_LIST *l;
int ind, rval;
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
ind = find_shopt (l->word->word);
if (ind < 0)
{
shopt_error (l->word->word);
rval = EXECUTION_FAILURE;
}
else
{
*shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */
if (shopt_vars[ind].set_func)
(*shopt_vars[ind].set_func) (shopt_vars[ind].name, mode);
}
}
set_bashopts ();
return (rval);
}
static void
print_shopt (name, val, flags)
char *name;
int val, flags;
{
if (flags & PFLAG)
printf ("shopt %s %s\n", val ? "-s" : "-u", name);
else
printf (OPTFMT, name, val ? on : off);
}
/* List the values of all or any of the `shopt' options. Returns 0 if
all were listed or all variables queried were on; 1 otherwise. */
static int
list_shopts (list, flags)
WORD_LIST *list;
int flags;
{
WORD_LIST *l;
int i, val, rval;
if (list == 0)
{
for (i = 0; shopt_vars[i].name; i++)
{
val = *shopt_vars[i].value;
if ((flags & QFLAG) == 0)
print_shopt (shopt_vars[i].name, val, flags);
}
return (sh_chkwrite (EXECUTION_SUCCESS));
}
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
i = find_shopt (l->word->word);
if (i < 0)
{
shopt_error (l->word->word);
rval = EXECUTION_FAILURE;
continue;
}
val = *shopt_vars[i].value;
if (val == 0)
rval = EXECUTION_FAILURE;
if ((flags & QFLAG) == 0)
print_shopt (l->word->word, val, flags);
}
return (sh_chkwrite (rval));
}
static int
list_some_shopts (mode, flags)
int mode, flags;
{
int val, i;
for (i = 0; shopt_vars[i].name; i++)
{
val = *shopt_vars[i].value;
if (((flags & QFLAG) == 0) && mode == val)
print_shopt (shopt_vars[i].name, val, flags);
}
return (sh_chkwrite (EXECUTION_SUCCESS));
}
static int
list_shopt_o_options (list, flags)
WORD_LIST *list;
int flags;
{
WORD_LIST *l;
int val, rval;
if (list == 0)
{
if ((flags & QFLAG) == 0)
list_minus_o_opts (-1, (flags & PFLAG));
return (sh_chkwrite (EXECUTION_SUCCESS));
}
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
val = minus_o_option_value (l->word->word);
if (val == -1)
{
sh_invalidoptname (l->word->word);
rval = EXECUTION_FAILURE;
continue;
}
if (val == 0)
rval = EXECUTION_FAILURE;
if ((flags & QFLAG) == 0)
{
if (flags & PFLAG)
printf ("set %co %s\n", val ? '-' : '+', l->word->word);
else
printf (OPTFMT, l->word->word, val ? on : off);
}
}
return (sh_chkwrite (rval));
}
static int
list_some_o_options (mode, flags)
int mode, flags;
{
if ((flags & QFLAG) == 0)
list_minus_o_opts (mode, (flags & PFLAG));
return (sh_chkwrite (EXECUTION_SUCCESS));
}
static int
set_shopt_o_options (mode, list, quiet)
int mode;
WORD_LIST *list;
int quiet;
{
WORD_LIST *l;
int rval;
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE)
rval = EXECUTION_FAILURE;
}
set_shellopts ();
return rval;
}
/* If we set or unset interactive_comments with shopt, make sure the
change is reflected in $SHELLOPTS. */
static int
set_shellopts_after_change (option_name, mode)
char *option_name;
int mode;
{
set_shellopts ();
return (0);
}
static int
shopt_enable_hostname_completion (option_name, mode)
char *option_name;
int mode;
{
return (enable_hostname_completion (mode));
}
static int
set_compatibility_level (option_name, mode)
char *option_name;
int mode;
{
int ind;
/* If we're setting something, redo some of the work we did above in
toggle_shopt(). Unset everything and reset the appropriate option
based on OPTION_NAME. */
if (mode)
{
shopt_compat31 = shopt_compat32 = 0;
shopt_compat40 = shopt_compat41 = shopt_compat42 = 0;
ind = find_shopt (option_name);
*shopt_vars[ind].value = mode;
}
/* Then set shell_compatibility_level based on what remains */
if (shopt_compat31)
shell_compatibility_level = 31;
else if (shopt_compat32)
shell_compatibility_level = 32;
else if (shopt_compat40)
shell_compatibility_level = 40;
else if (shopt_compat41)
shell_compatibility_level = 41;
else if (shopt_compat42)
shell_compatibility_level = 42;
else
shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
return 0;
}
/* Set and unset the various compatibility options from the value of
shell_compatibility_level; used by sv_shcompat */
void
set_compatibility_opts ()
{
shopt_compat31 = shopt_compat32 = shopt_compat40 = shopt_compat41 = shopt_compat42 = 0;
switch (shell_compatibility_level)
{
case DEFAULT_COMPAT_LEVEL:
break;
case 42:
shopt_compat42 = 1; break;
case 41:
shopt_compat41 = 1; break;
case 40:
shopt_compat40 = 1; break;
case 32:
shopt_compat32 = 1; break;
case 31:
shopt_compat31 = 1; break;
}
}
#if defined (READLINE)
static int
shopt_set_complete_direxpand (option_name, mode)
char *option_name;
int mode;
{
set_directory_hook ();
return 0;
}
#endif
#if defined (RESTRICTED_SHELL)
/* Don't allow the value of restricted_shell to be modified. */
static int
set_restricted_shell (option_name, mode)
char *option_name;
int mode;
{
static int save_restricted = -1;
if (save_restricted == -1)
save_restricted = shell_is_restricted (shell_name);
restricted_shell = save_restricted;
return (0);
}
#endif /* RESTRICTED_SHELL */
/* Not static so shell.c can call it to initialize shopt_login_shell */
int
set_login_shell (option_name, mode)
char *option_name;
int mode;
{
shopt_login_shell = login_shell != 0;
return (0);
}
char **
get_shopt_options ()
{
char **ret;
int n, i;
n = sizeof (shopt_vars) / sizeof (shopt_vars[0]);
ret = strvec_create (n + 1);
for (i = 0; shopt_vars[i].name; i++)
ret[i] = savestring (shopt_vars[i].name);
ret[i] = (char *)NULL;
return ret;
}
/*
* External interface for other parts of the shell. NAME is a string option;
* MODE is 0 if we want to unset an option; 1 if we want to set an option.
* REUSABLE is 1 if we want to print output in a form that may be reused.
*/
int
shopt_setopt (name, mode)
char *name;
int mode;
{
WORD_LIST *wl;
int r;
wl = add_string_to_list (name, (WORD_LIST *)NULL);
r = toggle_shopts (mode, wl, 0);
dispose_words (wl);
return r;
}
int
shopt_listopt (name, reusable)
char *name;
int reusable;
{
int i;
if (name == 0)
return (list_shopts ((WORD_LIST *)NULL, reusable ? PFLAG : 0));
i = find_shopt (name);
if (i < 0)
{
shopt_error (name);
return (EXECUTION_FAILURE);
}
print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
void
set_bashopts ()
{
char *value;
char tflag[N_SHOPT_OPTIONS];
int vsize, i, vptr, *ip, exported;
SHELL_VAR *v;
for (vsize = i = 0; shopt_vars[i].name; i++)
{
tflag[i] = 0;
if (GET_SHOPT_OPTION_VALUE (i))
{
vsize += strlen (shopt_vars[i].name) + 1;
tflag[i] = 1;
}
}
value = (char *)xmalloc (vsize + 1);
for (i = vptr = 0; shopt_vars[i].name; i++)
{
if (tflag[i])
{
strcpy (value + vptr, shopt_vars[i].name);
vptr += strlen (shopt_vars[i].name);
value[vptr++] = ':';
}
}
if (vptr)
vptr--; /* cut off trailing colon */
value[vptr] = '\0';
v = find_variable ("BASHOPTS");
/* Turn off the read-only attribute so we can bind the new value, and
note whether or not the variable was exported. */
if (v)
{
VUNSETATTR (v, att_readonly);
exported = exported_p (v);
}
else
exported = 0;
v = bind_variable ("BASHOPTS", value, 0);
/* Turn the read-only attribute back on, and turn off the export attribute
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
exported before we bound the new value. */
VSETATTR (v, att_readonly);
if (mark_modified_vars && exported == 0 && exported_p (v))
VUNSETATTR (v, att_exported);
free (value);
}
void
parse_bashopts (value)
char *value;
{
char *vname;
int vptr, ind;
vptr = 0;
while (vname = extract_colon_unit (value, &vptr))
{
ind = find_shopt (vname);
if (ind >= 0)
*shopt_vars[ind].value = 1;
free (vname);
}
}
void
initialize_bashopts (no_bashopts)
int no_bashopts;
{
char *temp;
SHELL_VAR *var;
if (no_bashopts == 0)
{
var = find_variable ("BASHOPTS");
/* set up any shell options we may have inherited. */
if (var && imported_p (var))
{
temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
if (temp)
{
parse_bashopts (temp);
free (temp);
}
}
}
/* Set up the $BASHOPTS variable. */
set_bashopts ();
}
+975
View File
@@ -0,0 +1,975 @@
/* rltty.c -- functions to prepare and restore the terminal for readline's
use. */
/* Copyright (C) 1992-2005 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
Readline is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Readline is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Readline. If not, see <http://www.gnu.org/licenses/>.
*/
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include "rldefs.h"
#if defined (GWINSZ_IN_SYS_IOCTL)
# include <sys/ioctl.h>
#endif /* GWINSZ_IN_SYS_IOCTL */
#include "rltty.h"
#include "readline.h"
#include "rlprivate.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal;
rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal;
static void set_winsize PARAMS((int));
/* **************************************************************** */
/* */
/* Saving and Restoring the TTY */
/* */
/* **************************************************************** */
/* Non-zero means that the terminal is in a prepped state. */
static int terminal_prepped;
static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars;
/* If non-zero, means that this process has called tcflow(fd, TCOOFF)
and output is suspended. */
#if defined (__ksr1__)
static int ksrflow;
#endif
/* Dummy call to force a backgrounded readline to stop before it tries
to get the tty settings. */
static void
set_winsize (tty)
int tty;
{
#if defined (TIOCGWINSZ)
struct winsize w;
if (ioctl (tty, TIOCGWINSZ, &w) == 0)
(void) ioctl (tty, TIOCSWINSZ, &w);
#endif /* TIOCGWINSZ */
}
#if defined (NO_TTY_DRIVER)
/* Nothing */
#elif defined (NEW_TTY_DRIVER)
/* Values for the `flags' field of a struct bsdtty. This tells which
elements of the struct bsdtty have been fetched from the system and
are valid. */
#define SGTTY_SET 0x01
#define LFLAG_SET 0x02
#define TCHARS_SET 0x04
#define LTCHARS_SET 0x08
struct bsdtty {
struct sgttyb sgttyb; /* Basic BSD tty driver information. */
int lflag; /* Local mode flags, like LPASS8. */
#if defined (TIOCGETC)
struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */
#endif
#if defined (TIOCGLTC)
struct ltchars ltchars; /* 4.2 BSD editing characters */
#endif
int flags; /* Bitmap saying which parts of the struct are valid. */
};
#define TIOTYPE struct bsdtty
static TIOTYPE otio;
static void save_tty_chars PARAMS((TIOTYPE *));
static int _get_tty_settings PARAMS((int, TIOTYPE *));
static int get_tty_settings PARAMS((int, TIOTYPE *));
static int _set_tty_settings PARAMS((int, TIOTYPE *));
static int set_tty_settings PARAMS((int, TIOTYPE *));
static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *));
static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t *));
static void
save_tty_chars (tiop)
TIOTYPE *tiop;
{
_rl_last_tty_chars = _rl_tty_chars;
if (tiop->flags & SGTTY_SET)
{
_rl_tty_chars.t_erase = tiop->sgttyb.sg_erase;
_rl_tty_chars.t_kill = tiop->sgttyb.sg_kill;
}
if (tiop->flags & TCHARS_SET)
{
_rl_intr_char = _rl_tty_chars.t_intr = tiop->tchars.t_intrc;
_rl_quit_char = _rl_tty_chars.t_quit = tiop->tchars.t_quitc;
_rl_tty_chars.t_start = tiop->tchars.t_startc;
_rl_tty_chars.t_stop = tiop->tchars.t_stopc;
_rl_tty_chars.t_eof = tiop->tchars.t_eofc;
_rl_tty_chars.t_eol = '\n';
_rl_tty_chars.t_eol2 = tiop->tchars.t_brkc;
}
if (tiop->flags & LTCHARS_SET)
{
_rl_susp_char = _rl_tty_chars.t_susp = tiop->ltchars.t_suspc;
_rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc;
_rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc;
_rl_tty_chars.t_flush = tiop->ltchars.t_flushc;
_rl_tty_chars.t_werase = tiop->ltchars.t_werasc;
_rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc;
}
_rl_tty_chars.t_status = -1;
}
static int
get_tty_settings (tty, tiop)
int tty;
TIOTYPE *tiop;
{
set_winsize (tty);
tiop->flags = tiop->lflag = 0;
errno = 0;
if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0)
return -1;
tiop->flags |= SGTTY_SET;
#if defined (TIOCLGET)
if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0)
tiop->flags |= LFLAG_SET;
#endif
#if defined (TIOCGETC)
if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0)
tiop->flags |= TCHARS_SET;
#endif
#if defined (TIOCGLTC)
if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0)
tiop->flags |= LTCHARS_SET;
#endif
return 0;
}
static int
set_tty_settings (tty, tiop)
int tty;
TIOTYPE *tiop;
{
if (tiop->flags & SGTTY_SET)
{
ioctl (tty, TIOCSETN, &(tiop->sgttyb));
tiop->flags &= ~SGTTY_SET;
}
_rl_echoing_p = 1;
#if defined (TIOCLSET)
if (tiop->flags & LFLAG_SET)
{
ioctl (tty, TIOCLSET, &(tiop->lflag));
tiop->flags &= ~LFLAG_SET;
}
#endif
#if defined (TIOCSETC)
if (tiop->flags & TCHARS_SET)
{
ioctl (tty, TIOCSETC, &(tiop->tchars));
tiop->flags &= ~TCHARS_SET;
}
#endif
#if defined (TIOCSLTC)
if (tiop->flags & LTCHARS_SET)
{
ioctl (tty, TIOCSLTC, &(tiop->ltchars));
tiop->flags &= ~LTCHARS_SET;
}
#endif
return 0;
}
static void
prepare_terminal_settings (meta_flag, oldtio, tiop)
int meta_flag;
TIOTYPE oldtio, *tiop;
{
_rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO);
_rl_echoctl = (oldtio.sgttyb.sg_flags & ECHOCTL);
/* Copy the original settings to the structure we're going to use for
our settings. */
tiop->sgttyb = oldtio.sgttyb;
tiop->lflag = oldtio.lflag;
#if defined (TIOCGETC)
tiop->tchars = oldtio.tchars;
#endif
#if defined (TIOCGLTC)
tiop->ltchars = oldtio.ltchars;
#endif
tiop->flags = oldtio.flags;
/* First, the basic settings to put us into character-at-a-time, no-echo
input mode. */
tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD);
tiop->sgttyb.sg_flags |= CBREAK;
/* If this terminal doesn't care how the 8th bit is used, then we can
use it for the meta-key. If only one of even or odd parity is
specified, then the terminal is using parity, and we cannot. */
#if !defined (ANYP)
# define ANYP (EVENP | ODDP)
#endif
if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) ||
((oldtio.sgttyb.sg_flags & ANYP) == 0))
{
tiop->sgttyb.sg_flags |= ANYP;
/* Hack on local mode flags if we can. */
#if defined (TIOCLGET)
# if defined (LPASS8)
tiop->lflag |= LPASS8;
# endif /* LPASS8 */
#endif /* TIOCLGET */
}
#if defined (TIOCGETC)
# if defined (USE_XON_XOFF)
/* Get rid of terminal output start and stop characters. */
tiop->tchars.t_stopc = -1; /* C-s */
tiop->tchars.t_startc = -1; /* C-q */
/* If there is an XON character, bind it to restart the output. */
if (oldtio.tchars.t_startc != -1)
rl_bind_key (oldtio.tchars.t_startc, rl_restart_output);
# endif /* USE_XON_XOFF */
/* If there is an EOF char, bind _rl_eof_char to it. */
if (oldtio.tchars.t_eofc != -1)
_rl_eof_char = oldtio.tchars.t_eofc;
# if defined (NO_KILL_INTR)
/* Get rid of terminal-generated SIGQUIT and SIGINT. */
tiop->tchars.t_quitc = -1; /* C-\ */
tiop->tchars.t_intrc = -1; /* C-c */
# endif /* NO_KILL_INTR */
#endif /* TIOCGETC */
#if defined (TIOCGLTC)
/* Make the interrupt keys go away. Just enough to make people happy. */
tiop->ltchars.t_dsuspc = -1; /* C-y */
tiop->ltchars.t_lnextc = -1; /* C-v */
#endif /* TIOCGLTC */
}
#else /* !defined (NEW_TTY_DRIVER) */
#if !defined (VMIN)
# define VMIN VEOF
#endif
#if !defined (VTIME)
# define VTIME VEOL
#endif
#if defined (TERMIOS_TTY_DRIVER)
# define TIOTYPE struct termios
# define DRAIN_OUTPUT(fd) tcdrain (fd)
# define GETATTR(tty, tiop) (tcgetattr (tty, tiop))
# ifdef M_UNIX
# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop))
# else
# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop))
# endif /* !M_UNIX */
#else
# define TIOTYPE struct termio
# define DRAIN_OUTPUT(fd)
# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop))
# define SETATTR(tty, tiop) (ioctl (tty, TCSETAW, tiop))
#endif /* !TERMIOS_TTY_DRIVER */
static TIOTYPE otio;
static void save_tty_chars PARAMS((TIOTYPE *));
static int _get_tty_settings PARAMS((int, TIOTYPE *));
static int get_tty_settings PARAMS((int, TIOTYPE *));
static int _set_tty_settings PARAMS((int, TIOTYPE *));
static int set_tty_settings PARAMS((int, TIOTYPE *));
static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *));
static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t *));
static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE));
#if defined (FLUSHO)
# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO)
#else
# define OUTPUT_BEING_FLUSHED(tp) 0
#endif
static void
save_tty_chars (tiop)
TIOTYPE *tiop;
{
_rl_last_tty_chars = _rl_tty_chars;
_rl_tty_chars.t_eof = tiop->c_cc[VEOF];
_rl_tty_chars.t_eol = tiop->c_cc[VEOL];
#ifdef VEOL2
_rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2];
#endif
_rl_tty_chars.t_erase = tiop->c_cc[VERASE];
#ifdef VWERASE
_rl_tty_chars.t_werase = tiop->c_cc[VWERASE];
#endif
_rl_tty_chars.t_kill = tiop->c_cc[VKILL];
#ifdef VREPRINT
_rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT];
#endif
_rl_intr_char = _rl_tty_chars.t_intr = tiop->c_cc[VINTR];
_rl_quit_char = _rl_tty_chars.t_quit = tiop->c_cc[VQUIT];
#ifdef VSUSP
_rl_susp_char = _rl_tty_chars.t_susp = tiop->c_cc[VSUSP];
#endif
#ifdef VDSUSP
_rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP];
#endif
#ifdef VSTART
_rl_tty_chars.t_start = tiop->c_cc[VSTART];
#endif
#ifdef VSTOP
_rl_tty_chars.t_stop = tiop->c_cc[VSTOP];
#endif
#ifdef VLNEXT
_rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT];
#endif
#ifdef VDISCARD
_rl_tty_chars.t_flush = tiop->c_cc[VDISCARD];
#endif
#ifdef VSTATUS
_rl_tty_chars.t_status = tiop->c_cc[VSTATUS];
#endif
}
#if defined (_AIX) || defined (_AIX41)
/* Currently this is only used on AIX */
static void
rltty_warning (msg)
char *msg;
{
_rl_errmsg ("warning: %s", msg);
}
#endif
#if defined (_AIX)
void
setopost(tp)
TIOTYPE *tp;
{
if ((tp->c_oflag & OPOST) == 0)
{
_rl_errmsg ("warning: turning on OPOST for terminal\r");
tp->c_oflag |= OPOST|ONLCR;
}
}
#endif
static int
_get_tty_settings (tty, tiop)
int tty;
TIOTYPE *tiop;
{
int ioctl_ret;
while (1)
{
ioctl_ret = GETATTR (tty, tiop);
if (ioctl_ret < 0)
{
if (errno != EINTR)
return -1;
else
continue;
}
if (OUTPUT_BEING_FLUSHED (tiop))
{
#if defined (FLUSHO)
_rl_errmsg ("warning: turning off output flushing");
tiop->c_lflag &= ~FLUSHO;
break;
#else
continue;
#endif
}
break;
}
return 0;
}
static int
get_tty_settings (tty, tiop)
int tty;
TIOTYPE *tiop;
{
set_winsize (tty);
errno = 0;
if (_get_tty_settings (tty, tiop) < 0)
return -1;
#if defined (_AIX)
setopost(tiop);
#endif
return 0;
}
static int
_set_tty_settings (tty, tiop)
int tty;
TIOTYPE *tiop;
{
while (SETATTR (tty, tiop) < 0)
{
if (errno != EINTR)
return -1;
errno = 0;
}
return 0;
}
static int
set_tty_settings (tty, tiop)
int tty;
TIOTYPE *tiop;
{
if (_set_tty_settings (tty, tiop) < 0)
return -1;
#if 0
#if defined (TERMIOS_TTY_DRIVER)
# if defined (__ksr1__)
if (ksrflow)
{
ksrflow = 0;
tcflow (tty, TCOON);
}
# else /* !ksr1 */
tcflow (tty, TCOON); /* Simulate a ^Q. */
# endif /* !ksr1 */
#else
ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
#endif /* !TERMIOS_TTY_DRIVER */
#endif /* 0 */
return 0;
}
static void
prepare_terminal_settings (meta_flag, oldtio, tiop)
int meta_flag;
TIOTYPE oldtio, *tiop;
{
_rl_echoing_p = (oldtio.c_lflag & ECHO);
#if defined (ECHOCTL)
_rl_echoctl = (oldtio.c_lflag & ECHOCTL);
#endif
tiop->c_lflag &= ~(ICANON | ECHO);
if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE)
_rl_eof_char = oldtio.c_cc[VEOF];
#if defined (USE_XON_XOFF)
#if defined (IXANY)
tiop->c_iflag &= ~(IXON | IXANY);
#else
/* `strict' Posix systems do not define IXANY. */
tiop->c_iflag &= ~IXON;
#endif /* IXANY */
#endif /* USE_XON_XOFF */
/* Only turn this off if we are using all 8 bits. */
if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag)
tiop->c_iflag &= ~(ISTRIP | INPCK);
/* Make sure we differentiate between CR and NL on input. */
tiop->c_iflag &= ~(ICRNL | INLCR);
#if !defined (HANDLE_SIGNALS)
tiop->c_lflag &= ~ISIG;
#else
tiop->c_lflag |= ISIG;
#endif
tiop->c_cc[VMIN] = 1;
tiop->c_cc[VTIME] = 0;
#if defined (FLUSHO)
if (OUTPUT_BEING_FLUSHED (tiop))
{
tiop->c_lflag &= ~FLUSHO;
oldtio.c_lflag &= ~FLUSHO;
}
#endif
/* Turn off characters that we need on Posix systems with job control,
just to be sure. This includes ^Y and ^V. This should not really
be necessary. */
#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE)
#if defined (VLNEXT)
tiop->c_cc[VLNEXT] = _POSIX_VDISABLE;
#endif
#if defined (VDSUSP)
tiop->c_cc[VDSUSP] = _POSIX_VDISABLE;
#endif
#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */
}
#endif /* !NEW_TTY_DRIVER */
/* Put the terminal in CBREAK mode so that we can detect key presses. */
#if defined (NO_TTY_DRIVER)
void
rl_prep_terminal (meta_flag)
int meta_flag;
{
_rl_echoing_p = 1;
}
void
rl_deprep_terminal ()
{
}
#else /* ! NO_TTY_DRIVER */
void
rl_prep_terminal (meta_flag)
int meta_flag;
{
int tty;
TIOTYPE tio;
if (terminal_prepped)
return;
itrace("rl_prep_terminal");
/* Try to keep this function from being INTerrupted. */
_rl_block_sigint ();
tty = rl_instream ? fileno (rl_instream) : fileno (stdin);
if (get_tty_settings (tty, &tio) < 0)
{
#if defined (ENOTSUP)
/* MacOS X and Linux, at least, lie about the value of errno if
tcgetattr fails. */
if (errno == ENOTTY || errno == EINVAL || errno == ENOTSUP)
#else
if (errno == ENOTTY || errno == EINVAL)
#endif
_rl_echoing_p = 1; /* XXX */
_rl_release_sigint ();
return;
}
otio = tio;
if (_rl_bind_stty_chars)
{
#if defined (VI_MODE)
/* If editing in vi mode, make sure we restore the bindings in the
insertion keymap no matter what keymap we ended up in. */
if (rl_editing_mode == vi_mode)
rl_tty_unset_default_bindings (vi_insertion_keymap);
else
#endif
rl_tty_unset_default_bindings (_rl_keymap);
}
save_tty_chars (&otio);
RL_SETSTATE(RL_STATE_TTYCSAVED);
if (_rl_bind_stty_chars)
{
#if defined (VI_MODE)
/* If editing in vi mode, make sure we set the bindings in the
insertion keymap no matter what keymap we ended up in. */
if (rl_editing_mode == vi_mode)
_rl_bind_tty_special_chars (vi_insertion_keymap, tio);
else
#endif
_rl_bind_tty_special_chars (_rl_keymap, tio);
}
prepare_terminal_settings (meta_flag, otio, &tio);
if (set_tty_settings (tty, &tio) < 0)
{
_rl_release_sigint ();
return;
}
if (_rl_enable_keypad)
_rl_control_keypad (1);
fflush (rl_outstream);
terminal_prepped = 1;
RL_SETSTATE(RL_STATE_TERMPREPPED);
_rl_release_sigint ();
}
/* Restore the terminal's normal settings and modes. */
void
rl_deprep_terminal ()
{
int tty;
if (!terminal_prepped)
return;
itrace("rl_deprep_terminal");
/* Try to keep this function from being interrupted. */
_rl_block_sigint ();
tty = rl_instream ? fileno (rl_instream) : fileno (stdin);
if (_rl_enable_keypad)
_rl_control_keypad (0);
fflush (rl_outstream);
if (set_tty_settings (tty, &otio) < 0)
{
_rl_release_sigint ();
return;
}
terminal_prepped = 0;
RL_UNSETSTATE(RL_STATE_TERMPREPPED);
_rl_release_sigint ();
}
#endif /* !NO_TTY_DRIVER */
/* **************************************************************** */
/* */
/* Bogus Flow Control */
/* */
/* **************************************************************** */
int
rl_restart_output (count, key)
int count, key;
{
#if defined (__MINGW32__)
return 0;
#else /* !__MING32__ */
int fildes = fileno (rl_outstream);
#if defined (TIOCSTART)
#if defined (apollo)
ioctl (&fildes, TIOCSTART, 0);
#else
ioctl (fildes, TIOCSTART, 0);
#endif /* apollo */
#else /* !TIOCSTART */
# if defined (TERMIOS_TTY_DRIVER)
# if defined (__ksr1__)
if (ksrflow)
{
ksrflow = 0;
tcflow (fildes, TCOON);
}
# else /* !ksr1 */
tcflow (fildes, TCOON); /* Simulate a ^Q. */
# endif /* !ksr1 */
# else /* !TERMIOS_TTY_DRIVER */
# if defined (TCXONC)
ioctl (fildes, TCXONC, TCOON);
# endif /* TCXONC */
# endif /* !TERMIOS_TTY_DRIVER */
#endif /* !TIOCSTART */
return 0;
#endif /* !__MINGW32__ */
}
int
rl_stop_output (count, key)
int count, key;
{
#if defined (__MINGW32__)
return 0;
#else
int fildes = fileno (rl_instream);
#if defined (TIOCSTOP)
# if defined (apollo)
ioctl (&fildes, TIOCSTOP, 0);
# else
ioctl (fildes, TIOCSTOP, 0);
# endif /* apollo */
#else /* !TIOCSTOP */
# if defined (TERMIOS_TTY_DRIVER)
# if defined (__ksr1__)
ksrflow = 1;
# endif /* ksr1 */
tcflow (fildes, TCOOFF);
# else
# if defined (TCXONC)
ioctl (fildes, TCXONC, TCOON);
# endif /* TCXONC */
# endif /* !TERMIOS_TTY_DRIVER */
#endif /* !TIOCSTOP */
return 0;
#endif /* !__MINGW32__ */
}
/* **************************************************************** */
/* */
/* Default Key Bindings */
/* */
/* **************************************************************** */
#if !defined (NO_TTY_DRIVER)
#define SET_SPECIAL(sc, func) set_special_char(kmap, &ttybuff, sc, func)
#endif
#if defined (NO_TTY_DRIVER)
#define SET_SPECIAL(sc, func)
#define RESET_SPECIAL(c)
#elif defined (NEW_TTY_DRIVER)
static void
set_special_char (kmap, tiop, sc, func)
Keymap kmap;
TIOTYPE *tiop;
int sc;
rl_command_func_t *func;
{
if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC)
kmap[(unsigned char)sc].function = func;
}
#define RESET_SPECIAL(c) \
if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) \
kmap[(unsigned char)c].function = rl_insert;
static void
_rl_bind_tty_special_chars (kmap, ttybuff)
Keymap kmap;
TIOTYPE ttybuff;
{
if (ttybuff.flags & SGTTY_SET)
{
SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout);
SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard);
}
# if defined (TIOCGLTC)
if (ttybuff.flags & LTCHARS_SET)
{
SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout);
SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert);
}
# endif /* TIOCGLTC */
}
#else /* !NEW_TTY_DRIVER */
static void
set_special_char (kmap, tiop, sc, func)
Keymap kmap;
TIOTYPE *tiop;
int sc;
rl_command_func_t *func;
{
unsigned char uc;
uc = tiop->c_cc[sc];
if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC)
kmap[uc].function = func;
}
/* used later */
#define RESET_SPECIAL(uc) \
if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \
kmap[uc].function = rl_insert;
static void
_rl_bind_tty_special_chars (kmap, ttybuff)
Keymap kmap;
TIOTYPE ttybuff;
{
SET_SPECIAL (VERASE, rl_rubout);
SET_SPECIAL (VKILL, rl_unix_line_discard);
# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
SET_SPECIAL (VLNEXT, rl_quoted_insert);
# endif /* VLNEXT && TERMIOS_TTY_DRIVER */
# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
SET_SPECIAL (VWERASE, rl_unix_word_rubout);
# endif /* VWERASE && TERMIOS_TTY_DRIVER */
}
#endif /* !NEW_TTY_DRIVER */
/* Set the system's default editing characters to their readline equivalents
in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */
void
rltty_set_default_bindings (kmap)
Keymap kmap;
{
#if !defined (NO_TTY_DRIVER)
TIOTYPE ttybuff;
int tty;
tty = fileno (rl_instream);
if (get_tty_settings (tty, &ttybuff) == 0)
_rl_bind_tty_special_chars (kmap, ttybuff);
#endif
}
/* New public way to set the system default editing chars to their readline
equivalents. */
void
rl_tty_set_default_bindings (kmap)
Keymap kmap;
{
rltty_set_default_bindings (kmap);
}
/* Rebind all of the tty special chars that readline worries about back
to self-insert. Call this before saving the current terminal special
chars with save_tty_chars(). This only works on POSIX termios or termio
systems. */
void
rl_tty_unset_default_bindings (kmap)
Keymap kmap;
{
/* Don't bother before we've saved the tty special chars at least once. */
if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0)
return;
RESET_SPECIAL (_rl_tty_chars.t_erase);
RESET_SPECIAL (_rl_tty_chars.t_kill);
# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER)
RESET_SPECIAL (_rl_tty_chars.t_lnext);
# endif /* VLNEXT && TERMIOS_TTY_DRIVER */
# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER)
RESET_SPECIAL (_rl_tty_chars.t_werase);
# endif /* VWERASE && TERMIOS_TTY_DRIVER */
}
#if defined (HANDLE_SIGNALS)
#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER)
int
_rl_disable_tty_signals ()
{
return 0;
}
int
_rl_restore_tty_signals ()
{
return 0;
}
#else
static TIOTYPE sigstty, nosigstty;
static int tty_sigs_disabled = 0;
int
_rl_disable_tty_signals ()
{
if (tty_sigs_disabled)
return 0;
if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0)
return -1;
nosigstty = sigstty;
nosigstty.c_lflag &= ~ISIG;
nosigstty.c_iflag &= ~IXON;
if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0)
return (_set_tty_settings (fileno (rl_instream), &sigstty));
tty_sigs_disabled = 1;
return 0;
}
int
_rl_restore_tty_signals ()
{
int r;
if (tty_sigs_disabled == 0)
return 0;
r = _set_tty_settings (fileno (rl_instream), &sigstty);
if (r == 0)
tty_sigs_disabled = 0;
return r;
}
#endif /* !NEW_TTY_DRIVER */
#endif /* HANDLE_SIGNALS */
+6 -1
View File
@@ -2788,11 +2788,16 @@ time_command_acceptable ()
case AND_AND:
case OR_OR:
case '&':
case WHILE:
case DO:
case UNTIL:
case IF:
case THEN:
case ELIF:
case ELSE:
case '{': /* } */
case '(': /* ) */
case '(': /* )( */
case ')': /* only valid in case statement */
case BANG: /* ! time pipeline */
case TIME: /* time time pipeline */
case TIMEOPT: /* time -p time pipeline */
+6
View File
@@ -73,6 +73,7 @@
#endif
#if defined (READLINE)
# include <readline/readline.h>
# include "bashline.h"
#endif
@@ -909,6 +910,11 @@ exit_shell (s)
fflush (stdout); /* XXX */
fflush (stderr);
#if defined (READLINE)
if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
(*rl_deprep_term_function) ();
#endif
/* Do trap[0] if defined. Allow it to override the exit status
passed to us. */
if (signal_is_trapped (0))
+1912
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -4753,6 +4753,11 @@ static struct temp_fifo *fifo_list = (struct temp_fifo *)NULL;
static int nfifo;
static int fifo_list_size;
void
clear_fifo_list ()
{
}
char *
copy_fifo_list (sizep)
int *sizep;
@@ -4891,6 +4896,31 @@ static char *dev_fd_list = (char *)NULL;
static int nfds;
static int totfds; /* The highest possible number of open files. */
void
clear_fifo (i)
int i;
{
if (dev_fd_list[i])
{
dev_fd_list[i] = 0;
nfds--;
}
}
void
clear_fifo_list ()
{
register int i;
if (nfds == 0)
return;
for (i = 0; nfds && i < totfds; i++)
clear_fifo (i);
nfds = 0;
}
char *
copy_fifo_list (sizep)
int *sizep;
+2
View File
@@ -265,6 +265,8 @@ extern char *copy_fifo_list __P((int *));
extern void unlink_new_fifos __P((char *, int));
extern void close_new_fifos __P((char *, int));
extern void clear_fifo_list __P((void));
extern WORD_LIST *list_string_with_quotes __P((char *));
#if defined (ARRAY_VARS)
+1 -1
View File
@@ -62,7 +62,7 @@ while [ $# -gt 0 ]; do
--version) shift ; do_version=y ;;
--) shift ; break ;;
-*) echo "bashbug: ${1}: invalid option" >&2
echo "$USAGE" >& 2
echo "$USAGE" >&2
exit 2 ;;
*) break ;;
esac
+271
View File
@@ -0,0 +1,271 @@
#!/bin/sh -
#
# bashbug - create a bug report and mail it to the bug address
#
# The bug address depends on the release status of the shell. Versions
# with status `devel', `alpha', `beta', or `rc' mail bug reports to
# chet@cwru.edu and, optionally, to bash-testers@cwru.edu.
# Other versions send mail to bug-bash@gnu.org.
#
# Copyright (C) 1996-2004 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# configuration section:
# these variables are filled in by the make target in Makefile
#
MACHINE="!MACHINE!"
OS="!OS!"
CC="!CC!"
CFLAGS="!CFLAGS!"
RELEASE="!RELEASE!"
PATCHLEVEL="!PATCHLEVEL!"
RELSTATUS="!RELSTATUS!"
MACHTYPE="!MACHTYPE!"
PATH=/bin:/usr/bin:/usr/local/bin:$PATH
export PATH
# Check if TMPDIR is set, default to /tmp
: ${TMPDIR:=/tmp}
#Securely create a temporary directory for the temporary files
TEMPDIR=$TMPDIR/bbug.$$
(umask 077 && mkdir $TEMPDIR) || {
echo "$0: could not create temporary directory" >&2
exit 1
}
TEMPFILE1=$TEMPDIR/bbug1
TEMPFILE2=$TEMPDIR/bbug2
USAGE="Usage: $0 [--help] [--version] [bug-report-email-address]"
VERSTR="GNU bashbug, version ${RELEASE}.${PATCHLEVEL}-${RELSTATUS}"
do_help= do_version=
while [ $# -gt 0 ]; do
case "$1" in
--help) shift ; do_help=y ;;
--version) shift ; do_version=y ;;
--) shift ; break ;;
-*) echo "bashbug: ${1}: invalid option" >&2
echo "$USAGE" >& 2
exit 2 ;;
*) break ;;
esac
done
if [ -n "$do_version" ]; then
echo "${VERSTR}"
exit 0
fi
if [ -n "$do_help" ]; then
echo "${VERSTR}"
echo "${USAGE}"
echo
cat << HERE_EOF
Bashbug is used to send mail to the Bash maintainers
for when Bash doesn't behave like you'd like, or expect.
Bashbug will start up your editor (as defined by the shell's
EDITOR environment variable) with a preformatted bug report
template for you to fill in. The report will be mailed to the
bug-bash mailing list by default. See the manual for details.
If you invoke bashbug by accident, just quit your editor without
saving any changes to the template, and no bug report will be sent.
HERE_EOF
exit 0
fi
# Figure out how to echo a string without a trailing newline
N=`echo 'hi there\c'`
case "$N" in
*c) n=-n c= ;;
*) n= c='\c' ;;
esac
BASHTESTERS="bash-testers@cwru.edu"
case "$RELSTATUS" in
alpha*|beta*|devel*|rc*) BUGBASH=chet@cwru.edu ;;
*) BUGBASH=bug-bash@gnu.org ;;
esac
case "$RELSTATUS" in
alpha*|beta*|devel*|rc*)
echo "$0: This is a testing release. Would you like your bug report"
echo "$0: to be sent to the bash-testers mailing list?"
echo $n "$0: Send to bash-testers? $c"
read ans
case "$ans" in
y*|Y*) BUGBASH="${BUGBASH},${BASHTESTERS}" ;;
esac ;;
esac
BUGADDR="${1-$BUGBASH}"
if [ -z "$DEFEDITOR" ] && [ -z "$EDITOR" ]; then
if [ -x /usr/bin/editor ]; then
DEFEDITOR=editor
elif [ -x /usr/local/bin/ce ]; then
DEFEDITOR=ce
elif [ -x /usr/local/bin/emacs ]; then
DEFEDITOR=emacs
elif [ -x /usr/contrib/bin/emacs ]; then
DEFEDITOR=emacs
elif [ -x /usr/bin/emacs ]; then
DEFEDITOR=emacs
elif [ -x /usr/bin/xemacs ]; then
DEFEDITOR=xemacs
elif [ -x /usr/contrib/bin/jove ]; then
DEFEDITOR=jove
elif [ -x /usr/local/bin/jove ]; then
DEFEDITOR=jove
elif [ -x /usr/bin/vi ]; then
DEFEDITOR=vi
else
echo "$0: No default editor found: attempting to use vi" >&2
DEFEDITOR=vi
fi
fi
: ${EDITOR=$DEFEDITOR}
: ${USER=${LOGNAME-`whoami`}}
trap 'rm -rf "$TEMPDIR"; exit 1' 1 2 3 13 15
trap 'rm -rf "$TEMPDIR"' 0
UN=
if (uname) >/dev/null 2>&1; then
UN=`uname -a`
fi
if [ -f /usr/lib/sendmail ] ; then
RMAIL="/usr/lib/sendmail"
SMARGS="-i -t"
elif [ -f /usr/sbin/sendmail ] ; then
RMAIL="/usr/sbin/sendmail"
SMARGS="-i -t"
else
RMAIL=rmail
SMARGS="$BUGADDR"
fi
INITIAL_SUBJECT='[50 character or so descriptive subject here (for reference)]'
cat > "$TEMPFILE1" <<EOF
From: ${USER}
To: ${BUGADDR}
Subject: ${INITIAL_SUBJECT}
Configuration Information [Automatically generated, do not change]:
Machine: $MACHINE
OS: $OS
Compiler: $CC
Compilation CFLAGS: $CFLAGS
uname output: $UN
Machine Type: $MACHTYPE
Bash Version: $RELEASE
Patch Level: $PATCHLEVEL
Release Status: $RELSTATUS
Description:
[Detailed description of the problem, suggestion, or complaint.]
Repeat-By:
[Describe the sequence of events that causes the problem
to occur.]
Fix:
[Description of how to fix the problem. If you don't know a
fix for the problem, don't include this section.]
EOF
cp "$TEMPFILE1" "$TEMPFILE2"
chmod u+w "$TEMPFILE1"
trap '' 2 # ignore interrupts while in editor
edstat=1
while [ $edstat -ne 0 ]; do
$EDITOR "$TEMPFILE1"
edstat=$?
if [ $edstat -ne 0 ]; then
echo "$0: editor \`$EDITOR' exited with nonzero status."
echo "$0: Perhaps it was interrupted."
echo "$0: Type \`y' to give up, and lose your bug report;"
echo "$0: type \`n' to re-enter the editor."
echo $n "$0: Do you want to give up? $c"
read ans
case "$ans" in
[Yy]*) exit 1 ;;
esac
continue
fi
# find the subject from the temp file and see if it's been changed
CURR_SUB=`grep '^Subject: ' "$TEMPFILE1" | sed 's|^Subject:[ ]*||' | sed 1q`
case "$CURR_SUB" in
"${INITIAL_SUBJECT}")
echo
echo "$0: You have not changed the subject from the default."
echo "$0: Please use a more descriptive subject header."
echo "$0: Type \`y' to give up, and lose your bug report;"
echo "$0: type \`n' to re-enter the editor."
echo $n "$0: Do you want to give up? $c"
read ans
case "$ans" in
[Yy]*) exit 1 ;;
esac
echo "$0: The editor will be restarted in five seconds."
sleep 5
edstat=1
;;
esac
done
trap 'rm -rf "$TEMPDIR"; exit 1' 2 # restore trap on SIGINT
if cmp -s "$TEMPFILE1" "$TEMPFILE2"
then
echo "File not changed, no bug report submitted."
exit
fi
echo $n "Send bug report to ${BUGADDR}? [y/n] $c"
read ans
case "$ans" in
[Nn]*) exit 0 ;;
esac
${RMAIL} $SMARGS < "$TEMPFILE1" || {
cat "$TEMPFILE1" >> $HOME/dead.bashbug
echo "$0: mail to ${BUGADDR} failed: report saved in $HOME/dead.bashbug" >&2
}
exit 0