Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
//
|
2016-05-01 01:37:19 +00:00
|
|
|
// The main loop of the fish program.
|
2005-09-20 13:26:39 +00:00
|
|
|
/*
|
2008-01-12 19:18:48 +00:00
|
|
|
Copyright (C) 2005-2008 Axel Liljencrantz
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2006-11-01 14:47:47 +00:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License version 2 as
|
|
|
|
published by the Free Software Foundation.
|
2005-09-20 13:26:39 +00:00
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2013-12-13 20:51:52 +00:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-09-20 13:26:39 +00:00
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2016-03-03 23:36:17 +00:00
|
|
|
#include <getopt.h>
|
2015-07-25 15:14:25 +00:00
|
|
|
#include <limits.h>
|
2016-05-01 01:37:19 +00:00
|
|
|
#include <locale.h>
|
2017-02-13 04:24:22 +00:00
|
|
|
#include <stddef.h>
|
2015-07-25 15:14:25 +00:00
|
|
|
#include <stdint.h>
|
2005-09-20 13:26:39 +00:00
|
|
|
#include <stdio.h>
|
2016-05-01 01:37:19 +00:00
|
|
|
#include <stdlib.h>
|
2019-04-10 20:58:29 +00:00
|
|
|
#include <sys/resource.h>
|
2016-05-01 01:37:19 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2019-10-13 22:50:48 +00:00
|
|
|
|
2019-05-05 10:09:25 +00:00
|
|
|
#include <cstring>
|
2019-03-12 21:06:01 +00:00
|
|
|
#include <cwchar>
|
2016-04-21 06:00:54 +00:00
|
|
|
#include <memory>
|
2016-05-01 01:37:19 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2005-09-20 13:26:39 +00:00
|
|
|
|
|
|
|
#include "builtin.h"
|
2016-05-01 01:37:19 +00:00
|
|
|
#include "common.h"
|
2005-09-20 13:26:39 +00:00
|
|
|
#include "env.h"
|
2005-10-05 22:37:08 +00:00
|
|
|
#include "event.h"
|
2016-05-01 01:37:19 +00:00
|
|
|
#include "expand.h"
|
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
|
|
|
#include "fish_version.h"
|
2019-04-20 07:15:51 +00:00
|
|
|
#include "flog.h"
|
2016-05-01 01:37:19 +00:00
|
|
|
#include "function.h"
|
2018-04-24 21:32:06 +00:00
|
|
|
#include "future_feature_flags.h"
|
2006-04-19 23:42:11 +00:00
|
|
|
#include "history.h"
|
2019-05-22 20:34:03 +00:00
|
|
|
#include "intern.h"
|
2016-05-01 01:37:19 +00:00
|
|
|
#include "io.h"
|
2021-07-27 15:44:02 +00:00
|
|
|
#include "parse_util.h"
|
2021-11-08 19:36:01 +00:00
|
|
|
#include "parser.h"
|
2016-05-01 01:37:19 +00:00
|
|
|
#include "path.h"
|
|
|
|
#include "proc.h"
|
|
|
|
#include "reader.h"
|
2017-02-08 01:21:35 +00:00
|
|
|
#include "signal.h"
|
2020-01-15 21:16:43 +00:00
|
|
|
#include "wcstringutil.h"
|
2016-05-01 01:37:19 +00:00
|
|
|
#include "wutil.h" // IWYU pragma: keep
|
2005-09-20 13:26:39 +00:00
|
|
|
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
// container to hold the options specified within the command line
|
|
|
|
class fish_cmd_opts_t {
|
2017-07-19 05:40:25 +00:00
|
|
|
public:
|
2018-04-24 21:32:06 +00:00
|
|
|
// Future feature flags values string
|
|
|
|
wcstring features;
|
2019-04-20 07:15:51 +00:00
|
|
|
// File path for debug output.
|
|
|
|
std::string debug_output;
|
2020-07-22 22:35:14 +00:00
|
|
|
// File path for profiling output, or empty for none.
|
|
|
|
std::string profile_output;
|
2021-01-08 16:25:00 +00:00
|
|
|
std::string profile_startup_output;
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
// Commands to be executed in place of interactive shell.
|
|
|
|
std::vector<std::string> batch_cmds;
|
|
|
|
// Commands to execute after the shell's config has been read.
|
|
|
|
std::vector<std::string> postconfig_cmds;
|
2019-04-10 20:58:29 +00:00
|
|
|
/// Whether to print rusage-self stats after execution.
|
|
|
|
bool print_rusage_self{false};
|
2021-02-15 19:57:11 +00:00
|
|
|
/// Whether no-config is set.
|
|
|
|
bool no_config{false};
|
2019-05-12 22:48:00 +00:00
|
|
|
/// Whether no-exec is set.
|
|
|
|
bool no_exec{false};
|
|
|
|
/// Whether this is a login shell.
|
|
|
|
bool is_login{false};
|
|
|
|
/// Whether this is an interactive session.
|
|
|
|
bool is_interactive_session{false};
|
2020-02-08 20:23:39 +00:00
|
|
|
/// Whether to enable private mode.
|
|
|
|
bool enable_private_mode{false};
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
};
|
|
|
|
|
2019-04-10 20:58:29 +00:00
|
|
|
/// \return a timeval converted to milliseconds.
|
2020-09-08 20:04:44 +00:00
|
|
|
static long long tv_to_msec(const struct timeval &tv) {
|
2019-11-19 01:08:16 +00:00
|
|
|
long long msec = static_cast<long long>(tv.tv_sec) * 1000; // milliseconds per second
|
|
|
|
msec += tv.tv_usec / 1000; // microseconds per millisecond
|
2019-04-10 20:58:29 +00:00
|
|
|
return msec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_rusage_self(FILE *fp) {
|
|
|
|
#ifndef HAVE_GETRUSAGE
|
|
|
|
fprintf(fp, "getrusage() not supported on this platform");
|
|
|
|
return;
|
|
|
|
#else
|
|
|
|
struct rusage rs;
|
|
|
|
if (getrusage(RUSAGE_SELF, &rs)) {
|
|
|
|
perror("getrusage");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
|
|
// Macs use bytes.
|
|
|
|
long rss_kb = rs.ru_maxrss / 1024;
|
|
|
|
#else
|
|
|
|
// Everyone else uses KB.
|
|
|
|
long rss_kb = rs.ru_maxrss;
|
|
|
|
#endif
|
|
|
|
fprintf(fp, " rusage self:\n");
|
2020-03-13 21:02:37 +00:00
|
|
|
fprintf(fp, " user time: %lld ms\n", tv_to_msec(rs.ru_utime));
|
|
|
|
fprintf(fp, " sys time: %lld ms\n", tv_to_msec(rs.ru_stime));
|
|
|
|
fprintf(fp, " total time: %lld ms\n", tv_to_msec(rs.ru_utime) + tv_to_msec(rs.ru_stime));
|
2019-04-10 20:58:29 +00:00
|
|
|
fprintf(fp, " max rss: %ld kb\n", rss_kb);
|
|
|
|
fprintf(fp, " signals: %ld\n", rs.ru_nsignals);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
static bool has_suffix(const std::string &path, const char *suffix, bool ignore_case) {
|
2019-03-12 22:07:07 +00:00
|
|
|
size_t pathlen = path.size(), suffixlen = std::strlen(suffix);
|
2016-05-01 01:37:19 +00:00
|
|
|
return pathlen >= suffixlen &&
|
2019-03-12 22:07:07 +00:00
|
|
|
!(ignore_case ? strcasecmp : std::strcmp)(path.c_str() + pathlen - suffixlen, suffix);
|
2012-07-08 22:20:39 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
/// Modifies the given path by calling realpath. Returns true if realpath succeeded, false
|
|
|
|
/// otherwise.
|
|
|
|
static bool get_realpath(std::string &path) {
|
2012-07-08 22:20:39 +00:00
|
|
|
char buff[PATH_MAX], *ptr;
|
2016-05-01 01:37:19 +00:00
|
|
|
if ((ptr = realpath(path.c_str(), buff))) {
|
2012-07-08 22:20:39 +00:00
|
|
|
path = ptr;
|
|
|
|
}
|
2019-11-19 02:34:50 +00:00
|
|
|
return ptr != nullptr;
|
2012-07-08 22:20:39 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
static struct config_paths_t determine_config_directory_paths(const char *argv0) {
|
2012-07-08 22:20:39 +00:00
|
|
|
struct config_paths_t paths;
|
|
|
|
bool done = false;
|
|
|
|
std::string exec_path = get_executable_path(argv0);
|
2016-05-01 01:37:19 +00:00
|
|
|
if (get_realpath(exec_path)) {
|
2020-01-19 12:53:23 +00:00
|
|
|
FLOGF(config, L"exec_path: '%s', argv[0]: '%s'", exec_path.c_str(), argv0);
|
2018-11-25 22:06:32 +00:00
|
|
|
// TODO: we should determine program_name from argv0 somewhere in this file
|
2018-10-14 02:36:59 +00:00
|
|
|
|
|
|
|
#ifdef CMAKE_BINARY_DIR
|
|
|
|
// Detect if we're running right out of the CMAKE build directory
|
2018-11-25 22:06:32 +00:00
|
|
|
if (string_prefixes_string(CMAKE_BINARY_DIR, exec_path.c_str())) {
|
2020-01-19 12:53:23 +00:00
|
|
|
FLOGF(config,
|
2019-05-05 10:09:25 +00:00
|
|
|
"Running out of build directory, using paths relative to CMAKE_SOURCE_DIR:\n %s",
|
|
|
|
CMAKE_SOURCE_DIR);
|
2018-10-14 02:36:59 +00:00
|
|
|
|
|
|
|
done = true;
|
|
|
|
paths.data = wcstring{L"" CMAKE_SOURCE_DIR} + L"/share";
|
2018-11-25 22:06:32 +00:00
|
|
|
paths.sysconf = wcstring{L"" CMAKE_SOURCE_DIR} + L"/etc";
|
|
|
|
paths.doc = wcstring{L"" CMAKE_SOURCE_DIR} + L"/user_doc/html";
|
|
|
|
paths.bin = wcstring{L"" CMAKE_BINARY_DIR};
|
2018-10-14 02:36:59 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
if (!done) {
|
2016-09-23 18:52:51 +00:00
|
|
|
// The next check is that we are in a reloctable directory tree
|
|
|
|
const char *installed_suffix = "/bin/fish";
|
|
|
|
const char *just_a_fish = "/fish";
|
2019-11-19 02:34:50 +00:00
|
|
|
const char *suffix = nullptr;
|
2016-09-23 18:52:51 +00:00
|
|
|
|
|
|
|
if (has_suffix(exec_path, installed_suffix, false)) {
|
|
|
|
suffix = installed_suffix;
|
|
|
|
} else if (has_suffix(exec_path, just_a_fish, false)) {
|
2020-01-19 12:53:23 +00:00
|
|
|
FLOGF(config, L"'fish' not in a 'bin/', trying paths relative to source tree");
|
2016-09-23 18:52:51 +00:00
|
|
|
suffix = just_a_fish;
|
2012-07-08 22:20:39 +00:00
|
|
|
}
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2016-09-23 18:52:51 +00:00
|
|
|
if (suffix) {
|
|
|
|
bool seems_installed = (suffix == installed_suffix);
|
|
|
|
|
2012-07-08 22:20:39 +00:00
|
|
|
wcstring base_path = str2wcstring(exec_path);
|
2019-03-12 22:07:07 +00:00
|
|
|
base_path.resize(base_path.size() - std::strlen(suffix));
|
2014-03-31 17:01:39 +00:00
|
|
|
|
2016-09-23 18:52:51 +00:00
|
|
|
paths.data = base_path + (seems_installed ? L"/share/fish" : L"/share");
|
|
|
|
paths.sysconf = base_path + (seems_installed ? L"/etc/fish" : L"/etc");
|
|
|
|
paths.doc = base_path + (seems_installed ? L"/share/doc/fish" : L"/user_doc/html");
|
|
|
|
paths.bin = base_path + (seems_installed ? L"/bin" : L"");
|
2014-03-31 17:01:39 +00:00
|
|
|
|
2018-07-22 03:57:21 +00:00
|
|
|
// Check only that the data and sysconf directories exist. Handle the doc
|
|
|
|
// directories separately.
|
|
|
|
struct stat buf;
|
|
|
|
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) {
|
2016-05-01 01:37:19 +00:00
|
|
|
// The docs dir may not exist; in that case fall back to the compiled in path.
|
2018-07-22 03:57:21 +00:00
|
|
|
if (0 != wstat(paths.doc, &buf)) {
|
2014-01-17 22:18:45 +00:00
|
|
|
paths.doc = L"" DOCDIR;
|
|
|
|
}
|
2012-07-08 22:20:39 +00:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
if (!done) {
|
|
|
|
// Fall back to what got compiled in.
|
2020-01-19 12:53:23 +00:00
|
|
|
FLOGF(config, L"Using compiled in paths:");
|
2012-07-08 22:20:39 +00:00
|
|
|
paths.data = L"" DATADIR "/fish";
|
|
|
|
paths.sysconf = L"" SYSCONFDIR "/fish";
|
2013-10-28 16:01:21 +00:00
|
|
|
paths.doc = L"" DOCDIR;
|
2013-04-16 05:22:19 +00:00
|
|
|
paths.bin = L"" BINDIR;
|
2012-07-08 22:20:39 +00:00
|
|
|
}
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2020-01-19 12:53:23 +00:00
|
|
|
FLOGF(config,
|
2016-10-05 03:06:14 +00:00
|
|
|
L"determine_config_directory_paths() results:\npaths.data: %ls\npaths.sysconf: "
|
|
|
|
L"%ls\npaths.doc: %ls\npaths.bin: %ls",
|
|
|
|
paths.data.c_str(), paths.sysconf.c_str(), paths.doc.c_str(), paths.bin.c_str());
|
2012-07-08 22:20:39 +00:00
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
2016-02-04 20:51:55 +00:00
|
|
|
// Source the file config.fish in the given directory.
|
2020-02-08 20:23:39 +00:00
|
|
|
static void source_config_in_directory(parser_t &parser, const wcstring &dir) {
|
2016-05-01 01:37:19 +00:00
|
|
|
// If the config.fish file doesn't exist or isn't readable silently return. Fish versions up
|
|
|
|
// thru 2.2.0 would instead try to source the file with stderr redirected to /dev/null to deal
|
|
|
|
// with that possibility.
|
2016-02-04 20:51:55 +00:00
|
|
|
//
|
2016-05-01 01:37:19 +00:00
|
|
|
// This introduces a race condition since the readability of the file can change between this
|
|
|
|
// test and the execution of the 'source' command. However, that is not a security problem in
|
|
|
|
// this context so we ignore it.
|
2016-02-04 20:51:55 +00:00
|
|
|
const wcstring config_pathname = dir + L"/config.fish";
|
2013-09-29 20:39:41 +00:00
|
|
|
const wcstring escaped_dir = escape_string(dir, ESCAPE_ALL);
|
2016-02-04 20:51:55 +00:00
|
|
|
const wcstring escaped_pathname = escaped_dir + L"/config.fish";
|
|
|
|
if (waccess(config_pathname, R_OK) != 0) {
|
2020-01-30 01:06:11 +00:00
|
|
|
FLOGF(config, L"not sourcing %ls (not readable or does not exist)",
|
|
|
|
escaped_pathname.c_str());
|
2016-02-04 20:51:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-01-19 12:53:23 +00:00
|
|
|
FLOGF(config, L"sourcing %ls", escaped_pathname.c_str());
|
2016-02-04 20:51:55 +00:00
|
|
|
|
|
|
|
const wcstring cmd = L"builtin source " + escaped_pathname;
|
2022-03-25 04:43:58 +00:00
|
|
|
|
|
|
|
parser.libdata().within_fish_init = true;
|
2019-12-23 00:27:03 +00:00
|
|
|
parser.eval(cmd, io_chain_t());
|
2022-03-25 04:43:58 +00:00
|
|
|
parser.libdata().within_fish_init = false;
|
2013-09-29 20:39:41 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
/// Parse init files. exec_path is the path of fish executable as determined by argv[0].
|
2020-04-03 19:24:31 +00:00
|
|
|
static void read_init(parser_t &parser, const struct config_paths_t &paths) {
|
2020-02-08 20:23:39 +00:00
|
|
|
source_config_in_directory(parser, paths.data);
|
|
|
|
source_config_in_directory(parser, paths.sysconf);
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
// We need to get the configuration directory before we can source the user configuration file.
|
|
|
|
// If path_get_config returns false then we have no configuration directory and no custom config
|
|
|
|
// to load.
|
2012-11-19 00:30:30 +00:00
|
|
|
wcstring config_dir;
|
2016-05-01 01:37:19 +00:00
|
|
|
if (path_get_config(config_dir)) {
|
2020-02-08 20:23:39 +00:00
|
|
|
source_config_in_directory(parser, config_dir);
|
2012-11-19 00:30:30 +00:00
|
|
|
}
|
2005-09-20 13:26:39 +00:00
|
|
|
}
|
|
|
|
|
2020-09-08 20:04:44 +00:00
|
|
|
static int run_command_list(parser_t &parser, std::vector<std::string> *cmds,
|
|
|
|
const io_chain_t &io) {
|
2019-11-19 21:46:47 +00:00
|
|
|
for (const auto &cmd : *cmds) {
|
2020-02-08 20:23:39 +00:00
|
|
|
wcstring cmd_wcs = str2wcstring(cmd);
|
2021-07-27 15:44:02 +00:00
|
|
|
// Parse into an ast and detect errors.
|
|
|
|
parse_error_list_t errors;
|
|
|
|
auto ast = ast::ast_t::parse(cmd_wcs, parse_flag_none, &errors);
|
|
|
|
bool errored = ast.errored();
|
|
|
|
if (!errored) {
|
|
|
|
errored = parse_util_detect_errors(ast, cmd_wcs, &errors);
|
|
|
|
}
|
|
|
|
if (!errored) {
|
|
|
|
// Construct a parsed source ref.
|
|
|
|
// Be careful to transfer ownership, this could be a very large string.
|
2021-11-08 19:36:01 +00:00
|
|
|
parsed_source_ref_t ps =
|
|
|
|
std::make_shared<parsed_source_t>(std::move(cmd_wcs), std::move(ast));
|
2021-07-27 15:44:02 +00:00
|
|
|
parser.eval(ps, io);
|
|
|
|
} else {
|
|
|
|
wcstring sb;
|
|
|
|
parser.get_backtrace(cmd_wcs, errors, sb);
|
|
|
|
std::fwprintf(stderr, L"%ls", sb.c_str());
|
|
|
|
// Note: We do not return here because that's how it historically worked.
|
|
|
|
// return 1;
|
|
|
|
}
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 12:49:40 +00:00
|
|
|
return 0;
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
}
|
|
|
|
|
2016-05-16 02:45:02 +00:00
|
|
|
/// Parse the argument list, return the index of the first non-flag arguments.
|
2018-11-28 14:07:58 +00:00
|
|
|
static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) {
|
2021-02-15 19:57:11 +00:00
|
|
|
static const char *const short_opts = "+hPilNnvc:C:p:d:f:D:o:";
|
2019-11-19 02:34:50 +00:00
|
|
|
static const struct option long_opts[] = {
|
|
|
|
{"command", required_argument, nullptr, 'c'},
|
|
|
|
{"init-command", required_argument, nullptr, 'C'},
|
|
|
|
{"features", required_argument, nullptr, 'f'},
|
|
|
|
{"debug", required_argument, nullptr, 'd'},
|
|
|
|
{"debug-output", required_argument, nullptr, 'o'},
|
|
|
|
{"debug-stack-frames", required_argument, nullptr, 'D'},
|
|
|
|
{"interactive", no_argument, nullptr, 'i'},
|
|
|
|
{"login", no_argument, nullptr, 'l'},
|
2021-02-15 19:57:11 +00:00
|
|
|
{"no-config", no_argument, nullptr, 'N'},
|
2019-11-19 02:34:50 +00:00
|
|
|
{"no-execute", no_argument, nullptr, 'n'},
|
|
|
|
{"print-rusage-self", no_argument, nullptr, 1},
|
|
|
|
{"print-debug-categories", no_argument, nullptr, 2},
|
|
|
|
{"profile", required_argument, nullptr, 'p'},
|
2021-01-08 16:25:00 +00:00
|
|
|
{"profile-startup", required_argument, nullptr, 3},
|
2019-11-19 02:34:50 +00:00
|
|
|
{"private", no_argument, nullptr, 'P'},
|
|
|
|
{"help", no_argument, nullptr, 'h'},
|
|
|
|
{"version", no_argument, nullptr, 'v'},
|
2022-04-01 21:25:02 +00:00
|
|
|
{}};
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2016-03-03 23:36:17 +00:00
|
|
|
int opt;
|
2019-11-19 02:34:50 +00:00
|
|
|
while ((opt = getopt_long(argc, argv, short_opts, long_opts, nullptr)) != -1) {
|
2016-05-01 01:37:19 +00:00
|
|
|
switch (opt) {
|
|
|
|
case 'c': {
|
2020-02-21 06:51:01 +00:00
|
|
|
opts->batch_cmds.emplace_back(optarg);
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'C': {
|
2020-02-21 06:51:01 +00:00
|
|
|
opts->postconfig_cmds.emplace_back(optarg);
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'd': {
|
2021-07-05 21:29:24 +00:00
|
|
|
activate_flog_categories_by_pattern(str2wcstring(optarg));
|
2020-05-15 22:54:26 +00:00
|
|
|
for (auto cat : get_flog_categories()) {
|
|
|
|
if (cat->enabled) {
|
2021-05-09 04:30:08 +00:00
|
|
|
std::fwprintf(stdout, L"Debug enabled for category: %ls\n", cat->name);
|
2020-05-15 22:54:26 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
2012-11-19 00:30:30 +00:00
|
|
|
}
|
2019-04-20 07:15:51 +00:00
|
|
|
case 'o': {
|
|
|
|
opts->debug_output = optarg;
|
|
|
|
break;
|
|
|
|
}
|
2018-04-24 21:32:06 +00:00
|
|
|
case 'f': {
|
|
|
|
opts->features = str2wcstring(optarg);
|
|
|
|
break;
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'h': {
|
2020-02-21 06:51:01 +00:00
|
|
|
opts->batch_cmds.emplace_back("__fish_print_help fish");
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
2012-11-19 00:30:30 +00:00
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'i': {
|
2019-05-12 22:48:00 +00:00
|
|
|
opts->is_interactive_session = true;
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'l': {
|
2019-05-12 22:48:00 +00:00
|
|
|
opts->is_login = true;
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-02-15 19:57:11 +00:00
|
|
|
case 'N': {
|
|
|
|
opts->no_config = true;
|
2021-04-11 11:09:03 +00:00
|
|
|
// --no-config implies private mode, we won't be saving history
|
|
|
|
opts->enable_private_mode = true;
|
2021-02-15 19:57:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'n': {
|
2019-05-12 22:48:00 +00:00
|
|
|
opts->no_exec = true;
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-04-10 20:58:29 +00:00
|
|
|
case 1: {
|
|
|
|
opts->print_rusage_self = true;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-20 07:15:51 +00:00
|
|
|
case 2: {
|
|
|
|
auto cats = get_flog_categories();
|
|
|
|
// Compute width of longest name.
|
|
|
|
int name_width = 0;
|
2020-04-02 23:04:04 +00:00
|
|
|
for (auto cat : cats) {
|
2019-11-19 01:08:16 +00:00
|
|
|
name_width = std::max(name_width, static_cast<int>(wcslen(cat->name)));
|
2019-04-20 07:15:51 +00:00
|
|
|
}
|
|
|
|
// A little extra space.
|
|
|
|
name_width += 2;
|
2020-04-02 23:04:04 +00:00
|
|
|
for (auto cat : cats) {
|
2019-04-20 07:15:51 +00:00
|
|
|
// Negating the name width left-justifies.
|
|
|
|
printf("%*ls %ls\n", -name_width, cat->name, _(cat->description));
|
|
|
|
}
|
|
|
|
exit(0);
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'p': {
|
2021-01-08 16:25:00 +00:00
|
|
|
// "--profile" - this does not activate profiling right away,
|
|
|
|
// rather it's done after startup is finished.
|
2020-07-22 22:35:14 +00:00
|
|
|
opts->profile_output = optarg;
|
2021-01-08 16:25:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: {
|
|
|
|
// With "--profile-startup" we immediately turn profiling on.
|
|
|
|
opts->profile_startup_output = optarg;
|
2014-02-09 22:04:43 +00:00
|
|
|
g_profiling_active = true;
|
2012-11-19 08:31:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-09-19 23:56:08 +00:00
|
|
|
case 'P': {
|
2020-02-08 20:23:39 +00:00
|
|
|
opts->enable_private_mode = true;
|
2018-09-19 23:56:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
case 'v': {
|
2019-03-12 21:06:01 +00:00
|
|
|
std::fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version());
|
2016-03-23 18:42:17 +00:00
|
|
|
exit(0);
|
2012-11-19 08:31:03 +00:00
|
|
|
}
|
2016-05-16 02:45:02 +00:00
|
|
|
case 'D': {
|
2020-11-15 10:32:52 +00:00
|
|
|
// TODO: Option is currently useless.
|
|
|
|
// Either remove it or make it work with FLOG.
|
2016-05-16 02:45:02 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 01:37:19 +00:00
|
|
|
default: {
|
2016-03-03 23:36:17 +00:00
|
|
|
// We assume getopt_long() has already emitted a diagnostic msg.
|
2016-03-23 18:42:17 +00:00
|
|
|
exit(1);
|
2012-11-19 08:31:03 +00:00
|
|
|
}
|
2012-11-19 00:30:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-19 04:05:00 +00:00
|
|
|
// If our command name begins with a dash that implies we're a login shell.
|
2019-05-12 22:48:00 +00:00
|
|
|
opts->is_login |= argv[0][0] == '-';
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2015-12-19 04:05:00 +00:00
|
|
|
// We are an interactive session if we have not been given an explicit
|
|
|
|
// command or file to execute and stdin is a tty. Note that the -i or
|
|
|
|
// --interactive options also force interactive mode.
|
2019-11-19 00:56:46 +00:00
|
|
|
if (opts->batch_cmds.empty() && optind == argc && isatty(STDIN_FILENO)) {
|
2020-12-06 21:40:45 +00:00
|
|
|
set_interactive_session(true);
|
2013-10-26 22:24:49 +00:00
|
|
|
}
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2015-12-19 04:05:00 +00:00
|
|
|
return optind;
|
2006-10-25 20:54:43 +00:00
|
|
|
}
|
|
|
|
|
2018-11-28 14:07:58 +00:00
|
|
|
int main(int argc, char **argv) {
|
2016-05-01 01:37:19 +00:00
|
|
|
int res = 1;
|
|
|
|
int my_optind = 0;
|
2006-10-25 20:54:43 +00:00
|
|
|
|
2018-11-28 14:08:24 +00:00
|
|
|
program_name = L"fish";
|
2012-11-19 00:30:30 +00:00
|
|
|
set_main_thread();
|
2012-02-28 02:43:24 +00:00
|
|
|
setup_fork_guards();
|
2017-05-03 03:55:41 +00:00
|
|
|
signal_unblock_all();
|
2022-03-25 04:43:58 +00:00
|
|
|
|
2016-06-04 02:05:13 +00:00
|
|
|
setlocale(LC_ALL, "");
|
2006-10-25 20:54:43 +00:00
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
// struct stat tmp;
|
|
|
|
// stat("----------FISH_HIT_MAIN----------", &tmp);
|
2006-11-11 10:48:40 +00:00
|
|
|
|
2019-11-19 02:34:50 +00:00
|
|
|
const char *dummy_argv[2] = {"fish", nullptr};
|
2018-11-28 14:08:24 +00:00
|
|
|
if (!argv[0]) {
|
2020-04-08 23:56:59 +00:00
|
|
|
argv = const_cast<char **>(dummy_argv); //!OCLINT(parameter reassignment)
|
|
|
|
argc = 1; //!OCLINT(parameter reassignment)
|
2018-11-28 14:08:24 +00:00
|
|
|
}
|
2020-09-28 15:10:40 +00:00
|
|
|
|
|
|
|
// Enable debug categories set in FISH_DEBUG.
|
|
|
|
// This is in *addition* to the ones given via --debug.
|
|
|
|
if (const char *debug_categories = getenv("FISH_DEBUG")) {
|
|
|
|
activate_flog_categories_by_pattern(str2wcstring(debug_categories));
|
|
|
|
}
|
|
|
|
|
2019-05-12 22:48:00 +00:00
|
|
|
fish_cmd_opts_t opts{};
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
my_optind = fish_parse_opt(argc, argv, &opts);
|
2012-11-19 00:30:30 +00:00
|
|
|
|
2019-04-20 07:15:51 +00:00
|
|
|
// Direct any debug output right away.
|
2020-09-28 15:10:40 +00:00
|
|
|
// --debug-output takes precedence, otherwise $FISH_DEBUG_OUTPUT is used.
|
|
|
|
if (opts.debug_output.empty()) {
|
|
|
|
const char *var = getenv("FISH_DEBUG_OUTPUT");
|
|
|
|
if (var) opts.debug_output = var;
|
|
|
|
}
|
|
|
|
|
2019-04-20 07:15:51 +00:00
|
|
|
FILE *debug_output = nullptr;
|
|
|
|
if (!opts.debug_output.empty()) {
|
|
|
|
debug_output = fopen(opts.debug_output.c_str(), "w");
|
|
|
|
if (!debug_output) {
|
|
|
|
fprintf(stderr, "Could not open file %s\n", opts.debug_output.c_str());
|
|
|
|
perror("fopen");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
set_cloexec(fileno(debug_output));
|
|
|
|
setlinebuf(debug_output);
|
|
|
|
set_flog_output_file(debug_output);
|
|
|
|
}
|
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
// No-exec is prohibited when in interactive mode.
|
2019-05-12 22:48:00 +00:00
|
|
|
if (opts.is_interactive_session && opts.no_exec) {
|
2020-01-19 12:38:47 +00:00
|
|
|
FLOGF(warning, _(L"Can not use the no-execute mode when running an interactive session"));
|
2019-05-12 22:48:00 +00:00
|
|
|
opts.no_exec = false;
|
2012-11-19 00:30:30 +00:00
|
|
|
}
|
2013-10-26 22:27:39 +00:00
|
|
|
|
2019-05-12 22:48:00 +00:00
|
|
|
// Apply our options.
|
|
|
|
if (opts.is_login) mark_login();
|
|
|
|
if (opts.no_exec) mark_no_exec();
|
2020-12-06 21:40:45 +00:00
|
|
|
if (opts.is_interactive_session) set_interactive_session(true);
|
2020-02-08 20:23:39 +00:00
|
|
|
if (opts.enable_private_mode) start_private_mode(env_stack_t::globals());
|
2019-05-12 22:48:00 +00:00
|
|
|
|
2016-05-01 01:37:19 +00:00
|
|
|
// Only save (and therefore restore) the fg process group if we are interactive. See issues
|
|
|
|
// #197 and #1002.
|
2020-12-06 21:40:45 +00:00
|
|
|
if (is_interactive_session()) {
|
2013-10-26 22:22:20 +00:00
|
|
|
save_term_foreground_process_group();
|
|
|
|
}
|
|
|
|
|
2021-02-15 17:59:54 +00:00
|
|
|
struct config_paths_t paths;
|
|
|
|
// If we're not executing, there's no need to find the config.
|
2021-04-11 09:52:30 +00:00
|
|
|
if (!opts.no_exec) {
|
2021-02-15 17:59:54 +00:00
|
|
|
paths = determine_config_directory_paths(argv[0]);
|
2021-02-15 19:57:11 +00:00
|
|
|
}
|
|
|
|
if (!opts.no_exec) {
|
2021-05-01 17:43:31 +00:00
|
|
|
env_init(&paths, /* do uvars */ !opts.no_config, /* default paths */ opts.no_config);
|
2021-02-15 17:59:54 +00:00
|
|
|
}
|
2020-02-08 20:23:39 +00:00
|
|
|
|
2018-04-24 21:32:06 +00:00
|
|
|
// Set features early in case other initialization depends on them.
|
2018-04-24 23:48:13 +00:00
|
|
|
// Start with the ones set in the environment, then those set on the command line (so the
|
|
|
|
// command line takes precedence).
|
2019-05-10 01:04:30 +00:00
|
|
|
if (auto features_var = env_stack_t::globals().get(L"fish_features")) {
|
2018-04-24 23:48:13 +00:00
|
|
|
for (const wcstring &s : features_var->as_list()) {
|
|
|
|
mutable_fish_features().set_from_string(s);
|
|
|
|
}
|
|
|
|
}
|
2018-04-24 21:32:06 +00:00
|
|
|
mutable_fish_features().set_from_string(opts.features);
|
2012-11-19 00:30:30 +00:00
|
|
|
proc_init();
|
|
|
|
builtin_init();
|
2017-02-16 04:09:26 +00:00
|
|
|
misc_init();
|
2012-11-19 00:30:30 +00:00
|
|
|
reader_init();
|
2006-03-10 13:38:09 +00:00
|
|
|
|
2012-01-23 05:40:08 +00:00
|
|
|
parser_t &parser = parser_t::principal_parser();
|
2022-03-28 01:59:34 +00:00
|
|
|
parser.set_syncs_uvars(!opts.no_config);
|
2012-01-23 05:40:08 +00:00
|
|
|
|
2021-02-15 19:57:11 +00:00
|
|
|
if (!opts.no_exec && !opts.no_config) {
|
2021-02-15 17:59:54 +00:00
|
|
|
read_init(parser, paths);
|
|
|
|
}
|
2022-03-17 18:02:12 +00:00
|
|
|
|
2022-06-13 15:17:29 +00:00
|
|
|
if (is_interactive_session() && opts.no_config && !opts.no_exec) {
|
2022-03-17 18:02:12 +00:00
|
|
|
// If we have no config, we default to the default key bindings.
|
|
|
|
parser.vars().set_one(L"fish_key_bindings", ENV_UNEXPORT, L"fish_default_key_bindings");
|
|
|
|
if (function_exists(L"fish_default_key_bindings", parser)) {
|
2022-03-19 21:53:43 +00:00
|
|
|
std::vector<std::string> cmd{"fish_default_key_bindings"};
|
2022-03-17 18:02:12 +00:00
|
|
|
run_command_list(parser, &cmd, {});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-06 08:24:54 +00:00
|
|
|
// Re-read the terminal modes after config, it might have changed them.
|
|
|
|
term_copy_modes();
|
|
|
|
|
2020-04-03 19:24:31 +00:00
|
|
|
// Stomp the exit status of any initialization commands (issue #635).
|
|
|
|
parser.set_last_statuses(statuses_t::just(STATUS_CMD_OK));
|
2013-05-05 09:33:17 +00:00
|
|
|
|
2021-01-08 16:25:00 +00:00
|
|
|
// If we're profiling startup to a separate file, write it now.
|
2021-04-21 20:31:58 +00:00
|
|
|
if (!opts.profile_startup_output.empty() &&
|
|
|
|
opts.profile_startup_output != opts.profile_output) {
|
2021-01-08 16:25:00 +00:00
|
|
|
parser.emit_profiling(opts.profile_startup_output.c_str());
|
|
|
|
|
|
|
|
// If we are profiling both, ensure the startup data only
|
|
|
|
// ends up in the startup file.
|
|
|
|
parser.clear_profiling();
|
|
|
|
}
|
|
|
|
|
|
|
|
g_profiling_active = !opts.profile_output.empty();
|
|
|
|
|
2020-04-03 19:24:31 +00:00
|
|
|
// Run post-config commands specified as arguments, if any.
|
|
|
|
if (!opts.postconfig_cmds.empty()) {
|
|
|
|
res = run_command_list(parser, &opts.postconfig_cmds, {});
|
|
|
|
}
|
Add '--init-command', '-C' to the command line switches.
In order to allow the execution of commands before dropping to an
interactive prompt, a new switch, '-C' or '--init-command' has been
added to those switches that we accept.
The documentation has been updated correspondingly.
The original code only supported a single command list to be executed,
and this command list terminates the shell when it completes. To allow
the new command list to preceed the original one, both have been
wrapped in a new container class 'command_line_switches_t'. This is
then passed around in place of the list of strings we used previously.
I had considered moving the interactive, login and other command line
switch states into this container, but doing so would change far more
of the code, moving the structure to be available globally, and I
wasn't confident of the impact. However, this might be a useful thing
to do in the future.
A new function, run_command_list, was lifted from the prior execution
code, and re-used for both the initial command and the regular command
execution.
2017-06-29 14:21:00 +00:00
|
|
|
|
2020-04-03 19:24:31 +00:00
|
|
|
if (!opts.batch_cmds.empty()) {
|
|
|
|
// Run the commands specified as arguments, if any.
|
|
|
|
if (get_login()) {
|
|
|
|
// Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds.
|
|
|
|
fish_xdm_login_hack_hack_hack_hack(&opts.batch_cmds, argc - my_optind,
|
|
|
|
argv + my_optind);
|
|
|
|
}
|
2020-09-26 12:45:51 +00:00
|
|
|
|
|
|
|
// Pass additional args as $argv.
|
|
|
|
// Note that we *don't* support setting argv[0]/$0, unlike e.g. bash.
|
|
|
|
wcstring_list_t list;
|
|
|
|
for (char **ptr = argv + my_optind; *ptr; ptr++) {
|
|
|
|
list.push_back(str2wcstring(*ptr));
|
|
|
|
}
|
|
|
|
parser.vars().set(L"argv", ENV_DEFAULT, std::move(list));
|
2020-04-03 19:24:31 +00:00
|
|
|
res = run_command_list(parser, &opts.batch_cmds, {});
|
2020-08-15 21:41:11 +00:00
|
|
|
parser.libdata().exit_current_script = false;
|
2020-04-03 19:24:31 +00:00
|
|
|
} else if (my_optind == argc) {
|
|
|
|
// Implicitly interactive mode.
|
2021-01-01 20:15:09 +00:00
|
|
|
if (opts.no_exec && isatty(STDIN_FILENO)) {
|
|
|
|
FLOGF(error, L"no-execute mode enabled and no script given. Exiting");
|
|
|
|
return EXIT_FAILURE; // above line should always exit
|
|
|
|
}
|
2020-04-03 19:24:31 +00:00
|
|
|
res = reader_read(parser, STDIN_FILENO, {});
|
|
|
|
} else {
|
|
|
|
const char *file = *(argv + (my_optind++));
|
|
|
|
autoclose_fd_t fd(open_cloexec(file, O_RDONLY));
|
|
|
|
if (!fd.valid()) {
|
2021-11-20 16:40:47 +00:00
|
|
|
FLOGF(error, _(L"Error reading script file '%s':"), file);
|
|
|
|
perror("error");
|
2016-05-01 01:37:19 +00:00
|
|
|
} else {
|
2020-04-03 19:24:31 +00:00
|
|
|
wcstring_list_t list;
|
|
|
|
for (char **ptr = argv + my_optind; *ptr; ptr++) {
|
|
|
|
list.push_back(str2wcstring(*ptr));
|
|
|
|
}
|
|
|
|
parser.vars().set(L"argv", ENV_DEFAULT, std::move(list));
|
|
|
|
|
|
|
|
auto &ld = parser.libdata();
|
|
|
|
wcstring rel_filename = str2wcstring(file);
|
|
|
|
scoped_push<const wchar_t *> filename_push{&ld.current_filename,
|
|
|
|
intern(rel_filename.c_str())};
|
|
|
|
res = reader_read(parser, fd.fd(), {});
|
|
|
|
if (res) {
|
|
|
|
FLOGF(warning, _(L"Error while reading file %ls\n"),
|
|
|
|
ld.current_filename ? ld.current_filename : _(L"Standard input"));
|
2012-11-19 00:30:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-12 21:00:44 +00:00
|
|
|
int exit_status = res ? STATUS_CMD_UNKNOWN : parser.get_last_status();
|
2021-05-17 22:33:33 +00:00
|
|
|
event_fire(parser, event_t::process_exit(getpid(), exit_status));
|
2019-01-04 04:20:43 +00:00
|
|
|
|
|
|
|
// Trigger any exit handlers.
|
2022-05-09 00:07:34 +00:00
|
|
|
event_fire_generic(parser, L"fish_exit", {to_string(exit_status)});
|
2013-10-26 22:27:39 +00:00
|
|
|
|
2013-10-26 22:22:20 +00:00
|
|
|
restore_term_mode();
|
2020-05-31 21:11:39 +00:00
|
|
|
restore_term_foreground_process_group_for_exit();
|
2014-03-31 17:01:39 +00:00
|
|
|
|
2021-01-08 16:25:00 +00:00
|
|
|
if (!opts.profile_output.empty()) {
|
2020-07-22 22:35:14 +00:00
|
|
|
parser.emit_profiling(opts.profile_output.c_str());
|
2014-02-09 22:04:43 +00:00
|
|
|
}
|
2014-03-31 17:01:39 +00:00
|
|
|
|
2018-09-29 00:20:54 +00:00
|
|
|
history_save_all();
|
2019-04-10 20:58:29 +00:00
|
|
|
if (opts.print_rusage_self) {
|
|
|
|
print_rusage_self(stderr);
|
|
|
|
}
|
2019-04-20 07:15:51 +00:00
|
|
|
if (debug_output) {
|
|
|
|
fclose(debug_output);
|
|
|
|
}
|
2014-10-28 00:23:08 +00:00
|
|
|
exit_without_destructors(exit_status);
|
2016-05-01 01:37:19 +00:00
|
|
|
return EXIT_FAILURE; // above line should always exit
|
2005-09-20 13:26:39 +00:00
|
|
|
}
|