Imported from ../bash-3.2.48.tar.gz.

This commit is contained in:
Jari Aalto 2008-11-18 13:15:12 +00:00
commit f1be666c7d
47 changed files with 703 additions and 159 deletions

42
array.c
View file

@ -120,7 +120,6 @@ ARRAY *a;
return(a1); return(a1);
} }
#ifdef INCLUDE_UNUSED
/* /*
* Make and return a new array composed of the elements in array A from * Make and return a new array composed of the elements in array A from
* S to E, inclusive. * S to E, inclusive.
@ -141,13 +140,12 @@ ARRAY_ELEMENT *s, *e;
for (p = s, i = 0; p != e; p = element_forw(p), i++) { for (p = s, i = 0; p != e; p = element_forw(p), i++) {
n = array_create_element (element_index(p), element_value(p)); n = array_create_element (element_index(p), element_value(p));
ADD_BEFORE(a->head, n); ADD_BEFORE(a->head, n);
mi = element_index(ae); mi = element_index(n);
} }
a->num_elements = i; a->num_elements = i;
a->max_index = mi; a->max_index = mi;
return a; return a;
} }
#endif
/* /*
* Walk the array, calling FUNC once for each element, with the array * Walk the array, calling FUNC once for each element, with the array
@ -300,6 +298,23 @@ ARRAY *array;
return array; return array;
} }
ARRAY *
array_quote_escapes(array)
ARRAY *array;
{
ARRAY_ELEMENT *a;
char *t;
if (array == 0 || array_head(array) == 0 || array_empty(array))
return (ARRAY *)NULL;
for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
t = quote_escapes (a->value);
FREE(a->value);
a->value = t;
}
return array;
}
/* /*
* Return a string whose elements are the members of array A beginning at * Return a string whose elements are the members of array A beginning at
* index START and spanning NELEM members. Null elements are counted. * index START and spanning NELEM members. Null elements are counted.
@ -311,9 +326,10 @@ ARRAY *a;
arrayind_t start, nelem; arrayind_t start, nelem;
int starsub, quoted; int starsub, quoted;
{ {
ARRAY *a2;
ARRAY_ELEMENT *h, *p; ARRAY_ELEMENT *h, *p;
arrayind_t i; arrayind_t i;
char *ifs, sep[2]; char *ifs, sep[2], *t;
p = a ? array_head (a) : 0; p = a ? array_head (a) : 0;
if (p == 0 || array_empty (a) || start > array_max_index(a)) if (p == 0 || array_empty (a) || start > array_max_index(a))
@ -336,6 +352,13 @@ int starsub, quoted;
for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p)) for (i = 0, h = p; p != a->head && i < nelem; i++, p = element_forw(p))
; ;
a2 = array_slice(a, h, p);
if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
array_quote(a2);
else
array_quote_escapes(a2);
if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) { if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) {
ifs = getifs(); ifs = getifs();
sep[0] = ifs ? *ifs : '\0'; sep[0] = ifs ? *ifs : '\0';
@ -343,7 +366,10 @@ int starsub, quoted;
sep[0] = ' '; sep[0] = ' ';
sep[1] = '\0'; sep[1] = '\0';
return (array_to_string_internal (h, p, sep, quoted)); t = array_to_string (a2, sep, 0);
array_dispose(a2);
return t;
} }
char * char *
@ -367,7 +393,9 @@ int mflags;
} }
if (mflags & MATCH_QUOTED) if (mflags & MATCH_QUOTED)
array_quote (a2); array_quote(a2);
else
array_quote_escapes(a2);
if (mflags & MATCH_STARSUB) { if (mflags & MATCH_STARSUB) {
ifs = getifs(); ifs = getifs();
sifs[0] = ifs ? *ifs : '\0'; sifs[0] = ifs ? *ifs : '\0';
@ -655,7 +683,7 @@ int quoted;
is = inttostr (element_index(ae), indstr, sizeof(indstr)); is = inttostr (element_index(ae), indstr, sizeof(indstr));
valstr = element_value (ae) ? sh_double_quote (element_value(ae)) valstr = element_value (ae) ? sh_double_quote (element_value(ae))
: (char *)NULL; : (char *)NULL;
elen = STRLEN (indstr) + 8 + STRLEN (valstr); elen = STRLEN (is) + 8 + STRLEN (valstr);
RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);
result[rlen++] = '['; result[rlen++] = '[';

View file

@ -55,6 +55,7 @@ extern int array_rshift __P((ARRAY *, int, char *));
extern ARRAY_ELEMENT *array_unshift_element __P((ARRAY *)); extern ARRAY_ELEMENT *array_unshift_element __P((ARRAY *));
extern int array_shift_element __P((ARRAY *, char *)); extern int array_shift_element __P((ARRAY *, char *));
extern ARRAY *array_quote __P((ARRAY *)); extern ARRAY *array_quote __P((ARRAY *));
extern ARRAY *array_quote_escapes __P((ARRAY *));
extern char *array_subrange __P((ARRAY *, arrayind_t, arrayind_t, int, int)); extern char *array_subrange __P((ARRAY *, arrayind_t, arrayind_t, int, int));
extern char *array_patsub __P((ARRAY *, char *, char *, int)); extern char *array_patsub __P((ARRAY *, char *, char *, int));

View file

@ -618,6 +618,8 @@ array_expand_index (s, len)
if (expok == 0) if (expok == 0)
{ {
last_command_exit_value = EXECUTION_FAILURE; last_command_exit_value = EXECUTION_FAILURE;
top_level_cleanup ();
jump_to_top_level (DISCARD); jump_to_top_level (DISCARD);
} }
return val; return val;
@ -720,7 +722,7 @@ array_value_internal (s, quoted, allow_all, rtype)
if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
{ {
if (rtype) if (rtype)
*rtype = 1; *rtype = (t[0] == '*') ? 1 : 2;
if (allow_all == 0) if (allow_all == 0)
{ {
err_badarraysub (s); err_badarraysub (s);

View file

@ -80,6 +80,7 @@ static struct ignorevar histignore =
list. This is different than the user-controlled behaviour; this list. This is different than the user-controlled behaviour; this
becomes zero when we read lines from a file, for example. */ becomes zero when we read lines from a file, for example. */
int remember_on_history = 1; int remember_on_history = 1;
int enable_history_list = 1; /* value for `set -o history' */
/* The number of lines that Bash has added to this history session. The /* The number of lines that Bash has added to this history session. The
difference between the number of the top element in the history list difference between the number of the top element in the history list
@ -234,7 +235,7 @@ bash_history_reinit (interact)
history_expansion = interact != 0; history_expansion = interact != 0;
history_expansion_inhibited = 1; history_expansion_inhibited = 1;
#endif #endif
remember_on_history = interact != 0; remember_on_history = enable_history_list = interact != 0;
history_inhibit_expansion_function = bash_history_inhibit_expansion; history_inhibit_expansion_function = bash_history_inhibit_expansion;
} }

View file

@ -31,6 +31,9 @@
#define HC_IGNBOTH (HC_IGNSPACE|HC_IGNDUPS) #define HC_IGNBOTH (HC_IGNSPACE|HC_IGNDUPS)
extern int remember_on_history; extern int remember_on_history;
extern int enable_history_list; /* value for `set -o history' */
extern int literal_history; /* controlled by `shopt lithist' */
extern int force_append_history;
extern int history_lines_this_session; extern int history_lines_this_session;
extern int history_lines_in_file; extern int history_lines_in_file;
extern int history_expansion; extern int history_expansion;

View file

@ -2357,7 +2357,7 @@ bash_directory_completion_hook (dirname)
if (should_expand_dirname) if (should_expand_dirname)
{ {
new_dirname = savestring (local_dirname); new_dirname = savestring (local_dirname);
wl = expand_prompt_string (new_dirname, 0); /* does the right thing */ wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */
if (wl) if (wl)
{ {
*dirname = string_list (wl); *dirname = string_list (wl);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 1987-2005 Free Software Foundation, Inc. /* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -131,6 +131,7 @@ no_args (list)
if (list) if (list)
{ {
builtin_error (_("too many arguments")); builtin_error (_("too many arguments"));
top_level_cleanup ();
jump_to_top_level (DISCARD); jump_to_top_level (DISCARD);
} }
} }
@ -395,7 +396,10 @@ get_numeric_arg (list, fatal)
if (fatal) if (fatal)
throw_to_top_level (); throw_to_top_level ();
else else
jump_to_top_level (DISCARD); {
top_level_cleanup ();
jump_to_top_level (DISCARD);
}
} }
no_args (list->next); no_args (list->next);
} }
@ -475,7 +479,11 @@ get_working_directory (for_whom)
if (the_current_working_directory == 0) if (the_current_working_directory == 0)
{ {
#if defined (GETCWD_BROKEN)
the_current_working_directory = getcwd (0, PATH_MAX);
#else
the_current_working_directory = getcwd (0, 0); the_current_working_directory = getcwd (0, 0);
#endif
if (the_current_working_directory == 0) if (the_current_working_directory == 0)
{ {
fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"), fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),

View file

@ -67,6 +67,14 @@ int parse_and_execute_level = 0;
static int cat_file __P((REDIRECT *)); static int cat_file __P((REDIRECT *));
#if defined (HISTORY)
static void
set_history_remembering ()
{
remember_on_history = enable_history_list;
}
#endif
/* How to force parse_and_execute () to clean up after itself. */ /* How to force parse_and_execute () to clean up after itself. */
void void
parse_and_execute_cleanup () parse_and_execute_cleanup ()
@ -115,7 +123,10 @@ parse_and_execute (string, from_file, flags)
lreset = flags & SEVAL_RESETLINE; lreset = flags & SEVAL_RESETLINE;
#if defined (HISTORY) #if defined (HISTORY)
unwind_protect_int (remember_on_history); /* can be used in scripts */ if (parse_and_execute_level == 0)
add_unwind_protect (set_history_remembering, (char *)NULL);
else
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY) # if defined (BANG_HISTORY)
if (interactive_shell) if (interactive_shell)
{ {
@ -237,6 +248,7 @@ parse_and_execute (string, from_file, flags)
* parse_and_execute has not been called recursively AND * parse_and_execute has not been called recursively AND
* we're not running a trap AND * we're not running a trap AND
* we have parsed the full command (string == '\0') AND * we have parsed the full command (string == '\0') AND
* we're not going to run the exit trap AND
* we have a simple command without redirections AND * we have a simple command without redirections AND
* the command is not being timed AND * the command is not being timed AND
* the command's return status is not being inverted * the command's return status is not being inverted
@ -247,7 +259,8 @@ parse_and_execute (string, from_file, flags)
running_trap == 0 && running_trap == 0 &&
*bash_input.location.string == '\0' && *bash_input.location.string == '\0' &&
command->type == cm_simple && command->type == cm_simple &&
!command->redirects && !command->value.Simple->redirects && signal_is_trapped (EXIT_TRAP) == 0 &&
command->redirects == 0 && command->value.Simple->redirects == 0 &&
((command->flags & CMD_TIME_PIPELINE) == 0) && ((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0)) ((command->flags & CMD_INVERT_RETURN) == 0))
{ {

View file

@ -1,7 +1,7 @@
This file is printf.def, from which is created printf.c. This file is printf.def, from which is created printf.c.
It implements the builtin "printf" in Bash. It implements the builtin "printf" in Bash.
Copyright (C) 1997-2005 Free Software Foundation, Inc. Copyright (C) 1997-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -49,6 +49,12 @@ $END
# define INT_MIN (-2147483647-1) # define INT_MIN (-2147483647-1)
#endif #endif
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <chartypes.h> #include <chartypes.h>
@ -64,6 +70,10 @@ $END
#include "bashgetopt.h" #include "bashgetopt.h"
#include "common.h" #include "common.h"
#if defined (PRI_MACROS_BROKEN)
# undef PRIdMAX
#endif
#if !defined (PRIdMAX) #if !defined (PRIdMAX)
# if HAVE_LONG_LONG # if HAVE_LONG_LONG
# define PRIdMAX "lld" # define PRIdMAX "lld"
@ -151,6 +161,10 @@ extern int errno;
#define SKIP1 "#'-+ 0" #define SKIP1 "#'-+ 0"
#define LENMODS "hjlLtz" #define LENMODS "hjlLtz"
#ifndef HAVE_ASPRINTF
extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
#endif
static void printf_erange __P((char *)); static void printf_erange __P((char *));
static int printstr __P((char *, char *, int, int, int)); static int printstr __P((char *, char *, int, int, int));
static int tescape __P((char *, char *, int *)); static int tescape __P((char *, char *, int *));

View file

@ -127,14 +127,14 @@ read_builtin (list)
WORD_LIST *list; WORD_LIST *list;
{ {
register char *varname; register char *varname;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code; int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
int input_is_tty, input_is_pipe, unbuffered_read; int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul;
int raw, edit, nchars, silent, have_timeout, fd; int raw, edit, nchars, silent, have_timeout, fd;
unsigned int tmout; unsigned int tmout;
intmax_t intval; intmax_t intval;
char c; char c;
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
char *e, *t, *t1; char *e, *t, *t1, *ps2, *tofree;
struct stat tsb; struct stat tsb;
SHELL_VAR *var; SHELL_VAR *var;
#if defined (ARRAY_VARS) #if defined (ARRAY_VARS)
@ -148,6 +148,7 @@ read_builtin (list)
USE_VAR(size); USE_VAR(size);
USE_VAR(i); USE_VAR(i);
USE_VAR(pass_next); USE_VAR(pass_next);
USE_VAR(print_ps2);
USE_VAR(saw_escape); USE_VAR(saw_escape);
USE_VAR(input_is_pipe); USE_VAR(input_is_pipe);
/* USE_VAR(raw); */ /* USE_VAR(raw); */
@ -163,6 +164,7 @@ read_builtin (list)
USE_VAR(rlind); USE_VAR(rlind);
#endif #endif
USE_VAR(list); USE_VAR(list);
USE_VAR(ps2);
i = 0; /* Index into the string that we are reading. */ i = 0; /* Index into the string that we are reading. */
raw = edit = 0; /* Not reading raw input by default. */ raw = edit = 0; /* Not reading raw input by default. */
@ -386,7 +388,8 @@ read_builtin (list)
setmode (0, O_TEXT); setmode (0, O_TEXT);
#endif #endif
for (eof = retval = 0;;) ps2 = 0;
for (print_ps2 = eof = retval = 0;;)
{ {
#if defined (READLINE) #if defined (READLINE)
if (edit) if (edit)
@ -412,6 +415,15 @@ read_builtin (list)
{ {
#endif #endif
if (print_ps2)
{
if (ps2 == 0)
ps2 = get_string_value ("PS2");
fprintf (stderr, "%s", ps2 ? ps2 : "");
fflush (stderr);
print_ps2 = 0;
}
if (unbuffered_read) if (unbuffered_read)
retval = zread (fd, &c, 1); retval = zread (fd, &c, 1);
else else
@ -440,7 +452,11 @@ read_builtin (list)
{ {
pass_next = 0; pass_next = 0;
if (c == '\n') if (c == '\n')
i--; /* back up over the CTLESC */ {
i--; /* back up over the CTLESC */
if (interactive && input_is_tty && raw == 0)
print_ps2 = 1;
}
else else
goto add_char; goto add_char;
continue; continue;
@ -658,12 +674,13 @@ add_char:
#else #else
/* Check whether or not the number of fields is exactly the same as the /* Check whether or not the number of fields is exactly the same as the
number of variables. */ number of variables. */
tofree = NULL;
if (*input_string) if (*input_string)
{ {
t1 = input_string; t1 = input_string;
t = get_word_from_string (&input_string, ifs_chars, &e); t = get_word_from_string (&input_string, ifs_chars, &e);
if (*input_string == 0) if (*input_string == 0)
input_string = t; tofree = input_string = t;
else else
input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape); input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
} }
@ -678,6 +695,8 @@ add_char:
else else
var = bind_read_variable (list->word->word, input_string); var = bind_read_variable (list->word->word, input_string);
stupidly_hack_special_variables (list->word->word); stupidly_hack_special_variables (list->word->word);
FREE (tofree);
if (var) if (var)
VUNSETATTR (var, att_invisible); VUNSETATTR (var, att_invisible);
xfree (orig_input_string); xfree (orig_input_string);

View file

@ -189,7 +189,7 @@ struct {
{ "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
#endif /* BANG_HISTORY */ #endif /* BANG_HISTORY */
#if defined (HISTORY) #if defined (HISTORY)
{ "history", '\0', &remember_on_history, bash_set_history, (setopt_get_func_t *)NULL }, { "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
#endif #endif
{ "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL }, { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
{ "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
@ -381,13 +381,17 @@ bash_set_history (on_or_off, option_name)
{ {
if (on_or_off == FLAG_ON) if (on_or_off == FLAG_ON)
{ {
enable_history_list = 1;
bash_history_enable (); bash_history_enable ();
if (history_lines_this_session == 0) if (history_lines_this_session == 0)
load_history (); load_history ();
} }
else else
bash_history_disable (); {
return (1 - remember_on_history); enable_history_list = 0;
bash_history_disable ();
}
return (1 - enable_history_list);
} }
#endif #endif
@ -565,7 +569,7 @@ void
reset_shell_options () reset_shell_options ()
{ {
#if defined (HISTORY) #if defined (HISTORY)
remember_on_history = 1; remember_on_history = enable_history_list = 1;
#endif #endif
ignoreeof = 0; ignoreeof = 0;
} }

View file

@ -101,11 +101,14 @@ static void shopt_error __P((char *));
static int set_shellopts_after_change __P((int)); static int set_shellopts_after_change __P((int));
static int set_compatibility_level __P((int));
#if defined (RESTRICTED_SHELL) #if defined (RESTRICTED_SHELL)
static int set_restricted_shell __P((int)); static int set_restricted_shell __P((int));
#endif #endif
static int shopt_login_shell; static int shopt_login_shell;
static int shopt_compat31;
typedef int shopt_set_func_t __P((int)); typedef int shopt_set_func_t __P((int));
@ -121,6 +124,7 @@ static struct {
#if defined (HISTORY) #if defined (HISTORY)
{ "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL }, { "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
#endif #endif
{ "compat31", &shopt_compat31, set_compatibility_level },
{ "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL }, { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
{ "execfail", &no_exit_on_failed_exec, (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 }, { "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
@ -459,6 +463,18 @@ set_shellopts_after_change (mode)
return (0); return (0);
} }
static int
set_compatibility_level (mode)
int mode;
{
/* Need to change logic here as we add more compatibility levels */
if (shopt_compat31)
shell_compatibility_level = 31;
else
shell_compatibility_level = 32;
return 0;
}
#if defined (RESTRICTED_SHELL) #if defined (RESTRICTED_SHELL)
/* Don't allow the value of restricted_shell to be modified. */ /* Don't allow the value of restricted_shell to be modified. */

View file

@ -1,7 +1,7 @@
/* config-bot.h */ /* config-bot.h */
/* modify settings or make new ones based on what autoconf tells us. */ /* modify settings or make new ones based on what autoconf tells us. */
/* Copyright (C) 1989-2002 Free Software Foundation, Inc. /* Copyright (C) 1989-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -70,9 +70,11 @@
# define TERMIOS_MISSING # define TERMIOS_MISSING
#endif #endif
/* If we have a getcwd(3), but it calls popen(), #undef HAVE_GETCWD so /* If we have a getcwd(3), but one that does not dynamically allocate memory,
the replacement in getcwd.c will be built. */ #undef HAVE_GETCWD so the replacement in getcwd.c will be built. We do
#if defined (HAVE_GETCWD) && defined (GETCWD_BROKEN) not do this on Solaris, because their implementation of loopback mounts
breaks the traditional file system assumptions that getcwd uses. */
#if defined (HAVE_GETCWD) && defined (GETCWD_BROKEN) && !defined (SOLARIS)
# undef HAVE_GETCWD # undef HAVE_GETCWD
#endif #endif

View file

@ -1,6 +1,6 @@
/* config.h -- Configuration file for bash. */ /* config.h -- Configuration file for bash. */
/* Copyright (C) 1987-2006 Free Software Foundation, Inc. /* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -413,6 +413,8 @@
#undef HAVE_DECL_STRTOLD #undef HAVE_DECL_STRTOLD
#undef PRI_MACROS_BROKEN
#undef STRTOLD_BROKEN #undef STRTOLD_BROKEN
/* Define if WCONTINUED is defined in system headers, but rejected by waitpid */ /* Define if WCONTINUED is defined in system headers, but rejected by waitpid */
@ -1006,6 +1008,9 @@
/* Define if you have the `dcgettext' function. */ /* Define if you have the `dcgettext' function. */
#undef HAVE_DCGETTEXT #undef HAVE_DCGETTEXT
/* Define if you have the `localeconv' function. */
#undef HAVE_LOCALECONV
/* Define if your system has a working `malloc' function. */ /* Define if your system has a working `malloc' function. */
/* #undef HAVE_MALLOC */ /* #undef HAVE_MALLOC */

5
configure vendored
View file

@ -4871,7 +4871,7 @@ _ACEOF
# static version specified as -llibname to override the # static version specified as -llibname to override the
# dynamic version # dynamic version
case "${host_os}" in case "${host_os}" in
darwin8*) READLINE_LIB='${READLINE_LIBRARY}' ;; darwin[89]*) READLINE_LIB='${READLINE_LIBRARY}' ;;
*) READLINE_LIB=-lreadline ;; *) READLINE_LIB=-lreadline ;;
esac esac
fi fi
@ -27316,7 +27316,8 @@ sco3.2v5*) LOCAL_CFLAGS="-b elf -DWAITPID_BROKEN -DPATH_MAX=1024" ;;
sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;; sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;;
sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;; sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;;
sunos4*) LOCAL_CFLAGS=-DSunOS4 ;; sunos4*) LOCAL_CFLAGS=-DSunOS4 ;;
solaris2.5*) LOCAL_CFLAGS=-DSunOS5 ;; solaris2.5*) LOCAL_CFLAGS="-DSunOS5 -DSOLARIS" ;;
solaris2*) LOCAL_CFLAGS=-DSOLARIS ;;
lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;;
linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading
case "`uname -r`" in case "`uname -r`" in

View file

@ -5,7 +5,7 @@ dnl report bugs to chet@po.cwru.edu
dnl dnl
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
# Copyright (C) 1987-2006 Free Software Foundation, Inc. # Copyright (C) 1987-2007 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -518,7 +518,7 @@ if test $opt_readline = yes; then
# static version specified as -llibname to override the # static version specified as -llibname to override the
# dynamic version # dynamic version
case "${host_os}" in case "${host_os}" in
darwin8*) READLINE_LIB='${READLINE_LIBRARY}' ;; darwin[[89]]*) READLINE_LIB='${READLINE_LIBRARY}' ;;
*) READLINE_LIB=-lreadline ;; *) READLINE_LIB=-lreadline ;;
esac esac
fi fi
@ -991,7 +991,8 @@ sco3.2v5*) LOCAL_CFLAGS="-b elf -DWAITPID_BROKEN -DPATH_MAX=1024" ;;
sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;; sco3.2v4*) LOCAL_CFLAGS="-DMUST_UNBLOCK_CHLD -DPATH_MAX=1024" ;;
sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;; sco3.2*) LOCAL_CFLAGS=-DMUST_UNBLOCK_CHLD ;;
sunos4*) LOCAL_CFLAGS=-DSunOS4 ;; sunos4*) LOCAL_CFLAGS=-DSunOS4 ;;
solaris2.5*) LOCAL_CFLAGS=-DSunOS5 ;; solaris2.5*) LOCAL_CFLAGS="-DSunOS5 -DSOLARIS" ;;
solaris2*) LOCAL_CFLAGS=-DSOLARIS ;;
lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;; lynxos*) LOCAL_CFLAGS=-DRECYCLES_PIDS ;;
linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading linux*) LOCAL_LDFLAGS=-rdynamic # allow dynamic loading
case "`uname -r`" in case "`uname -r`" in

View file

@ -7977,6 +7977,12 @@ attempts to save all lines of a multiple-line
command in the same history entry. This allows command in the same history entry. This allows
easy re-editing of multi-line commands. easy re-editing of multi-line commands.
.TP 8 .TP 8
.B compat31
If set,
.B bash
changes its behavior to that of version 3.1 with respect to quoted
arguments to the conditional command's =~ operator.
.TP 8
.B dotglob .B dotglob
If set, If set,
.B bash .B bash

View file

@ -3598,6 +3598,11 @@ attempts to save all lines of a multiple-line
command in the same history entry. This allows command in the same history entry. This allows
easy re-editing of multi-line commands. easy re-editing of multi-line commands.
@item compat31
If set, Bash
changes its behavior to that of version 3.1 with respect to quoted
arguments to the conditional command's =~ operator.
@item dotglob @item dotglob
If set, Bash includes filenames beginning with a `.' in If set, Bash includes filenames beginning with a `.' in
the results of filename expansion. the results of filename expansion.

View file

@ -1,6 +1,6 @@
/* execute_cmd.c -- Execute a COMMAND structure. */ /* execute_cmd.c -- Execute a COMMAND structure. */
/* Copyright (C) 1987-2005 Free Software Foundation, Inc. /* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -501,8 +501,15 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
volatile int last_pid; volatile int last_pid;
volatile int save_line_number; volatile int save_line_number;
#if 0
if (command == 0 || breaking || continuing || read_but_dont_execute) if (command == 0 || breaking || continuing || read_but_dont_execute)
return (EXECUTION_SUCCESS); return (EXECUTION_SUCCESS);
#else
if (breaking || continuing)
return (last_command_exit_value);
if (command == 0 || read_but_dont_execute)
return (EXECUTION_SUCCESS);
#endif
QUIT; QUIT;
run_pending_traps (); run_pending_traps ();
@ -614,7 +621,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
cleanup_redirects (redirection_undo_list); cleanup_redirects (redirection_undo_list);
redirection_undo_list = (REDIRECT *)NULL; redirection_undo_list = (REDIRECT *)NULL;
dispose_exec_redirects (); dispose_exec_redirects ();
return (EXECUTION_FAILURE); return (last_command_exit_value = EXECUTION_FAILURE);
} }
if (redirection_undo_list) if (redirection_undo_list)
@ -2546,7 +2553,8 @@ execute_cond_node (cond)
arg1 = cond_expand_word (cond->left->op, 0); arg1 = cond_expand_word (cond->left->op, 0);
if (arg1 == 0) if (arg1 == 0)
arg1 = nullstr; arg1 = nullstr;
arg2 = cond_expand_word (cond->right->op, patmatch||rmatch); arg2 = cond_expand_word (cond->right->op,
(rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0));
if (arg2 == 0) if (arg2 == 0)
arg2 = nullstr; arg2 = nullstr;
@ -3050,6 +3058,11 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (command_line == 0) if (command_line == 0)
command_line = savestring (the_printed_command_except_trap); command_line = savestring (the_printed_command_except_trap);
#if defined (PROCESS_SUBSTITUTION)
if ((subshell_environment & SUBSHELL_COMSUB) && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0)
simple_command->flags &= ~CMD_NO_FORK;
#endif
execute_disk_command (words, simple_command->redirects, command_line, execute_disk_command (words, simple_command->redirects, command_line,
pipe_in, pipe_out, async, fds_to_close, pipe_in, pipe_out, async, fds_to_close,
simple_command->flags); simple_command->flags);
@ -3875,6 +3888,8 @@ initialize_subshell ()
shell_variables = shell_variables->down; shell_variables = shell_variables->down;
clear_unwind_protect_list (0); clear_unwind_protect_list (0);
/* XXX -- are there other things we should be resetting here? */
parse_and_execute_level = 0; /* nothing left to restore it */
/* We're no longer inside a shell function. */ /* We're no longer inside a shell function. */
variable_context = return_catch_flag = 0; variable_context = return_catch_flag = 0;

7
expr.c
View file

@ -286,6 +286,8 @@ expr_unwind ()
free (expr_stack[expr_depth]); free (expr_stack[expr_depth]);
} }
free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */ free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
noeval = 0; /* XXX */
} }
static void static void
@ -319,6 +321,7 @@ evalexp (expr, validp)
procenv_t oevalbuf; procenv_t oevalbuf;
val = 0; val = 0;
noeval = 0;
FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf)); FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
@ -517,7 +520,8 @@ expcond ()
set_noeval = 1; set_noeval = 1;
noeval++; noeval++;
} }
val2 = explor ();
val2 = expcond ();
if (set_noeval) if (set_noeval)
noeval--; noeval--;
rval = cval ? val1 : val2; rval = cval ? val1 : val2;
@ -929,6 +933,7 @@ expr_streval (tok, e)
if (interactive_shell) if (interactive_shell)
{ {
expr_unwind (); expr_unwind ();
top_level_cleanup ();
jump_to_top_level (DISCARD); jump_to_top_level (DISCARD);
} }
else else

View file

@ -308,7 +308,7 @@ search_for_command (pathname)
if (hashed_file && (posixly_correct || check_hashed_filenames)) if (hashed_file && (posixly_correct || check_hashed_filenames))
{ {
st = file_status (hashed_file); st = file_status (hashed_file);
if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0) if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE))
{ {
phash_remove (pathname); phash_remove (pathname);
free (hashed_file); free (hashed_file);

75
jobs.c
View file

@ -250,6 +250,7 @@ static int job_exit_status __P((int));
static int job_exit_signal __P((int)); static int job_exit_signal __P((int));
static int set_job_status_and_cleanup __P((int)); static int set_job_status_and_cleanup __P((int));
static WAIT job_signal_status __P((int));
static WAIT raw_job_exit_status __P((int)); static WAIT raw_job_exit_status __P((int));
static void notify_of_job_status __P((void)); static void notify_of_job_status __P((void));
@ -783,11 +784,13 @@ reset_job_indices ()
if (jobs[js.j_firstj] == 0) if (jobs[js.j_firstj] == 0)
{ {
old = js.j_firstj++; old = js.j_firstj++;
if (old >= js.j_jobslots)
old = js.j_jobslots - 1;
while (js.j_firstj != old) while (js.j_firstj != old)
{ {
if (js.j_firstj >= js.j_jobslots) if (js.j_firstj >= js.j_jobslots)
js.j_firstj = 0; js.j_firstj = 0;
if (jobs[js.j_firstj]) if (jobs[js.j_firstj] || js.j_firstj == old) /* needed if old == 0 */
break; break;
js.j_firstj++; js.j_firstj++;
} }
@ -797,11 +800,13 @@ reset_job_indices ()
if (jobs[js.j_lastj] == 0) if (jobs[js.j_lastj] == 0)
{ {
old = js.j_lastj--; old = js.j_lastj--;
if (old < 0)
old = 0;
while (js.j_lastj != old) while (js.j_lastj != old)
{ {
if (js.j_lastj < 0) if (js.j_lastj < 0)
js.j_lastj = js.j_jobslots - 1; js.j_lastj = js.j_jobslots - 1;
if (jobs[js.j_lastj]) if (jobs[js.j_lastj] || js.j_lastj == old) /* needed if old == js.j_jobslots */
break; break;
js.j_lastj--; js.j_lastj--;
} }
@ -963,7 +968,11 @@ compact_jobs_list (flags)
reap_dead_jobs (); reap_dead_jobs ();
realloc_jobs_list (); realloc_jobs_list ();
return (js.j_lastj); #ifdef DEBUG
itrace("compact_jobs_list: returning %d", (js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0);
#endif
return ((js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0);
} }
/* Delete the job at INDEX from the job list. Must be called /* Delete the job at INDEX from the job list. Must be called
@ -984,8 +993,6 @@ delete_job (job_index, dflags)
temp = jobs[job_index]; temp = jobs[job_index];
if (temp == 0) if (temp == 0)
return; return;
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
if ((dflags & DEL_NOBGPID) == 0) if ((dflags & DEL_NOBGPID) == 0)
{ {
@ -1028,6 +1035,9 @@ delete_job (job_index, dflags)
js.j_firstj = js.j_lastj = 0; js.j_firstj = js.j_lastj = 0;
else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0) else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0)
reset_job_indices (); reset_job_indices ();
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
} }
/* Must be called with SIGCHLD blocked. */ /* Must be called with SIGCHLD blocked. */
@ -2210,6 +2220,26 @@ process_exit_status (status)
return (EXECUTION_SUCCESS); return (EXECUTION_SUCCESS);
} }
static WAIT
job_signal_status (job)
int job;
{
register PROCESS *p;
WAIT s;
p = jobs[job]->pipe;
do
{
s = p->status;
if (WIFSIGNALED(s) || WIFSTOPPED(s))
break;
p = p->next;
}
while (p != jobs[job]->pipe);
return s;
}
/* Return the exit status of the last process in the pipeline for job JOB. /* Return the exit status of the last process in the pipeline for job JOB.
This is the exit status of the entire job. */ This is the exit status of the entire job. */
static WAIT static WAIT
@ -2292,11 +2322,14 @@ wait_for (pid)
to finish. We don't want the shell to exit if an interrupt is to finish. We don't want the shell to exit if an interrupt is
received, only if one of the jobs run is killed via SIGINT. If received, only if one of the jobs run is killed via SIGINT. If
job control is not set, the job will be run in the same pgrp as job control is not set, the job will be run in the same pgrp as
the shell, and the shell will see any signals the job gets. */ the shell, and the shell will see any signals the job gets. In
fact, we want this set every time the waiting shell and the waited-
for process are in the same process group, including command
substitution. */
/* This is possibly a race condition -- should it go in stop_pipeline? */ /* This is possibly a race condition -- should it go in stop_pipeline? */
wait_sigint_received = 0; wait_sigint_received = 0;
if (job_control == 0) if (job_control == 0 || (subshell_environment&SUBSHELL_COMSUB))
{ {
old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
if (old_sigint_handler == SIG_IGN) if (old_sigint_handler == SIG_IGN)
@ -2442,15 +2475,7 @@ if (job == NO_JOB)
to a signal. We might want to change this later to just check to a signal. We might want to change this later to just check
the last process in the pipeline. If no process exits due to a the last process in the pipeline. If no process exits due to a
signal, S is left as the status of the last job in the pipeline. */ signal, S is left as the status of the last job in the pipeline. */
p = jobs[job]->pipe; s = job_signal_status (job);
do
{
s = p->status;
if (WIFSIGNALED(s) || WIFSTOPPED(s))
break;
p = p->next;
}
while (p != jobs[job]->pipe);
if (WIFSIGNALED (s) || WIFSTOPPED (s)) if (WIFSIGNALED (s) || WIFSTOPPED (s))
{ {
@ -2484,6 +2509,24 @@ if (job == NO_JOB)
} }
} }
} }
else if ((subshell_environment & SUBSHELL_COMSUB) && wait_sigint_received)
{
/* If waiting for a job in a subshell started to do command
substitution, simulate getting and being killed by the SIGINT to
pass the status back to our parent. */
s = job_signal_status (job);
if (WIFSIGNALED (s) && WTERMSIG (s) == SIGINT && signal_is_trapped (SIGINT) == 0)
{
UNBLOCK_CHILD (oset);
restore_sigint_handler ();
old_sigint_handler = set_signal_handler (SIGINT, SIG_DFL);
if (old_sigint_handler == SIG_IGN)
restore_sigint_handler ();
else
kill (getpid (), SIGINT);
}
}
/* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
signal handler path */ signal handler path */

View file

@ -428,7 +428,7 @@ get_y_or_n (for_pager)
return (1); return (1);
if (c == 'n' || c == 'N' || c == RUBOUT) if (c == 'n' || c == 'N' || c == RUBOUT)
return (0); return (0);
if (c == ABORT_CHAR) if (c == ABORT_CHAR || c < 0)
_rl_abort_internal (); _rl_abort_internal ();
if (for_pager && (c == NEWLINE || c == RETURN)) if (for_pager && (c == NEWLINE || c == RETURN))
return (2); return (2);

View file

@ -391,14 +391,14 @@ rl_expand_prompt (prompt)
t = ++p; t = ++p;
local_prompt = expand_prompt (p, &prompt_visible_length, local_prompt = expand_prompt (p, &prompt_visible_length,
&prompt_last_invisible, &prompt_last_invisible,
(int *)NULL, &prompt_invis_chars_first_line,
&prompt_physical_chars); &prompt_physical_chars);
c = *t; *t = '\0'; c = *t; *t = '\0';
/* The portion of the prompt string up to and including the /* The portion of the prompt string up to and including the
final newline is now null-terminated. */ final newline is now null-terminated. */
local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length, local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length,
(int *)NULL, (int *)NULL,
&prompt_invis_chars_first_line, (int *)NULL,
(int *)NULL); (int *)NULL);
*t = c; *t = c;
local_prompt_len = local_prompt ? strlen (local_prompt) : 0; local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
@ -561,6 +561,17 @@ rl_redisplay ()
wrap_offset = prompt_invis_chars_first_line = 0; wrap_offset = prompt_invis_chars_first_line = 0;
} }
#if defined (HANDLE_MULTIBYTE)
#define CHECK_INV_LBREAKS() \
do { \
if (newlines >= (inv_lbsize - 2)) \
{ \
inv_lbsize *= 2; \
inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
_rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \
} \
} while (0)
#else
#define CHECK_INV_LBREAKS() \ #define CHECK_INV_LBREAKS() \
do { \ do { \
if (newlines >= (inv_lbsize - 2)) \ if (newlines >= (inv_lbsize - 2)) \
@ -569,6 +580,7 @@ rl_redisplay ()
inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
} \ } \
} while (0) } while (0)
#endif /* HANDLE_MULTIBYTE */
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
#define CHECK_LPOS() \ #define CHECK_LPOS() \
@ -898,6 +910,10 @@ rl_redisplay ()
second and subsequent lines start at inv_lbreaks[N], offset by second and subsequent lines start at inv_lbreaks[N], offset by
OFFSET (which has already been calculated above). */ OFFSET (which has already been calculated above). */
#define INVIS_FIRST() (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset)
#define WRAP_OFFSET(line, offset) ((line == 0) \
? (offset ? INVIS_FIRST() : 0) \
: ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0))
#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0) #define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)
#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) #define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) #define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l])
@ -932,7 +948,13 @@ rl_redisplay ()
_rl_last_c_pos != o_cpos && _rl_last_c_pos != o_cpos &&
_rl_last_c_pos > wrap_offset && _rl_last_c_pos > wrap_offset &&
o_cpos < prompt_last_invisible) o_cpos < prompt_last_invisible)
_rl_last_c_pos -= wrap_offset; _rl_last_c_pos -= prompt_invis_chars_first_line; /* XXX - was wrap_offset */
else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth &&
(MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
cpos_adjusted == 0 &&
_rl_last_c_pos != o_cpos &&
_rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line))
_rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line);
/* If this is the line with the prompt, we might need to /* If this is the line with the prompt, we might need to
compensate for invisible characters in the new line. Do compensate for invisible characters in the new line. Do
@ -1036,7 +1058,7 @@ rl_redisplay ()
tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset; tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset;
else else
tx = nleft; tx = nleft;
if (_rl_last_c_pos > tx) if (tx >= 0 && _rl_last_c_pos > tx)
{ {
_rl_backspace (_rl_last_c_pos - tx); /* XXX */ _rl_backspace (_rl_last_c_pos - tx); /* XXX */
_rl_last_c_pos = tx; _rl_last_c_pos = tx;
@ -1192,7 +1214,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
int current_line, omax, nmax, inv_botlin; int current_line, omax, nmax, inv_botlin;
{ {
register char *ofd, *ols, *oe, *nfd, *nls, *ne; register char *ofd, *ols, *oe, *nfd, *nls, *ne;
int temp, lendiff, wsatend, od, nd; int temp, lendiff, wsatend, od, nd, twidth, o_cpos;
int current_invis_chars; int current_invis_chars;
int col_lendiff, col_temp; int col_lendiff, col_temp;
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
@ -1208,7 +1230,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
temp = _rl_last_c_pos; temp = _rl_last_c_pos;
else else
temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); temp = _rl_last_c_pos - WRAP_OFFSET (_rl_last_v_pos, visible_wrap_offset);
if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
&& _rl_last_v_pos == current_line - 1) && _rl_last_v_pos == current_line - 1)
{ {
@ -1453,6 +1475,8 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
_rl_last_c_pos = lendiff; _rl_last_c_pos = lendiff;
} }
o_cpos = _rl_last_c_pos;
/* When this function returns, _rl_last_c_pos is correct, and an absolute /* When this function returns, _rl_last_c_pos is correct, and an absolute
cursor postion in multibyte mode, but a buffer index when not in a cursor postion in multibyte mode, but a buffer index when not in a
multibyte locale. */ multibyte locale. */
@ -1462,7 +1486,9 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
/* We need to indicate that the cursor position is correct in the presence of /* We need to indicate that the cursor position is correct in the presence of
invisible characters in the prompt string. Let's see if setting this when invisible characters in the prompt string. Let's see if setting this when
we make sure we're at the end of the drawn prompt string works. */ we make sure we're at the end of the drawn prompt string works. */
if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 && _rl_last_c_pos == prompt_physical_chars) if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 &&
(_rl_last_c_pos > 0 || o_cpos > 0) &&
_rl_last_c_pos == prompt_physical_chars)
cpos_adjusted = 1; cpos_adjusted = 1;
#endif #endif
#endif #endif
@ -1506,11 +1532,31 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
{ {
/* Non-zero if we're increasing the number of lines. */ /* Non-zero if we're increasing the number of lines. */
int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin; int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
/* If col_lendiff is > 0, implying that the new string takes up more
screen real estate than the old, but lendiff is < 0, meaning that it
takes fewer bytes, we need to just output the characters starting
from the first difference. These will overwrite what is on the
display, so there's no reason to do a smart update. This can really
only happen in a multibyte environment. */
if (lendiff < 0)
{
_rl_output_some_chars (nfd, temp);
_rl_last_c_pos += _rl_col_width (nfd, 0, temp);
/* If nfd begins before any invisible characters in the prompt,
adjust _rl_last_c_pos to account for wrap_offset and set
cpos_adjusted to let the caller know. */
if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
{
_rl_last_c_pos -= wrap_offset;
cpos_adjusted = 1;
}
return;
}
/* Sometimes it is cheaper to print the characters rather than /* Sometimes it is cheaper to print the characters rather than
use the terminal's capabilities. If we're growing the number use the terminal's capabilities. If we're growing the number
of lines, make sure we actually cause the new line to wrap of lines, make sure we actually cause the new line to wrap
around on auto-wrapping terminals. */ around on auto-wrapping terminals. */
if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl)) else if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl))
{ {
/* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
_rl_horizontal_scroll_mode == 1, inserting the characters with _rl_horizontal_scroll_mode == 1, inserting the characters with
@ -1533,11 +1579,16 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
} }
else else
{ {
/* We have horizontal scrolling and we are not inserting at
the end. We have invisible characters in this line. This
is a dumb update. */
_rl_output_some_chars (nfd, temp); _rl_output_some_chars (nfd, temp);
_rl_last_c_pos += col_temp; _rl_last_c_pos += col_temp;
/* If nfd begins before any invisible characters in the prompt,
adjust _rl_last_c_pos to account for wrap_offset and set
cpos_adjusted to let the caller know. */
if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
{
_rl_last_c_pos -= wrap_offset;
cpos_adjusted = 1;
}
return; return;
} }
/* Copy (new) chars to screen from first diff to last match. */ /* Copy (new) chars to screen from first diff to last match. */
@ -1545,15 +1596,15 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
if ((temp - lendiff) > 0) if ((temp - lendiff) > 0)
{ {
_rl_output_some_chars (nfd + lendiff, temp - lendiff); _rl_output_some_chars (nfd + lendiff, temp - lendiff);
#if 1
/* XXX -- this bears closer inspection. Fixes a redisplay bug /* XXX -- this bears closer inspection. Fixes a redisplay bug
reported against bash-3.0-alpha by Andreas Schwab involving reported against bash-3.0-alpha by Andreas Schwab involving
multibyte characters and prompt strings with invisible multibyte characters and prompt strings with invisible
characters, but was previously disabled. */ characters, but was previously disabled. */
_rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
#else twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff);
_rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff); else
#endif twidth = temp - lendiff;
_rl_last_c_pos += twidth;
} }
} }
else else
@ -1586,8 +1637,22 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
temp = nls - nfd; temp = nls - nfd;
if (temp > 0) if (temp > 0)
{ {
/* If nfd begins at the prompt, or before the invisible
characters in the prompt, we need to adjust _rl_last_c_pos
in a multibyte locale to account for the wrap offset and
set cpos_adjusted accordingly. */
_rl_output_some_chars (nfd, temp); _rl_output_some_chars (nfd, temp);
_rl_last_c_pos += _rl_col_width (nfd, 0, temp);; if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
_rl_last_c_pos += _rl_col_width (nfd, 0, temp);
if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
{
_rl_last_c_pos -= wrap_offset;
cpos_adjusted = 1;
}
}
else
_rl_last_c_pos += temp;
} }
} }
/* Otherwise, print over the existing material. */ /* Otherwise, print over the existing material. */
@ -1595,8 +1660,20 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
{ {
if (temp > 0) if (temp > 0)
{ {
/* If nfd begins at the prompt, or before the invisible
characters in the prompt, we need to adjust _rl_last_c_pos
in a multibyte locale to account for the wrap offset and
set cpos_adjusted accordingly. */
_rl_output_some_chars (nfd, temp); _rl_output_some_chars (nfd, temp);
_rl_last_c_pos += col_temp; /* XXX */ _rl_last_c_pos += col_temp; /* XXX */
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
{
_rl_last_c_pos -= wrap_offset;
cpos_adjusted = 1;
}
}
} }
lendiff = (oe - old) - (ne - new); lendiff = (oe - old) - (ne - new);
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
@ -1721,7 +1798,7 @@ _rl_move_cursor_relative (new, data)
int woff; /* number of invisible chars on current line */ int woff; /* number of invisible chars on current line */
int cpos, dpos; /* current and desired cursor positions */ int cpos, dpos; /* current and desired cursor positions */
woff = W_OFFSET (_rl_last_v_pos, wrap_offset); woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset);
cpos = _rl_last_c_pos; cpos = _rl_last_c_pos;
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
/* If we have multibyte characters, NEW is indexed by the buffer point in /* If we have multibyte characters, NEW is indexed by the buffer point in
@ -1732,7 +1809,14 @@ _rl_move_cursor_relative (new, data)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{ {
dpos = _rl_col_width (data, 0, new); dpos = _rl_col_width (data, 0, new);
if (dpos > prompt_last_invisible) /* XXX - don't use woff here */ /* Use NEW when comparing against the last invisible character in the
prompt string, since they're both buffer indices and DPOS is a
desired display position. */
if ((new > prompt_last_invisible) || /* XXX - don't use woff here */
(prompt_physical_chars > _rl_screenwidth &&
_rl_last_v_pos == prompt_last_screen_line &&
wrap_offset != woff &&
new > (prompt_last_invisible-_rl_screenwidth-wrap_offset)))
{ {
dpos -= woff; dpos -= woff;
/* Since this will be assigned to _rl_last_c_pos at the end (more /* Since this will be assigned to _rl_last_c_pos at the end (more
@ -2380,6 +2464,8 @@ _rl_col_width (str, start, end)
if (end <= start) if (end <= start)
return 0; return 0;
if (MB_CUR_MAX == 1 || rl_byte_oriented)
return (end - start);
memset (&ps, 0, sizeof (mbstate_t)); memset (&ps, 0, sizeof (mbstate_t));

View file

@ -133,8 +133,11 @@ rl_get_char (key)
return (0); return (0);
*key = ibuffer[pop_index++]; *key = ibuffer[pop_index++];
#if 0
if (pop_index >= ibuffer_len) if (pop_index >= ibuffer_len)
#else
if (pop_index > ibuffer_len)
#endif
pop_index = 0; pop_index = 0;
return (1); return (1);
@ -151,7 +154,7 @@ _rl_unget_char (key)
{ {
pop_index--; pop_index--;
if (pop_index < 0) if (pop_index < 0)
pop_index = ibuffer_len - 1; pop_index = ibuffer_len;
ibuffer[pop_index] = key; ibuffer[pop_index] = key;
return (1); return (1);
} }
@ -250,7 +253,8 @@ rl_gather_tyi ()
while (chars_avail--) while (chars_avail--)
{ {
k = (*rl_getc_function) (rl_instream); k = (*rl_getc_function) (rl_instream);
rl_stuff_char (k); if (rl_stuff_char (k) == 0)
break; /* some problem; no more room */
if (k == NEWLINE || k == RETURN) if (k == NEWLINE || k == RETURN)
break; break;
} }
@ -373,7 +377,11 @@ rl_stuff_char (key)
RL_SETSTATE (RL_STATE_INPUTPENDING); RL_SETSTATE (RL_STATE_INPUTPENDING);
} }
ibuffer[push_index++] = key; ibuffer[push_index++] = key;
#if 0
if (push_index >= ibuffer_len) if (push_index >= ibuffer_len)
#else
if (push_index > ibuffer_len)
#endif
push_index = 0; push_index = 0;
return 1; return 1;
@ -513,7 +521,7 @@ _rl_read_mbchar (mbchar, size)
char *mbchar; char *mbchar;
int size; int size;
{ {
int mb_len = 0; int mb_len, c;
size_t mbchar_bytes_length; size_t mbchar_bytes_length;
wchar_t wc; wchar_t wc;
mbstate_t ps, ps_back; mbstate_t ps, ps_back;
@ -521,12 +529,18 @@ _rl_read_mbchar (mbchar, size)
memset(&ps, 0, sizeof (mbstate_t)); memset(&ps, 0, sizeof (mbstate_t));
memset(&ps_back, 0, sizeof (mbstate_t)); memset(&ps_back, 0, sizeof (mbstate_t));
mb_len = 0;
while (mb_len < size) while (mb_len < size)
{ {
RL_SETSTATE(RL_STATE_MOREINPUT); RL_SETSTATE(RL_STATE_MOREINPUT);
mbchar[mb_len++] = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
break;
mbchar[mb_len++] = c;
mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps); mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
if (mbchar_bytes_length == (size_t)(-1)) if (mbchar_bytes_length == (size_t)(-1))
break; /* invalid byte sequence for the current locale */ break; /* invalid byte sequence for the current locale */
@ -564,7 +578,7 @@ _rl_read_mbstring (first, mb, mlen)
c = first; c = first;
memset (mb, 0, mlen); memset (mb, 0, mlen);
for (i = 0; i < mlen; i++) for (i = 0; c >= 0 && i < mlen; i++)
{ {
mb[i] = (char)c; mb[i] = (char)c;
memset (&ps, 0, sizeof (mbstate_t)); memset (&ps, 0, sizeof (mbstate_t));

View file

@ -328,7 +328,14 @@ _rl_isearch_dispatch (cxt, c)
f = (rl_command_func_t *)NULL; f = (rl_command_func_t *)NULL;
/* Translate the keys we do something with to opcodes. */ if (c < 0)
{
cxt->sflags |= SF_FAILED;
cxt->history_pos = cxt->last_found_line;
return -1;
}
/* Translate the keys we do something with to opcodes. */
if (c >= 0 && _rl_keymap[c].type == ISFUNC) if (c >= 0 && _rl_keymap[c].type == ISFUNC)
{ {
f = _rl_keymap[c].function; f = _rl_keymap[c].function;

View file

@ -146,6 +146,8 @@ _rl_arg_dispatch (cxt, c)
rl_restore_prompt (); rl_restore_prompt ();
rl_clear_message (); rl_clear_message ();
RL_UNSETSTATE(RL_STATE_NUMERICARG); RL_UNSETSTATE(RL_STATE_NUMERICARG);
if (key < 0)
return -1;
return (_rl_dispatch (key, _rl_keymap)); return (_rl_dispatch (key, _rl_keymap));
} }
} }

View file

@ -645,6 +645,11 @@ _rl_dispatch_callback (cxt)
if ((cxt->flags & KSEQ_DISPATCHED) == 0) if ((cxt->flags & KSEQ_DISPATCHED) == 0)
{ {
nkey = _rl_subseq_getchar (cxt->okey); nkey = _rl_subseq_getchar (cxt->okey);
if (nkey < 0)
{
_rl_abort_internal ();
return -1;
}
r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg); r = _rl_dispatch_subseq (nkey, cxt->dmap, cxt->subseq_arg);
cxt->flags |= KSEQ_DISPATCHED; cxt->flags |= KSEQ_DISPATCHED;
} }

View file

@ -857,6 +857,9 @@ _rl_insert_next (count)
c = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
return -1;
#if defined (HANDLE_SIGNALS) #if defined (HANDLE_SIGNALS)
if (RL_ISSTATE (RL_STATE_CALLBACK) == 0) if (RL_ISSTATE (RL_STATE_CALLBACK) == 0)
_rl_restore_tty_signals (); _rl_restore_tty_signals ();
@ -1520,6 +1523,9 @@ _rl_char_search (count, fdir, bdir)
mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX); mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX);
if (mb_len <= 0)
return -1;
if (count < 0) if (count < 0)
return (_rl_char_search_internal (-count, bdir, mbchar, mb_len)); return (_rl_char_search_internal (-count, bdir, mbchar, mb_len));
else else
@ -1536,6 +1542,9 @@ _rl_char_search (count, fdir, bdir)
c = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
return -1;
if (count < 0) if (count < 0)
return (_rl_char_search_internal (-count, bdir, c)); return (_rl_char_search_internal (-count, bdir, c));
else else

View file

@ -886,6 +886,13 @@ rl_vi_domove (key, nextkey)
RL_SETSTATE(RL_STATE_MOREINPUT); RL_SETSTATE(RL_STATE_MOREINPUT);
c = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
{
*nextkey = 0;
return -1;
}
*nextkey = c; *nextkey = c;
if (!member (c, vi_motion)) if (!member (c, vi_motion))
@ -902,6 +909,11 @@ rl_vi_domove (key, nextkey)
RL_SETSTATE(RL_STATE_MOREINPUT); RL_SETSTATE(RL_STATE_MOREINPUT);
c = rl_read_key (); /* real command */ c = rl_read_key (); /* real command */
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
{
*nextkey = 0;
return -1;
}
*nextkey = c; *nextkey = c;
} }
else if (key == c && (key == 'd' || key == 'y' || key == 'c')) else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
@ -1224,14 +1236,22 @@ static int
_rl_vi_callback_char_search (data) _rl_vi_callback_char_search (data)
_rl_callback_generic_arg *data; _rl_callback_generic_arg *data;
{ {
int c;
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
_rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
#else #else
RL_SETSTATE(RL_STATE_MOREINPUT); RL_SETSTATE(RL_STATE_MOREINPUT);
_rl_vi_last_search_char = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
#endif #endif
if (c <= 0)
return -1;
#if !defined (HANDLE_MULTIBYTE)
_rl_vi_last_search_char = c;
#endif
_rl_callback_func = 0; _rl_callback_func = 0;
_rl_want_redisplay = 1; _rl_want_redisplay = 1;
@ -1247,6 +1267,7 @@ int
rl_vi_char_search (count, key) rl_vi_char_search (count, key)
int count, key; int count, key;
{ {
int c;
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
static char *target; static char *target;
static int tlen; static int tlen;
@ -1293,11 +1314,17 @@ rl_vi_char_search (count, key)
else else
{ {
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
_rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
if (c <= 0)
return -1;
_rl_vi_last_search_mblen = c;
#else #else
RL_SETSTATE(RL_STATE_MOREINPUT); RL_SETSTATE(RL_STATE_MOREINPUT);
_rl_vi_last_search_char = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
return -1;
_rl_vi_last_search_char = c;
#endif #endif
} }
} }
@ -1467,6 +1494,9 @@ _rl_vi_callback_getchar (mb, mlen)
c = rl_read_key (); c = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (c < 0)
return -1;
#if defined (HANDLE_MULTIBYTE) #if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
c = _rl_read_mbstring (c, mb, mlen); c = _rl_read_mbstring (c, mb, mlen);
@ -1485,6 +1515,9 @@ _rl_vi_callback_change_char (data)
_rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
if (c < 0)
return -1;
_rl_callback_func = 0; _rl_callback_func = 0;
_rl_want_redisplay = 1; _rl_want_redisplay = 1;
@ -1516,6 +1549,9 @@ rl_vi_change_char (count, key)
else else
_rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
if (c < 0)
return -1;
return (_rl_vi_change_char (count, c, mb)); return (_rl_vi_change_char (count, c, mb));
} }
@ -1650,7 +1686,7 @@ _rl_vi_set_mark ()
ch = rl_read_key (); ch = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT); RL_UNSETSTATE(RL_STATE_MOREINPUT);
if (ch < 'a' || ch > 'z') if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
{ {
rl_ding (); rl_ding ();
return -1; return -1;
@ -1702,7 +1738,7 @@ _rl_vi_goto_mark ()
rl_point = rl_mark; rl_point = rl_mark;
return 0; return 0;
} }
else if (ch < 'a' || ch > 'z') else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */
{ {
rl_ding (); rl_ding ();
return -1; return -1;

View file

@ -251,19 +251,21 @@ getcwd (buf, size)
{ {
size_t len = pathbuf + pathsize - pathp; size_t len = pathbuf + pathsize - pathp;
if (buf == NULL) if (buf == NULL && size <= 0)
{ size = len;
if (len < (size_t) size)
len = size; if ((size_t) size < len)
buf = (char *) malloc (len);
if (buf == NULL)
goto lose2;
}
else if ((size_t) size < len)
{ {
errno = ERANGE; errno = ERANGE;
goto lose2; goto lose2;
} }
if (buf == NULL)
{
buf = (char *) malloc (size);
if (buf == NULL)
goto lose2;
}
(void) memcpy((PTR_T) buf, (PTR_T) pathp, len); (void) memcpy((PTR_T) buf, (PTR_T) pathp, len);
} }

View file

@ -471,6 +471,8 @@ pow_10(n)
10^x ~= r 10^x ~= r
* log_10(200) = 2; * log_10(200) = 2;
* log_10(250) = 2; * log_10(250) = 2;
*
* NOTE: do not call this with r == 0 -- an infinite loop results.
*/ */
static int static int
log_10(r) log_10(r)
@ -576,8 +578,11 @@ numtoa(number, base, precision, fract)
{ {
integral_part[0] = '0'; integral_part[0] = '0';
integral_part[1] = '\0'; integral_part[1] = '\0';
fraction_part[0] = '0'; /* The fractional part has to take the precision into account */
fraction_part[1] = '\0'; for (ch = 0; ch < precision-1; ch++)
fraction_part[ch] = '0';
fraction_part[ch] = '0';
fraction_part[ch+1] = '\0';
if (fract) if (fract)
*fract = fraction_part; *fract = fraction_part;
return integral_part; return integral_part;
@ -663,7 +668,8 @@ number(p, d, base)
p->flags &= ~PF_ZEROPAD; p->flags &= ~PF_ZEROPAD;
sd = d; /* signed for ' ' padding in base 10 */ sd = d; /* signed for ' ' padding in base 10 */
flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; flags = 0;
flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
if (*p->pf == 'X') if (*p->pf == 'X')
flags |= FL_HEXUPPER; flags |= FL_HEXUPPER;
@ -733,7 +739,7 @@ lnumber(p, d, base)
p->flags &= ~PF_ZEROPAD; p->flags &= ~PF_ZEROPAD;
sd = d; /* signed for ' ' padding in base 10 */ sd = d; /* signed for ' ' padding in base 10 */
flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0; flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
if (*p->pf == 'X') if (*p->pf == 'X')
flags |= FL_HEXUPPER; flags |= FL_HEXUPPER;
@ -805,6 +811,7 @@ pointer(p, d)
PUT_CHAR(*tmp, p); PUT_CHAR(*tmp, p);
tmp++; tmp++;
} }
PAD_LEFT(p); PAD_LEFT(p);
} }
@ -972,11 +979,21 @@ floating(p, d)
if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp))) if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
tmp = t; tmp = t;
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
{
/* smash the trailing zeros unless altform */
for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
tmp2[i] = '\0';
if (tmp2[0] == '\0')
p->precision = 0;
}
/* calculate the padding. 1 for the dot */ /* calculate the padding. 1 for the dot */
p->width = p->width - p->width = p->width -
((d > 0. && p->justify == RIGHT) ? 1:0) - ((d > 0. && p->justify == RIGHT) ? 1:0) -
((p->flags & PF_SPACE) ? 1:0) - ((p->flags & PF_SPACE) ? 1:0) -
strlen(tmp) - p->precision - 1; strlen(tmp) - p->precision -
((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0); /* radix char */
PAD_RIGHT(p); PAD_RIGHT(p);
PUT_PLUS(d, p, 0.); PUT_PLUS(d, p, 0.);
PUT_SPACE(d, p, 0.); PUT_SPACE(d, p, 0.);
@ -991,11 +1008,6 @@ floating(p, d)
if (p->precision != 0 || (p->flags & PF_ALTFORM)) if (p->precision != 0 || (p->flags & PF_ALTFORM))
PUT_CHAR(decpoint, p); /* put the '.' */ PUT_CHAR(decpoint, p); /* put the '.' */
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
/* smash the trailing zeros unless altform */
for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
tmp2[i] = '\0';
for (; *tmp2; tmp2++) for (; *tmp2; tmp2++)
PUT_CHAR(*tmp2, p); /* the fraction */ PUT_CHAR(*tmp2, p); /* the fraction */
@ -1011,14 +1023,19 @@ exponent(p, d)
char *tmp, *tmp2; char *tmp, *tmp2;
int j, i; int j, i;
if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)) if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
return; /* already printed nan or inf */ return; /* already printed nan or inf */
GETLOCALEDATA(decpoint, thoussep, grouping); GETLOCALEDATA(decpoint, thoussep, grouping);
DEF_PREC(p); DEF_PREC(p);
j = log_10(d); if (d == 0.)
d = d / pow_10(j); /* get the Mantissa */ j = 0;
d = ROUND(d, p); else
{
j = log_10(d);
d = d / pow_10(j); /* get the Mantissa */
d = ROUND(d, p);
}
tmp = dtoa(d, p->precision, &tmp2); tmp = dtoa(d, p->precision, &tmp2);
/* 1 for unit, 1 for the '.', 1 for 'e|E', /* 1 for unit, 1 for the '.', 1 for 'e|E',
@ -1076,6 +1093,7 @@ exponent(p, d)
PUT_CHAR(*tmp, p); PUT_CHAR(*tmp, p);
tmp++; tmp++;
} }
PAD_LEFT(p); PAD_LEFT(p);
} }
#endif #endif
@ -1358,7 +1376,7 @@ conv_break:
STAR_ARGS(data); STAR_ARGS(data);
DEF_PREC(data); DEF_PREC(data);
d = GETDOUBLE(data); d = GETDOUBLE(data);
i = log_10(d); i = (d != 0.) ? log_10(d) : -1;
/* /*
* for '%g|%G' ANSI: use f if exponent * for '%g|%G' ANSI: use f if exponent
* is in the range or [-4,p] exclusively * is in the range or [-4,p] exclusively

54
parse.y
View file

@ -1029,6 +1029,7 @@ timespec: TIME
#define PST_CMDTOKEN 0x1000 /* command token OK - unused */ #define PST_CMDTOKEN 0x1000 /* command token OK - unused */
#define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */ #define PST_COMPASSIGN 0x2000 /* parsing x=(...) compound assignment */
#define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */ #define PST_ASSIGNOK 0x4000 /* assignment statement ok in this context */
#define PST_REGEXP 0x8000 /* parsing an ERE/BRE as a single word */
/* Initial size to allocate for tokens, and the /* Initial size to allocate for tokens, and the
amount to grow them by. */ amount to grow them by. */
@ -2591,6 +2592,9 @@ read_token (command)
return (character); return (character);
} }
if (parser_state & PST_REGEXP)
goto tokword;
/* Shell meta-characters. */ /* Shell meta-characters. */
if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0))
{ {
@ -2698,6 +2702,7 @@ read_token (command)
if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND)) if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
return (character); return (character);
tokword:
/* Okay, if we got this far, we have to read a word. Read one, /* Okay, if we got this far, we have to read a word. Read one,
and then check it against the known ones. */ and then check it against the known ones. */
result = read_token_word (character); result = read_token_word (character);
@ -2735,7 +2740,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
/* itrace("parse_matched_pair: open = %c close = %c", open, close); */ /* itrace("parse_matched_pair: open = %c close = %c", open, close); */
count = 1; count = 1;
pass_next_character = backq_backslash = was_dollar = in_comment = 0; pass_next_character = backq_backslash = was_dollar = in_comment = 0;
check_comment = (flags & P_COMMAND) && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0; check_comment = (flags & P_COMMAND) && qc != '`' && qc != '\'' && qc != '"' && (flags & P_DQUOTE) == 0;
/* RFLAGS is the set of flags we want to pass to recursive calls. */ /* RFLAGS is the set of flags we want to pass to recursive calls. */
rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE); rflags = (qc == '"') ? P_DQUOTE : (flags & P_DQUOTE);
@ -3202,8 +3207,11 @@ cond_term ()
if (tok == WORD && test_binop (yylval.word->word)) if (tok == WORD && test_binop (yylval.word->word))
op = yylval.word; op = yylval.word;
#if defined (COND_REGEXP) #if defined (COND_REGEXP)
else if (tok == WORD && STREQ (yylval.word->word,"=~")) else if (tok == WORD && STREQ (yylval.word->word, "=~"))
op = yylval.word; {
op = yylval.word;
parser_state |= PST_REGEXP;
}
#endif #endif
else if (tok == '<' || tok == '>') else if (tok == '<' || tok == '>')
op = make_word_from_token (tok); /* ( */ op = make_word_from_token (tok); /* ( */
@ -3234,6 +3242,7 @@ cond_term ()
/* rhs */ /* rhs */
tok = read_token (READ); tok = read_token (READ);
parser_state &= ~PST_REGEXP;
if (tok == WORD) if (tok == WORD)
{ {
tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL); tright = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
@ -3367,7 +3376,7 @@ read_token_word (character)
if (pass_next_character) if (pass_next_character)
{ {
pass_next_character = 0; pass_next_character = 0;
goto got_character; goto got_escaped_character;
} }
cd = current_delimiter (dstack); cd = current_delimiter (dstack);
@ -3419,9 +3428,34 @@ read_token_word (character)
goto next_character; goto next_character;
} }
#ifdef COND_REGEXP
/* When parsing a regexp as a single word inside a conditional command,
we need to special-case characters special to both the shell and
regular expressions. Right now, that is only '(' and '|'. */ /*)*/
if MBTEST((parser_state & PST_REGEXP) && (character == '(' || character == '|')) /*)*/
{
if (character == '|')
goto got_character;
push_delimiter (dstack, character);
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
pop_delimiter (dstack);
if (ttok == &matched_pair_error)
return -1; /* Bail immediately. */
RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
token_buffer_size, TOKEN_DEFAULT_GROW_SIZE);
token[token_index++] = character;
strcpy (token + token_index, ttok);
token_index += ttoklen;
FREE (ttok);
dollar_present = all_digit_token = 0;
goto next_character;
}
#endif /* COND_REGEXP */
#ifdef EXTENDED_GLOB #ifdef EXTENDED_GLOB
/* Parse a ksh-style extended pattern matching specification. */ /* Parse a ksh-style extended pattern matching specification. */
if (extended_glob && PATTERN_CHAR (character)) if MBTEST(extended_glob && PATTERN_CHAR (character))
{ {
peek_char = shell_getc (1); peek_char = shell_getc (1);
if MBTEST(peek_char == '(') /* ) */ if MBTEST(peek_char == '(') /* ) */
@ -3616,12 +3650,14 @@ read_token_word (character)
got_character: got_character:
all_digit_token &= DIGIT (character);
dollar_present |= character == '$';
if (character == CTLESC || character == CTLNUL) if (character == CTLESC || character == CTLNUL)
token[token_index++] = CTLESC; token[token_index++] = CTLESC;
got_escaped_character:
all_digit_token &= DIGIT (character);
dollar_present |= character == '$';
token[token_index++] = character; token[token_index++] = character;
RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size, RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
@ -4330,7 +4366,7 @@ not_escape:
if (promptvars || posixly_correct) if (promptvars || posixly_correct)
{ {
last_exit_value = last_command_exit_value; last_exit_value = last_command_exit_value;
list = expand_prompt_string (result, Q_DOUBLE_QUOTES); list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0);
free (result); free (result);
result = string_list (list); result = string_list (list);
dispose_words (list); dispose_words (list);

View file

@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */ looks for to find the patch level (for the sccs version string). */
#define PATCHLEVEL 0 #define PATCHLEVEL 48
#endif /* _PATCHLEVEL_H_ */ #endif /* _PATCHLEVEL_H_ */

View file

@ -1,6 +1,6 @@
/* pathexp.c -- The shell interface to the globbing library. */ /* pathexp.c -- The shell interface to the globbing library. */
/* Copyright (C) 1995-2002 Free Software Foundation, Inc. /* Copyright (C) 1995-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -110,6 +110,33 @@ unquoted_glob_pattern_p (string)
return (0); return (0);
} }
/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
be quoted to match itself. */
static inline int
ere_char (c)
int c;
{
switch (c)
{
case '.':
case '[':
case '\\':
case '(':
case ')':
case '*':
case '+':
case '?':
case '{':
case '|':
case '^':
case '$':
return 1;
default:
return 0;
}
return (0);
}
/* PATHNAME can contain characters prefixed by CTLESC; this indicates /* PATHNAME can contain characters prefixed by CTLESC; this indicates
that the character is to be quoted. We quote it here in the style that the character is to be quoted. We quote it here in the style
that the glob library recognizes. If flags includes QGLOB_CVTNULL, that the glob library recognizes. If flags includes QGLOB_CVTNULL,
@ -142,6 +169,8 @@ quote_string_for_globbing (pathname, qflags)
{ {
if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
continue; continue;
if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
continue;
temp[j++] = '\\'; temp[j++] = '\\';
i++; i++;
if (pathname[i] == '\0') if (pathname[i] == '\0')

View file

@ -1,6 +1,6 @@
/* pathexp.h -- The shell interface to the globbing library. */ /* pathexp.h -- The shell interface to the globbing library. */
/* Copyright (C) 1987-2005 Free Software Foundation, Inc. /* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -32,6 +32,7 @@ extern char *glob_error_return;
/* Flag values for quote_string_for_globbing */ /* Flag values for quote_string_for_globbing */
#define QGLOB_CVTNULL 0x01 /* convert QUOTED_NULL strings to '\0' */ #define QGLOB_CVTNULL 0x01 /* convert QUOTED_NULL strings to '\0' */
#define QGLOB_FILENAME 0x02 /* do correct quoting for matching filenames */ #define QGLOB_FILENAME 0x02 /* do correct quoting for matching filenames */
#define QGLOB_REGEXP 0x04 /* quote an ERE for regcomp/regexec */
#if defined (EXTENDED_GLOB) #if defined (EXTENDED_GLOB)
/* Flags to OR with other flag args to strmatch() to enabled the extended /* Flags to OR with other flag args to strmatch() to enabled the extended

BIN
po/ru.gmo Normal file

Binary file not shown.

View file

@ -12,7 +12,7 @@ msgstr ""
"Last-Translator: Evgeniy Dushistov <dushistov@mail.ru>\n" "Last-Translator: Evgeniy Dushistov <dushistov@mail.ru>\n"
"Language-Team: Russian <ru@li.org>\n" "Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=KOI8-R\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

View file

@ -89,6 +89,7 @@ extern int debugging_mode;
extern int executing, login_shell; extern int executing, login_shell;
extern int interactive, interactive_shell; extern int interactive, interactive_shell;
extern int startup_state; extern int startup_state;
extern int shell_compatibility_level;
/* Structure to pass around that holds a bitmap of file descriptors /* Structure to pass around that holds a bitmap of file descriptors
to close, and the size of that structure. Used in execute_cmd.c. */ to close, and the size of that structure. Used in execute_cmd.c. */

19
sig.c
View file

@ -350,6 +350,25 @@ reset_terminating_signals ()
#undef XSIG #undef XSIG
#undef XHANDLER #undef XHANDLER
/* Run some of the cleanups that should be performed when we run
jump_to_top_level from a builtin command context. XXX - might want to
also call reset_parser here. */
void
top_level_cleanup ()
{
/* Clean up string parser environment. */
while (parse_and_execute_level)
parse_and_execute_cleanup ();
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */
run_unwind_protects ();
loop_level = continuing = breaking = 0;
return_catch_flag = 0;
}
/* What to do when we've been interrupted, and it is safe to handle it. */ /* What to do when we've been interrupted, and it is safe to handle it. */
void void
throw_to_top_level () throw_to_top_level ()

1
sig.h
View file

@ -121,6 +121,7 @@ extern sighandler sigint_sighandler __P((int));
extern void initialize_signals __P((int)); extern void initialize_signals __P((int));
extern void initialize_terminating_signals __P((void)); extern void initialize_terminating_signals __P((void));
extern void reset_terminating_signals __P((void)); extern void reset_terminating_signals __P((void));
extern void top_level_cleanup __P((void));
extern void throw_to_top_level __P((void)); extern void throw_to_top_level __P((void));
extern void jump_to_top_level __P((int)) __attribute__((__noreturn__)); extern void jump_to_top_level __P((int)) __attribute__((__noreturn__));

119
subst.c
View file

@ -4,7 +4,7 @@
/* ``Have a little faith, there's magic in the night. You ain't a /* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */ beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2006 Free Software Foundation, Inc. /* Copyright (C) 1987-2007 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell. This file is part of GNU Bash, the Bourne Again SHell.
@ -137,7 +137,7 @@ unsigned char ifs_firstc;
/* Extern functions and variables from different files. */ /* Extern functions and variables from different files. */
extern int last_command_exit_value, last_command_exit_signal; extern int last_command_exit_value, last_command_exit_signal;
extern int subshell_environment; extern int subshell_environment;
extern int subshell_level; extern int subshell_level, parse_and_execute_level;
extern int eof_encountered; extern int eof_encountered;
extern int return_catch_flag, return_catch_value; extern int return_catch_flag, return_catch_value;
extern pid_t dollar_dollar_pid; extern pid_t dollar_dollar_pid;
@ -1278,7 +1278,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
{ {
if (no_longjmp_on_fatal_error == 0) if (no_longjmp_on_fatal_error == 0)
{ /* { */ { /* { */
report_error ("bad substitution: no closing `%s' in %s", "}", string); report_error (_("bad substitution: no closing `%s' in %s"), "}", string);
last_command_exit_value = EXECUTION_FAILURE; last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level (DISCARD); exp_jump_to_top_level (DISCARD);
} }
@ -1887,7 +1887,13 @@ string_list_dollar_at (list, quoted)
sep[1] = '\0'; sep[1] = '\0';
#endif #endif
/* XXX -- why call quote_list if ifs == 0? we can get away without doing
it now that quote_escapes quotes spaces */
#if 0
tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0)) tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
#else
tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
#endif
? quote_list (list) ? quote_list (list)
: list_quote_escapes (list); : list_quote_escapes (list);
@ -2646,11 +2652,12 @@ remove_backslashes (string)
/* This needs better error handling. */ /* This needs better error handling. */
/* Expand W for use as an argument to a unary or binary operator in a /* Expand W for use as an argument to a unary or binary operator in a
[[...]] expression. If SPECIAL is nonzero, this is the rhs argument [[...]] expression. If SPECIAL is 1, this is the rhs argument
to the != or == operator, and should be treated as a pattern. In to the != or == operator, and should be treated as a pattern. In
this case, we quote the string specially for the globbing code. The this case, we quote the string specially for the globbing code. If
caller is responsible for removing the backslashes if the unquoted SPECIAL is 2, this is an rhs argument for the =~ operator, and should
words is needed later. */ be quoted appropriately for regcomp/regexec. The caller is responsible
for removing the backslashes if the unquoted word is needed later. */
char * char *
cond_expand_word (w, special) cond_expand_word (w, special)
WORD_DESC *w; WORD_DESC *w;
@ -2658,6 +2665,7 @@ cond_expand_word (w, special)
{ {
char *r, *p; char *r, *p;
WORD_LIST *l; WORD_LIST *l;
int qflags;
if (w->word == 0 || w->word[0] == '\0') if (w->word == 0 || w->word[0] == '\0')
return ((char *)NULL); return ((char *)NULL);
@ -2672,8 +2680,11 @@ cond_expand_word (w, special)
} }
else else
{ {
qflags = QGLOB_CVTNULL;
if (special == 2)
qflags |= QGLOB_REGEXP;
p = string_list (l); p = string_list (l);
r = quote_string_for_globbing (p, QGLOB_CVTNULL); r = quote_string_for_globbing (p, qflags);
free (p); free (p);
} }
dispose_words (l); dispose_words (l);
@ -2803,9 +2814,10 @@ expand_string_assignment (string, quoted)
passed string when an error occurs. Might want to trap other calls passed string when an error occurs. Might want to trap other calls
to jump_to_top_level here so we don't endlessly loop. */ to jump_to_top_level here so we don't endlessly loop. */
WORD_LIST * WORD_LIST *
expand_prompt_string (string, quoted) expand_prompt_string (string, quoted, wflags)
char *string; char *string;
int quoted; int quoted;
int wflags;
{ {
WORD_LIST *value; WORD_LIST *value;
WORD_DESC td; WORD_DESC td;
@ -2813,7 +2825,7 @@ expand_prompt_string (string, quoted)
if (string == 0 || *string == 0) if (string == 0 || *string == 0)
return ((WORD_LIST *)NULL); return ((WORD_LIST *)NULL);
td.flags = 0; td.flags = wflags;
td.word = savestring (string); td.word = savestring (string);
no_longjmp_on_fatal_error = 1; no_longjmp_on_fatal_error = 1;
@ -2916,7 +2928,12 @@ expand_string (string, quoted)
/* Quote escape characters in string s, but no other characters. This is /* Quote escape characters in string s, but no other characters. This is
used to protect CTLESC and CTLNUL in variable values from the rest of used to protect CTLESC and CTLNUL in variable values from the rest of
the word expansion process after the variable is expanded. */ the word expansion process after the variable is expanded. If IFS is
null, we quote spaces as well, just in case we split on spaces later
(in the case of unquoted $@, we will eventually attempt to split the
entire word on spaces). Corresponding code exists in dequote_escapes.
Even if we don't end up splitting on spaces, quoting spaces is not a
problem. */
char * char *
quote_escapes (string) quote_escapes (string)
char *string; char *string;
@ -2924,17 +2941,19 @@ quote_escapes (string)
register char *s, *t; register char *s, *t;
size_t slen; size_t slen;
char *result, *send; char *result, *send;
int quote_spaces;
DECLARE_MBSTATE; DECLARE_MBSTATE;
slen = strlen (string); slen = strlen (string);
send = string + slen; send = string + slen;
quote_spaces = (ifs_value && *ifs_value == 0);
t = result = (char *)xmalloc ((slen * 2) + 1); t = result = (char *)xmalloc ((slen * 2) + 1);
s = string; s = string;
while (*s) while (*s)
{ {
if (*s == CTLESC || *s == CTLNUL) if (*s == CTLESC || *s == CTLNUL || (quote_spaces && *s == ' '))
*t++ = CTLESC; *t++ = CTLESC;
COPY_CHAR_P (t, s, send); COPY_CHAR_P (t, s, send);
} }
@ -2976,6 +2995,7 @@ dequote_escapes (string)
register char *s, *t; register char *s, *t;
size_t slen; size_t slen;
char *result, *send; char *result, *send;
int quote_spaces;
DECLARE_MBSTATE; DECLARE_MBSTATE;
if (string == 0) if (string == 0)
@ -2990,9 +3010,10 @@ dequote_escapes (string)
if (strchr (string, CTLESC) == 0) if (strchr (string, CTLESC) == 0)
return (strcpy (result, s)); return (strcpy (result, s));
quote_spaces = (ifs_value && *ifs_value == 0);
while (*s) while (*s)
{ {
if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL)) if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
{ {
s++; s++;
if (*s == '\0') if (*s == '\0')
@ -3954,7 +3975,11 @@ parameter_brace_remove_pattern (varname, value, patstr, rtype, quoted)
if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT) if (patspec == RP_LONG_LEFT || patspec == RP_LONG_RIGHT)
patstr++; patstr++;
pattern = getpattern (patstr, quoted, 1); /* Need to pass getpattern newly-allocated memory in case of expansion --
the expansion code will free the passed string on an error. */
temp1 = savestring (patstr);
pattern = getpattern (temp1, quoted, 1);
free (temp1);
temp1 = (char *)NULL; /* shut up gcc */ temp1 = (char *)NULL; /* shut up gcc */
switch (vtype) switch (vtype)
@ -4123,6 +4148,12 @@ unlink_fifo_list ()
nfifo = 0; nfifo = 0;
} }
int
fifos_pending ()
{
return nfifo;
}
static char * static char *
make_named_pipe () make_named_pipe ()
{ {
@ -4172,6 +4203,12 @@ add_fifo_list (fd)
nfds++; nfds++;
} }
int
fifos_pending ()
{
return 0; /* used for cleanup; not needed with /dev/fd */
}
void void
unlink_fifo_list () unlink_fifo_list ()
{ {
@ -4456,7 +4493,15 @@ read_comsub (fd, quoted)
/* Add the character to ISTRING, possibly after resizing it. */ /* Add the character to ISTRING, possibly after resizing it. */
RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL) /* This is essentially quote_string inline */
if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
istring[istring_index++] = CTLESC;
/* Escape CTLESC and CTLNUL in the output to protect those characters
from the rest of the word expansions (word splitting and globbing.)
This is essentially quote_escapes inline. */
else if (c == CTLESC)
istring[istring_index++] = CTLESC;
else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
istring[istring_index++] = CTLESC; istring[istring_index++] = CTLESC;
istring[istring_index++] = c; istring[istring_index++] = c;
@ -4578,7 +4623,8 @@ command_substitute (string, quoted)
#if defined (JOB_CONTROL) #if defined (JOB_CONTROL)
set_sigchld_handler (); set_sigchld_handler ();
stop_making_children (); stop_making_children ();
pipeline_pgrp = old_pipeline_pgrp; if (pid != 0)
pipeline_pgrp = old_pipeline_pgrp;
#else #else
stop_making_children (); stop_making_children ();
#endif /* JOB_CONTROL */ #endif /* JOB_CONTROL */
@ -4665,6 +4711,9 @@ command_substitute (string, quoted)
last_command_exit_value = rc; last_command_exit_value = rc;
rc = run_exit_trap (); rc = run_exit_trap ();
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
#endif
exit (rc); exit (rc);
} }
else else
@ -4763,7 +4812,7 @@ array_length_reference (s)
else else
t = (ind == 0) ? value_cell (var) : (char *)NULL; t = (ind == 0) ? value_cell (var) : (char *)NULL;
len = STRLEN (t); len = MB_STRLEN (t);
return (len); return (len);
} }
#endif /* ARRAY_VARS */ #endif /* ARRAY_VARS */
@ -4860,10 +4909,11 @@ parameter_brace_expand_word (name, var_is_special, quoted)
char *temp, *tt; char *temp, *tt;
intmax_t arg_index; intmax_t arg_index;
SHELL_VAR *var; SHELL_VAR *var;
int atype; int atype, rflags;
ret = 0; ret = 0;
temp = 0; temp = 0;
rflags = 0;
/* Handle multiple digit arguments, as in ${11}. */ /* Handle multiple digit arguments, as in ${11}. */
if (legal_number (name, &arg_index)) if (legal_number (name, &arg_index))
@ -4896,6 +4946,8 @@ parameter_brace_expand_word (name, var_is_special, quoted)
temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) temp = (*temp && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
? quote_string (temp) ? quote_string (temp)
: quote_escapes (temp); : quote_escapes (temp);
else if (atype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
rflags |= W_HASQUOTEDNULL;
} }
#endif #endif
else if (var = find_variable (name)) else if (var = find_variable (name))
@ -4923,6 +4975,7 @@ parameter_brace_expand_word (name, var_is_special, quoted)
{ {
ret = alloc_word_desc (); ret = alloc_word_desc ();
ret->word = temp; ret->word = temp;
ret->flags |= rflags;
} }
return ret; return ret;
} }
@ -5546,12 +5599,16 @@ parameter_brace_substring (varname, value, substr, quoted)
so verify_substring_values just returns the numbers specified and we so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */ rely on array_subrange to understand how to deal with them). */
tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
#if 0
/* array_subrange now calls array_quote_escapes as appropriate, so the
caller no longer needs to. */
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0) if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
{ {
temp = tt ? quote_escapes (tt) : (char *)NULL; temp = tt ? quote_escapes (tt) : (char *)NULL;
FREE (tt); FREE (tt);
} }
else else
#endif
temp = tt; temp = tt;
break; break;
#endif #endif
@ -5707,6 +5764,11 @@ parameter_brace_patsub (varname, value, patsub, quoted)
vtype &= ~VT_STARSUB; vtype &= ~VT_STARSUB;
mflags = 0; mflags = 0;
if (patsub && *patsub == '/')
{
mflags |= MATCH_GLOBREP;
patsub++;
}
/* Malloc this because expand_string_if_necessary or one of the expansion /* Malloc this because expand_string_if_necessary or one of the expansion
functions in its call chain may free it on a substitution error. */ functions in its call chain may free it on a substitution error. */
@ -5741,13 +5803,12 @@ parameter_brace_patsub (varname, value, patsub, quoted)
} }
/* ksh93 doesn't allow the match specifier to be a part of the expanded /* ksh93 doesn't allow the match specifier to be a part of the expanded
pattern. This is an extension. */ pattern. This is an extension. Make sure we don't anchor the pattern
at the beginning or end of the string if we're doing global replacement,
though. */
p = pat; p = pat;
if (pat && pat[0] == '/') if (mflags & MATCH_GLOBREP)
{ mflags |= MATCH_ANY;
mflags |= MATCH_GLOBREP|MATCH_ANY;
p++;
}
else if (pat && pat[0] == '#') else if (pat && pat[0] == '#')
{ {
mflags |= MATCH_BEG; mflags |= MATCH_BEG;
@ -5798,12 +5859,16 @@ parameter_brace_patsub (varname, value, patsub, quoted)
#if defined (ARRAY_VARS) #if defined (ARRAY_VARS)
case VT_ARRAYVAR: case VT_ARRAYVAR:
temp = array_patsub (array_cell (v), p, rep, mflags); temp = array_patsub (array_cell (v), p, rep, mflags);
#if 0
/* Don't need to do this anymore; array_patsub calls array_quote_escapes
as appropriate before adding the space separators. */
if (temp && (mflags & MATCH_QUOTED) == 0) if (temp && (mflags & MATCH_QUOTED) == 0)
{ {
tt = quote_escapes (temp); tt = quote_escapes (temp);
free (temp); free (temp);
temp = tt; temp = tt;
} }
#endif
break; break;
#endif #endif
} }
@ -7607,6 +7672,10 @@ exp_jump_to_top_level (v)
expand_no_split_dollar_star = 0; /* XXX */ expand_no_split_dollar_star = 0; /* XXX */
expanding_redir = 0; expanding_redir = 0;
if (parse_and_execute_level == 0)
top_level_cleanup (); /* from sig.c */
jump_to_top_level (v); jump_to_top_level (v);
} }
@ -7824,7 +7893,7 @@ glob_expand_word_list (tlist, eflags)
else if (fail_glob_expansion != 0) else if (fail_glob_expansion != 0)
{ {
report_error (_("no match: %s"), tlist->word->word); report_error (_("no match: %s"), tlist->word->word);
jump_to_top_level (DISCARD); exp_jump_to_top_level (DISCARD);
} }
else if (allow_null_glob_expansion == 0) else if (allow_null_glob_expansion == 0)
{ {

View file

@ -135,7 +135,7 @@ extern WORD_LIST *expand_string_unsplit __P((char *, int));
extern WORD_LIST *expand_string_assignment __P((char *, int)); extern WORD_LIST *expand_string_assignment __P((char *, int));
/* Expand a prompt string. */ /* Expand a prompt string. */
extern WORD_LIST *expand_prompt_string __P((char *, int)); extern WORD_LIST *expand_prompt_string __P((char *, int, int));
/* Expand STRING just as if you were expanding a word. This also returns /* Expand STRING just as if you were expanding a word. This also returns
a list of words. Note that filename globbing is *NOT* done for word a list of words. Note that filename globbing is *NOT* done for word
@ -222,6 +222,7 @@ extern WORD_LIST *expand_words_shellexp __P((WORD_LIST *));
extern char *command_substitute __P((char *, int)); extern char *command_substitute __P((char *, int));
extern char *pat_subst __P((char *, char *, char *, int)); extern char *pat_subst __P((char *, char *, char *, int));
extern int fifos_pending __P((void));
extern void unlink_fifo_list __P((void)); extern void unlink_fifo_list __P((void));
extern WORD_LIST *list_string_with_quotes __P((char *)); extern WORD_LIST *list_string_with_quotes __P((char *));

View file

@ -430,7 +430,7 @@ Case05---3---A:B:C---
Case06---1---A B C::--- Case06---1---A B C::---
Case07---3---A:B:C--- Case07---3---A:B:C---
Case08---3---A:B:C--- Case08---3---A:B:C---
./new-exp.tests: line 506: /${$(($#-1))}: bad substitution ./new-exp.tests: line 506: ${$(($#-1))}: bad substitution
argv[1] = <a> argv[1] = <a>
argv[2] = <b> argv[2] = <b>
argv[3] = <c> argv[3] = <c>

View file

@ -6,6 +6,7 @@ shopt -s cdspell
shopt -u checkhash shopt -u checkhash
shopt -u checkwinsize shopt -u checkwinsize
shopt -s cmdhist shopt -s cmdhist
shopt -u compat31
shopt -u dotglob shopt -u dotglob
shopt -u execfail shopt -u execfail
shopt -s expand_aliases shopt -s expand_aliases
@ -53,6 +54,7 @@ shopt -s sourcepath
shopt -u cdable_vars shopt -u cdable_vars
shopt -u checkhash shopt -u checkhash
shopt -u checkwinsize shopt -u checkwinsize
shopt -u compat31
shopt -u dotglob shopt -u dotglob
shopt -u execfail shopt -u execfail
shopt -u extdebug shopt -u extdebug
@ -77,6 +79,7 @@ shopt -u xpg_echo
cdable_vars off cdable_vars off
checkhash off checkhash off
checkwinsize off checkwinsize off
compat31 off
dotglob off dotglob off
execfail off execfail off
extdebug off extdebug off

View file

@ -1821,11 +1821,17 @@ make_variable_value (var, value, flags)
oval = value_cell (var); oval = value_cell (var);
lval = evalexp (oval, &expok); /* ksh93 seems to do this */ lval = evalexp (oval, &expok); /* ksh93 seems to do this */
if (expok == 0) if (expok == 0)
jump_to_top_level (DISCARD); {
top_level_cleanup ();
jump_to_top_level (DISCARD);
}
} }
rval = evalexp (value, &expok); rval = evalexp (value, &expok);
if (expok == 0) if (expok == 0)
jump_to_top_level (DISCARD); {
top_level_cleanup ();
jump_to_top_level (DISCARD);
}
if (flags & ASS_APPEND) if (flags & ASS_APPEND)
rval += lval; rval += lval;
retval = itos (rval); retval = itos (rval);
@ -3452,9 +3458,11 @@ push_func_var (data)
if (shell_variables == global_variables) if (shell_variables == global_variables)
var->attributes &= ~(att_tempvar|att_propagate); var->attributes &= ~(att_tempvar|att_propagate);
else else
shell_variables->flags |= VC_HASTMPVAR; shell_variables->flags |= VC_HASTMPVAR;
v->attributes |= var->attributes; v->attributes |= var->attributes;
} }
else
stupidly_hack_special_variables (var->name); /* XXX */
dispose_variable (var); dispose_variable (var);
} }
@ -3541,6 +3549,8 @@ push_exported_var (data)
var->attributes &= ~att_propagate; var->attributes &= ~att_propagate;
v->attributes |= var->attributes; v->attributes |= var->attributes;
} }
else
stupidly_hack_special_variables (var->name); /* XXX */
dispose_variable (var); dispose_variable (var);
} }

View file

@ -43,6 +43,9 @@ const char *release_status = (char *)0;
#endif #endif
const char *sccs_version = SCCSVERSION; const char *sccs_version = SCCSVERSION;
/* If == 31, shell compatible with bash-3.1, == 32 with bash-3.2, and so on */
int shell_compatibility_level = 32;
/* Functions for getting, setting, and displaying the shell version. */ /* Functions for getting, setting, and displaying the shell version. */
/* Forward declarations so we don't have to include externs.h */ /* Forward declarations so we don't have to include externs.h */
@ -79,5 +82,5 @@ show_shell_version (extended)
{ {
printf ("GNU bash, version %s (%s)\n", shell_version_string (), MACHTYPE); printf ("GNU bash, version %s (%s)\n", shell_version_string (), MACHTYPE);
if (extended) if (extended)
printf (_("Copyright (C) 2005 Free Software Foundation, Inc.\n")); printf (_("Copyright (C) 2007 Free Software Foundation, Inc.\n"));
} }