/// Silly function. static void builtin_complete_add2(const wchar_t *cmd, int cmd_type, const wchar_t *short_opt, const wcstring_list_t &gnu_opt, const wcstring_list_t &old_opt, int result_mode, const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, int flags) { size_t i; const wchar_t *s; for (s = short_opt; *s; s++) { complete_add(cmd, cmd_type, wcstring(1, *s), option_type_short, result_mode, condition, comp, desc, flags); } for (i = 0; i < gnu_opt.size(); i++) { complete_add(cmd, cmd_type, gnu_opt.at(i), option_type_double_long, result_mode, condition, comp, desc, flags); } for (i = 0; i < old_opt.size(); i++) { complete_add(cmd, cmd_type, old_opt.at(i), option_type_single_long, result_mode, condition, comp, desc, flags); } if (old_opt.empty() && gnu_opt.empty() && wcslen(short_opt) == 0) { complete_add(cmd, cmd_type, wcstring(), option_type_args_only, result_mode, condition, comp, desc, flags); } }
/** Silly function */ static void builtin_complete_remove2(const wchar_t *cmd, int cmd_type, const wchar_t *short_opt, const wcstring_list_t &gnu_opt, const wcstring_list_t &old_opt) { const wchar_t *s = (wchar_t *)short_opt; if (*s) { for (; *s; s++) { if (old_opt.empty() && gnu_opt.empty()) { complete_remove(cmd, cmd_type, *s, 0, 0); } else { builtin_complete_remove3(cmd, cmd_type, *s, gnu_opt, 0); builtin_complete_remove3(cmd, cmd_type, *s, old_opt, 1); } } } else if (gnu_opt.empty() && old_opt.empty()) { complete_remove(cmd, cmd_type, 0, 0, 0); } else { builtin_complete_remove3(cmd, cmd_type, 0, gnu_opt, 0); builtin_complete_remove3(cmd, cmd_type, 0, old_opt, 1); } }
void function_prepare_environment(const wcstring &name, const wchar_t *const *argv, const std::map<wcstring, env_var_t> &inherited_vars) { // Three components of the environment: // 1. argv // 2. named arguments // 3. inherited variables env_set_argv(argv); const wcstring_list_t named_arguments = function_get_named_arguments(name); if (!named_arguments.empty()) { const wchar_t *const *arg; size_t i; for (i = 0, arg = argv; i < named_arguments.size(); i++) { env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL | ENV_USER); if (*arg) arg++; } } for (std::map<wcstring, env_var_t>::const_iterator it = inherited_vars.begin(), end = inherited_vars.end(); it != end; ++it) { env_set(it->first, it->second.missing() ? NULL : it->second.c_str(), ENV_LOCAL | ENV_USER); } }
// Validate the given path `list`. If there are any entries referring to invalid directories which // contain a colon, then complain. Return true if any path element was valid, false if not. static bool validate_path_warning_on_colons(const wchar_t *cmd, const wchar_t *key, //!OCLINT(npath complexity) const wcstring_list_t &list, io_streams_t &streams, const environment_t &vars) { // Always allow setting an empty value. if (list.empty()) return true; bool any_success = false; // Don't bother validating (or complaining about) values that are already present. When // determining already-present values, use ENV_DEFAULT instead of the passed-in scope because // in: // // set -l PATH stuff $PATH // // where we are temporarily shadowing a variable, we want to compare against the shadowed value, // not the (missing) local value. Also don't bother to complain about relative paths, which // don't start with /. wcstring_list_t existing_values; const auto existing_variable = vars.get(key, ENV_DEFAULT); if (!existing_variable.missing_or_empty()) existing_variable->to_list(existing_values); for (const wcstring &dir : list) { if (!string_prefixes_string(L"/", dir) || contains(existing_values, dir)) { any_success = true; continue; } const wchar_t *colon = std::wcschr(dir.c_str(), L':'); bool looks_like_colon_sep = colon && colon[1]; if (!looks_like_colon_sep && any_success) { // Once we have one valid entry, skip the remaining ones unless we might warn. continue; } struct stat buff; bool valid = true; if (wstat(dir, &buff) == -1) { valid = false; } else if (!S_ISDIR(buff.st_mode)) { errno = ENOTDIR; valid = false; } else if (waccess(dir, X_OK) == -1) { valid = false; } if (valid) { any_success = true; } else if (looks_like_colon_sep) { streams.err.append_format(BUILTIN_SET_PATH_ERROR, cmd, key, dir.c_str(), std::strerror(errno)); streams.err.append_format(BUILTIN_SET_PATH_HINT, cmd, key, key, std::wcschr(dir.c_str(), L':') + 1); } } return any_success; }
void parse_util_set_argv(const wchar_t * const *argv, const wcstring_list_t &named_arguments) { if (*argv) { const wchar_t * const *arg; wcstring sb; for (arg=argv; *arg; arg++) { if (arg != argv) { sb.append(ARRAY_SEP_STR); } sb.append(*arg); } env_set(L"argv", sb.c_str(), ENV_LOCAL); } else { env_set(L"argv", 0, ENV_LOCAL); } if (! named_arguments.empty()) { const wchar_t * const *arg; size_t i; for (i=0, arg=argv; i < named_arguments.size(); i++) { env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL | ENV_USER); if (*arg) arg++; } } }
/** Silly function */ static void builtin_complete_add2(const wchar_t *cmd, int cmd_type, const wchar_t *short_opt, const wcstring_list_t &gnu_opt, const wcstring_list_t &old_opt, int result_mode, const wchar_t *condition, const wchar_t *comp, const wchar_t *desc, int flags) { size_t i; const wchar_t *s; for (s=short_opt; *s; s++) { complete_add(cmd, cmd_type, *s, 0, 0, result_mode, condition, comp, desc, flags); } for (i=0; i<gnu_opt.size(); i++) { complete_add(cmd, cmd_type, 0, gnu_opt.at(i).c_str(), 0, result_mode, condition, comp, desc, flags); } for (i=0; i<old_opt.size(); i++) { complete_add(cmd, cmd_type, 0, old_opt.at(i).c_str(), 1, result_mode, condition, comp, desc, flags); } if (old_opt.empty() && gnu_opt.empty() && wcslen(short_opt) == 0) { complete_add(cmd, cmd_type, 0, 0, 0, result_mode, condition, comp, desc, flags); } }
/** Call env_set. If this is a path variable, e.g. PATH, validate the elements. On error, print a description of the problem to stderr. */ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope) { size_t i; int retcode = 0; const wchar_t *val_str=NULL; if (is_path_variable(key)) { /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */ bool any_success = false; /* Don't bother validating (or complaining about) values that are already present */ wcstring_list_t existing_values; const env_var_t existing_variable = env_get_string(key, scope); if (! existing_variable.missing_or_empty()) tokenize_variable_array(existing_variable, existing_values); for (i=0; i< val.size() ; i++) { const wcstring &dir = val.at(i); if (list_contains_string(existing_values, dir)) { any_success = true; continue; } bool show_perror = false; int show_hint = 0; bool error = false; struct stat buff; if (wstat(dir, &buff)) { error = true; show_perror = true; } if (!(S_ISDIR(buff.st_mode))) { error = true; } if (!error) { any_success = true; } else { append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key); const wchar_t *colon = wcschr(dir.c_str(), L':'); if (colon && *(colon+1)) { show_hint = 1; } } if (show_perror) { builtin_wperror(L"set"); } if (show_hint) { append_format(stderr_buffer, _(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1); } } /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */ if (! val.empty() && ! any_success) { return 1; } } wcstring sb; if (! val.empty()) { for (i=0; i< val.size() ; i++) { sb.append(val[i]); if (i<val.size() - 1) { sb.append(ARRAY_SEP_STR); } } val_str = sb.c_str(); } switch (env_set(key, val_str, scope | ENV_USER)) { case ENV_PERM: { append_format(stderr_buffer, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key); retcode=1; break; } case ENV_SCOPE: { append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key); retcode=1; break; } case ENV_INVALID: { append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key); retcode=1; break; } } return retcode; }
/** Call env_set. If this is a path variable, e.g. PATH, validate the elements. On error, print a description of the problem to stderr. */ static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope, io_streams_t &streams) { size_t i; int retcode = 0; const wchar_t *val_str=NULL; if (is_path_variable(key)) { /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */ bool any_success = false; /* Don't bother validating (or complaining about) values that are already present. When determining already-present values, use ENV_DEFAULT instead of the passed-in scope because in: set -l PATH stuff $PATH where we are temporarily shadowing a variable, we want to compare against the shadowed value, not the (missing) local value. Also don't bother to complain about relative paths, which don't start with /. */ wcstring_list_t existing_values; const env_var_t existing_variable = env_get_string(key, ENV_DEFAULT); if (! existing_variable.missing_or_empty()) tokenize_variable_array(existing_variable, existing_values); for (i=0; i< val.size() ; i++) { const wcstring &dir = val.at(i); if (!string_prefixes_string(L"/", dir) || list_contains_string(existing_values, dir)) { any_success = true; continue; } bool show_perror = false; int show_hint = 0; bool error = false; struct stat buff; if (wstat(dir, &buff)) { error = true; show_perror = true; } if (!(S_ISDIR(buff.st_mode))) { error = true; } if (!error) { any_success = true; } else { streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key); const wchar_t *colon = wcschr(dir.c_str(), L':'); if (colon && *(colon+1)) { show_hint = 1; } } if (show_perror) { builtin_wperror(L"set", streams); } if (show_hint) { streams.err.append_format(_(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1); } } /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */ if (! val.empty() && ! any_success) { return 1; } } wcstring sb; if (! val.empty()) { for (i=0; i< val.size() ; i++) { sb.append(val[i]); if (i<val.size() - 1) { sb.append(ARRAY_SEP_STR); } } val_str = sb.c_str(); } switch (env_set(key, val_str, scope | ENV_USER)) { case ENV_PERM: { streams.err.append_format(_(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key); retcode=1; break; } case ENV_SCOPE: { streams.err.append_format(_(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key); retcode=1; break; } case ENV_INVALID: { streams.err.append_format(_(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key); retcode=1; break; } } return retcode; }
/** Call env_set. If this is a path variable, e.g. PATH, validate the elements. On error, print a description of the problem to stderr. */ static int my_env_set( const wchar_t *key, const wcstring_list_t &val, int scope ) { size_t i; int retcode = 0; const wchar_t *val_str=NULL; if( is_path_variable( key ) ) { /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */ bool any_success = false, any_error = false; for( i=0; i< val.size() ; i++ ) { bool show_perror = false; int show_hint = 0; bool error = false; struct stat buff; const wchar_t *dir = val[i].c_str(); if( wstat( dir, &buff ) ) { error = true; show_perror = true; } if( !( S_ISDIR(buff.st_mode) ) ) { error = true; } if( !error ) { any_success = true; } else { any_error = true; const wchar_t *colon; append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir, key); colon = wcschr( dir, L':' ); if( colon && *(colon+1) ) { show_hint = 1; } } if( show_perror ) { builtin_wperror( L"set" ); } if( show_hint ) { append_format(stderr_buffer, _(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr( dir, L':' )+1); } } /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */ if( ! val.empty() && ! any_success ) { return 1; } } wcstring sb; if( val.size() ) { for( i=0; i< val.size() ; i++ ) { sb.append(val[i]); if( i<val.size() - 1 ) { sb.append( ARRAY_SEP_STR ); } } val_str = sb.c_str(); } switch( env_set( key, val_str, scope | ENV_USER ) ) { case ENV_PERM: { append_format(stderr_buffer, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key); retcode=1; break; } case ENV_INVALID: { append_format(stderr_buffer, _(L"%ls: Unknown error"), L"set" ); retcode=1; break; } } return retcode; }