- _rl_domove_motion_cleanup: ditto for y/Y
- rl_domove_motion_callback: if t/T/;/, fail (return non-zero without
moving point), flag the motion command as having failed (MOVE_FAILED)
+
+ 4/6
+ ---
+subst.c
+ - command_substitute: save the return status of the child process in
+ last_command_subst_status; don't assign to last_command_exit_value
+ in posix mode (posix interp 1150)
+
+execute_cmd.c
+ - execute_null_command: a simple command without a command word but
+ with command substitutions now returns last_command_subst_status.
+ It may or may not have already modified $? depending on posix mode
+
+redir.c
+ - redir_varvalue: legal_number validity check should be == 0, not < 0
+ From a report by Grisha Levit <grishalevit@gmail.com>
+
+ 4/10
+ ----
+subst.c
+ - parameter_brace_expand_rhs: check for namerefs in the variable name
+ part of the ${name=word} expansion so we can go back and implement
+ the POSIX semantics of returning "the final value of parameter."
+ From a report by Grisha Levit <grishalevit@gmail.com>
+
+sig.c,sig.h
+ - sigpipe_handler: clean up, set $?, and throw to top level on receipt
+ of a SIGPIPE
+ - termsig_handler: if the variable builtin_catch_sigpipe is set (it's
+ not set anywhere yet), call sigpipe_handler instead of terminating
+ the shell. Still need to make sure a sighandler is installed for
+ SIGPIPE even if initialize_terminating_signals isn't called
That means, for example, that a backslash preceding a double quote
character will escape it and the backslash will be removed.
+@item
+Command substitutions don't set the @samp{?} special parameter. The exit
+status of a simple command without a command word is still the exit status
+of the last command substitution that occurred while evaluating the variable
+assignments and redirections in that command, but that does not happen until
+after all of the assignments and redirections.
+
@end enumerate
There is other @sc{posix} behavior that Bash does not implement by
Copyright (C) 1988-2023 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Tue Mar 21 11:05:49 EDT 2023
+@set LASTCHANGE Thu Apr 6 11:58:41 EDT 2023
@set EDITION 5.2
@set VERSION 5.2
-@set UPDATED 21 March 2023
-@set UPDATED-MONTH March 2023
+@set UPDATED 6 April 2023
+@set UPDATED-MONTH April 2023
if (r != 0)
return (EXECUTION_FAILURE);
else if (last_command_subst_pid != NO_PID)
- return (last_command_exit_value);
+ return (last_command_subst_status);
else
return (EXECUTION_SUCCESS);
}
WORD_LIST *list;
char *result, *t, *orig_string;
struct dstack save_dstack;
- int last_exit_value, last_comsub_pid;
+ int last_exit_value, last_comsub_pid, last_comsub_status;
#if defined (PROMPT_STRING_DECODE)
size_t result_size;
size_t result_index;
{
last_exit_value = last_command_exit_value;
last_comsub_pid = last_command_subst_pid;
+ last_comsub_status = last_command_subst_status;
list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0);
free (result);
result = string_list (list);
dispose_words (list);
last_command_exit_value = last_exit_value;
last_command_subst_pid = last_comsub_pid;
+ last_command_subst_status = last_comsub_status;
}
else
{
if (val == 0 || *val == 0)
return -1;
- if (legal_number (val, &vmax) < 0)
+ if (legal_number (val, &vmax) == 0)
return -1;
i = vmax; /* integer truncation */
/* Set to the value of any terminating signal received. */
volatile sig_atomic_t terminating_signal = 0;
+volatile int builtin_catch_sigpipe = 0;
+
/* The environment at the top-level R-E loop. We use this in
the case of error return. */
procenv_t top_level;
handling_termsig = terminating_signal; /* for termsig_sighandler */
terminating_signal = 0; /* keep macro from re-testing true. */
+ if (builtin_catch_sigpipe)
+ sigpipe_handler (sig);
+
/* I don't believe this condition ever tests true. */
if (sig == SIGINT && signal_is_trapped (SIGINT))
run_interrupt_trap (0);
set_exit_status (128 + sig);
throw_to_top_level ();
}
+
#if defined (READLINE)
/* Set the event hook so readline will call it after the signal handlers
finish executing, so if this interrupted character input we can get
SIGRETURN (0);
}
+void
+sigpipe_handler (int sig)
+{
+ handling_termsig = 0;
+ builtin_catch_sigpipe = 0;
+ last_command_exit_value = 128 + sig;
+ throw_to_top_level ();
+}
+
/* Signal functions used by the rest of the code. */
#if !defined (HAVE_POSIX_SIGNALS)
extern int interrupt_immediately; /* no longer used */
extern int terminate_immediately;
+extern volatile int builtin_catch_sigpipe; /* not used yet */
+
/* Functions from sig.c. */
extern sighandler termsig_sighandler (int);
extern void termsig_handler (int);
extern sighandler sigterm_sighandler (int);
+extern void sigpipe_handler (int);
+
/* Functions defined in trap.c. */
extern SigHandler *set_sigint_handler (void);
extern SigHandler *trap_to_sighandler (int);
/* Process ID of the last command executed within command substitution. */
pid_t last_command_subst_pid = NO_PID;
pid_t current_command_subst_pid = NO_PID;
+int last_command_subst_status = 0;
/* Variables used to keep track of the characters in IFS. */
SHELL_VAR *ifs_var;
istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
if (istring == &expand_param_error)
{
- last_command_exit_value = EXECUTION_FAILURE;
+ last_command_subst_status = EXECUTION_FAILURE;
istring = 0;
}
else
- last_command_exit_value = EXECUTION_SUCCESS; /* compat */
+ last_command_subst_status = EXECUTION_SUCCESS; /* compat */
last_command_subst_pid = dollar_dollar_pid;
+ if (posixly_correct == 0) /* POSIX interp 1150 */
+ last_command_exit_value = last_command_subst_status; /* XXX */
+
dispose_command (cmd);
ret = alloc_word_desc ();
ret->word = istring;
UNBLOCK_SIGNAL (oset);
current_command_subst_pid = pid;
- last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
+ last_command_subst_status = wait_for (pid, JWAIT_NOTERM);
last_command_subst_pid = pid;
last_made_pid = old_pid;
+ if (posixly_correct == 0) /* POSIX interp 1150 */
+ last_command_exit_value = last_command_subst_status; /* XXX */
+
#if defined (JOB_CONTROL)
/* If last_command_exit_value > 128, then the substituted command
was terminated by a signal. If that signal was SIGINT, then send
return &expand_wdesc_error;
}
}
-
+ /* We check for this here instead of letting bind_variable do it so we can
+ satisfy the POSIX semantics of returning the final value assigned to the
+ variable, even after assignment transformations (uppercase, lowercase, etc.).
+ We need the final name to get the right value back. */
+ else if ((v = find_variable_last_nameref (name, 0)) && nameref_p (v))
+ {
+ temp = nameref_cell (v);
+ /* shouldn't happen at this point, but... */
+ if (temp == 0 || *temp == 0)
+ {
+ report_error (_("%s: bad substitution"), name);
+ free (t1);
+ dispose_word (w);
+ return &expand_wdesc_error;
+ }
+ vname = savestring (temp);
+ }
+
arrayref = 0;
#if defined (ARRAY_VARS)
if (valid_array_reference (vname, 0))
extern int inherit_errexit;
extern pid_t last_command_subst_pid;
+extern int last_command_subst_status;
/* Evaluates to 1 if C is a character in $IFS. */
#define isifs(c) (ifs_cmap[(unsigned char)(c)] != 0)
one
expect <four>
four
+expect <X>
+X
+expect <X>
+X
errors = 0
1
2
echo $qux
ckval qux ${bar[3]}
+bar=()
+declare -n ref='bar[1]'
+
+echo "expect <X>"
+echo ${ref=X}
+ckval ref ${bar[1]}
+
+unset -n ref
+declare -n ref
+
+echo "expect <X>"
+echo ${ref=X}
+ckval ref ${ref}
+
# Need to add code and tests for `for' loop nameref variables
echo errors = $errors