diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index c1142a646..c8433d0b2 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -134,12 +134,13 @@ static wcstring functions_def(const wcstring &name) { out.append(esc_desc); } - if (!function_get_shadow_scope(name)) { + auto props = function_get_properties(name); + assert(props && "Should have function properties"); + if (!props->shadow_scope) { out.append(L" --no-scope-shadowing"); } - for (size_t i = 0; i < ev.size(); i++) { - const event_t *next = ev.at(i).get(); + for (const auto &next : ev) { switch (next->type) { case EVENT_SIGNAL: { append_format(out, L" --on-signal %ls", sig2wcs(next->param1.signal)); @@ -172,11 +173,11 @@ static wcstring functions_def(const wcstring &name) { } } - wcstring_list_t named = function_get_named_arguments(name); + const wcstring_list_t &named = props->named_arguments; if (!named.empty()) { append_format(out, L" --argument"); - for (size_t i = 0; i < named.size(); i++) { - append_format(out, L" %ls", named.at(i).c_str()); + for (const auto &name : named) { + append_format(out, L" %ls", name.c_str()); } } @@ -188,17 +189,14 @@ static wcstring functions_def(const wcstring &name) { // Output any inherited variables as `set -l` lines. std::map inherit_vars = function_get_inherit_vars(name); - for (std::map::const_iterator it = inherit_vars.begin(), - end = inherit_vars.end(); - it != end; ++it) { + for (const auto &kv : inherit_vars) { wcstring_list_t lst; - it->second.to_list(lst); + kv.second.to_list(lst); // This forced tab is crummy, but we don't know what indentation style the function uses. - append_format(out, L"\n\tset -l %ls", it->first.c_str()); - for (wcstring_list_t::const_iterator arg_it = lst.begin(), arg_end = lst.end(); - arg_it != arg_end; ++arg_it) { - wcstring earg = escape_string(*arg_it, ESCAPE_ALL); + append_format(out, L"\n\tset -l %ls", kv.first.c_str()); + for (const auto &arg : lst) { + wcstring earg = escape_string(arg, ESCAPE_ALL); out.push_back(L' '); out.append(earg); } @@ -224,6 +222,7 @@ static int report_function_metadata(const wchar_t *funcname, bool verbose, io_st int line_number = 0; if (function_exists(funcname)) { + auto props = function_get_properties(funcname); path = function_get_definition_file(funcname); if (path) { autoloaded = function_is_autoloaded(funcname) ? L"autoloaded" : L"not-autoloaded"; @@ -231,8 +230,7 @@ static int report_function_metadata(const wchar_t *funcname, bool verbose, io_st } else { path = L"stdin"; } - shadows_scope = - function_get_shadow_scope(funcname) ? L"scope-shadowing" : L"no-scope-shadowing"; + shadows_scope = props->shadow_scope ? L"scope-shadowing" : L"no-scope-shadowing"; function_get_desc(funcname, &description); description = escape_string(description, ESCAPE_NO_QUOTED); } diff --git a/src/exec.cpp b/src/exec.cpp index 8ceae0aab..e329a9646 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -792,19 +792,19 @@ void exec_job(parser_t &parser, job_t *j) { switch (p->type) { case INTERNAL_FUNCTION: { const wcstring func_name = p->argv0(); - wcstring def; - bool function_exists = function_get_definition(func_name, &def); - bool shadow_scope = function_get_shadow_scope(func_name); - const std::map inherit_vars = - function_get_inherit_vars(func_name); - - if (!function_exists) { + auto props = function_get_properties(func_name); + if (!props) { debug(0, _(L"Unknown function '%ls'"), p->argv0()); break; } + wcstring def; + function_get_definition(func_name, &def); + const std::map inherit_vars = + function_get_inherit_vars(func_name); + function_block_t *fb = - parser.push_block(p, func_name, shadow_scope); + parser.push_block(p, func_name, props->shadow_scope); function_prepare_environment(func_name, p->get_argv() + 1, inherit_vars); parser.forbid_function(func_name); diff --git a/src/function.cpp b/src/function.cpp index a39a34871..bd38b083e 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -177,6 +177,16 @@ void function_add(const function_data_t &data, const parser_t &parser) { } } +std::shared_ptr function_get_properties(const wcstring &name) { + if (parser_keywords_is_reserved(name)) return nullptr; + scoped_rlock locker(functions_lock); + auto where = loaded_functions.find(name); + if (where != loaded_functions.end()) { + return where->second.props; + } + return nullptr; +} + int function_exists(const wcstring &cmd) { if (parser_keywords_is_reserved(cmd)) return 0; scoped_rlock locker(functions_lock); @@ -242,24 +252,12 @@ bool function_get_definition(const wcstring &name, wcstring *out_definition) { return func != NULL; } -wcstring_list_t function_get_named_arguments(const wcstring &name) { - scoped_rlock locker(functions_lock); - const function_info_t *func = function_get(name); - return func ? func->props->named_arguments : wcstring_list_t(); -} - std::map function_get_inherit_vars(const wcstring &name) { scoped_rlock locker(functions_lock); const function_info_t *func = function_get(name); return func ? func->inherit_vars : std::map(); } -bool function_get_shadow_scope(const wcstring &name) { - scoped_rlock locker(functions_lock); - const function_info_t *func = function_get(name); - return func ? func->props->shadow_scope : false; -} - bool function_get_desc(const wcstring &name, wcstring *out_desc) { // Empty length string goes to NULL. scoped_rlock locker(functions_lock); @@ -348,21 +346,20 @@ int function_get_definition_lineno(const wcstring &name) { void function_prepare_environment(const wcstring &name, const wchar_t *const *argv, const std::map &inherited_vars) { env_set_argv(argv); - - const wcstring_list_t named_arguments = function_get_named_arguments(name); - if (!named_arguments.empty()) { + auto props = function_get_properties(name); + if (props && !props->named_arguments.empty()) { const wchar_t *const *arg = argv; - for (size_t i = 0; i < named_arguments.size(); i++) { + for (const wcstring &named_arg : props->named_arguments) { if (*arg) { - env_set_one(named_arguments.at(i), ENV_LOCAL | ENV_USER, *arg); + env_set_one(named_arg, ENV_LOCAL | ENV_USER, *arg); arg++; } else { - env_set_empty(named_arguments.at(i), ENV_LOCAL | ENV_USER); + env_set_empty(named_arg, ENV_LOCAL | ENV_USER); } } } - for (auto it = inherited_vars.begin(), end = inherited_vars.end(); it != end; ++it) { - env_set(it->first, ENV_LOCAL | ENV_USER, it->second.as_list()); + for (const auto &kv : inherited_vars) { + env_set(kv.first, ENV_LOCAL | ENV_USER, kv.second.as_list()); } } diff --git a/src/function.h b/src/function.h index ed796df50..078671b51 100644 --- a/src/function.h +++ b/src/function.h @@ -53,18 +53,24 @@ void function_add(const function_data_t &data, const parser_t &parser); /// Remove the function with the specified name. void function_remove(const wcstring &name); +/// Returns the properties for a function, or nullptr if none. This does not trigger autoloading. +std::shared_ptr function_get_properties(const wcstring &name); + /// Returns by reference the definition of the function with the name \c name. Returns true if /// successful, false if no function with the given name exists. +/// This does not trigger autoloading. bool function_get_definition(const wcstring &name, wcstring *out_definition); /// Returns by reference the description of the function with the name \c name. Returns true if the /// function exists and has a nonempty description, false if it does not. +/// This does not trigger autoloading. bool function_get_desc(const wcstring &name, wcstring *out_desc); /// Sets the description of the function with the name \c name. void function_set_desc(const wcstring &name, const wcstring &desc); /// Returns true if the function with the name name exists. +/// This may autoload. int function_exists(const wcstring &name); /// Attempts to load a function if not yet loaded. This is used by the completion machinery. @@ -91,14 +97,9 @@ bool function_is_autoloaded(const wcstring &name); const wchar_t *function_get_definition_file(const wcstring &name); /// Returns the linenumber where the definition of the specified function started. -/// -/// This function does not autoload functions, it will only work on functions that have already been -/// defined. +/// This does not trigger autoloading. int function_get_definition_lineno(const wcstring &name); -/// Returns a list of all named arguments of the specified function. -wcstring_list_t function_get_named_arguments(const wcstring &name); - /// Returns a mapping of all variables of the specified function that were inherited from the scope /// of the function definition to their values. std::map function_get_inherit_vars(const wcstring &name); @@ -107,8 +108,6 @@ std::map function_get_inherit_vars(const wcstring &name); /// is successful. bool function_copy(const wcstring &name, const wcstring &new_name); -/// Returns whether this function shadows variables of the underlying function. -bool function_get_shadow_scope(const wcstring &name); /// Prepares the environment for executing a function. void function_prepare_environment(const wcstring &name, const wchar_t *const *argv,