From edb973fadc8d359aa212999d8f447b0de9589789 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 4 Jan 2013 13:09:01 -0800 Subject: [PATCH] Hack around xdm's dumb assumption that the login shell is POSIX compliant so we no longer kill OpenSUSE https://github.com/fish-shell/fish-shell/issues/367 Also fix some formatting --- complete.cpp | 4 +- env_universal.cpp | 16 +++---- expand.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++ expand.h | 7 +++ fish.cpp | 74 ++++++++++++------------------ parser.cpp | 13 ++++++ util.h | 17 ------- wutil.cpp | 2 +- 8 files changed, 174 insertions(+), 72 deletions(-) diff --git a/complete.cpp b/complete.cpp index 55c7598a9..1739b8cd5 100644 --- a/complete.cpp +++ b/complete.cpp @@ -1970,11 +1970,11 @@ void complete(const wcstring &cmd, std::vector &comps, complete_ty See https://github.com/fish-shell/fish-shell/issues/378 */ if (commands_to_load != NULL && completer.has_commands_to_load()) do_file = false; - + /* And if we're autosuggesting, and the token is empty, don't do file suggestions */ if (type == COMPLETE_AUTOSUGGEST && current_token_unescape.empty()) do_file = false; - + /* This function wants the unescaped string */ diff --git a/env_universal.cpp b/env_universal.cpp index cea456ce1..c9dcc350b 100644 --- a/env_universal.cpp +++ b/env_universal.cpp @@ -113,14 +113,14 @@ static int try_get_socket_once(void) uname = pw->pw_name; } } - + std::string name; name.reserve(strlen(dir) + uname.size() + strlen(SOCK_FILENAME) + 2); name.append(dir); name.append("/"); name.append(SOCK_FILENAME); name.append(uname); - + free(dir); debug(3, L"Connect to socket %s at fd %2", name.c_str(), s); @@ -145,7 +145,7 @@ static int try_get_socket_once(void) } debug(3, L"Connected to fd %d", s); - + return s; } @@ -155,16 +155,16 @@ static int try_get_socket_once(void) static int get_socket(void) { get_socket_count++; - + int s = try_get_socket_once(); if (s < 0) { if (start_fishd) { debug(2, L"Could not connect to socket %d, starting fishd", s); - + start_fishd(); - + for (size_t i=0; s < 0 && i < DEFAULT_RETRY_COUNT; i++) { if (i > 0) @@ -176,13 +176,13 @@ static int get_socket(void) } } } - + if (s < 0) { debug(1, L"Could not connect to universal variable server, already tried manual restart (or no command supplied). You will not be able to share variable values between fish sessions. Is fish properly installed?"); return -1; } - + return s; } diff --git a/expand.cpp b/expand.cpp index bca069880..04d4def0c 100644 --- a/expand.cpp +++ b/expand.cpp @@ -1785,3 +1785,116 @@ bool expand_one(wcstring &string, expand_flags_t flags) } return result; } + + +/* + +https://github.com/fish-shell/fish-shell/issues/367 + +With them the Seed of Wisdom did I sow, +And with my own hand labour'd it to grow: +And this was all the Harvest that I reap'd--- +"I came like Water, and like Wind I go." + +*/ + +static std::string escape_single_quoted_hack_hack_hack_hack(const char *str) +{ + std::string result; + size_t len = strlen(str); + result.reserve(len + 2); + result.push_back('\''); + for (size_t i=0; i < len; i++) + { + char c = str[i]; + // Escape backslashes and single quotes only + if (c == '\\' || c == '\'') + result.push_back('\\'); + result.push_back(c); + } + result.push_back('\''); + return result; +} + +bool fish_xdm_login_hack_hack_hack_hack(std::vector *cmds, int argc, const char * const *argv) +{ + bool result = false; + if (cmds && cmds->size() == 1) + { + const std::string &cmd = cmds->at(0); + if (cmd == "exec \"${@}\"" || cmd == "exec \"$@\"") + { + /* We're going to construct a new command that starts with exec, and then has the remaining arguments escaped */ + std::string new_cmd = "exec"; + for (int i=1; i < argc; i++) + { + const char *arg = argv[i]; + if (arg) + { + new_cmd.push_back(' '); + new_cmd.append(escape_single_quoted_hack_hack_hack_hack(arg)); + } + } + + cmds->at(0) = new_cmd; + result = true; + } + } + return result; +} + +bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector *args) +{ + static signed char isSUSE = -1; + if (isSUSE == 0) + return false; + + bool result = false; + if (args && ! args->empty()) + { + const wcstring &cmd = args->at(0).completion; + if (cmd.find(L"DBUS_SESSION_BUS_") != wcstring::npos) + { + /* See if we are SUSE */ + if (isSUSE < 0) + { + struct stat buf = {}; + isSUSE = (0 == stat("/etc/SuSE-release", &buf)); + } + + if (isSUSE) + { + /* Look for an equal sign */ + size_t where = cmd.find(L'='); + if (where != wcstring::npos) + { + /* Oh my. It's presumably of the form foo=bar; find the = and split */ + const wcstring key = wcstring(cmd, 0, where); + + /* Trim whitespace and semicolon */ + wcstring val = wcstring(cmd, where+1); + size_t last_good = val.find_last_not_of(L"\n ;"); + if (last_good != wcstring::npos) + val.resize(last_good + 1); + + args->clear(); + args->push_back(completion_t(L"set")); + if (key == L"DBUS_SESSION_BUS_ADDRESS") + args->push_back(completion_t(L"-x")); + args->push_back(completion_t(key)); + args->push_back(completion_t(val)); + result = true; + } + else if (string_prefixes_string(L"export DBUS_SESSION_BUS_ADDRESS;", cmd)) + { + /* Nothing, we already exported it */ + args->clear(); + args->push_back(completion_t(L"echo")); + args->push_back(completion_t(L"-n")); + result = true; + } + } + } + } + return result; +} diff --git a/expand.h b/expand.h index 6426c6862..1dedf1732 100644 --- a/expand.h +++ b/expand.h @@ -200,4 +200,11 @@ void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_ */ std::vector expand_get_all_process_names(void); +/* Terrible hacks */ +bool fish_xdm_login_hack_hack_hack_hack(std::vector *cmds, int argc, const char * const *argv); +bool fish_openSUSE_dbus_hack_hack_hack_hack(std::vector *args); + + #endif + + diff --git a/fish.cpp b/fish.cpp index 4b6ab1e6a..86568d727 100644 --- a/fish.cpp +++ b/fish.cpp @@ -245,51 +245,26 @@ static int read_init(const struct config_paths_t &paths) Parse the argument list, return the index of the first non-switch arguments. */ -static int fish_parse_opt(int argc, char **argv, const char **cmd_ptr) +static int fish_parse_opt(int argc, char **argv, std::vector *out_cmds) { int my_optind; int force_interactive=0; + bool has_cmd = false; while (1) { static struct option long_options[] = { - { - "command", required_argument, 0, 'c' - } - , - { - "debug-level", required_argument, 0, 'd' - } - , - { - "interactive", no_argument, 0, 'i' - } - , - { - "login", no_argument, 0, 'l' - } - , - { - "no-execute", no_argument, 0, 'n' - } - , - { - "profile", required_argument, 0, 'p' - } - , - { - "help", no_argument, 0, 'h' - } - , - { - "version", no_argument, 0, 'v' - } - , - { - 0, 0, 0, 0 - } + { "command", required_argument, 0, 'c' }, + { "debug-level", required_argument, 0, 'd' }, + { "interactive", no_argument, 0, 'i' } , + { "login", no_argument, 0, 'l' }, + { "no-execute", no_argument, 0, 'n' }, + { "profile", required_argument, 0, 'p' }, + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { 0, 0, 0, 0 } } ; @@ -313,7 +288,8 @@ static int fish_parse_opt(int argc, char **argv, const char **cmd_ptr) case 'c': { - *cmd_ptr = optarg; + out_cmds->push_back(optarg ? optarg : ""); + has_cmd = true; is_interactive_session = 0; break; } @@ -340,7 +316,8 @@ static int fish_parse_opt(int argc, char **argv, const char **cmd_ptr) case 'h': { - *cmd_ptr = "__fish_print_help fish"; + out_cmds->push_back("__fish_print_help fish"); + has_cmd = true; break; } @@ -393,7 +370,7 @@ static int fish_parse_opt(int argc, char **argv, const char **cmd_ptr) We are an interactive session if we have not been given an explicit command to execute, _and_ stdin is a tty. */ - is_interactive_session &= (*cmd_ptr == 0); + is_interactive_session &= has_cmd; is_interactive_session &= (my_optind == argc); is_interactive_session &= isatty(STDIN_FILENO); @@ -439,7 +416,6 @@ extern int g_fork_count; int main(int argc, char **argv) { int res=1; - const char *cmd=0; int my_optind=0; set_main_thread(); @@ -453,7 +429,8 @@ int main(int argc, char **argv) //struct stat tmp; //stat("----------FISH_HIT_MAIN----------", &tmp); - my_optind = fish_parse_opt(argc, argv, &cmd); + std::vector cmds; + my_optind = fish_parse_opt(argc, argv, &cmds); /* No-exec is prohibited when in interactive mode @@ -483,10 +460,19 @@ int main(int argc, char **argv) const io_chain_t empty_ios; if (read_init(paths)) { - if (cmd != NULL) + /* Run the commands specified as arguments, if any */ + if (! cmds.empty()) { - const wcstring cmd_wcs = str2wcstring(cmd); - res = parser.eval(cmd_wcs, empty_ios, TOP); + /* Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. */ + if (is_login) + { + fish_xdm_login_hack_hack_hack_hack(&cmds, argc - my_optind, argv + my_optind); + } + for (size_t i=0; i < cmds.size(); i++) + { + const wcstring cmd_wcs = str2wcstring(cmds.at(i)); + res = parser.eval(cmd_wcs, empty_ios, TOP); + } reader_exit(0, 0); } else diff --git a/parser.cpp b/parser.cpp index 361c3d0f9..9e28020fd 100644 --- a/parser.cpp +++ b/parser.cpp @@ -2071,6 +2071,18 @@ int parser_t::parse_job(process_t *p, } } + // Disabled pending discussion in https://github.com/fish-shell/fish-shell/issues/367 +#if 0 + if (! has_command && ! use_implicit_cd) + { + if (fish_openSUSE_dbus_hack_hack_hack_hack(&args)) + { + has_command = true; + p->type = INTERNAL_BUILTIN; + } + } +#endif + /* Check if the specified command exists */ if (! has_command && ! use_implicit_cd) { @@ -3858,3 +3870,4 @@ breakpoint_block_t::breakpoint_block_t() : block_t(BREAKPOINT) { } + diff --git a/util.h b/util.h index c3ef0ca94..ee7142be2 100644 --- a/util.h +++ b/util.h @@ -1,11 +1,5 @@ /** \file util.h Generic utilities library. - - All containers in this library except strinb_buffer_t are written - so that they don't allocate any memory until the first element is - inserted into them. That way it is known to be very cheap to - initialize various containers at startup, supporting the fish - notion of doing as much lazy initalization as possible. */ #ifndef FISH_UTIL_H @@ -15,17 +9,6 @@ #include #include -/** - Buffer for concatenating arbitrary data. -*/ -typedef struct buffer -{ - char *buff; /**