diff options
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 @@ -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 @@ -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); @@ -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); \ } \ @@ -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 @@ -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++; @@ -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_ */ @@ -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 @@ -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)); } } |