summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CWRU/CWRU.chlog65
-rw-r--r--CWRU/CWRU.chlog~63
-rw-r--r--MANIFEST1
-rw-r--r--NOTES6
-rw-r--r--arrayfunc.c7
-rw-r--r--arrayfunc.c~37
-rw-r--r--bashline.c7
-rw-r--r--bashline.c~2
-rw-r--r--builtins/mapfile.def2
-rw-r--r--builtins/mapfile.def~2
-rw-r--r--builtins/printf.def1
-rw-r--r--doc/bash.19
-rw-r--r--general.c2
-rw-r--r--general.c~4
-rw-r--r--lib/glob/glob.c6
-rw-r--r--lib/glob/glob.c~2
-rw-r--r--lib/readline/bind.c1
-rw-r--r--lib/readline/doc/readline.35
-rw-r--r--lib/readline/doc/rluser.texi5
-rw-r--r--lib/readline/doc/version.texi4
-rw-r--r--lib/readline/histexpand.c42
-rw-r--r--lib/readline/readline.c4
-rw-r--r--lib/readline/rlprivate.h1
-rw-r--r--lib/readline/signals.c5
-rw-r--r--lib/readline/text.c2
-rw-r--r--lib/readline/text.c~9
-rw-r--r--lib/readline/undo.c3
-rw-r--r--lib/readline/undo.c~328
-rw-r--r--lib/sh/uconvert.c2
-rw-r--r--lib/sh/uconvert.c~116
-rw-r--r--patchlevel.h2
-rw-r--r--subst.c3
-rw-r--r--subst.c~161
-rw-r--r--tests/nquote.right3
-rw-r--r--tests/nquote.tests2
-rw-r--r--tests/nquote1.sub6
-rw-r--r--variables.c5
-rw-r--r--variables.c~23
38 files changed, 876 insertions, 72 deletions
diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog
index 629780b8..e55ecd83 100644
--- a/CWRU/CWRU.chlog
+++ b/CWRU/CWRU.chlog
@@ -8702,3 +8702,68 @@ subst.c
execute_cmd.c
- add fflush(stdout) and fflush(stderr) to child coproc code before
calling exit after execute_in_subshell
+
+ 8/31
+ ----
+lib/readline/{{bind,readline}.c,rlprivate.h}
+ - new bindable variable, "echo-control-characters", enabled by default.
+ This controls whether or not readline honors the tty ECHOCTL bit
+ and displays characters corresponding to keyboard-generated signals.
+ Controlled by _rl_echo_control_chars variable, declared in readline.c
+
+lib/readline/signals.c
+ - if _rl_echo_control_chars == 0, don't go through _rl_echo_signal_char
+
+
+lib/readline/doc/{readline.3,rluser.texi}
+ - document "echo-control-characters" bindable variable
+
+ 9/1
+ ---
+lib/readline/histexpand.c
+ - hist_string_extract_single_quoted now takes an additional argument:
+ a flags word. The only defined value (flags & 1) allows backslash
+ to quote the single quote. This is to inhibit history expansion
+ inside $'...' containing an escaped single quote.
+ - change history_expand to call hist_string_extract_single_quoted
+ with flags == 1 if it sees $'. Fixes bug reported by Sean
+ Donner <sean.donner@gmail.com>
+
+ 9/2
+ ---
+builtins/printf.def
+ - add a call to sh_wrerror if ferror() succeeds in the PRETURN macro,
+ to print an error message in the case that the final fflush fails
+ (for instance, because it attempts to write data that didn't have a
+ trailing newline). Fixes bug reported by Stefano Lattarini
+ <stefano.lattarini@gmail.com>
+
+ 9/7
+ ---
+arrayfunc.c
+ - some fixes to assign_compound_array_list to avoid null pointer
+ dereferences pointed out by clang/scan-build
+
+lib/glob/glob.c
+ - fixes to udequote_pathname and wdequote_pathname to avoid possible
+ null pointer dereferences pointed out by clang/scan-build
+
+lib/readline/undo.c
+ - fix to _rl_copy_undo_list (function unused) to avoid deref of
+ uninitialized pointer pointed out by clang/scan-build
+
+general.c
+ - fix string_to_rlimtype so it works if passed a null pointer (though
+ it never is)
+
+builtins/mapfile.def
+ - fix to mapfile() to avoid possible null pointer dereference pointed
+ out by clang/scan-build
+
+variables.c
+ - fix to valid_exportstr to avoid possible null pointer dereferences
+ pointed out by clang/scan-build
+
+bashline.c
+ - fix to bash_execute_unix_command to avoid possible null pointer
+ dereference if READLINE_LINE or READLINE_POINT is not bound
diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~
index eb755bf8..61731efe 100644
--- a/CWRU/CWRU.chlog~
+++ b/CWRU/CWRU.chlog~
@@ -8128,7 +8128,7 @@ lib/sh/casemod.c
multibyte character
lib/readline/mbutil.c
- - fix _rl_find_next_mbchar_internalto not call mbrtowc at the end of
+ - fix _rl_find_next_mbchar_internal to not call mbrtowc at the end of
the string, since implementations return different values -- just
break the loop immediately
@@ -8702,3 +8702,64 @@ subst.c
execute_cmd.c
- add fflush(stdout) and fflush(stderr) to child coproc code before
calling exit after execute_in_subshell
+
+ 8/31
+ ----
+lib/readline/{{bind,readline}.c,rlprivate.h}
+ - new bindable variable, "echo-control-characters", enabled by default.
+ This controls whether or not readline honors the tty ECHOCTL bit
+ and displays characters corresponding to keyboard-generated signals.
+ Controlled by _rl_echo_control_chars variable, declared in readline.c
+
+lib/readline/signals.c
+ - if _rl_echo_control_chars == 0, don't go through _rl_echo_signal_char
+
+
+lib/readline/doc/{readline.3,rluser.texi}
+ - document "echo-control-characters" bindable variable
+
+ 9/1
+ ---
+lib/readline/histexpand.c
+ - hist_string_extract_single_quoted now takes an additional argument:
+ a flags word. The only defined value (flags & 1) allows backslash
+ to quote the single quote. This is to inhibit history expansion
+ inside $'...' containing an escaped single quote.
+ - change history_expand to call hist_string_extract_single_quoted
+ with flags == 1 if it sees $'. Fixes bug reported by Sean
+ Donner <sean.donner@gmail.com>
+
+ 9/2
+ ---
+builtins/printf.def
+ - add a call to sh_wrerror if ferror() succeeds in the PRETURN macro,
+ to print an error message in the case that the final fflush fails
+ (for instance, because it attempts to write data that didn't have a
+ trailing newline). Fixes bug reported by Stefano Lattarini
+ <stefano.lattarini@gmail.com>
+
+ 9/7
+ ---
+arrayfunc.c
+ - some fixes to assign_compound_array_list to avoid null pointer
+ dereferences pointed out by clang/scan-build
+
+lib/glob/glob.c
+ - fixes to udequote_pathname and wdequote_pathname to avoid possible
+ null pointer dereferences pointed out by clang/scan-build
+
+lib/readline/undo.c
+ - fix to _rl_copy_undo_list (function unused) to avoid deref of
+ uninitialized pointer pointed out by clang/scan-build
+
+general.c
+ - fix string_to_rlimtype so it works if passed a null pointer (though
+ it never is)
+
+builtins/mapfile.def
+ - fix to mapfile() to avoid possible null pointer dereference pointed
+ out by clang/scan-build
+
+variables.c
+ - fix to valid_exportstr to avoid possible null pointer dereferences
+ pointed out by clang/scan-build
diff --git a/MANIFEST b/MANIFEST
index 2aa41834..3d553028 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -907,6 +907,7 @@ tests/new-exp7.sub f
tests/new-exp.right f
tests/nquote.tests f
tests/nquote.right f
+tests/nquote1.sub f
tests/nquote1.tests f
tests/nquote1.right f
tests/nquote2.tests f
diff --git a/NOTES b/NOTES
index b938d02b..4fe9e6ca 100644
--- a/NOTES
+++ b/NOTES
@@ -344,4 +344,8 @@ Platform-Specific Configuration and Operation Notes
Apple ships inadequate dynamic libreadline and libhistory "replacements"
as standard libraries.
-
+20. If you're on a system like SGI Irix, and you get an error about not
+ being able to refer to a dynamic symbol
+ (ld: non-dynamic relocations refer to dynamic symbol PC), add
+ -DNEED_EXTERN_PC to the LOCAL_CFLAGS variable in lib/readline/Makefile.in
+ and rebuild.
diff --git a/arrayfunc.c b/arrayfunc.c
index b5941096..218faf3d 100644
--- a/arrayfunc.c
+++ b/arrayfunc.c
@@ -407,6 +407,7 @@ expand_compound_array_assignment (var, value, flags)
return nlist;
}
+/* Callers ensure that VAR is not NULL */
void
assign_compound_array_list (var, nlist, flags)
SHELL_VAR *var;
@@ -431,9 +432,9 @@ assign_compound_array_list (var, nlist, flags)
value. */
if ((flags & ASS_APPEND) == 0)
{
- if (array_p (var) && a)
+ if (a && array_p (var))
array_flush (a);
- else if (assoc_p (var) && h)
+ else if (h && assoc_p (var))
assoc_flush (h);
}
@@ -447,7 +448,7 @@ assign_compound_array_list (var, nlist, flags)
/* We have a word of the form [ind]=value */
if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
{
- len = skipsubscript (w, 0, assoc_p (var) != 0);
+ len = skipsubscript (w, 0, (var && assoc_p (var) != 0));
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
diff --git a/arrayfunc.c~ b/arrayfunc.c~
index 88b56d5a..06e40a54 100644
--- a/arrayfunc.c~
+++ b/arrayfunc.c~
@@ -98,7 +98,7 @@ convert_var_to_assoc (var)
oldval = value_cell (var);
hash = assoc_create (0);
if (oldval)
- assoc_insert (hash, "0", oldval);
+ assoc_insert (hash, savestring ("0"), oldval);
FREE (value_cell (var));
var_setassoc (var, hash);
@@ -431,9 +431,9 @@ assign_compound_array_list (var, nlist, flags)
value. */
if ((flags & ASS_APPEND) == 0)
{
- if (array_p (var) && a)
+ if (a && array_p (var))
array_flush (a);
- else if (assoc_p (var) && h)
+ else if (h && assoc_p (var))
assoc_flush (h);
}
@@ -447,7 +447,7 @@ assign_compound_array_list (var, nlist, flags)
/* We have a word of the form [ind]=value */
if ((list->word->flags & W_ASSIGNMENT) && w[0] == '[')
{
- len = skipsubscript (w, 0);
+ len = skipsubscript (w, 0, (var && assoc_p (var) != 0));
/* XXX - changes for `+=' */
if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
@@ -560,8 +560,9 @@ quote_assign (string)
{
size_t slen;
int saw_eq;
- char *temp, *t;
+ char *temp, *t, *subs;
const char *s, *send;
+ int ss, se;
DECLARE_MBSTATE;
slen = strlen (string);
@@ -573,6 +574,20 @@ quote_assign (string)
{
if (*s == '=')
saw_eq = 1;
+ if (saw_eq == 0 && *s == '[') /* looks like a subscript */
+ {
+ ss = s - string;
+ se = skipsubscript (string, ss, 0);
+ subs = substring (s, ss, se);
+ *t++ = '\\';
+ strcpy (t, subs);
+ t += se - ss;
+ *t++ = '\\';
+ *t++ = ']';
+ s += se + 1;
+ free (subs);
+ continue;
+ }
if (saw_eq == 0 && (glob_char_p (s) || isifs (*s)))
*t++ = '\\';
@@ -596,7 +611,7 @@ quote_array_assignment_chars (list)
if (l->word == 0 || l->word->word == 0 || l->word->word[0] == '\0')
continue; /* should not happen, but just in case... */
/* Don't bother if it doesn't look like [ind]=value */
- if (l->word->word[0] != '[' || xstrchr (l->word->word, '=') == 0) /* ] */
+ if (l->word->word[0] != '[' || mbschr (l->word->word, '=') == 0) /* ] */
continue;
nword = quote_assign (l->word->word);
free (l->word->word);
@@ -619,7 +634,7 @@ unbind_array_element (var, sub)
char *akey;
ARRAY_ELEMENT *ae;
- len = skipsubscript (sub, 0);
+ len = skipsubscript (sub, 0, 0);
if (sub[len] != ']' || len == 0)
{
builtin_error ("%s[%s: %s", var->name, sub, _(bash_badsub_errmsg));
@@ -713,7 +728,7 @@ valid_array_reference (name)
char *t;
int r, len;
- t = xstrchr (name, '['); /* ] */
+ t = mbschr (name, '['); /* ] */
if (t)
{
*t = '\0';
@@ -722,7 +737,7 @@ valid_array_reference (name)
if (r == 0)
return 0;
/* Check for a properly-terminated non-blank subscript. */
- len = skipsubscript (t, 0);
+ len = skipsubscript (t, 0, 0);
if (t[len] != ']' || len == 1)
return 0;
for (r = 1; r < len; r++)
@@ -773,7 +788,7 @@ array_variable_name (s, subp, lenp)
char *t, *ret;
int ind, ni;
- t = xstrchr (s, '[');
+ t = mbschr (s, '[');
if (t == 0)
{
if (subp)
@@ -783,7 +798,7 @@ array_variable_name (s, subp, lenp)
return ((char *)NULL);
}
ind = t - s;
- ni = skipsubscript (s, ind);
+ ni = skipsubscript (s, ind, 0);
if (ni <= ind + 1 || s[ni] != ']')
{
err_badarraysub (s);
diff --git a/bashline.c b/bashline.c
index a2e55c87..1e0f8e3d 100644
--- a/bashline.c
+++ b/bashline.c
@@ -3433,7 +3433,7 @@ bash_execute_unix_command (count, key)
register int i, r;
intmax_t mi;
sh_parser_state_t ps;
- char *cmd, *value, *l, *ce;
+ char *cmd, *value, *l, *l1, *ce;
SHELL_VAR *v;
char ibuf[INT_STRLEN_BOUND(int) + 1];
@@ -3482,7 +3482,7 @@ bash_execute_unix_command (count, key)
v = bind_variable ("READLINE_LINE", rl_line_buffer, 0);
if (v)
VSETATTR (v, att_exported);
- l = value_cell (v);
+ l = v ? value_cell (v) : 0;
value = inttostr (rl_point, ibuf, sizeof (ibuf));
v = bind_int_variable ("READLINE_POINT", value);
if (v)
@@ -3494,7 +3494,8 @@ bash_execute_unix_command (count, key)
restore_parser_state (&ps);
v = find_variable ("READLINE_LINE");
- if (value_cell (v) != l)
+ l1 = v ? value_cell (v) : 0;
+ if (l1 != l)
maybe_make_readline_line (value_cell (v));
v = find_variable ("READLINE_POINT");
if (v && legal_number (value_cell (v), &mi))
diff --git a/bashline.c~ b/bashline.c~
index b5313351..a2e55c87 100644
--- a/bashline.c~
+++ b/bashline.c~
@@ -502,6 +502,8 @@ initialize_readline ()
do other expansion on directory names. */
rl_directory_completion_hook = bash_directory_completion_hook;
+ rl_filename_rewrite_hook = bash_filename_rewrite_hook;
+
/* Tell the filename completer we want a chance to ignore some names. */
rl_ignore_some_completions_function = filename_completion_ignore;
diff --git a/builtins/mapfile.def b/builtins/mapfile.def
index 62f66c47..a1682f76 100644
--- a/builtins/mapfile.def
+++ b/builtins/mapfile.def
@@ -153,7 +153,7 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n
entry = find_or_make_array_variable (array_name, 1);
if (entry == 0 || readonly_p (entry) || noassign_p (entry))
{
- if (readonly_p (entry))
+ if (entry && readonly_p (entry))
err_readonly (array_name);
return (EXECUTION_FAILURE);
diff --git a/builtins/mapfile.def~ b/builtins/mapfile.def~
index e37cd227..62f66c47 100644
--- a/builtins/mapfile.def~
+++ b/builtins/mapfile.def~
@@ -281,7 +281,7 @@ mapfile_builtin (list)
break;
case 'c':
code = legal_number (list_optarg, &intval);
- if (code == 0 || intval < 0 || intval != (unsigned)intval)
+ if (code == 0 || intval <= 0 || intval != (unsigned)intval)
{
builtin_error (_("%s: invalid callback quantum"), list_optarg);
return (EXECUTION_FAILURE);
diff --git a/builtins/printf.def b/builtins/printf.def
index 8740bf70..b33fda8d 100644
--- a/builtins/printf.def
+++ b/builtins/printf.def
@@ -156,6 +156,7 @@ extern int errno;
fflush (stdout); \
if (ferror (stdout)) \
{ \
+ sh_wrerror (); \
clearerr (stdout); \
return (EXECUTION_FAILURE); \
} \
diff --git a/doc/bash.1 b/doc/bash.1
index 5d891a72..26d46b13 100644
--- a/doc/bash.1
+++ b/doc/bash.1
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet@po.cwru.edu
.\"
-.\" Last Change: Sat Aug 22 12:02:47 EDT 2009
+.\" Last Change: Mon Aug 31 08:59:57 EDT 2009
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2009 August 22" "GNU Bash-4.0"
+.TH BASH 1 "2009 August 31" "GNU Bash-4.0"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -4947,6 +4947,11 @@ can be set to either
or
.BR vi .
.TP
+.B echo\-control\-characters (On)
+When set to \fBOn\fP, on operating systems that indicate they support it,
+readline echoes a character corresponding to a signal generated from the
+keyboard.
+.TP
.B enable\-keypad (Off)
When set to \fBOn\fP, readline will try to enable the application
keypad when it is called. Some systems need this to enable the
diff --git a/general.c b/general.c
index 7fc71187..36b2f5b3 100644
--- a/general.c
+++ b/general.c
@@ -98,7 +98,7 @@ string_to_rlimtype (s)
neg = 0;
while (s && *s && whitespace (*s))
s++;
- if (*s == '-' || *s == '+')
+ if (s && (*s == '-' || *s == '+'))
{
neg = *s == '-';
s++;
diff --git a/general.c~ b/general.c~
index 4cf877fd..7fc71187 100644
--- a/general.c~
+++ b/general.c~
@@ -285,7 +285,7 @@ assignment (string, flags)
#if defined (ARRAY_VARS)
if (c == '[')
{
- newi = skipsubscript (string, indx);
+ newi = skipsubscript (string, indx, 0);
if (string[newi++] != ']')
return (0);
if (string[newi] == '+' && string[newi+1] == '=')
@@ -577,7 +577,7 @@ int
absolute_program (string)
const char *string;
{
- return ((char *)xstrchr (string, '/') != (char *)NULL);
+ return ((char *)mbschr (string, '/') != (char *)NULL);
}
/* **************************************************************** */
diff --git a/lib/glob/glob.c b/lib/glob/glob.c
index 52362495..72242a3b 100644
--- a/lib/glob/glob.c
+++ b/lib/glob/glob.c
@@ -246,7 +246,8 @@ udequote_pathname (pathname)
if (pathname[i - 1] == 0)
break;
}
- pathname[j] = '\0';
+ if (pathname)
+ pathname[j] = '\0';
}
#if HANDLE_MULTIBYTE
@@ -279,7 +280,8 @@ wdequote_pathname (pathname)
if (wpathname[i - 1] == L'\0')
break;
}
- wpathname[j] = L'\0';
+ if (wpathname)
+ wpathname[j] = L'\0';
/* Convert the wide character string into unibyte character set. */
memset (&ps, '\0', sizeof(mbstate_t));
diff --git a/lib/glob/glob.c~ b/lib/glob/glob.c~
index ffe7b316..52362495 100644
--- a/lib/glob/glob.c~
+++ b/lib/glob/glob.c~
@@ -637,7 +637,7 @@ glob_vector (pat, dir, flags)
continue;
}
- convfn = fnxform (dp->d_name, D_NAMLEN (dp));
+ convfn = fnx_fromfs (dp->d_name, D_NAMLEN (dp));
if (strmatch (pat, convfn, mflags) != FNM_NOMATCH)
{
if (nalloca < ALLOCA_MAX)
diff --git a/lib/readline/bind.c b/lib/readline/bind.c
index 77b018ab..580346cc 100644
--- a/lib/readline/bind.c
+++ b/lib/readline/bind.c
@@ -1426,6 +1426,7 @@ static const struct {
{ "completion-ignore-case", &_rl_completion_case_fold, 0 },
{ "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 },
{ "disable-completion", &rl_inhibit_completion, 0 },
+ { "echo-control-characters", &_rl_echo_control_chars, 0 },
{ "enable-keypad", &_rl_enable_keypad, 0 },
{ "expand-tilde", &rl_complete_with_tilde_expansion, 0 },
{ "history-preserve-point", &_rl_history_preserve_point, 0 },
diff --git a/lib/readline/doc/readline.3 b/lib/readline/doc/readline.3
index 84bc4eb3..6bdca19d 100644
--- a/lib/readline/doc/readline.3
+++ b/lib/readline/doc/readline.3
@@ -401,6 +401,11 @@ can be set to either
or
.BR vi .
.TP
+.B echo\-control\-characters (On)
+When set to \fBOn\fP, on operating systems that indicate they support it,
+readline echoes a character corresponding to a signal generated from the
+keyboard.
+.TP
.B enable\-keypad (Off)
When set to \fBOn\fP, readline will try to enable the application
keypad when it is called. Some systems need this to enable the
diff --git a/lib/readline/doc/rluser.texi b/lib/readline/doc/rluser.texi
index e499e41d..619de1d2 100644
--- a/lib/readline/doc/rluser.texi
+++ b/lib/readline/doc/rluser.texi
@@ -474,6 +474,11 @@ key bindings is used. By default, Readline starts up in Emacs editing
mode, where the keystrokes are most similar to Emacs. This variable can be
set to either @samp{emacs} or @samp{vi}.
+@item echo-control-characters
+When set to @samp{on}, on operating systems that indicate they support it,
+readline echoes a character corresponding to a signal generated from the
+keyboard. The default is @samp{on}.
+
@item enable-keypad
@vindex enable-keypad
When set to @samp{on}, Readline will try to enable the application
diff --git a/lib/readline/doc/version.texi b/lib/readline/doc/version.texi
index b9fac6b8..d8474adb 100644
--- a/lib/readline/doc/version.texi
+++ b/lib/readline/doc/version.texi
@@ -4,7 +4,7 @@ Copyright (C) 1988-2009 Free Software Foundation, Inc.
@set EDITION 6.0
@set VERSION 6.0
-@set UPDATED 22 August 2009
+@set UPDATED 31 August 2009
@set UPDATED-MONTH August 2009
-@set LASTCHANGE Sat Aug 22 12:02:34 EDT 2009
+@set LASTCHANGE Mon Aug 31 09:01:30 EDT 2009
diff --git a/lib/readline/histexpand.c b/lib/readline/histexpand.c
index bf5ac0ed..c209a850 100644
--- a/lib/readline/histexpand.c
+++ b/lib/readline/histexpand.c
@@ -305,16 +305,20 @@ get_history_event (string, caller_index, delimiting_quote)
/* Extract the contents of STRING as if it is enclosed in single quotes.
SINDEX, when passed in, is the offset of the character immediately
following the opening single quote; on exit, SINDEX is left pointing
- to the closing single quote. */
+ to the closing single quote. FLAGS currently used to allow backslash
+ to escape a single quote (e.g., for bash $'...'). */
static void
-hist_string_extract_single_quoted (string, sindex)
+hist_string_extract_single_quoted (string, sindex, flags)
char *string;
- int *sindex;
+ int *sindex, flags;
{
register int i;
for (i = *sindex; string[i] && string[i] != '\''; i++)
- ;
+ {
+ if ((flags & 1) && string[i] == '\\' && string[i+1])
+ i++;
+ }
*sindex = i;
}
@@ -924,7 +928,7 @@ history_expand (hstring, output)
char **output;
{
register int j;
- int i, r, l, passc, cc, modified, eindex, only_printing, dquote;
+ int i, r, l, passc, cc, modified, eindex, only_printing, dquote, flag;
char *string;
/* The output string, and its length. */
@@ -1044,8 +1048,9 @@ history_expand (hstring, output)
else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'')
{
/* If this is bash, single quotes inhibit history expansion. */
+ flag = (i > 0 && string[i - 1] == '$');
i++;
- hist_string_extract_single_quoted (string, &i);
+ hist_string_extract_single_quoted (string, &i, flag);
}
else if (history_quotes_inhibit_expansion && string[i] == '\\')
{
@@ -1130,8 +1135,9 @@ history_expand (hstring, output)
{
int quote, slen;
+ flag = (i > 0 && string[i - 1] == '$');
quote = i++;
- hist_string_extract_single_quoted (string, &i);
+ hist_string_extract_single_quoted (string, &i, flag);
slen = i - quote + 2;
temp = (char *)xmalloc (slen);
@@ -1435,17 +1441,21 @@ history_tokenize_word (string, ind)
i += 2;
return i;
}
- else
+ else if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
+ (peek == '>' && string[i] == '&') ||
+ (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
+ (peek == '(' && string[i] == '$')) /* ) */
{
- if ((peek == '&' && (string[i] == '>' || string[i] == '<')) ||
- (peek == '>' && string[i] == '&') ||
- (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */
- (peek == '(' && string[i] == '$')) /* ) */
- {
- i += 2;
- return i;
- }
+ i += 2;
+ return i;
}
+#if 0
+ else if (peek == '\'' && string[i] == '$')
+ {
+ i += 2; /* XXX */
+ return i;
+ }
+#endif
if (string[i] != '$')
{
diff --git a/lib/readline/readline.c b/lib/readline/readline.c
index b12ae1f2..c0e78d4f 100644
--- a/lib/readline/readline.c
+++ b/lib/readline/readline.c
@@ -275,6 +275,10 @@ int _rl_bind_stty_chars = 1;
its initial state. */
int _rl_revert_all_at_newline = 0;
+/* Non-zero means to honor the termios ECHOCTL bit and echo control
+ characters corresponding to keyboard-generated signals. */
+int _rl_echo_control_chars = 1;
+
/* **************************************************************** */
/* */
/* Top Level Functions */
diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h
index b09f45e0..819f1278 100644
--- a/lib/readline/rlprivate.h
+++ b/lib/readline/rlprivate.h
@@ -421,6 +421,7 @@ extern int _rl_convert_meta_chars_to_ascii;
extern int _rl_output_meta_chars;
extern int _rl_bind_stty_chars;
extern int _rl_revert_all_at_newline;
+extern int _rl_echo_control_chars;
extern char *_rl_comment_begin;
extern unsigned char _rl_parsing_conditionalized_out;
extern Keymap _rl_keymap;
diff --git a/lib/readline/signals.c b/lib/readline/signals.c
index 8cad338b..11c92d2c 100644
--- a/lib/readline/signals.c
+++ b/lib/readline/signals.c
@@ -101,7 +101,8 @@ int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */
int _rl_interrupt_immediately = 0;
int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including <signal.h> everywhere */
-/* If non-zero, print characters corresponding to received signals. */
+/* If non-zero, print characters corresponding to received signals as long as
+ the user has indicated his desire to do so (_rl_echo_control_chars). */
int _rl_echoctl = 0;
int _rl_intr_char = 0;
@@ -637,7 +638,7 @@ rl_echo_signal_char (sig)
char cstr[3];
int cslen, c;
- if (_rl_echoctl == 0)
+ if (_rl_echoctl == 0 || _rl_echo_control_chars == 0)
return;
switch (sig)
diff --git a/lib/readline/text.c b/lib/readline/text.c
index 4e1aa0cb..fc391894 100644
--- a/lib/readline/text.c
+++ b/lib/readline/text.c
@@ -1151,7 +1151,7 @@ int
rl_delete_horizontal_space (count, ignore)
int count, ignore;
{
- int start = rl_point;
+ int start;
while (rl_point && whitespace (rl_line_buffer[rl_point - 1]))
rl_point--;
diff --git a/lib/readline/text.c~ b/lib/readline/text.c~
index a8c0a538..4e1aa0cb 100644
--- a/lib/readline/text.c~
+++ b/lib/readline/text.c~
@@ -189,10 +189,13 @@ _rl_replace_text (text, start, end)
{
int n;
+ n = 0;
rl_begin_undo_group ();
- rl_delete_text (start, end + 1);
+ if (start <= end)
+ rl_delete_text (start, end + 1);
rl_point = start;
- n = rl_insert_text (text);
+ if (*text)
+ n = rl_insert_text (text);
rl_end_undo_group ();
return n;
@@ -583,7 +586,7 @@ rl_skip_csi_sequence (count, key)
RL_SETSTATE (RL_STATE_MOREINPUT);
do
ch = rl_read_key ();
- while (ch >= 0x20 && ch < 0x40)
+ while (ch >= 0x20 && ch < 0x40);
RL_UNSETSTATE (RL_STATE_MOREINPUT);
return 0;
diff --git a/lib/readline/undo.c b/lib/readline/undo.c
index c0ba631f..eb042b29 100644
--- a/lib/readline/undo.c
+++ b/lib/readline/undo.c
@@ -139,6 +139,9 @@ _rl_copy_undo_list (head)
{
UNDO_LIST *list, *new, *roving, *c;
+ if (head == 0)
+ return head;
+
list = head;
new = 0;
while (list)
diff --git a/lib/readline/undo.c~ b/lib/readline/undo.c~
new file mode 100644
index 00000000..c0ba631f
--- /dev/null
+++ b/lib/readline/undo.c~
@@ -0,0 +1,328 @@
+/* readline.c -- a general facility for reading lines of input
+ with emacs style editing and completion. */
+
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library (Readline), a library
+ for reading lines of text with interactive input and history editing.
+
+ Readline is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Readline is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Readline. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h> /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "xmalloc.h"
+
+extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+ the undo list. */
+int _rl_doing_an_undo = 0;
+
+/* How many unclosed undo groups we currently have. */
+int _rl_undo_group_level = 0;
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* **************************************************************** */
+/* */
+/* Undo, and Undoing */
+/* */
+/* **************************************************************** */
+
+static UNDO_LIST *
+alloc_undo_entry (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp;
+
+ temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+ temp->what = what;
+ temp->start = start;
+ temp->end = end;
+ temp->text = text;
+
+ temp->next = (UNDO_LIST *)NULL;
+ return temp;
+}
+
+/* Remember how to undo something. Concatenate some undos if that
+ seems right. */
+void
+rl_add_undo (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp;
+
+ temp = alloc_undo_entry (what, start, end, text);
+ temp->next = rl_undo_list;
+ rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+void
+rl_free_undo_list ()
+{
+ UNDO_LIST *release, *orig_list;
+
+ orig_list = rl_undo_list;
+ while (rl_undo_list)
+ {
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+
+ if (release->what == UNDO_DELETE)
+ xfree (release->text);
+
+ xfree (release);
+ }
+ rl_undo_list = (UNDO_LIST *)NULL;
+ replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
+}
+
+UNDO_LIST *
+_rl_copy_undo_entry (entry)
+ UNDO_LIST *entry;
+{
+ UNDO_LIST *new;
+
+ new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
+ new->text = entry->text ? savestring (entry->text) : 0;
+ return new;
+}
+
+UNDO_LIST *
+_rl_copy_undo_list (head)
+ UNDO_LIST *head;
+{
+ UNDO_LIST *list, *new, *roving, *c;
+
+ list = head;
+ new = 0;
+ while (list)
+ {
+ c = _rl_copy_undo_entry (list);
+ if (new == 0)
+ roving = new = c;
+ else
+ {
+ roving->next = c;
+ roving = roving->next;
+ }
+ list = list->next;
+ }
+
+ roving->next = 0;
+ return new;
+}
+
+/* Undo the next thing in the list. Return 0 if there
+ is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+ UNDO_LIST *release;
+ int waiting_for_begin, start, end;
+
+#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
+
+ start = end = waiting_for_begin = 0;
+ do
+ {
+ if (rl_undo_list == 0)
+ return (0);
+
+ _rl_doing_an_undo = 1;
+ RL_SETSTATE(RL_STATE_UNDOING);
+
+ /* To better support vi-mode, a start or end value of -1 means
+ rl_point, and a value of -2 means rl_end. */
+ if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
+ {
+ start = TRANS (rl_undo_list->start);
+ end = TRANS (rl_undo_list->end);
+ }
+
+ switch (rl_undo_list->what)
+ {
+ /* Undoing deletes means inserting some text. */
+ case UNDO_DELETE:
+ rl_point = start;
+ rl_insert_text (rl_undo_list->text);
+ xfree (rl_undo_list->text);
+ break;
+
+ /* Undoing inserts means deleting some text. */
+ case UNDO_INSERT:
+ rl_delete_text (start, end);
+ rl_point = start;
+ break;
+
+ /* Undoing an END means undoing everything 'til we get to a BEGIN. */
+ case UNDO_END:
+ waiting_for_begin++;
+ break;
+
+ /* Undoing a BEGIN means that we are done with this group. */
+ case UNDO_BEGIN:
+ if (waiting_for_begin)
+ waiting_for_begin--;
+ else
+ rl_ding ();
+ break;
+ }
+
+ _rl_doing_an_undo = 0;
+ RL_UNSETSTATE(RL_STATE_UNDOING);
+
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+ replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
+
+ xfree (release);
+ }
+ while (waiting_for_begin);
+
+ return (1);
+}
+#undef TRANS
+
+int
+_rl_fix_last_undo_of_type (type, start, end)
+ int type, start, end;
+{
+ UNDO_LIST *rl;
+
+ for (rl = rl_undo_list; rl; rl = rl->next)
+ {
+ if (rl->what == type)
+ {
+ rl->start = start;
+ rl->end = end;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Begin a group. Subsequent undos are undone as an atomic operation. */
+int
+rl_begin_undo_group ()
+{
+ rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+ _rl_undo_group_level++;
+ return 0;
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+int
+rl_end_undo_group ()
+{
+ rl_add_undo (UNDO_END, 0, 0, 0);
+ _rl_undo_group_level--;
+ return 0;
+}
+
+/* Save an undo entry for the text from START to END. */
+int
+rl_modifying (start, end)
+ int start, end;
+{
+ if (start > end)
+ {
+ SWAP (start, end);
+ }
+
+ if (start != end)
+ {
+ char *temp = rl_copy_text (start, end);
+ rl_begin_undo_group ();
+ rl_add_undo (UNDO_DELETE, start, end, temp);
+ rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+ rl_end_undo_group ();
+ }
+ return 0;
+}
+
+/* Revert the current line to its previous state. */
+int
+rl_revert_line (count, key)
+ int count, key;
+{
+ if (rl_undo_list == 0)
+ rl_ding ();
+ else
+ {
+ while (rl_undo_list)
+ rl_do_undo ();
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_point = rl_mark = 0; /* rl_end should be set correctly */
+#endif
+ }
+
+ return 0;
+}
+
+/* Do some undoing of things that were done. */
+int
+rl_undo_command (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return 0; /* Nothing to do. */
+
+ while (count)
+ {
+ if (rl_do_undo ())
+ count--;
+ else
+ {
+ rl_ding ();
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/lib/sh/uconvert.c b/lib/sh/uconvert.c
index 10095653..3d656df0 100644
--- a/lib/sh/uconvert.c
+++ b/lib/sh/uconvert.c
@@ -92,7 +92,7 @@ uconvert(s, ip, up)
ipart = (ipart * 10) + (*p - '0');
}
- if (*p == 0)
+ if (p == 0 || *p == 0) /* callers ensure p can never be 0; this is to shut up clang */
RETURN(1);
if (*p == DECIMAL)
diff --git a/lib/sh/uconvert.c~ b/lib/sh/uconvert.c~
new file mode 100644
index 00000000..10095653
--- /dev/null
+++ b/lib/sh/uconvert.c~
@@ -0,0 +1,116 @@
+/* uconvert - convert string representations of decimal numbers into whole
+ number/fractional value pairs. */
+
+/* Copyright (C) 2008,2009 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (TIME_WITH_SYS_TIME)
+# include <sys/time.h>
+# include <time.h>
+#else
+# if defined (HAVE_SYS_TIME_H)
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "chartypes.h"
+
+#include "shell.h"
+#include "builtins.h"
+
+#define DECIMAL '.' /* XXX - should use locale */
+
+#define RETURN(x) \
+do { \
+ if (ip) *ip = ipart * mult; \
+ if (up) *up = upart; \
+ return (x); \
+} while (0)
+
+/*
+ * An incredibly simplistic floating point converter.
+ */
+static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 };
+
+/* Take a decimal number int-part[.[micro-part]] and convert it to the whole
+ and fractional portions. The fractional portion is returned in
+ millionths (micro); callers are responsible for multiplying appropriately.
+ Return 1 if value converted; 0 if invalid integer for either whole or
+ fractional parts. */
+int
+uconvert(s, ip, up)
+ char *s;
+ long *ip, *up;
+{
+ int n, mult;
+ long ipart, upart;
+ char *p;
+
+ ipart = upart = 0;
+ mult = 1;
+
+ if (s && (*s == '-' || *s == '+'))
+ {
+ mult = (*s == '-') ? -1 : 1;
+ p = s + 1;
+ }
+ else
+ p = s;
+
+ for ( ; p && *p; p++)
+ {
+ if (*p == DECIMAL) /* decimal point */
+ break;
+ if (DIGIT(*p) == 0)
+ RETURN(0);
+ ipart = (ipart * 10) + (*p - '0');
+ }
+
+ if (*p == 0)
+ RETURN(1);
+
+ if (*p == DECIMAL)
+ p++;
+
+ /* Look for up to six digits past a decimal point. */
+ for (n = 0; n < 6 && p[n]; n++)
+ {
+ if (DIGIT(p[n]) == 0)
+ RETURN(0);
+ upart = (upart * 10) + (p[n] - '0');
+ }
+
+ /* Now convert to millionths */
+ upart *= multiplier[n];
+
+ if (n == 6 && p[6] >= '5' && p[6] <= '9')
+ upart++; /* round up 1 */
+
+ RETURN(1);
+}
diff --git a/patchlevel.h b/patchlevel.h
index 325b37d6..c10ac99e 100644
--- a/patchlevel.h
+++ b/patchlevel.h
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
-#define PATCHLEVEL 28
+#define PATCHLEVEL 33
#endif /* _PATCHLEVEL_H_ */
diff --git a/subst.c b/subst.c
index 3e91f1c6..e715e737 100644
--- a/subst.c
+++ b/subst.c
@@ -1031,7 +1031,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
char *charlist;
int flags;
{
- register int i = *sindex;
+ register int i;
#if defined (HANDLE_MULTIBYTE)
size_t clen;
wchar_t *wcharlist;
@@ -2662,7 +2662,6 @@ do_assignment_internal (word, expand)
}
else
#endif
-
if (expand && temp[0])
value = expand_string_if_necessary (temp, 0, expand_string_assignment);
else
diff --git a/subst.c~ b/subst.c~
index c8d1cf49..b7cafb67 100644
--- a/subst.c~
+++ b/subst.c~
@@ -314,6 +314,135 @@ static WORD_LIST *expand_word_list_internal __P((WORD_LIST *, int));
/* */
/* **************************************************************** */
+#if defined (DEBUG)
+void
+dump_word_flags (flags)
+ int flags;
+{
+ int f;
+
+ f = flags;
+ fprintf (stderr, "%d -> ", f);
+ if (f & W_ASSIGNASSOC)
+ {
+ f &= ~W_ASSIGNASSOC;
+ fprintf (stderr, "W_ASSIGNASSOC%s", f ? "|" : "");
+ }
+ if (f & W_HASCTLESC)
+ {
+ f &= ~W_HASCTLESC;
+ fprintf (stderr, "W_HASCTLESC%s", f ? "|" : "");
+ }
+ if (f & W_NOPROCSUB)
+ {
+ f &= ~W_NOPROCSUB;
+ fprintf (stderr, "W_NOPROCSUB%s", f ? "|" : "");
+ }
+ if (f & W_DQUOTE)
+ {
+ f &= ~W_DQUOTE;
+ fprintf (stderr, "W_DQUOTE%s", f ? "|" : "");
+ }
+ if (f & W_HASQUOTEDNULL)
+ {
+ f &= ~W_HASQUOTEDNULL;
+ fprintf (stderr, "W_HASQUOTEDNULL%s", f ? "|" : "");
+ }
+ if (f & W_ASSIGNARG)
+ {
+ f &= ~W_ASSIGNARG;
+ fprintf (stderr, "W_ASSIGNARG%s", f ? "|" : "");
+ }
+ if (f & W_ASSNBLTIN)
+ {
+ f &= ~W_ASSNBLTIN;
+ fprintf (stderr, "W_ASSNBLTIN%s", f ? "|" : "");
+ }
+ if (f & W_COMPASSIGN)
+ {
+ f &= ~W_COMPASSIGN;
+ fprintf (stderr, "W_COMPASSIGN%s", f ? "|" : "");
+ }
+ if (f & W_NOEXPAND)
+ {
+ f &= ~W_NOEXPAND;
+ fprintf (stderr, "W_NOEXPAND%s", f ? "|" : "");
+ }
+ if (f & W_ITILDE)
+ {
+ f &= ~W_ITILDE;
+ fprintf (stderr, "W_ITILDE%s", f ? "|" : "");
+ }
+ if (f & W_NOTILDE)
+ {
+ f &= ~W_NOTILDE;
+ fprintf (stderr, "W_NOTILDE%s", f ? "|" : "");
+ }
+ if (f & W_ASSIGNRHS)
+ {
+ f &= ~W_ASSIGNRHS;
+ fprintf (stderr, "W_ASSIGNRHS%s", f ? "|" : "");
+ }
+ if (f & W_NOCOMSUB)
+ {
+ f &= ~W_NOCOMSUB;
+ fprintf (stderr, "W_NOCOMSUB%s", f ? "|" : "");
+ }
+ if (f & W_DOLLARSTAR)
+ {
+ f &= ~W_DOLLARSTAR;
+ fprintf (stderr, "W_DOLLARSTAR%s", f ? "|" : "");
+ }
+ if (f & W_DOLLARAT)
+ {
+ f &= ~W_DOLLARAT;
+ fprintf (stderr, "W_DOLLARAT%s", f ? "|" : "");
+ }
+ if (f & W_TILDEEXP)
+ {
+ f &= ~W_TILDEEXP;
+ fprintf (stderr, "W_TILDEEXP%s", f ? "|" : "");
+ }
+ if (f & W_NOSPLIT2)
+ {
+ f &= ~W_NOSPLIT2;
+ fprintf (stderr, "W_NOSPLIT2%s", f ? "|" : "");
+ }
+ if (f & W_NOGLOB)
+ {
+ f &= ~W_NOGLOB;
+ fprintf (stderr, "W_NOGLOB%s", f ? "|" : "");
+ }
+ if (f & W_NOSPLIT)
+ {
+ f &= ~W_NOSPLIT;
+ fprintf (stderr, "W_NOSPLIT%s", f ? "|" : "");
+ }
+ if (f & W_GLOBEXP)
+ {
+ f &= ~W_GLOBEXP;
+ fprintf (stderr, "W_GLOBEXP%s", f ? "|" : "");
+ }
+ if (f & W_ASSIGNMENT)
+ {
+ f &= ~W_ASSIGNMENT;
+ fprintf (stderr, "W_ASSIGNMENT%s", f ? "|" : "");
+ }
+ if (f & W_QUOTED)
+ {
+ f &= ~W_QUOTED;
+ fprintf (stderr, "W_QUOTED%s", f ? "|" : "");
+ }
+ if (f & W_HASDOLLAR)
+ {
+ f &= ~W_HASDOLLAR;
+ fprintf (stderr, "W_HASDOLLAR%s", f ? "|" : "");
+ }
+ fprintf (stderr, "\n");
+ fflush (stderr);
+}
+#endif
+
#ifdef INCLUDE_UNUSED
static char *
quoted_substring (string, start, end)
@@ -588,7 +717,7 @@ string_extract (string, sindex, charlist, flags)
{
int ni;
/* If this is an array subscript, skip over it and continue. */
- ni = skipsubscript (string, i);
+ ni = skipsubscript (string, i, 0);
if (string[ni] == ']')
i = ni;
}
@@ -902,7 +1031,7 @@ string_extract_verbatim (string, slen, sindex, charlist, flags)
char *charlist;
int flags;
{
- register int i = *sindex;
+ register int i;
#if defined (HANDLE_MULTIBYTE)
size_t clen;
wchar_t *wcharlist;
@@ -1380,7 +1509,10 @@ unquote_bang (string)
#define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
/* This function assumes s[i] == open; returns with s[ret] == close; used to
- parse array subscripts. FLAGS currently unused. */
+ parse array subscripts. FLAGS & 1 means to not attempt to skip over
+ matched pairs of quotes or backquotes, or skip word expansions; it is
+ intended to be used after expansion has been performed and during final
+ assignment parsing (see arrayfunc.c:assign_compound_array_list()). */
static int
skip_matched_pair (string, start, open, close, flags)
const char *string;
@@ -1421,13 +1553,13 @@ skip_matched_pair (string, start, open, close, flags)
ADVANCE_CHAR (string, slen, i);
continue;
}
- else if (c == '`')
+ else if ((flags & 1) == 0 && c == '`')
{
backq = 1;
i++;
continue;
}
- else if (c == open)
+ else if ((flags & 1) == 0 && c == open)
{
count++;
i++;
@@ -1441,13 +1573,13 @@ skip_matched_pair (string, start, open, close, flags)
i++;
continue;
}
- else if (c == '\'' || c == '"')
+ else if ((flags & 1) == 0 && (c == '\'' || c == '"'))
{
i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
: skip_double_quoted (ss, slen, ++i);
/* no increment, the skip functions increment past the closing quote. */
}
- else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
+ else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
@@ -1472,11 +1604,11 @@ skip_matched_pair (string, start, open, close, flags)
#if defined (ARRAY_VARS)
int
-skipsubscript (string, start)
+skipsubscript (string, start, flags)
const char *string;
- int start;
+ int start, flags;
{
- return (skip_matched_pair (string, start, '[', ']', 0));
+ return (skip_matched_pair (string, start, '[', ']', flags));
}
#endif
@@ -1810,8 +1942,9 @@ split_at_delims (string, slen, delims, sentinel, nwp, cwp)
/* Special case for SENTINEL at the end of STRING. If we haven't found
the word containing SENTINEL yet, and the index we're looking for is at
- the end of STRING, add an additional null argument and set the current
- word pointer to that. */
+ the end of STRING (or past the end of the previously-found token,
+ possible if the end of the line is composed solely of IFS whitespace)
+ add an additional null argument and set the current word pointer to that. */
if (cwp && cw == -1 && (sentinel >= slen || sentinel >= te))
{
if (whitespace (string[sentinel - 1]))
@@ -4865,7 +4998,7 @@ command_substitute (string, quoted)
if (wordexp_only && read_but_dont_execute)
{
- last_command_exit_value = 125;
+ last_command_exit_value = EX_WEXPCOMSUB;
jump_to_top_level (EXITPROG);
}
@@ -6635,7 +6768,7 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
*contains_dollar_at = 1;
}
free (x);
- free (xlist);
+ dispose_words (xlist);
free (temp1);
*indexp = sindex;
diff --git a/tests/nquote.right b/tests/nquote.right
index 6d936d5e..267f0e7f 100644
--- a/tests/nquote.right
+++ b/tests/nquote.right
@@ -35,3 +35,6 @@ argv[1] = <hello, $world>
;foo
argv[1] = <^I>
argv[1] = <'A^IB'>
+hello' world
+hello world!
+hello' world!
diff --git a/tests/nquote.tests b/tests/nquote.tests
index 62d90b99..720c3e15 100644
--- a/tests/nquote.tests
+++ b/tests/nquote.tests
@@ -114,3 +114,5 @@ args ()
unset mytab
recho "${mytab:-$'\t'}"
recho "$( args $'A\tB' )"
+
+${THIS_SH} ./nquote1.sub
diff --git a/tests/nquote1.sub b/tests/nquote1.sub
new file mode 100644
index 00000000..b3bc0db3
--- /dev/null
+++ b/tests/nquote1.sub
@@ -0,0 +1,6 @@
+set -o history
+set -H
+
+echo $'hello\' world'
+echo $'hello world!'
+echo $'hello\' world!'
diff --git a/variables.c b/variables.c
index bdc27c7e..b178661e 100644
--- a/variables.c
+++ b/variables.c
@@ -3366,6 +3366,11 @@ valid_exportstr (v)
char *s;
s = v->exportstr;
+ if (s == 0)
+ {
+ internal_error (_("%s has null exportstr"), v->name);
+ return (0);
+ }
if (legal_variable_starter ((unsigned char)*s) == 0)
{
internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
diff --git a/variables.c~ b/variables.c~
index 1223b058..bdc27c7e 100644
--- a/variables.c~
+++ b/variables.c~
@@ -2226,7 +2226,7 @@ bind_variable_internal (name, value, table, hflags, aflags)
}
else if (assoc_p (entry))
{
- assoc_insert (assoc_cell (entry), "0", newval);
+ assoc_insert (assoc_cell (entry), savestring ("0"), newval);
free (newval);
}
else
@@ -4644,11 +4644,32 @@ sv_xtracefd (name)
char *name;
{
SHELL_VAR *v;
+ char *t, *e;
+ int fd;
+ FILE *fp;
v = find_variable (name);
if (v == 0)
+ {
+ xtrace_reset ();
+ return;
+ }
+
+ t = value_cell (v);
+ if (t == 0 || *t == 0)
xtrace_reset ();
else
{
+ fd = (int)strtol (t, &e, 10);
+ if (e != t && *e == '\0' && sh_validfd (fd))
+ {
+ fp = fdopen (fd, "w");
+ if (fp == 0)
+ internal_error (_("%s: %s: cannot open as FILE"), name, value_cell (v));
+ else
+ xtrace_set (fd, fp);
+ }
+ else
+ internal_error (_("%s: %s: invalid value for trace file descriptor"), name, value_cell (v));
}
}