Change builtins to return maybe_t<int> instead of int

This commit is contained in:
Soumya 2020-07-18 10:25:43 -07:00 committed by ridiculousfish
parent 56c64281bd
commit 8dd2d4f15d
78 changed files with 197 additions and 101 deletions

View File

@ -4,7 +4,7 @@
//
// 1). Create a function in builtin.c with the following signature:
//
// <tt>static int builtin_NAME(parser_t &parser, io_streams_t &streams, wchar_t **argv)</tt>
// <tt>static maybe_t<int> builtin_NAME(parser_t &parser, io_streams_t &streams, wchar_t **argv)</tt>
//
// where NAME is the name of the builtin, and args is a zero-terminated list of arguments.
//
@ -201,7 +201,7 @@ void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wch
/// A generic bultin that only supports showing a help message. This is only a placeholder that
/// prints the help message. Useful for commands that live in the parser.
static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
static maybe_t<int> builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;
@ -228,7 +228,7 @@ static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **ar
// Since this is just for counting, it can be massive.
#define COUNT_CHUNK_SIZE (512 * 256)
/// Implementation of the builtin count command, used to count the number of arguments sent to it.
static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
static maybe_t<int> builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
int argc = 0;
@ -256,7 +256,7 @@ static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv
/// This function handles both the 'continue' and the 'break' builtins that are used for loop
/// control.
static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
static maybe_t<int> builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int is_break = (std::wcscmp(argv[0], L"break") == 0);
int argc = builtin_count_args(argv);
@ -287,7 +287,7 @@ static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar
}
/// Implementation of the builtin breakpoint command, used to launch the interactive debugger.
static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
static maybe_t<int> builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
if (argv[1] != nullptr) {
streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, cmd, 0, builtin_count_args(argv) - 1);
@ -313,21 +313,21 @@ static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t *
return parser.get_last_status();
}
int builtin_true(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_true(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
UNUSED(streams);
UNUSED(argv);
return STATUS_CMD_OK;
}
int builtin_false(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_false(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
UNUSED(streams);
UNUSED(argv);
return STATUS_CMD_ERROR;
}
int builtin_gettext(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_gettext(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
UNUSED(streams);
for (int i = 1; i < builtin_count_args(argv); i++) {
@ -459,8 +459,11 @@ proc_status_t builtin_run(parser_t &parser, wchar_t **argv, io_streams_t &stream
}
if (const builtin_data_t *data = builtin_lookup(argv[0])) {
int ret = data->func(parser, streams, argv);
return proc_status_t::from_exit_code(ret);
maybe_t<int> ret = data->func(parser, streams, argv);
if (!ret) {
return proc_status_t::empty();
}
return proc_status_t::from_exit_code(ret.value());
}
FLOGF(error, UNKNOWN_BUILTIN_ERR_MSG, argv[0]);

View File

@ -20,7 +20,7 @@ struct builtin_data_t {
// Name of the builtin.
const wchar_t *name;
// Function pointer to the builtin implementation.
int (*func)(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> (*func)(parser_t &parser, io_streams_t &streams, wchar_t **argv);
// Description of what the builtin does.
const wchar_t *desc;

View File

@ -684,7 +684,7 @@ static void set_argparse_result_vars(env_stack_t &vars, const argparse_cmd_opts_
/// an external command also means its output has to be in a form that can be eval'd. Because our
/// version is a builtin it can directly set variables local to the current scope (e.g., a
/// function). It doesn't need to write anything to stdout that then needs to be eval'd.
int builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
argparse_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_ARGPARSE_H
#define FISH_BUILTIN_ARGPARSE_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -37,7 +37,7 @@ static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j) {
}
/// Builtin for putting a job in the background.
int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_BG_H
#define FISH_BUILTIN_BG_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -413,7 +413,7 @@ int parse_cmd_opts(bind_cmd_opts_t &opts, int *optind, //!OCLINT(high ncss meth
}
/// The bind builtin, used for setting character sequences.
int builtin_bind_t::builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_bind_t::builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bind_cmd_opts_t opts;

View File

@ -11,7 +11,7 @@ struct bind_cmd_opts_t;
class builtin_bind_t {
public:
int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv);
builtin_bind_t() : input_mappings_(input_mappings()) {}
@ -38,7 +38,7 @@ class builtin_bind_t {
io_streams_t &streams);
};
inline int builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
inline maybe_t<int> builtin_bind(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
builtin_bind_t bind;
return bind.builtin_bind(parser, streams, argv);
}

View File

@ -70,7 +70,7 @@ static int parse_cmd_opts(block_cmd_opts_t &opts, int *optind, //!OCLINT(high n
}
/// The block builtin, used for temporarily blocking events.
int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
block_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_BLOCK_H
#define FISH_BUILTIN_BLOCK_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -65,7 +65,7 @@ static int parse_cmd_opts(builtin_cmd_opts_t &opts, int *optind, int argc, wchar
/// The builtin builtin, used for giving builtins precedence over functions. Mostly handled by the
/// parser. All this code does is some additional operational modes, such as printing a list of all
/// builtins, printing help, etc.
int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
builtin_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_BUILTIN_H
#define FISH_BUILTIN_BUILTIN_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -20,7 +20,7 @@
/// The cd builtin. Changes the current directory to the one specified or to $HOME if none is
/// specified. The directory can be relative to any directory in the CDPATH variable.
int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_CD_H
#define FISH_BUILTIN_CD_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -73,7 +73,7 @@ static int parse_cmd_opts(command_cmd_opts_t &opts, int *optind, int argc, wchar
/// Implementation of the builtin 'command'. Actual command running is handled by the parser, this
/// just processes the flags.
int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
command_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_COMMAND_H
#define FISH_BUILTIN_COMMAND_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -121,7 +121,7 @@ static void write_part(const wchar_t *begin, const wchar_t *end, int cut_at_curs
}
/// The commandline builtin. It is used for specifying a new value for the commandline.
int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Pointer to what the commandline builtin considers to be the current contents of the command
// line buffer.
const wchar_t *current_buffer = nullptr;

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -110,7 +110,7 @@ static void builtin_complete_remove(const wcstring_list_t &cmds, const wcstring_
/// The complete builtin. Used for specifying programmable tab-completions. Calls the functions in
// complete.cpp for any heavy lifting.
int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
wchar_t *cmd = argv[0];

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -58,7 +58,7 @@ static int parse_cmd_opts(contains_cmd_opts_t &opts, int *optind, int argc, wcha
/// Implementation of the builtin contains command, used to check if a specified string is part of
/// a list.
int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
contains_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_CONTAINS_H
#define FISH_BUILTIN_CONTAINS_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -42,7 +42,7 @@ static int disown_job(const wchar_t *cmd, parser_t &parser, io_streams_t &stream
}
/// Builtin for removing jobs from the job list.
int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_DISOWN_H
#define FISH_BUILTIN_DISOWN_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -180,7 +180,7 @@ static bool builtin_echo_parse_numeric_sequence(const wchar_t *str, size_t *cons
///
/// Bash only respects -n if it's the first argument. We'll do the same. We also support a new,
/// fish specific, option -s to mean "no spaces".
int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
UNUSED(cmd);
int argc = builtin_count_args(argv);

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_ECHO_H
#define FISH_BUILTIN_ECHO_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -11,7 +11,7 @@
#include "wutil.h" // IWYU pragma: keep
/// Implementation of the builtin emit command, used to create events.
int builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_EMIT_H
#define FISH_BUILTIN_EMIT_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -15,7 +15,7 @@
#include "wutil.h" // IWYU pragma: keep
/// Implementation of eval builtin.
int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
int argc = builtin_count_args(argv);
if (argc <= 1) {
return STATUS_CMD_OK;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_EVAL_H
#define FISH_BUILTIN_EVAL_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -58,7 +58,7 @@ static int parse_cmd_opts(exit_cmd_opts_t &opts, int *optind, //!OCLINT(high nc
}
/// The exit builtin. Calls reader_exit to exit and returns the value specified.
int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
exit_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_EXIT_H
#define FISH_BUILTIN_EXIT_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -21,7 +21,7 @@
#include "wutil.h" // IWYU pragma: keep
/// Builtin for putting a job in the foreground.
int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_FG_H
#define FISH_BUILTIN_FG_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -199,7 +199,7 @@ static int validate_function_name(int argc, const wchar_t *const *argv, wcstring
/// Define a function. Calls into `function.cpp` to perform the heavy lifting of defining a
/// function.
int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
maybe_t<int> builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
const parsed_source_ref_t &source, const ast::block_statement_t &func_node) {
assert(source && "Missing source in builtin_function");
// The wgetopt function expects 'function' as the first argument. Make a new wcstring_list with

View File

@ -12,6 +12,6 @@ namespace ast {
struct block_statement_t;
}
int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
maybe_t<int> builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_list_t &c_args,
const parsed_source_ref_t &source, const ast::block_statement_t &func_node);
#endif

View File

@ -282,7 +282,7 @@ static int report_function_metadata(const wchar_t *funcname, bool verbose, io_st
}
/// The functions builtin, used for listing and erasing functions.
int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
functions_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_FUNCTIONS_H
#define FISH_BUILTIN_FUNCTIONS_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -200,7 +200,7 @@ static int parse_cmd_opts(history_cmd_opts_t &opts, int *optind, //!OCLINT(high
}
/// Manipulate history of interactive commands executed by the user.
int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
history_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_HISTORY_H
#define FISH_BUILTIN_HISTORY_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -121,7 +121,7 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
}
/// The jobs builtin. Used for printing running jobs. Defined in builtin_jobs.c.
int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bool found = false;

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -232,7 +232,7 @@ static int evaluate_expression(const wchar_t *cmd, const parser_t &parser, io_st
}
/// The math builtin evaluates math expressions.
int builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
math_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_MATH_H
#define FISH_BUILTIN_MATH_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -737,7 +737,7 @@ int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wch
}
/// The printf builtin.
int builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -19,7 +19,7 @@ static const struct woption long_options[] = {{L"help", no_argument, nullptr, 'h
{L"logical", no_argument, nullptr, 'L'},
{L"physical", no_argument, nullptr, 'P'},
{nullptr, 0, nullptr, 0}};
int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_PWD_H
#define FISH_BUILTIN_PWD_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -27,7 +27,7 @@ static std::minstd_rand get_seeded_engine() {
}
/// The random builtin generates random numbers.
int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
help_only_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_RANDOM_H
#define FISH_BUILTIN_RANDOM_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -431,7 +431,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
}
/// The read builtin. Reads from stdin and stores the values in environment variables.
int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
wcstring buff;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_READ_H
#define FISH_BUILTIN_READ_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -17,7 +17,7 @@
/// An implementation of the external realpath command. Doesn't support any options.
/// In general scripts shouldn't invoke this directly. They should just use `realpath` which
/// will fallback to this builtin if an external command cannot be found.
int builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
help_only_cmd_opts_t opts;
int argc = builtin_count_args(argv);

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_REALPATH_H
#define FISH_BUILTIN_REALPATH_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -57,7 +57,7 @@ static int parse_cmd_opts(return_cmd_opts_t &opts, int *optind, //!OCLINT(high
}
/// Function for handling the return builtin.
int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
return_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_RETURN_H
#define FISH_BUILTIN_RETURN_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -804,7 +804,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
}
/// The set builtin creates, updates, and erases (removes, deletes) variables.
int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
const int incoming_exit_status = parser.get_last_status();
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -67,7 +67,7 @@ static char dim_esc[] = "\x1B[2m";
#endif
/// set_color builtin.
int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// By the time this is called we should have initialized the curses subsystem.
assert(curses_initialized);

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -22,7 +22,7 @@
/// The source builtin, sometimes called `.`. Evaluates the contents of a file in the current
/// context.
int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
const wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_SOURCE_H
#define FISH_BUILTIN_SOURCE_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -274,7 +274,7 @@ static int parse_cmd_opts(status_cmd_opts_t &opts, int *optind, //!OCLINT(high
}
/// The status builtin. Gives various status information on fish.
int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
status_cmd_opts_t opts;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_STATUS_H
#define FISH_BUILTIN_STATUS_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -1451,7 +1451,7 @@ string_subcommands[] = {
{nullptr, nullptr}};
/// The string builtin, for manipulating strings.
int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
if (argc <= 1) {

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -845,7 +845,7 @@ static bool unary_primary_evaluate(test_expressions::token_t token, const wcstri
/// supports a more limited range of functionality.
///
/// Return status is the final shell status, i.e. 0 for true, 1 for false and 2 for error.
int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
UNUSED(parser);
using namespace test_expressions;

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_TEST_H
#define FISH_BUILTIN_TEST_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -149,7 +149,7 @@ static int set_limit(int resource, int hard, int soft, rlim_t value, io_streams_
}
/// The ulimit builtin, used for setting resource limits.
int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wchar_t *cmd = argv[0];
int argc = builtin_count_args(argv);
bool report_all = false;

View File

@ -7,5 +7,5 @@
class parser_t;
int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -172,7 +172,7 @@ static bool find_job_by_name(const wchar_t *proc, std::vector<job_id_t> &ids,
/// The following function is invoked on the main thread, because the job operation is not thread
/// safe. It waits for child jobs, not for child processes individually.
int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
maybe_t<int> builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
ASSERT_IS_MAIN_THREAD();
int retval = STATUS_CMD_OK;
const wchar_t *cmd = argv[0];

View File

@ -2,8 +2,10 @@
#ifndef FISH_BUILTIN_WAIT_H
#define FISH_BUILTIN_WAIT_H
#include "maybe.h"
class parser_t;
struct io_streams_t;
int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv);
#endif

View File

@ -289,7 +289,11 @@ static void run_internal_process_or_short_circuit(parser_t &parser, const std::s
if (p->is_last_in_job) {
FLOGF(exec_job_status, L"Set status of job %d (%ls) to %d using short circuit",
j->job_id(), j->preview().c_str(), p->status);
parser.set_last_statuses(j->get_statuses());
auto statuses = j->get_statuses();
if (statuses) {
parser.set_last_statuses(statuses.value());
parser.libdata().status_count++;
}
}
} else {
run_internal_process(p, std::move(outdata), std::move(errdata), ios);

View File

@ -2519,7 +2519,7 @@ static void test_is_potential_path() {
}
/// Test the 'test' builtin.
int builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_test(parser_t &parser, io_streams_t &streams, wchar_t **argv);
static bool run_one_test_test(int expected, wcstring_list_t &lst, bool bracket) {
parser_t &parser = parser_t::principal_parser();
size_t i, count = lst.size();
@ -2535,13 +2535,16 @@ static bool run_one_test_test(int expected, wcstring_list_t &lst, bool bracket)
argv[i + 1] = NULL;
null_output_stream_t null{};
io_streams_t streams(null, null);
int result = builtin_test(parser, streams, argv);
maybe_t<int> result = builtin_test(parser, streams, argv);
if (expected != result) err(L"expected builtin_test() to return %d, got %d", expected, result);
if (result != expected) {
std::wstring got = result ? std::to_wstring(result.value()) : L"nothing";
err(L"expected builtin_test() to return %d, got %s", expected, got.c_str());
}
delete[] argv;
return expected == result;
return result == expected;
}
static bool run_test_test(int expected, const wcstring &str) {
@ -5098,7 +5101,7 @@ static void test_pcre2_escape() {
}
}
int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
maybe_t<int> builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv);
static void run_one_string_test(const wchar_t *const *argv, int expected_rc,
const wchar_t *expected_out) {
parser_t &parser = parser_t::principal_parser();
@ -5106,15 +5109,16 @@ static void run_one_string_test(const wchar_t *const *argv, int expected_rc,
null_output_stream_t errs{};
io_streams_t streams(outs, errs);
streams.stdin_is_directly_redirected = false; // read from argv instead of stdin
int rc = builtin_string(parser, streams, const_cast<wchar_t **>(argv));
maybe_t<int> rc = builtin_string(parser, streams, const_cast<wchar_t **>(argv));
wcstring args;
for (int i = 0; argv[i] != NULL; i++) {
args += escape_string(argv[i], ESCAPE_ALL) + L' ';
}
args.resize(args.size() - 1);
if (rc != expected_rc) {
err(L"Test failed on line %lu: [%ls]: expected return code %d but got %d", __LINE__,
args.c_str(), expected_rc, rc);
std::wstring got = rc ? std::to_wstring(rc.value()) : L"nothing";
err(L"Test failed on line %lu: [%ls]: expected return code %d but got %s", __LINE__,
args.c_str(), expected_rc, got.c_str());
} else if (outs.contents() != expected_out) {
err(L"Test failed on line %lu: [%ls]: expected [%ls] but got [%ls]", __LINE__, args.c_str(),
escape_string(expected_out, ESCAPE_ALL).c_str(),

View File

@ -3,6 +3,7 @@
#include <cassert>
#include <type_traits>
#include <utility>
namespace maybe_detail {
// Template magic to make maybe_t<T> copyable iff T is copyable.

View File

@ -392,13 +392,17 @@ end_execution_reason_t parse_execution_context_t::run_function_statement(
buffered_output_stream_t outs(0);
buffered_output_stream_t errs(0);
io_streams_t streams(outs, errs);
int err = builtin_function(*parser, streams, arguments, pstree, statement);
parser->libdata().status_count++;
parser->set_last_statuses(statuses_t::just(err));
int err_code = 0;
maybe_t<int> err = builtin_function(*parser, streams, arguments, pstree, statement);
if (err) {
err_code = err.value();
parser->libdata().status_count++;
parser->set_last_statuses(statuses_t::just(err_code));
}
wcstring errtext = errs.contents();
if (!errtext.empty()) {
return this->report_error(err, header, L"%ls", errtext.c_str());
return this->report_error(err_code, header, L"%ls", errtext.c_str());
}
return result;
}

View File

@ -167,17 +167,30 @@ bool job_t::signal(int signal) {
return true;
}
statuses_t job_t::get_statuses() const {
maybe_t<statuses_t> job_t::get_statuses() const {
statuses_t st{};
bool has_status = false;
int laststatus = 0;
st.pipestatus.reserve(processes.size());
for (const auto &p : processes) {
auto status = p->status;
if (status.is_empty()) {
// Corner case for if a variable assignment is part of a pipeline.
// e.g. `false | set foo bar | true` will push 1 in the second spot,
// for a complete pipestatus of `1 1 0`.
st.pipestatus.push_back(laststatus);
continue;
}
if (status.signal_exited()) {
st.kill_signal = status.signal_code();
}
laststatus = status.status_value();
has_status = true;
st.pipestatus.push_back(status.status_value());
}
int laststatus = st.pipestatus.back();
if (!has_status) {
return none();
}
st.status = flags().negate ? !laststatus : laststatus;
return st;
}
@ -997,8 +1010,11 @@ void job_t::continue_job(parser_t &parser, bool in_foreground) {
// finished.
const auto &p = processes.back();
if (p->status.normal_exited() || p->status.signal_exited()) {
parser.set_last_statuses(get_statuses());
parser.libdata().status_count++;
auto statuses = get_statuses();
if (statuses) {
parser.set_last_statuses(statuses.value());
parser.libdata().status_count++;
}
}
}
}

View File

@ -54,7 +54,12 @@ using job_group_ref_t = std::shared_ptr<job_group_t>;
class proc_status_t {
int status_{};
explicit proc_status_t(int status) : status_(status) {}
/// If set, there is no actual status to report, e.g. background or variable assignment.
bool empty_{};
explicit proc_status_t(int status) : status_(status), empty_(false) {}
proc_status_t(int status, bool empty) : status_(status), empty_(empty) {}
/// Encode a return value \p ret and signal \p sig into a status value like waitpid() does.
static constexpr int w_exitcode(int ret, int sig) {
@ -84,6 +89,12 @@ class proc_status_t {
return proc_status_t(w_exitcode(0 /* ret */, sig));
}
/// Construct an empty status_t (e.g. `set foo bar`).
static proc_status_t empty() {
bool empty = true;
return proc_status_t(0, empty);
}
/// \return if we are stopped (as in SIGSTOP).
bool stopped() const { return WIFSTOPPED(status_); }
@ -111,6 +122,9 @@ class proc_status_t {
/// \return if this status represents success.
bool is_success() const { return normal_exited() && exit_code() == EXIT_SUCCESS; }
/// \return if this status is empty.
bool is_empty() const { return empty_; }
/// \return the value appropriate to populate $status.
int status_value() const {
if (signal_exited()) {
@ -465,7 +479,7 @@ class job_t {
bool signal(int signal);
/// \returns the statuses for this job.
statuses_t get_statuses() const;
maybe_t<statuses_t> get_statuses() const;
};
/// Whether this shell is attached to the keyboard at all.