mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 13:18:59 +08:00
Make subcommands modify $status, and make builtin_set not modify status unless it fails
https://github.com/fish-shell/fish-shell/issues/547 https://github.com/fish-shell/fish-shell/issues/214
This commit is contained in:
parent
0db1b6ce44
commit
ad8d68dd43
|
@ -358,11 +358,9 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
|
|||
/* If we have a script, either built-in or a file source, then run it */
|
||||
if (really_load && has_script_source)
|
||||
{
|
||||
if (exec_subshell(script_source) == -1)
|
||||
if (exec_subshell(script_source, false /* do not apply exit status */) == -1)
|
||||
{
|
||||
/*
|
||||
Do nothing on failiure
|
||||
*/
|
||||
/* Do nothing on failure */
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -215,7 +215,7 @@ wcstring builtin_help_get(parser_t &parser, const wchar_t *name)
|
|||
wcstring out;
|
||||
const wcstring name_esc = escape_string(name, 1);
|
||||
const wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str());
|
||||
if (exec_subshell(cmd, lst) >= 0)
|
||||
if (exec_subshell(cmd, lst, false /* don't apply exit status */) >= 0)
|
||||
{
|
||||
for (size_t i=0; i<lst.size(); i++)
|
||||
{
|
||||
|
|
|
@ -379,58 +379,21 @@ static void print_variables(int include_values, int esc, bool shorten_ok, int sc
|
|||
*/
|
||||
static int builtin_set(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
|
||||
/**
|
||||
Variables used for parsing the argument list
|
||||
*/
|
||||
static const struct woption
|
||||
long_options[] =
|
||||
/** Variables used for parsing the argument list */
|
||||
const struct woption long_options[] =
|
||||
{
|
||||
{
|
||||
L"export", no_argument, 0, 'x'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"global", no_argument, 0, 'g'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"local", no_argument, 0, 'l'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"erase", no_argument, 0, 'e'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"names", no_argument, 0, 'n'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"unexport", no_argument, 0, 'u'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"universal", no_argument, 0, 'U'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"long", no_argument, 0, 'L'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"query", no_argument, 0, 'q'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
{ L"export", no_argument, 0, 'x' },
|
||||
{ L"global", no_argument, 0, 'g' },
|
||||
{ L"local", no_argument, 0, 'l' },
|
||||
{ L"erase", no_argument, 0, 'e' },
|
||||
{ L"names", no_argument, 0, 'n' },
|
||||
{ L"unexport", no_argument, 0, 'u' },
|
||||
{ L"universal", no_argument, 0, 'U' },
|
||||
{ L"long", no_argument, 0, 'L' },
|
||||
{ L"query", no_argument, 0, 'q' },
|
||||
{ L"help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 }
|
||||
} ;
|
||||
|
||||
const wchar_t *short_options = L"+xglenuULqh";
|
||||
|
||||
|
@ -443,6 +406,8 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
|
|||
int erase = 0, list = 0, unexport=0;
|
||||
int universal = 0, query=0;
|
||||
bool shorten_ok = true;
|
||||
bool preserve_incoming_failure_exit_status = true;
|
||||
const int incoming_exit_status = proc_get_last_status();
|
||||
|
||||
/*
|
||||
Variables used for performing the actual work
|
||||
|
@ -474,10 +439,12 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
|
|||
|
||||
case 'e':
|
||||
erase = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
list = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
|
@ -506,6 +473,7 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
|
|||
|
||||
case 'q':
|
||||
query = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
|
@ -825,6 +793,8 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
|
|||
|
||||
free(dest);
|
||||
|
||||
if (retcode == STATUS_BUILTIN_OK && preserve_incoming_failure_exit_status)
|
||||
retcode = incoming_exit_status;
|
||||
return retcode;
|
||||
|
||||
}
|
||||
|
|
2
color.h
2
color.h
|
@ -135,7 +135,7 @@ public:
|
|||
/** Returns whether the color is bold */
|
||||
bool is_bold() const
|
||||
{
|
||||
return !! (flags & flag_bold);
|
||||
return !!(flags & flag_bold);
|
||||
}
|
||||
|
||||
/** Set whether the color is bold */
|
||||
|
|
2
common.h
2
common.h
|
@ -150,7 +150,7 @@ extern const wchar_t *program_name;
|
|||
read( 0, &exit_read_buff, 1 ); \
|
||||
exit_without_destructors( 1 ); \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Exit program at once, leaving an error message about running out of memory.
|
||||
|
|
|
@ -465,7 +465,7 @@ bool completer_t::condition_test(const wcstring &condition)
|
|||
if (cached_entry == condition_cache.end())
|
||||
{
|
||||
/* Compute new value and reinsert it */
|
||||
test_res = (0 == exec_subshell(condition));
|
||||
test_res = (0 == exec_subshell(condition, false /* don't apply exit status */));
|
||||
condition_cache[condition] = test_res;
|
||||
}
|
||||
else
|
||||
|
@ -1007,7 +1007,7 @@ void completer_t::complete_cmd_desc(const wcstring &str)
|
|||
since apropos is only called once.
|
||||
*/
|
||||
wcstring_list_t list;
|
||||
if (exec_subshell(lookup_cmd, list) != -1)
|
||||
if (exec_subshell(lookup_cmd, list, false /* don't apply exit status */) != -1)
|
||||
{
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,8 +11,7 @@ By defining the \c fish_prompt function, the user can choose a custom
|
|||
prompt. The \c fish_prompt function is executed when the prompt is to
|
||||
be shown, and the output is used as a prompt.
|
||||
|
||||
Please keep in mind that the function is executed by <a
|
||||
href='index.html#expand-command-substitution'>command substitution</a>, and so the exit status of commands within fish_prompt will not modify the <a href="index.html#variables-status">$status</a> seen outside of fish_prompt.
|
||||
The exit status of commands within \c fish_prompt will not modify the <a href="index.html#variables-status">$status</a> seen outside of fish_prompt.
|
||||
|
||||
\subsection fish_prompt-example Example
|
||||
|
||||
|
|
|
@ -578,9 +578,8 @@ this list is executed, and substituted by the output. If the output is
|
|||
more than one line long, each line will be expanded to a new
|
||||
parameter.
|
||||
|
||||
A command substitution will not change the value of the <a
|
||||
href='#variables-status'>status</a> variable outside of the command
|
||||
substitution.
|
||||
The exit status of the last run command substitution is available in the <a
|
||||
href='#variables-status'>status</a> variable.
|
||||
|
||||
Only part of the output can be used, see <a href='#expand-index-range'>index
|
||||
range expansion</a> for details.
|
||||
|
|
|
@ -68,13 +68,14 @@ non-switch arguments. For example, <code>set flags -l</code> will have
|
|||
the effect of setting the value of the variable <code>flags</code> to
|
||||
'-l', not making the variable local.
|
||||
|
||||
In assignment mode, set exits with an exit status of zero it the
|
||||
variable assignments where sucessfully performed, with a non-zero exit
|
||||
status otherwise. In query mode, the exit status is the number of
|
||||
variables that where not found. In erase mode, set exits with a zero
|
||||
exit status in case of success, with a non-zero exit status if the
|
||||
commandline was invalid, if the variable was write-protected or if the
|
||||
variable did not exist.
|
||||
In assignment mode, set exits with a non-zero exit status if variable
|
||||
assignments could not be successfully performed. If the variable assignments
|
||||
were performed, the exit status is unchanged. This allows simultaneous capture
|
||||
of the output and exit status of a subcommand, e.g. <code>if set output
|
||||
(command)</code>. In query mode, the exit status is the number of variables that
|
||||
were not found. In erase mode, set exits with a zero exit status in case of
|
||||
success, with a non-zero exit status if the commandline was invalid, if the
|
||||
variable was write-protected or if the variable did not exist.
|
||||
|
||||
\subsection set-example Example
|
||||
|
||||
|
@ -85,3 +86,9 @@ variable did not exist.
|
|||
<code>set -e smurf</code> removes the variable \c smurf.
|
||||
|
||||
<code>set PATH[4] ~/bin</code> changes the fourth element of the \c PATH array to \c ~/bin
|
||||
|
||||
<pre>if set python_path (which python)
|
||||
echo "Python is at $python_path"
|
||||
end</pre>
|
||||
|
||||
The above outputs the path to Python if \c which returns true.
|
||||
|
|
81
exec.cpp
81
exec.cpp
|
@ -125,7 +125,7 @@ void exec_close(int fd)
|
|||
int exec_pipe(int fd[2])
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
|
||||
int res;
|
||||
while ((res=pipe(fd)))
|
||||
{
|
||||
|
@ -621,11 +621,11 @@ void exec(parser_t &parser, job_t *j)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// This is a pipe that the "current" process in our loop below reads from
|
||||
// Only pipe_read->pipe_fd[0] is used
|
||||
shared_ptr<io_pipe_t> pipe_read(new io_pipe_t(0, true));
|
||||
|
||||
|
||||
// This is the pipe that the "current" process in our loop below writes to
|
||||
shared_ptr<io_pipe_t> pipe_write(new io_pipe_t(1, false));
|
||||
|
||||
|
@ -687,7 +687,7 @@ void exec(parser_t &parser, job_t *j)
|
|||
set_child_group(j, &keepalive, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This loop loops over every process_t in the job, starting it as
|
||||
appropriate. This turns out to be rather complex, since a
|
||||
|
@ -695,17 +695,17 @@ void exec(parser_t &parser, job_t *j)
|
|||
|
||||
The loop also has to handle pipelining between the jobs.
|
||||
*/
|
||||
|
||||
|
||||
/* We can have up to three pipes "in flight" at a time:
|
||||
|
||||
|
||||
1. The pipe the current process should read from (courtesy of the previous process)
|
||||
2. The pipe that the current process should write to
|
||||
3. The pipe that the next process should read from (courtesy of us)
|
||||
|
||||
|
||||
We are careful to set these to -1 when closed, so if we exit the loop abruptly, we can still close them.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int pipe_current_read = -1, pipe_current_write = -1, pipe_next_read = -1;
|
||||
for (process_t *p=j->first_process; p; p = p->next)
|
||||
{
|
||||
|
@ -713,10 +713,10 @@ void exec(parser_t &parser, job_t *j)
|
|||
assert(pipe_current_read == -1);
|
||||
pipe_current_read = pipe_next_read;
|
||||
pipe_next_read = -1;
|
||||
|
||||
|
||||
/* Record the current read in pipe_read */
|
||||
pipe_read->pipe_fd[0] = pipe_current_read;
|
||||
|
||||
|
||||
/* See if we need a pipe */
|
||||
const bool pipes_to_next_command = (p->next != NULL);
|
||||
|
||||
|
@ -760,15 +760,15 @@ void exec(parser_t &parser, job_t *j)
|
|||
job_mark_process_as_failed(j, p);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// This tells the redirection about the fds, but the redirection does not close them
|
||||
memcpy(pipe_write->pipe_fd, local_pipe, sizeof(int)*2);
|
||||
|
||||
|
||||
// Record our pipes
|
||||
// The fds should be negative to indicate that we aren't overwriting an fd we failed to close
|
||||
assert(pipe_current_write == -1);
|
||||
pipe_current_write = local_pipe[1];
|
||||
|
||||
|
||||
assert(pipe_next_read == -1);
|
||||
pipe_next_read = local_pipe[0];
|
||||
}
|
||||
|
@ -838,7 +838,7 @@ void exec(parser_t &parser, job_t *j)
|
|||
j->io.push_back(io_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! exec_error)
|
||||
{
|
||||
internal_exec_helper(parser, def.c_str(), TOP, j->io);
|
||||
|
@ -865,7 +865,7 @@ void exec(parser_t &parser, job_t *j)
|
|||
j->io.push_back(io_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! exec_error)
|
||||
{
|
||||
internal_exec_helper(parser, p->argv0(), TOP, j->io);
|
||||
|
@ -1389,7 +1389,7 @@ void exec(parser_t &parser, job_t *j)
|
|||
exec_close(pipe_current_read);
|
||||
pipe_current_read = -1;
|
||||
}
|
||||
|
||||
|
||||
/* Close the write end too, since the curent child subprocess already has a copy of it. */
|
||||
if (pipe_current_write >= 0)
|
||||
{
|
||||
|
@ -1397,7 +1397,7 @@ void exec(parser_t &parser, job_t *j)
|
|||
pipe_current_write = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Clean up any file descriptors we left open */
|
||||
if (pipe_current_read >= 0)
|
||||
exec_close(pipe_current_read);
|
||||
|
@ -1405,7 +1405,7 @@ void exec(parser_t &parser, job_t *j)
|
|||
exec_close(pipe_current_write);
|
||||
if (pipe_next_read >= 0)
|
||||
exec_close(pipe_next_read);
|
||||
|
||||
|
||||
/* The keepalive process is no longer needed, so we terminate it with extreme prejudice */
|
||||
if (needs_keepalive)
|
||||
{
|
||||
|
@ -1438,11 +1438,11 @@ void exec(parser_t &parser, job_t *j)
|
|||
}
|
||||
|
||||
|
||||
static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
|
||||
static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, bool apply_exit_status)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
int prev_subshell = is_subshell;
|
||||
int status, prev_status;
|
||||
const int prev_status = proc_get_last_status();
|
||||
char sep=0;
|
||||
|
||||
const env_var_t ifs = env_get_string(L"IFS");
|
||||
|
@ -1456,38 +1456,33 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
|
|||
else
|
||||
{
|
||||
sep = 0;
|
||||
debug(0, L"Warning - invalid command substitution separator '%lc'. Please change the firsta character of IFS", ifs[0]);
|
||||
debug(0, L"Warning - invalid command substitution separator '%lc'. Please change the first character of IFS", ifs[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
is_subshell=1;
|
||||
|
||||
prev_status = proc_get_last_status();
|
||||
|
||||
const shared_ptr<io_buffer_t> io_buffer(io_buffer_t::create(0));
|
||||
|
||||
int subcommand_status = -1; //assume the worst
|
||||
|
||||
// IO buffer creation may fail (e.g. if we have too many open files to make a pipe), so this may be null
|
||||
if (io_buffer.get() == NULL)
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
else
|
||||
const shared_ptr<io_buffer_t> io_buffer(io_buffer_t::create(0));
|
||||
if (io_buffer.get() != NULL)
|
||||
{
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
if (parser.eval(cmd, io_chain_t(io_buffer), SUBST))
|
||||
if (parser.eval(cmd, io_chain_t(io_buffer), SUBST) == 0)
|
||||
{
|
||||
status = -1;
|
||||
subcommand_status = proc_get_last_status();
|
||||
}
|
||||
else
|
||||
{
|
||||
status = proc_get_last_status();
|
||||
}
|
||||
|
||||
|
||||
io_buffer->read();
|
||||
}
|
||||
|
||||
proc_set_last_status(prev_status);
|
||||
// If the caller asked us to preserve the exit status, restore the old status
|
||||
// Otherwise set the status of the subcommand
|
||||
proc_set_last_status(apply_exit_status ? subcommand_status : prev_status);
|
||||
|
||||
|
||||
is_subshell = prev_subshell;
|
||||
|
||||
|
@ -1515,17 +1510,17 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
|
|||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return subcommand_status;
|
||||
}
|
||||
|
||||
int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs)
|
||||
int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs, bool apply_exit_status)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
return exec_subshell_internal(cmd, &outputs);
|
||||
return exec_subshell_internal(cmd, &outputs, apply_exit_status);
|
||||
}
|
||||
|
||||
__warn_unused int exec_subshell(const wcstring &cmd)
|
||||
__warn_unused int exec_subshell(const wcstring &cmd, bool apply_exit_status)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
return exec_subshell_internal(cmd, NULL);
|
||||
return exec_subshell_internal(cmd, NULL, apply_exit_status);
|
||||
}
|
||||
|
|
4
exec.h
4
exec.h
|
@ -54,8 +54,8 @@ void exec(parser_t &parser, job_t *j);
|
|||
|
||||
\return the status of the last job to exit, or -1 if en error was encountered.
|
||||
*/
|
||||
__warn_unused int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs);
|
||||
__warn_unused int exec_subshell(const wcstring &cmd);
|
||||
__warn_unused int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs, bool preserve_exit_status);
|
||||
__warn_unused int exec_subshell(const wcstring &cmd, bool preserve_exit_status);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1352,7 +1352,7 @@ static int expand_cmdsubst(parser_t &parser, const wcstring &input, std::vector<
|
|||
|
||||
const wcstring subcmd(paran_begin + 1, paran_end-paran_begin - 1);
|
||||
|
||||
if (exec_subshell(subcmd, sub_res) == -1)
|
||||
if (exec_subshell(subcmd, sub_res, true /* do apply exit status */) == -1)
|
||||
{
|
||||
parser.error(CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution");
|
||||
return 0;
|
||||
|
|
4
kill.cpp
4
kill.cpp
|
@ -112,7 +112,7 @@ void kill_add(const wcstring &str)
|
|||
|
||||
if (! cmd.empty())
|
||||
{
|
||||
if (exec_subshell(cmd) == -1)
|
||||
if (exec_subshell(cmd, false /* do not apply exit status */) == -1)
|
||||
{
|
||||
/*
|
||||
Do nothing on failiure
|
||||
|
@ -175,7 +175,7 @@ static void kill_check_x_buffer()
|
|||
wcstring cmd = L"xsel -t 500 -b";
|
||||
wcstring new_cut_buffer=L"";
|
||||
wcstring_list_t list;
|
||||
if (exec_subshell(cmd, list) != -1)
|
||||
if (exec_subshell(cmd, list, false /* do not apply exit status */) != -1)
|
||||
{
|
||||
|
||||
for (i=0; i<list.size(); i++)
|
||||
|
|
13
parser.cpp
13
parser.cpp
|
@ -1203,7 +1203,7 @@ bool parser_t::job_remove(job_t *j)
|
|||
void parser_t::job_promote(job_t *job)
|
||||
{
|
||||
signal_block();
|
||||
|
||||
|
||||
job_list_t::iterator loc = std::find(my_job_list.begin(), my_job_list.end(), job);
|
||||
assert(loc != my_job_list.end());
|
||||
|
||||
|
@ -2900,11 +2900,12 @@ int parser_t::test_args(const wchar_t * buff, wcstring *out, const wchar_t *pre
|
|||
}
|
||||
|
||||
// helper type used in parser::test below
|
||||
struct block_info_t {
|
||||
struct block_info_t
|
||||
{
|
||||
int position; //tokenizer position
|
||||
block_type_t type; //type of the block
|
||||
int indentation; //indentation associated with the block
|
||||
|
||||
|
||||
bool has_had_case; //if we are a switch, whether we've encountered a case
|
||||
};
|
||||
|
||||
|
@ -2922,7 +2923,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
|
|||
|
||||
tokenizer_t * const previous_tokenizer=current_tokenizer;
|
||||
const int previous_pos=current_tokenizer_pos;
|
||||
|
||||
|
||||
// These are very nearly stacks, but sometimes we have to inspect non-top elements (e.g. return)
|
||||
std::vector<struct block_info_t> block_infos;
|
||||
int indentation_sum = 0; //sum of indentation in block_infos
|
||||
|
@ -3040,7 +3041,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
|
|||
{
|
||||
tok_next(&tok);
|
||||
tok_set_pos(&tok, mark);
|
||||
|
||||
|
||||
/* Test that end is not used when not inside any block */
|
||||
if (block_infos.empty())
|
||||
{
|
||||
|
@ -3060,7 +3061,7 @@ int parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const w
|
|||
{
|
||||
indentation_sum -= block_infos.back().indentation;
|
||||
block_infos.pop_back();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "exec.h"
|
||||
|
||||
#ifndef JOIN_THREADS_BEFORE_FORK
|
||||
#define JOIN_THREADS_BEFORE_FORK 0
|
||||
#define JOIN_THREADS_BEFORE_FORK 0
|
||||
#endif
|
||||
|
||||
/** The number of times to try to call fork() before giving up */
|
||||
|
|
2
proc.cpp
2
proc.cpp
|
@ -328,7 +328,7 @@ void job_set_flag(job_t *j, unsigned int flag, int set)
|
|||
|
||||
int job_get_flag(const job_t *j, unsigned int flag)
|
||||
{
|
||||
return !! (j->flags & flag);
|
||||
return !!(j->flags & flag);
|
||||
}
|
||||
|
||||
int job_signal(job_t *j, int signal)
|
||||
|
|
18
reader.cpp
18
reader.cpp
|
@ -692,7 +692,7 @@ void reader_write_title()
|
|||
wcstring_list_t lst;
|
||||
|
||||
proc_push_interactive(0);
|
||||
if (exec_subshell(title, lst) != -1)
|
||||
if (exec_subshell(title, lst, false /* do not apply exit status */) != -1)
|
||||
{
|
||||
size_t i;
|
||||
if (lst.size() > 0)
|
||||
|
@ -718,6 +718,9 @@ static void exec_prompt()
|
|||
data->left_prompt_buff.clear();
|
||||
data->right_prompt_buff.clear();
|
||||
|
||||
/* Do not allow the exit status of the prompts to leak through */
|
||||
const bool apply_exit_status = false;
|
||||
|
||||
/* If we have any prompts, they must be run non-interactively */
|
||||
if (data->left_prompt.size() || data->right_prompt.size())
|
||||
{
|
||||
|
@ -726,9 +729,9 @@ static void exec_prompt()
|
|||
if (! data->left_prompt.empty())
|
||||
{
|
||||
wcstring_list_t prompt_list;
|
||||
// status is ignored
|
||||
if (exec_subshell(data->left_prompt, prompt_list))
|
||||
if (exec_subshell(data->left_prompt, prompt_list, apply_exit_status))
|
||||
{
|
||||
// returned status value is ignored
|
||||
}
|
||||
for (size_t i = 0; i < prompt_list.size(); i++)
|
||||
{
|
||||
|
@ -741,8 +744,9 @@ static void exec_prompt()
|
|||
{
|
||||
wcstring_list_t prompt_list;
|
||||
// status is ignored
|
||||
if (exec_subshell(data->right_prompt, prompt_list))
|
||||
if (exec_subshell(data->right_prompt, prompt_list, apply_exit_status))
|
||||
{
|
||||
// returned status value is ignored
|
||||
}
|
||||
for (size_t i = 0; i < prompt_list.size(); i++)
|
||||
{
|
||||
|
@ -1048,10 +1052,10 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
|
|||
wcstring msg;
|
||||
wcstring prefix_esc;
|
||||
char *foo;
|
||||
|
||||
|
||||
shared_ptr<io_buffer_t> in(io_buffer_t::create(true));
|
||||
shared_ptr<io_buffer_t> out(io_buffer_t::create(false));
|
||||
|
||||
|
||||
// The above may fail e.g. if we have too many open fds
|
||||
if (in.get() == NULL || out.get() == NULL)
|
||||
return;
|
||||
|
@ -1140,7 +1144,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
|
|||
free(foo);
|
||||
|
||||
out->fd = 4;
|
||||
|
||||
|
||||
term_donate();
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
io_chain_t io_chain;
|
||||
|
|
|
@ -1373,20 +1373,20 @@ void s_reset(screen_t *s, screen_reset_mode_t mode)
|
|||
}
|
||||
else
|
||||
{
|
||||
// draw in "bright black" (gray)
|
||||
// draw in "bright black" (gray)
|
||||
abandon_line_string.append(L"\x1b[0m" //bright
|
||||
L"\x1b[30;1m"); //black
|
||||
}
|
||||
abandon_line_string.push_back(omitted_newline_char);
|
||||
abandon_line_string.append(L"\x1b[0m"); //normal text ANSI escape sequence
|
||||
abandon_line_string.append(screen_width - non_space_width, L' ');
|
||||
|
||||
|
||||
}
|
||||
abandon_line_string.push_back(L'\r');
|
||||
// now we are certainly on a new line. But we may have dropped the omitted newline char on it. So append enough spaces to overwrite the omitted newline char, and then
|
||||
abandon_line_string.append(non_space_width, L' ');
|
||||
abandon_line_string.push_back(L'\r');
|
||||
|
||||
|
||||
const std::string narrow_abandon_line_string = wcs2string(abandon_line_string);
|
||||
write_loop(STDOUT_FILENO, narrow_abandon_line_string.c_str(), narrow_abandon_line_string.size());
|
||||
s->actual.cursor.x = 0;
|
||||
|
|
|
@ -160,3 +160,20 @@ else
|
|||
end;
|
||||
|
||||
set -U -e baz
|
||||
|
||||
echo "Verify subcommand statuses"
|
||||
echo (false) $status (true) $status (false) $status
|
||||
|
||||
echo "Verify that set passes through exit status, except when passed -n or -q or -e"
|
||||
false ; set foo bar ; echo 1 $status # passthrough
|
||||
true ; set foo bar ; echo 2 $status # passthrough
|
||||
false ; set -q foo ; echo 3 $status # no passthrough
|
||||
true ; set -q foo ; echo 4 $status # no passthrough
|
||||
false ; set -n > /dev/null ; echo 5 $status # no passthrough
|
||||
false ; set -e foo ; echo 6 $status # no passthrough
|
||||
true ; set -e foo ; echo 7 $status # no passthrough
|
||||
false ; set -h > /dev/null ; echo 8 $status # no passthrough
|
||||
true ; set -NOT_AN_OPTION 2> /dev/null ; echo 9 $status # no passthrough
|
||||
false ; set foo (echo A; true) ; echo 10 $status $foo
|
||||
true ; set foo (echo B; false) ; echo 11 $status $foo
|
||||
true
|
||||
|
|
|
@ -20,3 +20,17 @@ Test 19 pass
|
|||
Test 20 pass
|
||||
Test 21 pass
|
||||
Test 22 pass
|
||||
Verify subcommand statuses
|
||||
1 0 1
|
||||
Verify that set passes through exit status, except when passed -n or -q or -e
|
||||
1 1
|
||||
2 0
|
||||
3 0
|
||||
4 0
|
||||
5 0
|
||||
6 0
|
||||
7 1
|
||||
8 0
|
||||
9 1
|
||||
10 0 A
|
||||
11 1 B
|
||||
|
|
|
@ -336,7 +336,7 @@ static wcstring complete_get_desc_suffix_internal(const wcstring &suff)
|
|||
wcstring_list_t lst;
|
||||
wcstring desc;
|
||||
|
||||
if (exec_subshell(cmd, lst) != -1)
|
||||
if (exec_subshell(cmd, lst, false /* do not apply exit status */) != -1)
|
||||
{
|
||||
if (lst.size()>0)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user