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 22:21:00 +08:00
|
|
|
//
|
2016-05-01 09:37:19 +08:00
|
|
|
// The main loop of the fish program.
|
2005-09-20 21:26:39 +08:00
|
|
|
/*
|
2008-01-13 03:18:48 +08:00
|
|
|
Copyright (C) 2005-2008 Axel Liljencrantz
|
2005-09-20 21:26:39 +08:00
|
|
|
|
2006-11-01 22:47:47 +08: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 21:26:39 +08: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-14 04:51:52 +08:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-09-20 21:26:39 +08:00
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2016-03-04 07:36:17 +08:00
|
|
|
#include <getopt.h>
|
2015-07-25 23:14:25 +08:00
|
|
|
#include <limits.h>
|
2016-05-01 09:37:19 +08:00
|
|
|
#include <locale.h>
|
2017-02-13 12:24:22 +08:00
|
|
|
#include <stddef.h>
|
2015-07-25 23:14:25 +08:00
|
|
|
#include <stdint.h>
|
2005-09-20 21:26:39 +08:00
|
|
|
#include <stdio.h>
|
2016-05-01 09:37:19 +08:00
|
|
|
#include <stdlib.h>
|
2005-09-20 21:26:39 +08:00
|
|
|
#include <string.h>
|
2016-05-01 09:37:19 +08:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <wchar.h>
|
2017-02-14 12:37:27 +08:00
|
|
|
|
2016-04-21 14:00:54 +08:00
|
|
|
#include <memory>
|
2016-05-01 09:37:19 +08:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2005-09-20 21:26:39 +08:00
|
|
|
|
|
|
|
#include "builtin.h"
|
2016-05-01 09:37:19 +08:00
|
|
|
#include "common.h"
|
2005-09-20 21:26:39 +08:00
|
|
|
#include "env.h"
|
2005-10-06 06:37:08 +08:00
|
|
|
#include "event.h"
|
2016-05-01 09:37:19 +08:00
|
|
|
#include "expand.h"
|
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
|
|
|
#include "fish_version.h"
|
|
|
|
#include "function.h"
|
2018-04-25 05:32:06 +08:00
|
|
|
#include "future_feature_flags.h"
|
2006-04-20 07:42:11 +08:00
|
|
|
#include "history.h"
|
2016-05-01 09:37:19 +08:00
|
|
|
#include "io.h"
|
|
|
|
#include "parser.h"
|
|
|
|
#include "path.h"
|
|
|
|
#include "proc.h"
|
|
|
|
#include "reader.h"
|
2017-02-08 09:21:35 +08:00
|
|
|
#include "signal.h"
|
2016-05-01 09:37:19 +08:00
|
|
|
#include "wutil.h" // IWYU pragma: keep
|
2005-09-20 21:26:39 +08:00
|
|
|
|
2016-04-14 00:00:07 +08:00
|
|
|
// PATH_MAX may not exist.
|
2012-07-09 06:20:39 +08:00
|
|
|
#ifndef PATH_MAX
|
2016-04-14 00:00:07 +08:00
|
|
|
#define PATH_MAX 4096
|
2012-07-09 06:20:39 +08:00
|
|
|
#endif
|
|
|
|
|
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 22:21:00 +08:00
|
|
|
// container to hold the options specified within the command line
|
|
|
|
class fish_cmd_opts_t {
|
2017-07-19 13:40:25 +08:00
|
|
|
public:
|
2018-04-25 05:32:06 +08:00
|
|
|
// Future feature flags values string
|
|
|
|
wcstring features;
|
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 22:21:00 +08: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;
|
|
|
|
};
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
/// If we are doing profiling, the filename to output to.
|
2014-02-10 06:04:43 +08:00
|
|
|
static const char *s_profiling_output_filename = NULL;
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
static bool has_suffix(const std::string &path, const char *suffix, bool ignore_case) {
|
2012-07-09 06:20:39 +08:00
|
|
|
size_t pathlen = path.size(), suffixlen = strlen(suffix);
|
2016-05-01 09:37:19 +08:00
|
|
|
return pathlen >= suffixlen &&
|
|
|
|
!(ignore_case ? strcasecmp : strcmp)(path.c_str() + pathlen - suffixlen, suffix);
|
2012-07-09 06:20:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
/// Modifies the given path by calling realpath. Returns true if realpath succeeded, false
|
|
|
|
/// otherwise.
|
|
|
|
static bool get_realpath(std::string &path) {
|
2012-07-09 06:20:39 +08:00
|
|
|
char buff[PATH_MAX], *ptr;
|
2016-05-01 09:37:19 +08:00
|
|
|
if ((ptr = realpath(path.c_str(), buff))) {
|
2012-07-09 06:20:39 +08:00
|
|
|
path = ptr;
|
|
|
|
}
|
|
|
|
return ptr != NULL;
|
|
|
|
}
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
// OS X function for getting the executable path.
|
2012-07-09 06:20:39 +08:00
|
|
|
extern "C" {
|
2016-05-01 09:37:19 +08:00
|
|
|
int _NSGetExecutablePath(char *buf, uint32_t *bufsize);
|
2012-07-09 06:20:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
/// Return the path to the current executable. This needs to be realpath'd.
|
|
|
|
static std::string get_executable_path(const char *argv0) {
|
2016-04-14 00:00:07 +08:00
|
|
|
char buff[PATH_MAX];
|
2016-04-13 10:03:07 +08:00
|
|
|
|
2012-07-09 06:20:39 +08:00
|
|
|
#if __APPLE__
|
2016-04-13 10:03:07 +08:00
|
|
|
// On OS X use it's proprietary API to get the path to the executable.
|
2016-09-23 23:45:03 +08:00
|
|
|
// This is basically grabbing exec_path after argc, argv, envp, ...: for us
|
|
|
|
// https://opensource.apple.com/source/adv_cmds/adv_cmds-163/ps/print.c
|
2016-04-13 10:03:07 +08:00
|
|
|
uint32_t buffSize = sizeof buff;
|
|
|
|
if (_NSGetExecutablePath(buff, &buffSize) == 0) return std::string(buff);
|
|
|
|
#else
|
|
|
|
// On non-OS X UNIXes, try /proc directory.
|
|
|
|
ssize_t len;
|
2016-04-14 00:00:07 +08:00
|
|
|
len = readlink("/proc/self/exe", buff, sizeof buff - 1); // Linux
|
2016-04-13 10:03:07 +08:00
|
|
|
if (len == -1) {
|
2016-04-14 00:00:07 +08:00
|
|
|
len = readlink("/proc/curproc/file", buff, sizeof buff - 1); // BSD
|
2016-04-13 10:03:07 +08:00
|
|
|
if (len == -1) {
|
2016-04-14 00:00:07 +08:00
|
|
|
len = readlink("/proc/self/path/a.out", buff, sizeof buff - 1); // Solaris
|
2016-04-13 10:01:28 +08:00
|
|
|
}
|
|
|
|
}
|
2016-04-13 10:03:07 +08:00
|
|
|
if (len > 0) {
|
|
|
|
buff[len] = '\0';
|
|
|
|
return std::string(buff);
|
|
|
|
}
|
|
|
|
#endif
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-04-13 10:03:07 +08:00
|
|
|
// Just return argv0, which probably won't work (i.e. it's not an absolute path or a path
|
|
|
|
// relative to the working directory, but instead something the caller found via $PATH). We'll
|
|
|
|
// eventually fall back to the compile time paths.
|
2012-07-09 06:20:39 +08:00
|
|
|
return std::string(argv0 ? argv0 : "");
|
|
|
|
}
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
static struct config_paths_t determine_config_directory_paths(const char *argv0) {
|
2012-07-09 06:20:39 +08:00
|
|
|
struct config_paths_t paths;
|
|
|
|
bool done = false;
|
|
|
|
std::string exec_path = get_executable_path(argv0);
|
2016-05-01 09:37:19 +08:00
|
|
|
if (get_realpath(exec_path)) {
|
2016-09-23 23:45:03 +08:00
|
|
|
debug(2, L"exec_path: '%s'", exec_path.c_str());
|
2016-05-01 09:37:19 +08:00
|
|
|
if (!done) {
|
2016-09-24 02:52:51 +08: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";
|
|
|
|
const char *suffix = NULL;
|
|
|
|
|
|
|
|
if (has_suffix(exec_path, installed_suffix, false)) {
|
|
|
|
suffix = installed_suffix;
|
|
|
|
} else if (has_suffix(exec_path, just_a_fish, false)) {
|
|
|
|
debug(2, L"'fish' not in a 'bin/', trying paths relative to source tree");
|
|
|
|
suffix = just_a_fish;
|
2012-07-09 06:20:39 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-09-24 02:52:51 +08:00
|
|
|
if (suffix) {
|
|
|
|
bool seems_installed = (suffix == installed_suffix);
|
|
|
|
|
2012-07-09 06:20:39 +08:00
|
|
|
wcstring base_path = str2wcstring(exec_path);
|
|
|
|
base_path.resize(base_path.size() - strlen(suffix));
|
2014-04-01 01:01:39 +08:00
|
|
|
|
2016-09-24 02:52:51 +08: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-04-01 01:01:39 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
// Check only that the data and sysconf directories exist. Handle the doc
|
|
|
|
// directories separately.
|
2012-07-09 06:20:39 +08:00
|
|
|
struct stat buf;
|
2016-05-01 09:37:19 +08:00
|
|
|
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) {
|
|
|
|
// The docs dir may not exist; in that case fall back to the compiled in path.
|
|
|
|
if (0 != wstat(paths.doc, &buf)) {
|
2014-01-18 06:18:45 +08:00
|
|
|
paths.doc = L"" DOCDIR;
|
|
|
|
}
|
2012-07-09 06:20:39 +08:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
if (!done) {
|
|
|
|
// Fall back to what got compiled in.
|
2016-09-24 02:52:51 +08:00
|
|
|
debug(2, L"Using compiled in paths:");
|
2012-07-09 06:20:39 +08:00
|
|
|
paths.data = L"" DATADIR "/fish";
|
|
|
|
paths.sysconf = L"" SYSCONFDIR "/fish";
|
2013-10-29 00:01:21 +08:00
|
|
|
paths.doc = L"" DOCDIR;
|
2013-04-16 13:22:19 +08:00
|
|
|
paths.bin = L"" BINDIR;
|
2012-07-09 06:20:39 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-10-05 11:06:14 +08:00
|
|
|
debug(2,
|
|
|
|
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-09 06:20:39 +08:00
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
2016-02-05 04:51:55 +08:00
|
|
|
// Source the file config.fish in the given directory.
|
2016-05-01 09:37:19 +08:00
|
|
|
static void source_config_in_directory(const wcstring &dir) {
|
|
|
|
// 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-05 04:51:55 +08:00
|
|
|
//
|
2016-05-01 09:37:19 +08: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-05 04:51:55 +08:00
|
|
|
const wcstring config_pathname = dir + L"/config.fish";
|
2013-09-30 04:39:41 +08:00
|
|
|
const wcstring escaped_dir = escape_string(dir, ESCAPE_ALL);
|
2016-02-05 04:51:55 +08:00
|
|
|
const wcstring escaped_pathname = escaped_dir + L"/config.fish";
|
|
|
|
if (waccess(config_pathname, R_OK) != 0) {
|
2016-05-01 09:37:19 +08:00
|
|
|
debug(2, L"not sourcing %ls (not readable or does not exist)", escaped_pathname.c_str());
|
2016-02-05 04:51:55 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
debug(2, L"sourcing %ls", escaped_pathname.c_str());
|
|
|
|
|
|
|
|
const wcstring cmd = L"builtin source " + escaped_pathname;
|
2013-09-30 04:39:41 +08:00
|
|
|
parser_t &parser = parser_t::principal_parser();
|
2014-02-21 02:57:13 +08:00
|
|
|
parser.set_is_within_fish_initialization(true);
|
2013-09-30 04:39:41 +08:00
|
|
|
parser.eval(cmd, io_chain_t(), TOP);
|
2014-02-21 02:57:13 +08:00
|
|
|
parser.set_is_within_fish_initialization(false);
|
2013-09-30 04:39:41 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
/// Parse init files. exec_path is the path of fish executable as determined by argv[0].
|
|
|
|
static int read_init(const struct config_paths_t &paths) {
|
2013-09-30 04:39:41 +08:00
|
|
|
source_config_in_directory(paths.data);
|
|
|
|
source_config_in_directory(paths.sysconf);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-05-01 09:37:19 +08: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 08:30:30 +08:00
|
|
|
wcstring config_dir;
|
2016-05-01 09:37:19 +08:00
|
|
|
if (path_get_config(config_dir)) {
|
2013-09-30 04:39:41 +08:00
|
|
|
source_config_in_directory(config_dir);
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2005-09-20 21:26:39 +08: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 22:21:00 +08:00
|
|
|
int run_command_list(std::vector<std::string> *cmds, const io_chain_t &io) {
|
|
|
|
int res = 1;
|
|
|
|
parser_t &parser = parser_t::principal_parser();
|
|
|
|
|
|
|
|
for (size_t i = 0; i < cmds->size(); i++) {
|
|
|
|
const wcstring cmd_wcs = str2wcstring(cmds->at(i));
|
|
|
|
res = parser.eval(cmd_wcs, io, TOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2016-05-16 10:45:02 +08:00
|
|
|
/// Parse the argument list, return the index of the first non-flag arguments.
|
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 22:21:00 +08:00
|
|
|
static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) {
|
2018-04-25 05:32:06 +08:00
|
|
|
static const char *short_opts = "+hilnvc:C:p:d:f:D:";
|
2017-06-11 03:30:09 +08:00
|
|
|
static const struct option long_opts[] = {{"command", required_argument, NULL, 'c'},
|
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 22:21:00 +08:00
|
|
|
{"init-command", required_argument, NULL, 'C'},
|
2018-04-25 05:32:06 +08:00
|
|
|
{"features", required_argument, NULL, 'f'},
|
2017-06-11 03:30:09 +08:00
|
|
|
{"debug-level", required_argument, NULL, 'd'},
|
|
|
|
{"debug-stack-frames", required_argument, NULL, 'D'},
|
|
|
|
{"interactive", no_argument, NULL, 'i'},
|
|
|
|
{"login", no_argument, NULL, 'l'},
|
|
|
|
{"no-execute", no_argument, NULL, 'n'},
|
|
|
|
{"profile", required_argument, NULL, 'p'},
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
|
|
|
{"version", no_argument, NULL, 'v'},
|
|
|
|
{NULL, 0, NULL, 0}};
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-03-04 07:36:17 +08:00
|
|
|
int opt;
|
2016-05-01 09:37:19 +08:00
|
|
|
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'c': {
|
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 22:21:00 +08:00
|
|
|
opts->batch_cmds.push_back(optarg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'C': {
|
|
|
|
opts->postconfig_cmds.push_back(optarg);
|
2012-11-19 16:31:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'd': {
|
2012-11-19 16:31:03 +08:00
|
|
|
char *end;
|
|
|
|
long tmp;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2012-11-19 16:31:03 +08:00
|
|
|
errno = 0;
|
|
|
|
tmp = strtol(optarg, &end, 10);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
if (tmp >= 0 && tmp <= 10 && !*end && !errno) {
|
2012-11-19 16:31:03 +08:00
|
|
|
debug_level = (int)tmp;
|
2016-05-01 09:37:19 +08:00
|
|
|
} else {
|
2016-05-16 10:45:02 +08:00
|
|
|
fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg);
|
2016-03-24 02:42:17 +08:00
|
|
|
exit(1);
|
2012-11-19 16:31:03 +08:00
|
|
|
}
|
|
|
|
break;
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2018-04-25 05:32:06 +08:00
|
|
|
case 'f': {
|
|
|
|
opts->features = str2wcstring(optarg);
|
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'h': {
|
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 22:21:00 +08:00
|
|
|
opts->batch_cmds.push_back("__fish_print_help fish");
|
2012-11-19 16:31:03 +08:00
|
|
|
break;
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'i': {
|
2017-06-20 12:05:34 +08:00
|
|
|
is_interactive_session = true;
|
2012-11-19 16:31:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'l': {
|
2017-06-20 12:05:34 +08:00
|
|
|
is_login = true;
|
2012-11-19 16:31:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'n': {
|
2015-12-19 12:05:00 +08:00
|
|
|
no_exec = 1;
|
2012-11-19 16:31:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'p': {
|
2014-02-10 06:04:43 +08:00
|
|
|
s_profiling_output_filename = optarg;
|
|
|
|
g_profiling_active = true;
|
2012-11-19 16:31:03 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
case 'v': {
|
|
|
|
fwprintf(stdout, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version());
|
2016-03-24 02:42:17 +08:00
|
|
|
exit(0);
|
2016-11-02 13:36:30 +08:00
|
|
|
break;
|
2012-11-19 16:31:03 +08:00
|
|
|
}
|
2016-05-16 10:45:02 +08:00
|
|
|
case 'D': {
|
|
|
|
char *end;
|
|
|
|
long tmp;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
tmp = strtol(optarg, &end, 10);
|
|
|
|
|
|
|
|
if (tmp > 0 && tmp <= 128 && !*end && !errno) {
|
|
|
|
debug_stack_frames = (int)tmp;
|
|
|
|
} else {
|
|
|
|
fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-05-01 09:37:19 +08:00
|
|
|
default: {
|
2016-03-04 07:36:17 +08:00
|
|
|
// We assume getopt_long() has already emitted a diagnostic msg.
|
2016-03-24 02:42:17 +08:00
|
|
|
exit(1);
|
2016-11-02 13:36:30 +08:00
|
|
|
break;
|
2012-11-19 16:31:03 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-19 12:05:00 +08:00
|
|
|
// If our command name begins with a dash that implies we're a login shell.
|
|
|
|
is_login |= argv[0][0] == '-';
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2015-12-19 12:05:00 +08: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.
|
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 22:21:00 +08:00
|
|
|
if (opts->batch_cmds.size() == 0 && optind == argc && isatty(STDIN_FILENO)) {
|
2015-12-19 12:05:00 +08:00
|
|
|
is_interactive_session = 1;
|
2013-10-27 06:24:49 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2015-12-19 12:05:00 +08:00
|
|
|
return optind;
|
2006-10-26 04:54:43 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
int res = 1;
|
|
|
|
int my_optind = 0;
|
2006-10-26 04:54:43 +08:00
|
|
|
|
2016-06-04 10:05:13 +08:00
|
|
|
program_name = L"fish";
|
2012-11-19 08:30:30 +08:00
|
|
|
set_main_thread();
|
2012-02-28 10:43:24 +08:00
|
|
|
setup_fork_guards();
|
2017-05-03 11:55:41 +08:00
|
|
|
signal_unblock_all();
|
2016-06-04 10:05:13 +08:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
fish_setlocale();
|
2006-10-26 04:54:43 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
// struct stat tmp;
|
|
|
|
// stat("----------FISH_HIT_MAIN----------", &tmp);
|
2006-11-11 18:48:40 +08:00
|
|
|
|
2016-07-28 07:35:33 +08:00
|
|
|
if (!argv[0]) {
|
|
|
|
static const char *dummy_argv[2] = {"fish", NULL};
|
|
|
|
argv = (char **)dummy_argv; //!OCLINT(parameter reassignment)
|
|
|
|
argc = 1; //!OCLINT(parameter reassignment)
|
|
|
|
}
|
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 22:21:00 +08:00
|
|
|
fish_cmd_opts_t opts;
|
|
|
|
my_optind = fish_parse_opt(argc, argv, &opts);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
// No-exec is prohibited when in interactive mode.
|
|
|
|
if (is_interactive_session && no_exec) {
|
2012-11-19 08:30:30 +08:00
|
|
|
debug(1, _(L"Can not use the no-execute mode when running an interactive session"));
|
|
|
|
no_exec = 0;
|
|
|
|
}
|
2013-10-27 06:27:39 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
// Only save (and therefore restore) the fg process group if we are interactive. See issues
|
|
|
|
// #197 and #1002.
|
|
|
|
if (is_interactive_session) {
|
2013-10-27 06:22:20 +08:00
|
|
|
save_term_foreground_process_group();
|
|
|
|
}
|
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
|
2017-02-16 12:09:26 +08:00
|
|
|
env_init(&paths);
|
2018-04-25 05:32:06 +08:00
|
|
|
// Set features early in case other initialization depends on them.
|
|
|
|
mutable_fish_features().set_from_string(opts.features);
|
2012-11-19 08:30:30 +08:00
|
|
|
proc_init();
|
|
|
|
builtin_init();
|
2017-02-16 12:09:26 +08:00
|
|
|
misc_init();
|
2012-11-19 08:30:30 +08:00
|
|
|
reader_init();
|
2006-03-10 21:38:09 +08:00
|
|
|
|
2012-01-23 13:40:08 +08:00
|
|
|
parser_t &parser = parser_t::principal_parser();
|
|
|
|
|
2012-08-15 15:57:56 +08:00
|
|
|
const io_chain_t empty_ios;
|
2016-05-01 09:37:19 +08:00
|
|
|
if (read_init(paths)) {
|
|
|
|
// Stomp the exit status of any initialization commands (issue #635).
|
2017-05-04 15:18:02 +08:00
|
|
|
proc_set_last_status(STATUS_CMD_OK);
|
2013-05-05 17:33:17 +08: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 22:21:00 +08:00
|
|
|
// Run post-config commands specified as arguments, if any.
|
|
|
|
if (!opts.postconfig_cmds.empty()) {
|
|
|
|
res = run_command_list(&opts.postconfig_cmds, empty_ios);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!opts.batch_cmds.empty()) {
|
|
|
|
// Run the commands specified as arguments, if any.
|
2016-05-01 09:37:19 +08:00
|
|
|
if (is_login) {
|
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 22:21:00 +08:00
|
|
|
// 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);
|
2013-01-05 05:09:01 +08: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 22:21:00 +08:00
|
|
|
res = run_command_list(&opts.batch_cmds, empty_ios);
|
2012-11-19 08:30:30 +08:00
|
|
|
reader_exit(0, 0);
|
2016-05-01 09:37:19 +08:00
|
|
|
} else if (my_optind == argc) {
|
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 22:21:00 +08:00
|
|
|
// Implicitly interactive mode.
|
2016-03-16 05:03:27 +08:00
|
|
|
res = reader_read(STDIN_FILENO, empty_ios);
|
2016-05-01 09:37:19 +08:00
|
|
|
} else {
|
|
|
|
char *file = *(argv + (my_optind++));
|
2016-03-16 05:03:27 +08:00
|
|
|
int fd = open(file, O_RDONLY);
|
2016-05-01 09:37:19 +08:00
|
|
|
if (fd == -1) {
|
2016-03-16 05:03:27 +08:00
|
|
|
perror(file);
|
2016-05-01 09:37:19 +08:00
|
|
|
} else {
|
|
|
|
// OK to not do this atomically since we cannot have gone multithreaded yet.
|
2012-03-02 16:27:40 +08:00
|
|
|
set_cloexec(fd);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2017-07-09 04:14:30 +08:00
|
|
|
wcstring_list_t list;
|
|
|
|
for (char **ptr = argv + my_optind; *ptr; ptr++) {
|
|
|
|
list.push_back(str2wcstring(*ptr));
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2017-08-06 06:08:39 +08:00
|
|
|
env_set(L"argv", ENV_DEFAULT, list);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2012-12-20 05:31:06 +08:00
|
|
|
const wcstring rel_filename = str2wcstring(file);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-01-04 04:12:53 +08:00
|
|
|
reader_push_current_filename(rel_filename.c_str());
|
2012-11-19 08:30:30 +08:00
|
|
|
|
|
|
|
res = reader_read(fd, empty_ios);
|
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
if (res) {
|
2017-02-14 12:37:27 +08:00
|
|
|
debug(1, _(L"Error while reading file %ls\n"),
|
|
|
|
reader_current_filename() ? reader_current_filename()
|
|
|
|
: _(L"Standard input"));
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
|
|
|
reader_pop_current_filename();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-04 15:18:02 +08:00
|
|
|
int exit_status = res ? STATUS_CMD_UNKNOWN : proc_get_last_status();
|
2014-10-28 08:23:08 +08:00
|
|
|
|
2018-02-03 23:38:15 +08:00
|
|
|
// TODO: The generic process-exit event is useless and unused.
|
|
|
|
// Remove this in future.
|
2014-10-28 08:23:08 +08:00
|
|
|
proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), exit_status);
|
2018-02-03 23:38:15 +08:00
|
|
|
event_fire_generic(L"fish_exit");
|
2013-10-27 06:27:39 +08:00
|
|
|
|
2013-10-27 06:22:20 +08:00
|
|
|
restore_term_mode();
|
2012-11-18 18:16:14 +08:00
|
|
|
restore_term_foreground_process_group();
|
2014-04-01 01:01:39 +08:00
|
|
|
|
2016-05-01 09:37:19 +08:00
|
|
|
if (g_profiling_active) {
|
2014-02-10 06:04:43 +08:00
|
|
|
parser.emit_profiling(s_profiling_output_filename);
|
|
|
|
}
|
2014-04-01 01:01:39 +08:00
|
|
|
|
2018-02-11 09:21:55 +08:00
|
|
|
history_save_all();
|
2012-11-19 08:30:30 +08:00
|
|
|
proc_destroy();
|
2014-10-28 08:23:08 +08:00
|
|
|
exit_without_destructors(exit_status);
|
2016-05-01 09:37:19 +08:00
|
|
|
return EXIT_FAILURE; // above line should always exit
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|