diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index b0b90bf5..7ce16461 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -8931,3 +8931,49 @@ eval.c - execute_prompt_command: PROMPT_COMMAND can now be an array, subsuming PROMPT_COMMANDS, which bash no longer looks for. Prompted by a suggestion from Martijn Dekker + + 8/26 + ---- +builtins/fc.def + - fc_gethnum: now takes a flags word as the third argument, with two + current flag values: HN_LISTING, which means we are listing history + entries, and HN_FIRST, which means we are parsing the first in a + first,last range of history entries + - fc_gethnum: if we have a number >= 0, and it's out of range, return + different values (0 or last history) depending on whether we are + parsing the first or last in a range argument. Based on a report from + Martijn Dekker + + 8/31 + ---- +parse.y + - grammar: call handle_eof_input_unit from the eof-after-error + production only from interactive top-level shells, so a syntax error + in `eval' doesn't exit an interactive shell. Report and fix from + Koichi Murase + +bashline.c + - bash_execute_unix_command: if we call parse_and_execute with allocated + memory, make sure not to include SEVAL_NOFREE in the flags so it will + free that command string before returning. Report and fix from + Koichi Murase + +array.[ch] + - array_to_argv: now takes a second argument: COUNTP; returns the number + of elements stored in the strvec + - array_to_argv: don't store array elements with null values; it makes + it hard for callers to walk the whole array reliably + +pcomplete.c + - gen_shell_function_matches: change call to array_to_argv + +array.h + - execute_array_command: now takes the entire ARRAY * as the first + parameter + +eval.c + - execute_array_command: now takes the entire array, puts the elements + into a strvec, and executes each element of the strvevc as a command. + This protects against a command from PROMPT_COMMAND[n] unsetting the + corresponding element of PROMPT_COMMAND. + From a report from Koichi Murase diff --git a/array.c b/array.c index abfa5df4..6d3554bf 100644 --- a/array.c +++ b/array.c @@ -810,22 +810,29 @@ WORD_LIST *list; } char ** -array_to_argv (a) +array_to_argv (a, countp) ARRAY *a; +int *countp; { char **ret, *t; int i; ARRAY_ELEMENT *ae; - if (a == 0 || array_empty(a)) + if (a == 0 || array_empty(a)) { + if (countp) + *countp = 0; return ((char **)NULL); + } ret = strvec_create (array_num_elements (a) + 1); i = 0; for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { t = element_value (ae); - ret[i++] = t ? savestring (t) : (char *)NULL; + if (t) + ret[i++] = savestring (t); } ret[i] = (char *)NULL; + if (countp) + *countp = i; return (ret); } diff --git a/array.h b/array.h index a610de7c..fe218470 100644 --- a/array.h +++ b/array.h @@ -84,7 +84,7 @@ extern WORD_LIST *array_keys_to_word_list PARAMS((ARRAY *)); extern ARRAY *array_assign_list PARAMS((ARRAY *, WORD_LIST *)); -extern char **array_to_argv PARAMS((ARRAY *)); +extern char **array_to_argv PARAMS((ARRAY *, int *)); extern char *array_to_kvpair PARAMS((ARRAY *, int)); extern char *array_to_assign PARAMS((ARRAY *, int)); @@ -121,7 +121,7 @@ extern ARRAY *array_from_string PARAMS((char *, char *)); #define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*') -/* In eval.c, but uses ARRAY_ELEMENT * */ -extern int execute_array_command PARAMS((ARRAY_ELEMENT *, void *)); +/* In eval.c, but uses ARRAY * */ +extern int execute_array_command PARAMS((ARRAY *, void *)); #endif /* _ARRAY_H_ */ diff --git a/bashline.c b/bashline.c index de1d7b49..f1fb4dfa 100644 --- a/bashline.c +++ b/bashline.c @@ -4340,7 +4340,7 @@ bash_execute_unix_command (count, key) save_parser_state (&ps); rl_clear_signals (); - r = parse_and_execute (savestring (cmd), "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); + r = parse_and_execute (savestring (cmd), "bash_execute_unix_command", SEVAL_NOHIST); rl_set_signals (); restore_parser_state (&ps); diff --git a/builtins/fc.def b/builtins/fc.def index 7ebbc5c0..467dbcbc 100644 --- a/builtins/fc.def +++ b/builtins/fc.def @@ -90,6 +90,10 @@ extern int errno; #define HIST_ERANGE INT_MIN+1 #define HIST_NOTFOUND INT_MIN+2 +/* Values for the flags argument to fc_gethnum */ +#define HN_LISTING 0x01 +#define HN_FIRST 0x02 + extern int unlink PARAMS((const char *)); extern FILE *sh_mktmpfp PARAMS((char *, int, char **)); @@ -205,7 +209,7 @@ fc_builtin (list) break; case 'l': - listing = 1; + listing = HN_LISTING; /* for fc_gethnum */ break; case 'r': @@ -329,7 +333,7 @@ fc_builtin (list) if (list) { - histbeg = fc_gethnum (list->word->word, hlist, listing); + histbeg = fc_gethnum (list->word->word, hlist, listing|HN_FIRST); list = list->next; if (list) @@ -538,7 +542,9 @@ fc_number (list) /* Return an absolute index into HLIST which corresponds to COMMAND. If COMMAND is a number, then it was specified in relative terms. If it is a string, then it is the start of a command line present in HLIST. - MODE is 1 if we are listing commands, 0 if we are executing them. */ + MODE includes HN_LISTING if we are listing commands, and does not if we + are executing them. If MODE includes HN_FIRST we are looking for the + first history number specification. */ static int fc_gethnum (command, hlist, mode) char *command; @@ -546,9 +552,10 @@ fc_gethnum (command, hlist, mode) int mode; { int sign, n, clen, rh; - register int i, j, last_hist, real_last; + register int i, j, last_hist, real_last, listing; register char *s; + listing = mode & HN_LISTING; sign = 1; /* Count history elements. */ for (i = 0; hlist[i]; i++); @@ -601,19 +608,33 @@ fc_gethnum (command, hlist, mode) n = atoi (s); n *= sign; + /* We want to return something that is an offset to HISTORY_BASE. */ + /* If the value is negative or zero, then it is an offset from the current history item. */ + /* We don't use HN_FIRST here, so we don't return different values + depending on whether we're looking for the first or last in a + pair of range arguments, but nobody else does, either. */ if (n < 0) { n += i + 1; return (n < 0 ? 0 : n); } else if (n == 0) - return ((sign == -1) ? (mode ? real_last : HIST_INVALID) : i); + return ((sign == -1) ? (listing ? real_last : HIST_INVALID) : i); else { + /* If we're out of range (greater than I (last history entry) or + less than HISTORY_BASE, we want to return different values + based on whether or not we are looking for the first or last + value in a desired range of history entries. */ n -= history_base; - return (i < n ? i : n); + if (n < 0) + return (mode & HN_FIRST ? 0 : i); + else if (n >= i) + return (mode & HN_FIRST ? 0 : i); + else + return n; } } diff --git a/eval.c b/eval.c index ed3b0f24..1d967da1 100644 --- a/eval.c +++ b/eval.c @@ -263,17 +263,25 @@ send_pwd_to_eterm () } #if defined (ARRAY_VARS) +/* Caller ensures that A has a non-zero number of elements */ int -execute_array_command (ae, v) - ARRAY_ELEMENT *ae; +execute_array_command (a, v) + ARRAY *a; void *v; { - char *tag, *command; + char *tag; + char **argv; + int argc, i; tag = (char *)v; - command = element_value (ae); - if (command && *command) - execute_variable_command (command, tag); + argc = 0; + argv = array_to_argv (a, &argc); + for (i = 0; i < argc; i++) + { + if (argv[i] && argv[i][0]) + execute_variable_command (argv[i], tag); + } + strvec_dispose (argv); return 0; } #endif @@ -294,11 +302,11 @@ execute_prompt_command () if (array_p (pcv)) { if ((pcmds = array_cell (pcv)) && array_num_elements (pcmds) > 0) - array_walk (pcmds, execute_array_command, "PROMPT_COMMAND"); + execute_array_command (pcmds, "PROMPT_COMMAND"); return; } else if (assoc_p (pcv)) - return; + return; /* currently don't allow associative arrays here */ #endif command_to_execute = value_cell (pcv); diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 7af79ef7..fc5c3adb 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -148,7 +148,7 @@ static int complete_fncmp PARAMS((const char *, int, const char *, int)); static void display_matches PARAMS((char **)); static int compute_lcd_of_matches PARAMS((char **, int, const char *)); static int postprocess_matches PARAMS((char ***, int)); -static int compare_match PARAMS((const char *, const char *)); +static int compare_match PARAMS((char *, const char *)); static int complete_get_screenwidth PARAMS((void)); static char *make_quoted_replacement PARAMS((char *, int, char *)); @@ -1969,7 +1969,7 @@ _rl_free_match_list (char **matches) MATCH that is the product of filename completion, which acts on the dequoted text. */ static int -compare_match (const char *text, const char *match) +compare_match (char *text, const char *match) { char *temp; int r; diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 954031d8..050f5068 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -65,7 +65,8 @@ #define SF_FOUND 0x02 #define SF_FAILED 0x04 #define SF_CHGKMAP 0x08 -#define SF_PATTERN 0x10 /* unused so far */ +#define SF_PATTERN 0x10 +#define SF_NOCASE 0x20 /* unused so far */ typedef struct __rl_search_context { diff --git a/parse.y b/parse.y index 4b7363d6..471669c9 100644 --- a/parse.y +++ b/parse.y @@ -420,9 +420,9 @@ inputunit: simple_list simple_list_terminator global_command = (COMMAND *)NULL; if (last_command_exit_value == 0) last_command_exit_value = EX_BADUSAGE; /* force error return */ - handle_eof_input_unit (); if (interactive && parse_and_execute_level == 0) { + handle_eof_input_unit (); YYACCEPT; } else diff --git a/pcomplete.c b/pcomplete.c index d5b12e49..fe1a0320 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -1184,7 +1184,7 @@ gen_shell_function_matches (cs, cmd, text, line, ind, lwords, nw, cw, foundp) /* XXX - should we filter the list of completions so only those matching TEXT are returned? Right now, we do not. */ sl = strlist_create (0); - sl->list = array_to_argv (a); + sl->list = array_to_argv (a, 0); sl->list_len = sl->list_size = array_num_elements (a); } diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 0b063810..c8bef8dd 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/history.right b/tests/history.right index 6652156c..379de48b 100644 --- a/tests/history.right +++ b/tests/history.right @@ -241,5 +241,26 @@ c d echo d d -11 # other out-of-range behavior for future work -12 fc -l 498 502 +a +b +c +d +e +f +4 echo d +5 echo e +6 echo f +out of range 1 +6 echo f +7 fc -l +8 echo out of range 1 +out of range 2 +8 echo out of range 1 +9 fc -l 502 498 +10 echo out of range 2 +out of range 3 +10 echo out of range 2 +11 fc -l 498 502 +12 echo out of range 3 +out of range 4 +13 fc -l 1 99 diff --git a/tests/history5.sub b/tests/history5.sub index 9b88c546..c44ace8a 100644 --- a/tests/history5.sub +++ b/tests/history5.sub @@ -14,7 +14,7 @@ trap 'rm -f $HISTFILE' 0 1 2 3 6 15 -HISTFILE=$TMPDIR/foohist-$$ +HISTFILE=$TMPDIR/fchist-$$ unset HISTIGNORE HISTCONTROL set -o history @@ -33,6 +33,23 @@ fc -l -0 echo d fc -s 0 -# other out-of-range behavior for future work -fc -l 498 502 +HISTSIZE=4 +history -c + +echo a +echo b +echo c +echo d +echo e +echo f +fc -l + +echo out of range 1 fc -l 502 498 +echo out of range 2 +fc -l 498 502 +echo out of range 3 +fc -l 1 99 +# other out-of-range behavior for future work +echo out of range 4 +fc -l -20 -40