From 7840d53ecf258003f7325778f28f862d7f3dba94 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Tue, 13 Jun 2017 21:20:21 -0700 Subject: [PATCH] split builtin source into its own module --- Makefile.in | 2 +- src/builtin.cpp | 66 +-------------------- src/builtin_source.cpp | 127 +++++++++++++++++++++++++++++++++++++++++ src/builtin_source.h | 9 +++ 4 files changed, 138 insertions(+), 66 deletions(-) create mode 100644 src/builtin_source.cpp create mode 100644 src/builtin_source.h diff --git a/Makefile.in b/Makefile.in index 73923a1d8..2ae564ac9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -101,7 +101,7 @@ HAVE_DOXYGEN=@HAVE_DOXYGEN@ FISH_OBJS := obj/autoload.o obj/builtin.o obj/builtin_bind.o obj/builtin_block.o \ obj/builtin_commandline.o obj/builtin_emit.o obj/builtin_functions.o \ obj/builtin_history.o obj/builtin_status.o obj/builtin_read.o \ - obj/builtin_random.o obj/builtin_echo.o \ + obj/builtin_source.o obj/builtin_random.o obj/builtin_echo.o \ obj/builtin_disown.o obj/builtin_function.o \ obj/builtin_complete.o obj/builtin_jobs.o obj/builtin_printf.o \ obj/builtin_set.o obj/builtin_set_color.o obj/builtin_string.o \ diff --git a/src/builtin.cpp b/src/builtin.cpp index aa79d79c1..40827a424 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -18,7 +18,6 @@ #include "config.h" // IWYU pragma: keep #include -#include #include #include #include @@ -46,6 +45,7 @@ #include "builtin_read.h" #include "builtin_set.h" #include "builtin_set_color.h" +#include "builtin_source.h" #include "builtin_status.h" #include "builtin_string.h" #include "builtin_test.h" @@ -557,70 +557,6 @@ static int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **a return STATUS_CMD_ERROR; } -/// The . (dot) builtin, sometimes called source. Evaluates the contents of a file. -static int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { - ASSERT_IS_MAIN_THREAD(); - int fd; - int res = STATUS_CMD_OK; - struct stat buf; - int argc; - - argc = builtin_count_args(argv); - - const wchar_t *fn, *fn_intern; - - if (argc < 2 || (wcscmp(argv[1], L"-") == 0)) { - fn = L"-"; - fn_intern = fn; - fd = dup(streams.stdin_fd); - } else { - if ((fd = wopen_cloexec(argv[1], O_RDONLY)) == -1) { - streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), - argv[0], argv[1]); - builtin_wperror(L"source", streams); - return STATUS_CMD_ERROR; - } - - if (fstat(fd, &buf) == -1) { - close(fd); - streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), - argv[0], argv[1]); - builtin_wperror(L"source", streams); - return STATUS_CMD_ERROR; - } - - if (!S_ISREG(buf.st_mode)) { - close(fd); - streams.err.append_format(_(L"%ls: '%ls' is not a file\n"), argv[0], argv[1]); - return STATUS_CMD_ERROR; - } - - fn_intern = intern(argv[1]); - } - - const source_block_t *sb = parser.push_block(fn_intern); - reader_push_current_filename(fn_intern); - - env_set_argv(argc > 1 ? argv + 2 : argv + 1); - - res = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t()); - - parser.pop_block(sb); - - if (res) { - streams.err.append_format(_(L"%ls: Error while reading file '%ls'\n"), argv[0], - fn_intern == intern_static(L"-") ? L"" : fn_intern); - } else { - res = proc_get_last_status(); - } - - // Do not close fd after calling reader_read. reader_read automatically closes it before calling - // eval. - reader_pop_current_filename(); - - return res; -} - /// Builtin for putting a job in the foreground. static int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) { job_t *j = NULL; diff --git a/src/builtin_source.cpp b/src/builtin_source.cpp new file mode 100644 index 000000000..46df593d6 --- /dev/null +++ b/src/builtin_source.cpp @@ -0,0 +1,127 @@ +// Implementation of the source builtin. +#include "config.h" // IWYU pragma: keep + +#include +#include +#include // for NULL, close, dup +#include // for wcscmp + +#include "builtin.h" +#include "builtin_source.h" +#include "common.h" +#include "env.h" +#include "fallback.h" // IWYU pragma: keep +#include "intern.h" +#include "io.h" +#include "parser.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, int argc, wchar_t **argv, + parser_t &parser, io_streams_t &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 '?': { + builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]); + return STATUS_INVALID_ARGS; + } + default: { + DIE("unexpected retval from wgetopt_long"); + break; + } + } + } + + *optind = w.woptind; + return STATUS_CMD_OK; +} + +/// 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) { + ASSERT_IS_MAIN_THREAD(); + 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_INVALID_ARGS; + } + + int fd; + struct stat buf; + const wchar_t *fn, *fn_intern; + + if (argc == optind || wcscmp(argv[optind], L"-") == 0) { + // Either a bare `source` which means to implicitly read from stdin or an explicit `-`. + fn = L"-"; + fn_intern = fn; + fd = dup(streams.stdin_fd); + } else { + if ((fd = wopen_cloexec(argv[optind], O_RDONLY)) == -1) { + streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), + cmd, argv[optind]); + builtin_wperror(cmd, streams); + return STATUS_CMD_ERROR; + } + + if (fstat(fd, &buf) == -1) { + close(fd); + streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), + cmd, argv[optind]); + builtin_wperror(L"source", streams); + return STATUS_CMD_ERROR; + } + + if (!S_ISREG(buf.st_mode)) { + close(fd); + streams.err.append_format(_(L"%ls: '%ls' is not a file\n"), cmd, argv[optind]); + return STATUS_CMD_ERROR; + } + + fn_intern = intern(argv[optind]); + } + + const source_block_t *sb = parser.push_block(fn_intern); + reader_push_current_filename(fn_intern); + + // This is slightly subtle. If this is a bare `source` with no args then `argv + optind` already + // points to the end of argv. Otherwise we want to skip the file name to get to the args if any. + env_set_argv(argv + optind + (argc == optind ? 0 : 1)); + + retval = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t()); + + parser.pop_block(sb); + + if (retval != STATUS_CMD_OK) { + streams.err.append_format(_(L"%ls: Error while reading file '%ls'\n"), cmd, + fn_intern == intern_static(L"-") ? L"" : fn_intern); + } else { + retval = proc_get_last_status(); + } + + // Do not close fd after calling reader_read. reader_read automatically closes it before calling + // eval. + reader_pop_current_filename(); + return retval; +} diff --git a/src/builtin_source.h b/src/builtin_source.h new file mode 100644 index 000000000..4aaf1259e --- /dev/null +++ b/src/builtin_source.h @@ -0,0 +1,9 @@ +// Prototypes for executing builtin_source function. +#ifndef FISH_BUILTIN_SOURCE_H +#define FISH_BUILTIN_SOURCE_H + +class parser_t; +struct io_streams_t; + +int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv); +#endif