int function_exists_no_autoload( const wcstring &cmd, const env_vars_snapshot_t &vars ) { if( parser_keywords_is_reserved(cmd) ) return 0; scoped_lock lock(functions_lock); return loaded_functions.find(cmd) != loaded_functions.end() || function_autoloader.can_load(cmd, vars); }
int function_exists( const wcstring &cmd ) { if( parser_keywords_is_reserved(cmd) ) return 0; scoped_lock lock(functions_lock); load(cmd); return loaded_functions.find(cmd) != loaded_functions.end(); }
static int validate_function_name(int argc, const wchar_t *const *argv, wcstring &function_name, const wchar_t *cmd, io_streams_t &streams) { if (argc < 2) { // This is currently impossible but let's be paranoid. streams.err.append_format(_(L"%ls: Expected function name"), cmd); return STATUS_INVALID_ARGS; } function_name = argv[1]; if (!valid_func_name(function_name)) { streams.err.append_format(_(L"%ls: Illegal function name '%ls'"), cmd, function_name.c_str()); return STATUS_INVALID_ARGS; } if (parser_keywords_is_reserved(function_name)) { streams.err.append_format( _(L"%ls: The name '%ls' is reserved,\nand can not be used as a function name"), cmd, function_name.c_str()); return STATUS_INVALID_ARGS; } return STATUS_CMD_OK; }
void function_load(const wcstring &cmd) { if (!parser_keywords_is_reserved(cmd)) { scoped_lock locker(functions_lock); load(cmd); } }
/// The functions builtin, used for listing and erasing functions. int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) { const wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); functions_cmd_opts_t opts; int optind; int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { builtin_print_help(parser, streams, cmd, streams.out); return STATUS_CMD_OK; } // Erase, desc, query, copy and list are mutually exclusive. bool describe = opts.description ? true : false; if (describe + opts.erase + opts.list + opts.query + opts.copy > 1) { streams.err.append_format(_(L"%ls: Invalid combination of options\n"), cmd); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } if (opts.erase) { for (int i = optind; i < argc; i++) function_remove(argv[i]); return STATUS_CMD_OK; } if (opts.description) { wchar_t *func; if (argc - optind != 1) { streams.err.append_format(_(L"%ls: Expected exactly one function name\n"), cmd); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } func = argv[optind]; if (!function_exists(func)) { streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, func); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } function_set_desc(func, opts.description); return STATUS_CMD_OK; } if (opts.report_metadata) { if (argc - optind != 1) { streams.err.append_format(_(L"%ls: Expected exactly one function name for --details\n"), cmd); return STATUS_INVALID_ARGS; } const wchar_t *funcname = argv[optind]; return report_function_metadata(funcname, opts.verbose, streams, false); } if (opts.handlers) { maybe_t<event_type_t> type_filter; if (opts.handlers_type) { type_filter = event_type_for_name(opts.handlers_type); if (! type_filter) { streams.err.append_format(_(L"%ls: Expected generic | variable | signal | exit | job-id for --handlers-type\n"), cmd); return STATUS_INVALID_ARGS; } } event_print(streams, type_filter); return STATUS_CMD_OK; } // If we query with no argument, just return false. if (opts.query && argc == optind) { return STATUS_CMD_ERROR; } if (opts.list || argc == optind) { wcstring_list_t names = function_get_names(opts.show_hidden); std::sort(names.begin(), names.end()); bool is_screen = !streams.out_is_redirected && isatty(STDOUT_FILENO); if (is_screen) { wcstring buff; for (size_t i = 0; i < names.size(); i++) { buff.append(names.at(i)); buff.append(L", "); } streams.out.append(reformat_for_screen(buff)); } else { for (size_t i = 0; i < names.size(); i++) { streams.out.append(names.at(i).c_str()); streams.out.append(L"\n"); } } return STATUS_CMD_OK; } if (opts.copy) { wcstring current_func; wcstring new_func; if (argc - optind != 2) { streams.err.append_format(_(L"%ls: Expected exactly two names (current function name, " L"and new function name)\n"), cmd); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } current_func = argv[optind]; new_func = argv[optind + 1]; if (!function_exists(current_func)) { streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, current_func.c_str()); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } if (!valid_func_name(new_func) || parser_keywords_is_reserved(new_func)) { streams.err.append_format(_(L"%ls: Illegal function name '%ls'\n"), cmd, new_func.c_str()); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_INVALID_ARGS; } // Keep things simple: don't allow existing names to be copy targets. if (function_exists(new_func)) { streams.err.append_format( _(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), cmd, new_func.c_str(), current_func.c_str()); builtin_print_error_trailer(parser, streams.err, cmd); return STATUS_CMD_ERROR; } if (function_copy(current_func, new_func)) return STATUS_CMD_OK; return STATUS_CMD_ERROR; } int res = STATUS_CMD_OK; for (int i = optind; i < argc; i++) { if (!function_exists(argv[i])) { res++; } else { if (!opts.query) { if (i != optind) streams.out.append(L"\n"); const wchar_t *funcname = argv[optind]; report_function_metadata(funcname, opts.verbose, streams, true); streams.out.append(functions_def(funcname)); } } } return res; }