diff --git a/env.cpp b/env.cpp index 106af3b46..0b262f11b 100644 --- a/env.cpp +++ b/env.cpp @@ -50,6 +50,7 @@ #include "reader.h" #include "parser.h" #include "env_universal.h" +#include "env_universal_common.h" #include "input.h" #include "event.h" #include "path.h" @@ -129,6 +130,13 @@ static env_node_t *top = NULL; /** Bottom node on the function stack */ static env_node_t *global_env = NULL; +/** Universal variables global instance. Initialized in env_init. */ +static env_universal_t *s_universal_variables = NULL; + +/* Getter for universal variables */ +static env_universal_t *uvars() { + return s_universal_variables; +} /** Table for global variables @@ -331,9 +339,7 @@ static void react_to_variable_change(const wcstring &key) Universal variable callback function. This function makes sure the proper events are triggered when an event occurs. */ -static void universal_callback(fish_message_type_t type, - const wchar_t *name, - const wchar_t *val) +static void universal_callback(fish_message_type_t type, const wchar_t *name, const wchar_t *val) { const wchar_t *str = NULL; @@ -554,7 +560,9 @@ void env_init(const struct config_paths_t *paths /* or NULL */) env_set(L"version", version.c_str(), ENV_GLOBAL); env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL); - env_universal_init(universal_callback); + /* Set up universal variables. The empty string means to use the deafult path. */ + assert(s_universal_variables == NULL); + s_universal_variables = new env_universal_t(L""); /* Set up SHLVL variable @@ -586,32 +594,6 @@ void env_init(const struct config_paths_t *paths /* or NULL */) env_set(FISH_BIND_MODE_VAR, DEFAULT_BIND_MODE, ENV_GLOBAL); } -void env_destroy() -{ - env_universal_destroy(); - - while (&top->env != global) - { - env_pop(); - } - - env_read_only.clear(); - env_electric.clear(); - - var_table_t::iterator iter; - for (iter = global->begin(); iter != global->end(); ++iter) - { - const var_entry_t &entry = iter->second; - if (entry.exportv) - { - mark_changed_exported(); - break; - } - } - - delete top; -} - /** Search all visible scopes in order for the specified key. Return the first scope in which it was found. @@ -688,23 +670,32 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode) if (var_mode & ENV_UNIVERSAL) { - bool exportv; + const bool old_export = uvars() && uvars()->get_export(key); + bool new_export; if (var_mode & ENV_EXPORT) { // export - exportv = true; + new_export = true; } else if (var_mode & ENV_UNEXPORT) { // unexport - exportv = false; + new_export = false; } else { // not changing the export - exportv = env_universal_get_export(key); + new_export = old_export; + } + if (uvars()) + { + uvars()->set(key, val, new_export); + env_universal_barrier(); + if (old_export || new_export) + { + mark_changed_exported(); + } } - env_universal_set(key, val, exportv); is_universal = 1; } @@ -753,7 +744,7 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode) env_universal_barrier(); } - if (! env_universal_get(key).missing()) + if (uvars() && ! uvars()->get(key).missing()) { bool exportv; if (var_mode & ENV_EXPORT) @@ -766,10 +757,11 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode) } else { - exportv = env_universal_get_export(key); + exportv = uvars()->get_export(key); } - env_universal_set(key, val, exportv); + uvars()->set(key, val, exportv); + env_universal_barrier(); is_universal = 1; done = 1; @@ -817,7 +809,6 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode) if (has_changed_old || has_changed_new) mark_changed_exported(); } - } if (!is_universal) @@ -917,7 +908,7 @@ int env_remove(const wcstring &key, int var_mode) !(var_mode & ENV_GLOBAL) && !(var_mode & ENV_LOCAL)) { - erased = env_universal_remove(key); + erased = uvars() && uvars()->remove(key); } react_to_variable_change(key); @@ -1000,16 +991,12 @@ env_var_t env_get_string(const wcstring &key) env_universal_barrier(); } - env_var_t item = env_universal_get(key); - - if (item.missing() || (wcscmp(item.c_str(), ENV_NULL)==0)) + env_var_t env_var = uvars() ? uvars()->get(key) : env_var_t::missing_var(); + if (env_var == ENV_NULL) { - return env_var_t::missing_var(); - } - else - { - return item; + env_var = env_var_t::missing_var(); } + return env_var; } } @@ -1079,15 +1066,15 @@ bool env_exist(const wchar_t *key, int mode) env_universal_barrier(); } - if (! env_universal_get(key).missing()) + if (uvars() && ! uvars()->get(key).missing()) { if (mode & ENV_EXPORT) { - return env_universal_get_export(key) == 1; + return uvars()->get_export(key); } else if (mode & ENV_UNEXPORT) { - return env_universal_get_export(key) == 0; + return ! uvars()->get_export(key); } return 1; @@ -1254,13 +1241,9 @@ wcstring_list_t env_get_names(int flags) } - if (show_universal) + if (show_universal && uvars()) { - - wcstring_list_t uni_list; - env_universal_get_names(uni_list, - show_exported, - show_unexported); + const wcstring_list_t uni_list = uvars()->get_names(show_exported, show_unexported); names.insert(uni_list.begin(), uni_list.end()); } @@ -1340,18 +1323,20 @@ static void update_export_array_if_necessary(bool recalc) get_exported(top, vals); - wcstring_list_t uni; - env_universal_get_names(uni, 1, 0); - for (i=0; iget_names(true, false); + for (i=0; i(key, val)); + const wcstring &key = uni.at(i); + const env_var_t val = uvars()->get(key); + + if (! val.missing() && val != ENV_NULL) + { + // Note that std::map::insert does NOT overwrite a value already in the map, + // which we depend on here + vals.insert(std::pair(key, val)); + } } } @@ -1385,6 +1370,28 @@ env_vars_snapshot_t::env_vars_snapshot_t(const wchar_t * const *keys) } } + +void env_universal_barrier() +{ + ASSERT_IS_MAIN_THREAD(); + if (uvars()) + { + callback_data_list_t changes; + bool changed = uvars()->sync(&changes); + if (changed) + { + universal_notifier_t::default_notifier().post_notification(); + } + + /* Post callbacks */ + for (size_t i=0; i < changes.size(); i++) + { + const callback_data_t &data = changes.at(i); + universal_callback(data.type, data.key.c_str(), data.val.c_str()); + } + } +} + env_vars_snapshot_t::env_vars_snapshot_t() { } /* The "current" variables are not a snapshot at all, but instead trampoline to env_get_string, etc. We identify the current snapshot based on pointer values. */ diff --git a/env.h b/env.h index 7898a1253..d1a40f7de 100644 --- a/env.h +++ b/env.h @@ -68,12 +68,6 @@ struct config_paths_t */ void env_init(const struct config_paths_t *paths = NULL); -/** - Destroy environment variable data -*/ -void env_destroy(); - - /** Set the value of the environment variable whose name matches key to val. @@ -205,6 +199,9 @@ void env_push(bool new_scope); */ void env_pop(); +/** Synchronizes all universal variable changes: writes everything out, reads stuff in */ +void env_universal_barrier(); + /** Returns an array containing all exported variables in a format suitable for execv. */ const char * const * env_export_arr(bool recalc); diff --git a/env_universal.cpp b/env_universal.cpp index a9c812e6a..fa6e6b5d6 100644 --- a/env_universal.cpp +++ b/env_universal.cpp @@ -40,88 +40,3 @@ #include "env.h" -/** - Set to true after initialization has been performed -*/ -static bool s_env_univeral_inited = false; -static void (*external_callback)(fish_message_type_t type, const wchar_t *name, const wchar_t *val); - -void env_universal_barrier(); - -/** - Callback function used whenever a new fishd message is recieved -*/ -static void callback(fish_message_type_t type, const wchar_t *name, const wchar_t *val) -{ - if (external_callback) - external_callback(type, name, val); -} - -void env_universal_init(void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val)) -{ - external_callback = cb; - env_universal_common_init(&callback); - s_env_univeral_inited = true; -} - -void env_universal_destroy() -{ - s_env_univeral_inited = false; -} - - -env_var_t env_universal_get(const wcstring &name) -{ - if (!s_env_univeral_inited) - return env_var_t::missing_var(); - - return env_universal_common_get(name); -} - -bool env_universal_get_export(const wcstring &name) -{ - if (!s_env_univeral_inited) - return false; - - return env_universal_common_get_export(name); -} - -void env_universal_barrier() -{ - ASSERT_IS_MAIN_THREAD(); - UNIVERSAL_LOG("BARRIER"); - env_universal_common_sync(); -} - - -void env_universal_set(const wcstring &name, const wcstring &value, bool exportv) -{ - if (!s_env_univeral_inited) - return; - - debug(3, L"env_universal_set( \"%ls\", \"%ls\" )", name.c_str(), value.c_str()); - - env_universal_common_set(name.c_str(), value.c_str(), exportv); - env_universal_barrier(); -} - -bool env_universal_remove(const wcstring &name) -{ - if (!s_env_univeral_inited) - return false; - - return env_universal_common_remove(name); -} - -void env_universal_get_names(wcstring_list_t &lst, - bool show_exported, - bool show_unexported) -{ - if (!s_env_univeral_inited) - return; - - env_universal_common_get_names(lst, - show_exported, - show_unexported); -} - diff --git a/env_universal.h b/env_universal.h index 5c15c86db..c84ab8b6f 100644 --- a/env_universal.h +++ b/env_universal.h @@ -10,56 +10,4 @@ #include "env_universal_common.h" #include "env.h" -/** - Initialize the envuni library -*/ -void env_universal_init(void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val)); -/** - Free memory used by envuni -*/ -void env_universal_destroy(); - -/** - Get the value of a universal variable -*/ -env_var_t env_universal_get(const wcstring &name); - -/** - Get the export flag of the variable with the specified - name. Returns 0 if the variable doesn't exist. -*/ -bool env_universal_get_export(const wcstring &name); - -/** - Set the value of a universal variable -*/ -void env_universal_set(const wcstring &name, const wcstring &val, bool exportv); -/** - Erase a universal variable - - \return true if the variable existed, and false if the variable did not exist -*/ -bool env_universal_remove(const wcstring &name); - -/** - Read all available messages from the server. -*/ -int env_universal_read_all(); - -/** - Get the names of all universal variables - - \param l the list to insert the names into - \param show_exported whether exported variables should be shown - \param show_unexported whether unexported variables should be shown -*/ -void env_universal_get_names(wcstring_list_t &list, - bool show_exported, - bool show_unexported); - -/** - Synchronize with fishd -*/ -void env_universal_barrier(); - #endif diff --git a/env_universal_common.cpp b/env_universal_common.cpp index 60411b46e..ce4f4f9a6 100644 --- a/env_universal_common.cpp +++ b/env_universal_common.cpp @@ -34,6 +34,17 @@ #include #endif +/** + The set command +*/ +#define SET_STR L"SET" + +/** + The set_export command +*/ +#define SET_EXPORT_STR L"SET_EXPORT" + + /** Non-wide version of the set command */ @@ -76,37 +87,10 @@ static env_universal_t &default_universal_vars() return s_default_vars; } -/** - Callback function, should be called on all events -*/ -struct callback_data_t -{ - fish_message_type_t type; - wcstring key; - wcstring val; - - callback_data_t(fish_message_type_t t, const wcstring &k, const wcstring &v) : type(t), key(k), val(v) - { - } -}; - static void (*callback)(fish_message_type_t type, const wchar_t *key, const wchar_t *val); -/* Post callbacks that we have determined in this list. We do this here, instead of at the point where we determined that the values changed, because we determine those under a lock, and reentrancy would cause a deadlock */ -static void post_callbacks(const callback_data_list_t &callbacks) -{ - if (callback != NULL) - { - for (size_t i=0; i < callbacks.size(); i++) - { - const callback_data_t &data = callbacks.at(i); - callback(data.type, data.key.c_str(), data.val.c_str()); - } - } -} - void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val)) { callback = cb; @@ -148,18 +132,6 @@ void env_universal_common_set(const wchar_t *key, const wchar_t *val, bool expor } } -void env_universal_common_sync() -{ - assert(! synchronizes_via_fishd()); - callback_data_list_t callbacks; - bool changed = default_universal_vars().sync(&callbacks); - if (changed) - { - universal_notifier_t::default_notifier().post_notification(); - } - post_callbacks(callbacks); -} - static void report_error(int err_code, const wchar_t *err_format, ...) { va_list va; @@ -279,17 +251,14 @@ static bool append_file_entry(fish_message_type_t type, const wcstring &key_in, return success; } -/** - Put exported or unexported variables in a string list -*/ -void env_universal_common_get_names(wcstring_list_t &lst, bool show_exported, bool show_unexported) +wcstring_list_t env_universal_get_names(bool show_exported, bool show_unexported) { - const wcstring_list_t names = default_universal_vars().get_names(show_exported, show_unexported); - lst.insert(lst.end(), names.begin(), names.end()); + return default_universal_vars().get_names(show_exported, show_unexported); + } -env_var_t env_universal_common_get(const wcstring &name) +env_var_t env_universal_get(const wcstring &name) { return default_universal_vars().get(name); } @@ -531,8 +500,7 @@ static env_var_t fishd_env_get(const char *key) } else { - const wcstring wkey = str2wcstring(key); - return env_universal_common_get(wkey); + return env_var_t::missing_var(); } } @@ -725,6 +693,7 @@ bool env_universal_t::open_and_acquire_lock(const wcstring &path, int *out_fd) /* Returns true if modified variables were written, false if not. (There may still be variable changes due to other processes on a false return). */ bool env_universal_t::sync(callback_data_list_t *callbacks) { + UNIVERSAL_LOG("sync"); scoped_lock locker(lock); /* Our saving strategy: @@ -844,14 +813,15 @@ void env_universal_t::read_message_internal(int fd, callback_data_list_t *callba { break; } + const size_t bufflen = (size_t)amt; // Walk over it by lines. The contents of an unterminated line will be left in 'line' for the next iteration. size_t line_start = 0; - while (line_start < sizeof buffer) + while (line_start < amt) { // Run until we hit a newline size_t cursor = line_start; - while (cursor < sizeof buffer && buffer[cursor] != '\n') + while (cursor < bufflen && buffer[cursor] != '\n') { cursor++; } @@ -860,13 +830,11 @@ void env_universal_t::read_message_internal(int fd, callback_data_list_t *callba line.append(buffer + line_start, cursor - line_start); // Process it if it's a newline (which is true if we are before the end of the buffer) - if (cursor < sizeof buffer && ! line.empty()) + if (cursor < bufflen && ! line.empty()) { if (utf8_to_wchar_string(line, &wide_line)) { - wchar_t *tmp = wcsdup(wide_line.c_str()); - this->parse_message_internal(tmp, callbacks); - free(tmp); + this->parse_message_internal(wide_line, callbacks); } line.clear(); } @@ -882,9 +850,10 @@ void env_universal_t::read_message_internal(int fd, callback_data_list_t *callba /** Parse message msg */ -void env_universal_t::parse_message_internal(wchar_t *msg, callback_data_list_t *callbacks) +void env_universal_t::parse_message_internal(const wcstring &msgstr, callback_data_list_t *callbacks) { ASSERT_IS_LOCKED(lock); + const wchar_t *msg = msgstr.c_str(); // debug( 3, L"parse_message( %ls );", msg ); @@ -893,11 +862,11 @@ void env_universal_t::parse_message_internal(wchar_t *msg, callback_data_list_t if (match(msg, SET_STR) || match(msg, SET_EXPORT_STR)) { - wchar_t *name, *tmp; + const wchar_t *name, *tmp; bool exportv = match(msg, SET_EXPORT_STR); name = msg+(exportv?wcslen(SET_EXPORT_STR):wcslen(SET_STR)); - while (wcschr(L"\t ", *name)) + while (name[0] == L'\t' || name[0] == L' ') name++; tmp = wcschr(name, L':'); @@ -1516,11 +1485,6 @@ class universal_notifier_null_t : public universal_notifier_t static universal_notifier_t::notifier_strategy_t fetch_default_strategy_from_environment() { - if (synchronizes_via_fishd()) - { - return universal_notifier_t::strategy_null; - } - universal_notifier_t::notifier_strategy_t result = universal_notifier_t::strategy_default; const struct diff --git a/env_universal_common.h b/env_universal_common.h index ced45994f..c827716e1 100644 --- a/env_universal_common.h +++ b/env_universal_common.h @@ -9,16 +9,6 @@ #include "util.h" #include "env.h" -/** - The set command -*/ -#define SET_STR L"SET" - -/** - The set_export command -*/ -#define SET_EXPORT_STR L"SET_EXPORT" - /** The different types of messages found in the fishd file */ @@ -33,59 +23,22 @@ typedef enum */ #define ENV_UNIVERSAL_BUFFER_SIZE 1024 -/** - Init the library -*/ -void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val)); - -/** - Add all variable names to the specified list - - This function operate agains the local copy of all universal - variables, it does not communicate with any other process. -*/ -void env_universal_common_get_names(wcstring_list_t &lst, - bool show_exported, - bool show_unexported); - -/** - Perform the specified variable assignment. - - This function operate agains the local copy of all universal - variables, it does not communicate with any other process. - - Do not call this function. Create a message to do it. This function - is only to be used when fishd is dead. -*/ -void env_universal_common_set(const wchar_t *key, const wchar_t *val, bool exportv); - -/** - Remove the specified variable. Returns true if it was removed, false if it was not found. -*/ -bool env_universal_common_remove(const wcstring &key); - -/** - Get the value of the variable with the specified name - - This function operate agains the local copy of all universal - variables, it does not communicate with any other process. -*/ -env_var_t env_universal_common_get(const wcstring &name); - -/** - Get the export flag of the variable with the specified - name. Returns false if the variable doesn't exist. - - This function operate agains the local copy of all universal - variables, it does not communicate with any other process. -*/ -bool env_universal_common_get_export(const wcstring &name); - -/** Synchronizes all changse: writes everything out, reads stuff in */ -void env_universal_common_sync(); - typedef std::vector callback_data_list_t; +/** + Callback data, reflecting a change in universal variables +*/ +struct callback_data_t +{ + fish_message_type_t type; + wcstring key; + wcstring val; + + callback_data_t(fish_message_type_t t, const wcstring &k, const wcstring &v) : type(t), key(k), val(v) + { + } +}; + /** Class representing universal variables */ class env_universal_t { @@ -104,7 +57,7 @@ class env_universal_t void load_from_fd(int fd, callback_data_list_t *callbacks); void erase_unmodified_values(); - void parse_message_internal(wchar_t *msg, callback_data_list_t *callbacks); + void parse_message_internal(const wcstring &msg, callback_data_list_t *callbacks); void set_internal(const wcstring &key, const wcstring &val, bool exportv, bool overwrite); bool remove_internal(const wcstring &name); @@ -216,8 +169,6 @@ public: std::string get_machine_identifier(); bool get_hostname_identifier(std::string *result); -/* Temporary */ -bool synchronizes_via_fishd(); bool universal_log_enabled(); #define UNIVERSAL_LOG(x) if (universal_log_enabled()) fprintf(stderr, "UNIVERSAL LOG: %s\n", x) diff --git a/fish.cpp b/fish.cpp index 12d70092c..9f9b2ed2c 100644 --- a/fish.cpp +++ b/fish.cpp @@ -540,8 +540,6 @@ int main(int argc, char **argv) wutil_destroy(); event_destroy(); - env_destroy(); - if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); diff --git a/fish_tests.cpp b/fish_tests.cpp index 8fd773d52..939dafb48 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -3469,7 +3469,6 @@ int main(int argc, char **argv) // say( L"Testing performance" ); // perf_complete(); - env_destroy(); reader_destroy(); builtin_destroy(); wutil_destroy();