2016-05-01 11:31:02 +08:00
|
|
|
// Functions for storing and retrieving function information. These functions also take care of
|
|
|
|
// autoloading functions in the $fish_function_path. Actual function evaluation is taken care of by
|
|
|
|
// the parser and to some degree the builtin handling library.
|
|
|
|
//
|
2016-05-19 06:30:21 +08:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
|
2016-04-21 14:00:54 +08:00
|
|
|
// IWYU pragma: no_include <type_traits>
|
2016-05-01 11:31:02 +08:00
|
|
|
#include <dirent.h>
|
2016-06-24 08:24:19 +08:00
|
|
|
#include <errno.h>
|
2011-12-27 11:18:46 +08:00
|
|
|
#include <pthread.h>
|
2016-05-01 11:31:02 +08:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <wchar.h>
|
2012-01-14 15:44:18 +08:00
|
|
|
#include <map>
|
2016-05-01 11:31:02 +08:00
|
|
|
#include <memory>
|
2012-01-14 15:44:18 +08:00
|
|
|
#include <set>
|
2015-07-25 23:14:25 +08:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
2005-09-20 21:26:39 +08:00
|
|
|
|
2015-07-25 23:14:25 +08:00
|
|
|
#include "autoload.h"
|
2005-09-20 21:26:39 +08:00
|
|
|
#include "common.h"
|
2016-05-01 11:31:02 +08:00
|
|
|
#include "env.h"
|
2005-10-06 06:37:08 +08:00
|
|
|
#include "event.h"
|
2016-05-01 11:31:02 +08:00
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
|
|
|
#include "function.h"
|
|
|
|
#include "intern.h"
|
2007-04-22 17:50:26 +08:00
|
|
|
#include "parser_keywords.h"
|
2016-05-01 11:31:02 +08:00
|
|
|
#include "reader.h"
|
|
|
|
#include "wutil.h" // IWYU pragma: keep
|
2005-09-20 21:26:39 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Table containing all functions.
|
2012-05-19 05:00:36 +08:00
|
|
|
typedef std::map<wcstring, function_info_t> function_map_t;
|
2012-01-14 15:44:18 +08:00
|
|
|
static function_map_t loaded_functions;
|
2011-12-27 11:18:46 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Functions that shouldn't be autoloaded (anymore).
|
2015-03-11 21:14:56 +08:00
|
|
|
static std::set<wcstring> function_tombstones;
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Lock for functions.
|
2011-12-27 11:18:46 +08:00
|
|
|
static pthread_mutex_t functions_lock;
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Autoloader for functions.
|
|
|
|
class function_autoload_t : public autoload_t {
|
|
|
|
public:
|
2012-01-26 10:40:08 +08:00
|
|
|
function_autoload_t();
|
|
|
|
virtual void command_removed(const wcstring &cmd);
|
|
|
|
};
|
|
|
|
|
|
|
|
static function_autoload_t function_autoloader;
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Constructor
|
|
|
|
function_autoload_t::function_autoload_t() : autoload_t(L"fish_function_path", NULL, 0) {}
|
2012-01-26 10:40:08 +08:00
|
|
|
|
2015-04-08 17:58:29 +08:00
|
|
|
static bool function_remove_ignore_autoload(const wcstring &name, bool tombstone = true);
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Callback when an autoloaded function is removed.
|
|
|
|
void function_autoload_t::command_removed(const wcstring &cmd) {
|
2015-04-08 17:58:29 +08:00
|
|
|
function_remove_ignore_autoload(cmd, false);
|
2012-01-26 10:40:08 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Kludgy flag set by the load function in order to tell function_add that the function being
|
|
|
|
/// defined is autoloaded. There should be a better way to do this...
|
2012-03-04 07:20:30 +08:00
|
|
|
static bool is_autoload = false;
|
2006-02-08 17:20:05 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Make sure that if the specified function is a dynamically loaded function, it has been fully
|
|
|
|
/// loaded.
|
|
|
|
static int load(const wcstring &name) {
|
2011-12-27 13:56:23 +08:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-11-19 08:30:30 +08:00
|
|
|
bool was_autoload = is_autoload;
|
|
|
|
int res;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2015-04-06 23:38:18 +08:00
|
|
|
bool no_more_autoload = function_tombstones.count(name) > 0;
|
2016-05-01 11:31:02 +08:00
|
|
|
if (no_more_autoload) return 0;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2012-01-14 15:44:18 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter != loaded_functions.end() && !iter->second.is_autoload) {
|
|
|
|
// We have a non-autoload version already.
|
2012-11-19 08:30:30 +08:00
|
|
|
return 0;
|
2011-12-27 11:18:46 +08:00
|
|
|
}
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
is_autoload = true;
|
|
|
|
res = function_autoloader.load(name, true);
|
|
|
|
is_autoload = was_autoload;
|
|
|
|
return res;
|
2006-02-08 17:20:05 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
/// Insert a list of all dynamically loaded functions into the specified list.
|
|
|
|
static void autoload_names(std::set<wcstring> &names, int get_hidden) {
|
2012-11-19 08:30:30 +08:00
|
|
|
size_t i;
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
const env_var_t path_var_wstr = env_get_string(L"fish_function_path");
|
|
|
|
if (path_var_wstr.missing()) return;
|
2012-11-19 08:30:30 +08:00
|
|
|
const wchar_t *path_var = path_var_wstr.c_str();
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2012-01-11 04:51:09 +08:00
|
|
|
wcstring_list_t path_list;
|
2006-02-09 01:37:18 +08:00
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
tokenize_variable_array(path_var, path_list);
|
2016-05-01 11:31:02 +08:00
|
|
|
for (i = 0; i < path_list.size(); i++) {
|
2012-11-19 08:30:30 +08:00
|
|
|
const wcstring &ndir_str = path_list.at(i);
|
|
|
|
const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
|
|
|
|
DIR *dir = wopendir(ndir);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (!dir) continue;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
|
|
|
wcstring name;
|
2016-05-01 11:31:02 +08:00
|
|
|
while (wreaddir(dir, name)) {
|
2012-11-19 08:30:30 +08:00
|
|
|
const wchar_t *fn = name.c_str();
|
|
|
|
const wchar_t *suffix;
|
2016-05-01 11:31:02 +08:00
|
|
|
if (!get_hidden && fn[0] == L'_') continue;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
|
|
|
suffix = wcsrchr(fn, L'.');
|
2016-05-01 11:31:02 +08:00
|
|
|
if (suffix && (wcscmp(suffix, L".fish") == 0)) {
|
2012-01-14 15:44:18 +08:00
|
|
|
wcstring name(fn, suffix - fn);
|
|
|
|
names.insert(name);
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(dir);
|
2012-11-18 18:23:22 +08:00
|
|
|
}
|
2006-02-08 17:20:05 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_init() {
|
|
|
|
// PCA: This recursive lock was introduced early in my work. I would like to make this a
|
|
|
|
// non-recursive lock but I haven't fully investigated all the call paths (for autoloading
|
|
|
|
// functions, etc.).
|
2011-12-27 11:18:46 +08:00
|
|
|
pthread_mutexattr_t a;
|
|
|
|
VOMIT_ON_FAILURE(pthread_mutexattr_init(&a));
|
2016-05-01 11:31:02 +08:00
|
|
|
VOMIT_ON_FAILURE(pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE));
|
2011-12-27 11:18:46 +08:00
|
|
|
VOMIT_ON_FAILURE(pthread_mutex_init(&functions_lock, &a));
|
|
|
|
VOMIT_ON_FAILURE(pthread_mutexattr_destroy(&a));
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars) {
|
|
|
|
std::map<wcstring, env_var_t> result;
|
|
|
|
for (wcstring_list_t::const_iterator it = vars.begin(), end = vars.end(); it != end; ++it) {
|
2014-10-03 06:59:24 +08:00
|
|
|
result.insert(std::make_pair(*it, env_get_string(*it)));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
function_info_t::function_info_t(const function_data_t &data, const wchar_t *filename,
|
|
|
|
int def_offset, bool autoload)
|
|
|
|
: definition(data.definition),
|
|
|
|
description(data.description),
|
|
|
|
definition_file(intern(filename)),
|
|
|
|
definition_offset(def_offset),
|
|
|
|
named_arguments(data.named_arguments),
|
|
|
|
inherit_vars(snapshot_vars(data.inherit_vars)),
|
|
|
|
is_autoload(autoload),
|
2016-05-09 06:57:56 +08:00
|
|
|
shadow_scope(data.shadow_scope) {}
|
2016-05-01 11:31:02 +08:00
|
|
|
|
|
|
|
function_info_t::function_info_t(const function_info_t &data, const wchar_t *filename,
|
|
|
|
int def_offset, bool autoload)
|
|
|
|
: definition(data.definition),
|
|
|
|
description(data.description),
|
|
|
|
definition_file(intern(filename)),
|
|
|
|
definition_offset(def_offset),
|
|
|
|
named_arguments(data.named_arguments),
|
|
|
|
inherit_vars(data.inherit_vars),
|
|
|
|
is_autoload(autoload),
|
2016-05-09 06:57:56 +08:00
|
|
|
shadow_scope(data.shadow_scope) {}
|
2016-05-01 11:31:02 +08:00
|
|
|
|
|
|
|
void function_add(const function_data_t &data, const parser_t &parser, int definition_line_offset) {
|
2016-10-10 05:38:26 +08:00
|
|
|
UNUSED(parser);
|
2012-03-04 07:20:30 +08:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
CHECK(!data.name.empty(), );
|
|
|
|
CHECK(data.definition, );
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Remove the old function.
|
2012-11-19 08:30:30 +08:00
|
|
|
function_remove(data.name);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Create and store a new function.
|
2012-03-04 07:20:30 +08:00
|
|
|
const wchar_t *filename = reader_current_filename();
|
2013-12-21 09:44:37 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
const function_map_t::value_type new_pair(
|
|
|
|
data.name, function_info_t(data, filename, definition_line_offset, is_autoload));
|
2012-05-19 05:00:36 +08:00
|
|
|
loaded_functions.insert(new_pair);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Add event handlers.
|
|
|
|
for (std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end();
|
|
|
|
++iter) {
|
2012-12-20 18:48:36 +08:00
|
|
|
event_add_handler(*iter);
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
int function_exists(const wcstring &cmd) {
|
|
|
|
if (parser_keywords_is_reserved(cmd)) return 0;
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-01-29 06:56:13 +08:00
|
|
|
load(cmd);
|
2012-11-18 18:23:22 +08:00
|
|
|
return loaded_functions.find(cmd) != loaded_functions.end();
|
2011-12-27 11:18:46 +08:00
|
|
|
}
|
2010-09-18 09:51:16 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_load(const wcstring &cmd) {
|
|
|
|
if (!parser_keywords_is_reserved(cmd)) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2015-10-08 09:59:41 +08:00
|
|
|
load(cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
int function_exists_no_autoload(const wcstring &cmd, const env_vars_snapshot_t &vars) {
|
|
|
|
if (parser_keywords_is_reserved(cmd)) return 0;
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2016-05-01 11:31:02 +08:00
|
|
|
return loaded_functions.find(cmd) != loaded_functions.end() ||
|
|
|
|
function_autoloader.can_load(cmd, vars);
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
static bool function_remove_ignore_autoload(const wcstring &name, bool tombstone) {
|
|
|
|
// Note: the lock may be held at this point, but is recursive.
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2015-03-11 21:14:56 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Not found. Not erasing.
|
|
|
|
if (iter == loaded_functions.end()) return false;
|
2015-03-11 21:14:56 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Removing an auto-loaded function. Prevent it from being auto-reloaded.
|
|
|
|
if (iter->second.is_autoload && tombstone) function_tombstones.insert(name);
|
2015-03-11 21:14:56 +08:00
|
|
|
|
|
|
|
loaded_functions.erase(iter);
|
|
|
|
event_t ev(EVENT_ANY);
|
2016-05-01 11:31:02 +08:00
|
|
|
ev.function_name = name;
|
2015-03-11 21:14:56 +08:00
|
|
|
event_remove(ev);
|
|
|
|
return true;
|
2012-01-26 10:40:08 +08:00
|
|
|
}
|
2006-02-05 21:10:35 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_remove(const wcstring &name) {
|
|
|
|
if (function_remove_ignore_autoload(name)) function_autoloader.unload(name);
|
2012-01-24 12:32:36 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
static const function_info_t *function_get(const wcstring &name) {
|
|
|
|
// The caller must lock the functions_lock before calling this; however our mutex is currently
|
|
|
|
// recursive, so trylock will never fail. We need a way to correctly check if a lock is locked
|
|
|
|
// (or better yet, make our lock non-recursive).
|
|
|
|
// ASSERT_IS_LOCKED(functions_lock);
|
2012-01-24 12:32:36 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter == loaded_functions.end()) {
|
2012-05-19 05:00:36 +08:00
|
|
|
return NULL;
|
2012-01-24 12:32:36 +08:00
|
|
|
}
|
2016-05-05 06:19:47 +08:00
|
|
|
return &iter->second;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
bool function_get_definition(const wcstring &name, wcstring *out_definition) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (func && out_definition) {
|
2012-05-18 10:37:46 +08:00
|
|
|
out_definition->assign(func->definition);
|
|
|
|
}
|
|
|
|
return func != NULL;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
2007-04-17 04:06:11 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
wcstring_list_t function_get_named_arguments(const wcstring &name) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2012-01-24 12:43:39 +08:00
|
|
|
return func ? func->named_arguments : wcstring_list_t();
|
2007-04-17 04:06:11 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
std::map<wcstring, env_var_t> function_get_inherit_vars(const wcstring &name) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2014-10-03 06:59:24 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
return func ? func->inherit_vars : std::map<wcstring, env_var_t>();
|
2014-10-03 06:59:24 +08:00
|
|
|
}
|
|
|
|
|
2016-05-09 06:57:56 +08:00
|
|
|
int function_get_shadow_scope(const wcstring &name) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2016-05-09 06:57:56 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
|
|
|
return func ? func->shadow_scope : false;
|
2007-04-23 06:10:33 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
bool function_get_desc(const wcstring &name, wcstring *out_desc) {
|
|
|
|
// Empty length string goes to NULL.
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (out_desc && func && !func->description.empty()) {
|
2012-05-18 10:46:08 +08:00
|
|
|
out_desc->assign(_(func->description.c_str()));
|
|
|
|
return true;
|
2016-05-01 11:31:02 +08:00
|
|
|
} else {
|
2012-05-18 10:46:08 +08:00
|
|
|
return false;
|
2012-01-24 12:43:39 +08:00
|
|
|
}
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
void function_set_desc(const wcstring &name, const wcstring &desc) {
|
2012-11-19 08:30:30 +08:00
|
|
|
load(name);
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
function_map_t::iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter != loaded_functions.end()) {
|
2012-05-19 05:00:36 +08:00
|
|
|
iter->second.description = desc;
|
|
|
|
}
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
bool function_copy(const wcstring &name, const wcstring &new_name) {
|
2012-03-04 07:20:30 +08:00
|
|
|
bool result = false;
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-01-14 15:44:18 +08:00
|
|
|
function_map_t::const_iterator iter = loaded_functions.find(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (iter != loaded_functions.end()) {
|
|
|
|
// This new instance of the function shouldn't be tied to the definition file of the
|
|
|
|
// original, so pass NULL filename, etc.
|
|
|
|
const function_map_t::value_type new_pair(new_name,
|
|
|
|
function_info_t(iter->second, NULL, 0, false));
|
2012-05-19 05:00:36 +08:00
|
|
|
loaded_functions.insert(new_pair);
|
2012-03-04 07:20:30 +08:00
|
|
|
result = true;
|
2012-01-14 15:44:18 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
return result;
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
wcstring_list_t function_get_names(int get_hidden) {
|
2012-01-14 15:44:18 +08:00
|
|
|
std::set<wcstring> names;
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-11-19 08:30:30 +08:00
|
|
|
autoload_names(names, get_hidden);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2012-01-14 15:44:18 +08:00
|
|
|
function_map_t::const_iterator iter;
|
2016-05-01 11:31:02 +08:00
|
|
|
for (iter = loaded_functions.begin(); iter != loaded_functions.end(); ++iter) {
|
2012-01-14 15:44:18 +08:00
|
|
|
const wcstring &name = iter->first;
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
// Maybe skip hidden.
|
|
|
|
if (!get_hidden) {
|
2012-05-19 05:00:36 +08:00
|
|
|
if (name.empty() || name.at(0) == L'_') continue;
|
2012-01-14 15:44:18 +08:00
|
|
|
}
|
|
|
|
names.insert(name);
|
|
|
|
}
|
|
|
|
return wcstring_list_t(names.begin(), names.end());
|
2005-09-20 21:26:39 +08:00
|
|
|
}
|
2005-10-06 06:37:08 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
const wchar_t *function_get_definition_file(const wcstring &name) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2012-01-24 12:43:39 +08:00
|
|
|
return func ? func->definition_file : NULL;
|
2006-01-26 22:48:10 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
int function_get_definition_offset(const wcstring &name) {
|
2016-07-21 13:30:58 +08:00
|
|
|
scoped_lock locker(functions_lock);
|
2012-05-19 05:00:36 +08:00
|
|
|
const function_info_t *func = function_get(name);
|
2012-01-24 12:43:39 +08:00
|
|
|
return func ? func->definition_offset : -1;
|
2006-01-26 22:48:10 +08:00
|
|
|
}
|
2015-08-16 04:37:17 +08:00
|
|
|
|
2016-05-01 11:31:02 +08:00
|
|
|
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
|
2015-08-16 04:37:17 +08:00
|
|
|
env_set_argv(argv);
|
2016-05-01 11:31:02 +08:00
|
|
|
|
2015-08-16 04:37:17 +08:00
|
|
|
const wcstring_list_t named_arguments = function_get_named_arguments(name);
|
2016-05-01 11:31:02 +08:00
|
|
|
if (!named_arguments.empty()) {
|
|
|
|
const wchar_t *const *arg;
|
2015-08-16 04:37:17 +08:00
|
|
|
size_t i;
|
2016-05-01 11:31:02 +08:00
|
|
|
for (i = 0, arg = argv; i < named_arguments.size(); i++) {
|
2015-08-16 04:37:17 +08:00
|
|
|
env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL | ENV_USER);
|
2016-05-01 11:31:02 +08:00
|
|
|
|
|
|
|
if (*arg) arg++;
|
2015-08-16 04:37:17 +08:00
|
|
|
}
|
|
|
|
}
|
2016-05-01 11:31:02 +08:00
|
|
|
|
|
|
|
for (std::map<wcstring, env_var_t>::const_iterator it = inherited_vars.begin(),
|
|
|
|
end = inherited_vars.end();
|
|
|
|
it != end; ++it) {
|
2015-08-16 04:37:17 +08:00
|
|
|
env_set(it->first, it->second.missing() ? NULL : it->second.c_str(), ENV_LOCAL | ENV_USER);
|
|
|
|
}
|
|
|
|
}
|