diff --git a/src/builtin_exit.cpp b/src/builtin_exit.cpp new file mode 100644 index 000000000..b3c22a944 --- /dev/null +++ b/src/builtin_exit.cpp @@ -0,0 +1,89 @@ +// Implementation of the exit builtin. +#include "config.h" // IWYU pragma: keep + +#include +#include + +#include "builtin.h" +#include "builtin_exit.h" +#include "common.h" +#include "fallback.h" // IWYU pragma: keep +#include "io.h" +#include "proc.h" +#include "reader.h" +#include "wgetopt.h" +#include "wutil.h" // IWYU pragma: keep + +struct cmd_opts { + bool print_help = false; +}; +static const wchar_t *short_options = L"h"; +static const struct woption long_options[] = {{L"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}}; + +static int parse_cmd_opts(struct cmd_opts *opts, int *optind, //!OCLINT(high ncss method) + int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) { + UNUSED(parser); + UNUSED(streams); + wchar_t *cmd = argv[0]; + int opt; + wgetopter_t w; + while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) { + switch (opt) { //!OCLINT(too few branches) + case 'h': { + opts->print_help = true; + return STATUS_CMD_OK; + } + case '?': { + // We would normally invoke builtin_unknown_option() and return an error. + // But for this command we want to let it try and parse the value as a negative + // return value. + *optind = w.woptind - 1; + return STATUS_CMD_OK; + } + default: { + DIE("unexpected retval from wgetopt_long"); + break; + } + } + } + + *optind = w.woptind; + return STATUS_CMD_OK; +} + +/// 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) { + const wchar_t *cmd = argv[0]; + int argc = builtin_count_args(argv); + struct cmd_opts opts; + + int optind; + int retval = parse_cmd_opts(&opts, &optind, argc, argv, parser, streams); + if (retval != STATUS_CMD_OK) return retval; + + if (opts.print_help) { + builtin_print_help(parser, streams, cmd, streams.out); + return STATUS_CMD_OK; + } + + if (optind + 1 < argc) { + streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd); + builtin_print_help(parser, streams, cmd, streams.err); + return STATUS_INVALID_ARGS; + } + + if (optind == argc) { + retval = proc_get_last_status(); + } else { + retval = fish_wcstoi(argv[optind]); + if (errno) { + streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd, + argv[optind]); + builtin_print_help(parser, streams, cmd, streams.err); + return STATUS_INVALID_ARGS; + } + } + reader_exit(1, 0); + return retval; +} diff --git a/src/builtin_exit.h b/src/builtin_exit.h new file mode 100644 index 000000000..1a279ab5f --- /dev/null +++ b/src/builtin_exit.h @@ -0,0 +1,9 @@ +// Prototypes for executing builtin_exit function. +#ifndef FISH_BUILTIN_EXIT_H +#define FISH_BUILTIN_EXIT_H + +class parser_t; +struct io_streams_t; + +int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv); +#endif