aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-06-18 11:19:28 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-06-18 11:19:28 -0700
commit3bc2dda00d33b513dc009fc58d1a3e20f8ee55df (patch)
treec3063f3e5a945b572d1bcfbe999f913833f3c5ae
parentf4bc1ef4a2933e397e3c25827cb8db013c76fa0f (diff)
parentee8e9c0291b2c7525a8470765bd88166b25e9b6b (diff)
Merge branch 'death_of_fishd'
Incorporates more removal and cleanup of fishd remnants.
-rw-r--r--Makefile.in81
-rw-r--r--builtin_set.cpp2
-rw-r--r--common.cpp8
-rw-r--r--common.h2
-rw-r--r--doc_src/fishd.txt33
-rw-r--r--env.cpp197
-rw-r--r--env.h9
-rw-r--r--env_universal.cpp522
-rw-r--r--env_universal.h73
-rw-r--r--env_universal_common.cpp776
-rw-r--r--env_universal_common.h223
-rw-r--r--fish.cpp2
-rw-r--r--fish.xcodeproj/project.pbxproj133
-rw-r--r--fish.xcodeproj/xcshareddata/xcschemes/fishd.xcscheme86
-rw-r--r--fish_tests.cpp63
-rw-r--r--fishd.cpp971
-rw-r--r--input_common.cpp24
-rw-r--r--parser.cpp1
18 files changed, 444 insertions, 2762 deletions
diff --git a/Makefile.in b/Makefile.in
index f2761e96..d808471a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -86,7 +86,7 @@ COMMON_FILES := util.cpp fallback.cpp
FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \
highlight.o history.o kill.o parser.o proc.o reader.o sanity.o \
tokenizer.o wildcard.o wgetopt.o wutil.o input.o output.o intern.o \
- env_universal.o env_universal_common.o input_common.o event.o \
+ env_universal_common.o input_common.o event.o \
signal.o io.o parse_util.o common.o screen.o path.o autoload.o \
parser_keywords.o iothread.o color.o postfork.o \
builtin_test.o parse_tree.o parse_productions.o parse_execution.o \
@@ -112,14 +112,6 @@ FISH_TESTS_OBJS := $(FISH_OBJS) fish_tests.o
#
-# All objects that the system needs to build fishd
-#
-
-FISHD_OBJS := fishd.o env_universal_common.o wutil.o print_help.o \
- common.o utf8.o fish_version.o
-
-
-#
# All objects needed to build mimedb
#
@@ -181,7 +173,7 @@ FUNCTIONS_DIR_FILES := $(wildcard share/functions/*.fish)
# Programs to install
#
-PROGRAMS := fish mimedb fishd fish_indent
+PROGRAMS := fish mimedb fish_indent
#
# Manual pages to install
@@ -689,14 +681,6 @@ fish: $(FISH_OBJS) fish.o
#
-# Build the fishd program.
-#
-
-fishd: $(FISHD_OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) $(FISHD_OBJS) $(LIBS) -o $@
-
-
-#
# Build the fish_tests program.
#
@@ -724,8 +708,8 @@ fish_indent: $(FISH_INDENT_OBJS)
# Neat little program to show output from terminal
#
-key_reader: key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o iothread.o utf8.o
- $(CXX) $(CXXFLAGS) $(LDFLAGS_FISH) key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o iothread.o utf8.o $(LIBS) -o $@
+key_reader: key_reader.o input_common.o common.o env_universal_common.o wutil.o iothread.o utf8.o
+ $(CXX) $(CXXFLAGS) $(LDFLAGS_FISH) key_reader.o input_common.o common.o env_universal_common.o wutil.o iothread.o utf8.o $(LIBS) -o $@
#
@@ -776,6 +760,14 @@ clean:
autoload.o: config.h autoload.h common.h util.h lru.h wutil.h signal.h env.h
autoload.o: exec.h proc.h io.h parse_tree.h tokenizer.h parse_constants.h
+builtin.o: config.h signal.h fallback.h util.h wutil.h common.h builtin.h
+builtin.o: io.h function.h event.h complete.h proc.h parse_tree.h tokenizer.h
+builtin.o: parse_constants.h parser.h reader.h highlight.h env.h color.h
+builtin.o: wgetopt.h sanity.h wildcard.h expand.h input_common.h input.h
+builtin.o: intern.h exec.h parse_util.h autoload.h lru.h parser_keywords.h
+builtin.o: path.h history.h builtin_set.cpp builtin_commandline.cpp
+builtin.o: builtin_complete.cpp builtin_ulimit.cpp builtin_jobs.cpp
+builtin.o: builtin_set_color.cpp output.h screen.h builtin_printf.cpp
builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h common.h
builtin_commandline.o: builtin.h io.h wgetopt.h reader.h complete.h
builtin_commandline.o: highlight.h env.h color.h proc.h parse_tree.h
@@ -786,23 +778,15 @@ builtin_complete.o: config.h signal.h fallback.h util.h wutil.h common.h
builtin_complete.o: builtin.h io.h complete.h wgetopt.h parser.h proc.h
builtin_complete.o: parse_tree.h tokenizer.h parse_constants.h event.h
builtin_complete.o: function.h reader.h highlight.h env.h color.h
-builtin.o: config.h signal.h fallback.h util.h wutil.h common.h builtin.h
-builtin.o: io.h function.h event.h complete.h proc.h parse_tree.h tokenizer.h
-builtin.o: parse_constants.h parser.h reader.h highlight.h env.h color.h
-builtin.o: wgetopt.h sanity.h wildcard.h expand.h input_common.h input.h
-builtin.o: intern.h exec.h parse_util.h autoload.h lru.h parser_keywords.h
-builtin.o: path.h history.h builtin_set.cpp builtin_commandline.cpp
-builtin.o: builtin_complete.cpp builtin_ulimit.cpp builtin_jobs.cpp
-builtin.o: builtin_set_color.cpp output.h screen.h builtin_printf.cpp
builtin_jobs.o: config.h fallback.h signal.h util.h wutil.h common.h
builtin_jobs.o: builtin.h io.h proc.h parse_tree.h tokenizer.h
builtin_jobs.o: parse_constants.h parser.h event.h function.h wgetopt.h
builtin_printf.o: common.h util.h
-builtin_set_color.o: config.h builtin.h util.h io.h common.h color.h output.h
-builtin_set_color.o: screen.h highlight.h env.h
builtin_set.o: config.h signal.h fallback.h util.h wutil.h common.h builtin.h
builtin_set.o: io.h env.h expand.h parse_constants.h wgetopt.h proc.h
builtin_set.o: parse_tree.h tokenizer.h parser.h event.h function.h
+builtin_set_color.o: config.h builtin.h util.h io.h common.h color.h output.h
+builtin_set_color.o: screen.h highlight.h env.h
builtin_test.o: config.h common.h util.h builtin.h io.h wutil.h proc.h
builtin_test.o: signal.h parse_tree.h tokenizer.h parse_constants.h
builtin_ulimit.o: config.h fallback.h signal.h util.h builtin.h io.h common.h
@@ -819,12 +803,11 @@ complete.o: parse_util.h autoload.h lru.h parser_keywords.h path.h iothread.h
env.o: config.h signal.h fallback.h util.h wutil.h common.h proc.h io.h
env.o: parse_tree.h tokenizer.h parse_constants.h env.h sanity.h expand.h
env.o: history.h reader.h complete.h highlight.h color.h parser.h event.h
-env.o: function.h env_universal.h env_universal_common.h input.h
-env.o: input_common.h path.h fish_version.h
-env_universal_common.o: config.h signal.h fallback.h util.h common.h wutil.h
-env_universal_common.o: utf8.h env_universal_common.h env.h
-env_universal.o: config.h signal.h fallback.h util.h common.h wutil.h
-env_universal.o: env_universal_common.h env.h env_universal.h
+env.o: function.h env_universal_common.h input.h input_common.h path.h
+env.o: fish_version.h
+env_universal_common.o: config.h env_universal_common.h wutil.h common.h
+env_universal_common.o: util.h env.h fallback.h signal.h utf8.h path.h
+env_universal_common.o: iothread.h
event.o: config.h signal.h fallback.h util.h wutil.h common.h function.h
event.o: event.h input_common.h proc.h io.h parse_tree.h tokenizer.h
event.o: parse_constants.h parser.h
@@ -842,8 +825,6 @@ fish.o: highlight.h env.h color.h builtin.h function.h event.h wutil.h
fish.o: sanity.h proc.h parse_tree.h tokenizer.h parse_constants.h parser.h
fish.o: expand.h intern.h exec.h output.h screen.h history.h path.h input.h
fish.o: input_common.h fish_version.h
-fishd.o: config.h signal.h fallback.h util.h common.h wutil.h
-fishd.o: env_universal_common.h env.h path.h print_help.h fish_version.h
fish_indent.o: config.h fallback.h signal.h util.h common.h wutil.h
fish_indent.o: tokenizer.h print_help.h parser_keywords.h fish_version.h
fish_tests.o: config.h signal.h fallback.h util.h common.h proc.h io.h
@@ -851,7 +832,7 @@ fish_tests.o: parse_tree.h tokenizer.h parse_constants.h reader.h complete.h
fish_tests.o: highlight.h env.h color.h builtin.h function.h event.h
fish_tests.o: autoload.h lru.h wutil.h expand.h parser.h output.h screen.h
fish_tests.o: exec.h path.h history.h iothread.h postfork.h parse_util.h
-fish_tests.o: pager.h input.h input_common.h utf8.h
+fish_tests.o: pager.h input.h input_common.h utf8.h env_universal_common.h
fish_version.o: fish_version.h
function.o: config.h signal.h wutil.h common.h util.h fallback.h function.h
function.o: event.h proc.h io.h parse_tree.h tokenizer.h parse_constants.h
@@ -866,13 +847,12 @@ history.o: config.h fallback.h signal.h util.h sanity.h tokenizer.h common.h
history.o: reader.h io.h complete.h highlight.h env.h color.h parse_tree.h
history.o: parse_constants.h wutil.h history.h intern.h path.h autoload.h
history.o: lru.h iothread.h
-input_common.o: config.h fallback.h signal.h util.h common.h wutil.h
-input_common.o: input_common.h env_universal.h env_universal_common.h env.h
-input_common.o: iothread.h
input.o: config.h signal.h fallback.h util.h wutil.h common.h reader.h io.h
input.o: complete.h highlight.h env.h color.h proc.h parse_tree.h tokenizer.h
input.o: parse_constants.h sanity.h input_common.h input.h parser.h event.h
input.o: function.h expand.h output.h screen.h intern.h
+input_common.o: config.h fallback.h signal.h util.h common.h wutil.h
+input_common.o: input_common.h iothread.h
intern.o: config.h fallback.h signal.h util.h wutil.h common.h intern.h
io.o: config.h fallback.h signal.h util.h wutil.h common.h exec.h proc.h io.h
io.o: parse_tree.h tokenizer.h parse_constants.h
@@ -894,14 +874,6 @@ parse_execution.o: expand.h builtin.h parser.h event.h function.h reader.h
parse_execution.o: highlight.h env.h color.h wutil.h exec.h path.h
parse_productions.o: parse_productions.h parse_tree.h config.h util.h
parse_productions.o: common.h tokenizer.h parse_constants.h
-parser.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
-parser.o: parse_tree.h tokenizer.h parse_constants.h parser.h event.h
-parser.o: function.h parser_keywords.h exec.h wildcard.h expand.h complete.h
-parser.o: builtin.h env.h reader.h highlight.h color.h sanity.h
-parser.o: env_universal.h env_universal_common.h intern.h parse_util.h
-parser.o: autoload.h lru.h path.h parse_execution.h
-parser_keywords.o: config.h fallback.h signal.h common.h util.h
-parser_keywords.o: parser_keywords.h
parse_tree.o: parse_productions.h parse_tree.h config.h util.h common.h
parse_tree.o: tokenizer.h parse_constants.h fallback.h signal.h wutil.h
parse_tree.o: proc.h io.h
@@ -909,6 +881,13 @@ parse_util.o: config.h fallback.h signal.h util.h wutil.h common.h
parse_util.o: tokenizer.h parse_util.h autoload.h lru.h parse_tree.h
parse_util.o: parse_constants.h expand.h intern.h exec.h proc.h io.h env.h
parse_util.o: wildcard.h complete.h parser.h event.h function.h builtin.h
+parser.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
+parser.o: parse_tree.h tokenizer.h parse_constants.h parser.h event.h
+parser.o: function.h parser_keywords.h exec.h wildcard.h expand.h complete.h
+parser.o: builtin.h env.h reader.h highlight.h color.h sanity.h intern.h
+parser.o: parse_util.h autoload.h lru.h path.h parse_execution.h
+parser_keywords.o: config.h fallback.h signal.h common.h util.h
+parser_keywords.o: parser_keywords.h
path.o: config.h fallback.h signal.h util.h common.h env.h wutil.h path.h
path.o: expand.h parse_constants.h
postfork.o: signal.h postfork.h config.h common.h util.h proc.h io.h
@@ -941,9 +920,9 @@ wildcard.o: config.h fallback.h signal.h util.h wutil.h common.h complete.h
wildcard.o: wildcard.h expand.h parse_constants.h reader.h io.h highlight.h
wildcard.o: env.h color.h exec.h proc.h parse_tree.h tokenizer.h
wutil.o: config.h fallback.h signal.h util.h common.h wutil.h
-xdgmimealias.o: xdgmimealias.h xdgmime.h xdgmimeint.h
xdgmime.o: xdgmime.h xdgmimeint.h xdgmimeglob.h xdgmimemagic.h xdgmimealias.h
xdgmime.o: xdgmimeparent.h
+xdgmimealias.o: xdgmimealias.h xdgmime.h xdgmimeint.h
xdgmimeglob.o: xdgmimeglob.h xdgmime.h xdgmimeint.h
xdgmimeint.o: xdgmimeint.h xdgmime.h
xdgmimemagic.o: xdgmimemagic.h xdgmime.h xdgmimeint.h
diff --git a/builtin_set.cpp b/builtin_set.cpp
index 63341649..598d6c40 100644
--- a/builtin_set.cpp
+++ b/builtin_set.cpp
@@ -428,7 +428,7 @@ static int builtin_set(parser_t &parser, wchar_t **argv)
int slice=0;
int i;
- wchar_t *bad_char;
+ const wchar_t *bad_char = NULL;
/* Parse options to obtain the requested operation and the modifiers */
diff --git a/common.cpp b/common.cpp
index a9c57949..81d7b839 100644
--- a/common.cpp
+++ b/common.cpp
@@ -486,17 +486,17 @@ void append_format(wcstring &str, const wchar_t *format, ...)
va_end(va);
}
-wchar_t *wcsvarname(const wchar_t *str)
+const wchar_t *wcsvarname(const wchar_t *str)
{
while (*str)
{
if ((!iswalnum(*str)) && (*str != L'_'))
{
- return (wchar_t *)str;
+ return str;
}
str++;
}
- return 0;
+ return NULL;
}
const wchar_t *wcsfuncname(const wchar_t *str)
@@ -2129,7 +2129,7 @@ static pid_t initial_foreground_process_group = -1;
bool is_forked_child(void)
{
- /* Just bail if nobody's called setup_fork_guards - e.g. fishd */
+ /* Just bail if nobody's called setup_fork_guards, e.g. some of our tools */
if (! initial_pid) return false;
bool is_child_of_fork = (getpid() != initial_pid);
diff --git a/common.h b/common.h
index 18821509..ca4c8337 100644
--- a/common.h
+++ b/common.h
@@ -650,7 +650,7 @@ char **wcsv2strv(const wchar_t * const *in);
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
-wchar_t *wcsvarname(const wchar_t *str);
+const wchar_t *wcsvarname(const wchar_t *str);
/**
diff --git a/doc_src/fishd.txt b/doc_src/fishd.txt
deleted file mode 100644
index 0eb3088a..00000000
--- a/doc_src/fishd.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-\section fishd fishd - universal variable daemon
-
-\subsection fishd-synopsis Synopsis
- <tt>fishd [(-h|--help|-v|--version)]</tt>
-
-\subsection fishd-description Description
-
-The \c fishd daemon is used to load, save and distribute universal
-variable information. \c fish automatically connects to \c fishd via a socket
-on startup.
-
-\c fishd is started and stopped automatically.
-
-The following options are available if starting \c fishd manually:
-
-- <tt>-h</tt> or <tt>--help</tt> displays this help message and then exits
-- <tt>-v</tt> or <tt>--version</tt> displays the current fish version and then exits
-
-\subsection fishd-files Files
-
-- \c ~/.config/fish/fishd.MACHINE_ID - permanent storage location for universal
- variable data. \c MACHINE_ID is generally based on the machine's MAC address.
-
- The data is stored as a set of \c set and \c set_export commands such as
- would be parsed by fishd. The file must always be stored in YAML format.
- If an instance of fishd is running (which is generally the case), manual
- modifications to \c ~/.fishd.MACHINE_ID will be lost. Do NOT edit this file manually!
-
-- \c /tmp/fishd.socket.USERNAME - the socket which fishd uses to communicate
-with all clients.
-
-- /tmp/fishd.log.USERNAME - the fishd log file
-
diff --git a/env.cpp b/env.cpp
index 086f181a..43a34288 100644
--- a/env.cpp
+++ b/env.cpp
@@ -49,7 +49,7 @@
#include "history.h"
#include "reader.h"
#include "parser.h"
-#include "env_universal.h"
+#include "env_universal_common.h"
#include "input.h"
#include "event.h"
#include "path.h"
@@ -57,12 +57,6 @@
#include "complete.h"
#include "fish_version.h"
-/** Command used to start fishd */
-#define FISHD_CMD L"fishd ^ /dev/null"
-
-// Version for easier debugging
-//#define FISHD_CMD L"fishd"
-
/** Value denoting a null string */
#define ENV_NULL L"\x1d"
@@ -135,6 +129,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
@@ -219,43 +220,6 @@ env_node_t *env_node_t::next_scope_to_search(void)
return this->new_scope ? global_env : this->next;
}
-
-/**
- When fishd isn't started, this function is provided to
- env_universal as a callback, it tries to start up fishd. It's
- implementation is a bit of a hack, since it evaluates a bit of
- shellscript, and it might be used at times when that might not be
- the best idea.
-*/
-static void start_fishd()
-{
- struct passwd *pw = getpwuid(getuid());
-
- debug(3, L"Spawning new copy of fishd");
-
- if (!pw)
- {
- debug(0, _(L"Could not get user information"));
- return;
- }
-
- wcstring cmd = format_string(FISHD_CMD, pw->pw_name);
-
- /* Prefer the fishd in __fish_bin_dir, if exists */
- const env_var_t bin_dir = env_get_string(L"__fish_bin_dir");
- if (! bin_dir.missing_or_empty())
- {
- wcstring path = bin_dir + L"/fishd";
- if (waccess(path, X_OK) == 0)
- {
- /* The path command just looks like 'fishd', so insert the bin path to make it absolute */
- cmd.insert(0, bin_dir + L"/");
- }
- }
- parser_t &parser = parser_t::principal_parser();
- parser.eval(cmd, io_chain_t(), TOP);
-}
-
/**
Return the current umask value.
*/
@@ -374,9 +338,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;
@@ -388,13 +350,13 @@ static void universal_callback(fish_message_type_t type,
str=L"SET";
break;
}
-
+
case ERASE:
{
str=L"ERASE";
break;
}
-
+
default:
break;
}
@@ -604,15 +566,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);
- const env_var_t fishd_dir_wstr = env_get_string(L"FISHD_SOCKET_DIR");
- const env_var_t user_dir_wstr = env_get_string(L"USER");
-
- wchar_t * fishd_dir = fishd_dir_wstr.missing()?NULL:const_cast<wchar_t*>(fishd_dir_wstr.c_str());
- wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast<wchar_t*>(user_dir_wstr.c_str());
-
- env_universal_init(fishd_dir , user_dir ,
- &start_fishd,
- &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
@@ -644,32 +600,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.
@@ -746,23 +676,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;
}
@@ -811,7 +750,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)
@@ -824,10 +763,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;
@@ -875,7 +815,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)
@@ -975,7 +914,7 @@ int env_remove(const wcstring &key, int var_mode)
!(var_mode & ENV_GLOBAL) &&
!(var_mode & ENV_LOCAL))
{
- erased = ! env_universal_remove(key.c_str());
+ erased = uvars() && uvars()->remove(key);
}
react_to_variable_change(key);
@@ -1058,16 +997,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))
- {
- return env_var_t::missing_var();
- }
- else
+ env_var_t env_var = uvars() ? uvars()->get(key) : env_var_t::missing_var();
+ if (env_var == ENV_NULL)
{
- return item;
+ env_var = env_var_t::missing_var();
}
+ return env_var;
}
}
@@ -1137,15 +1072,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;
@@ -1312,13 +1247,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());
}
@@ -1398,18 +1329,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; i<uni.size(); i++)
+ if (uvars())
{
- const wcstring &key = uni.at(i);
- const env_var_t val = env_universal_get(key);
-
- if (! val.missing() && wcscmp(val.c_str(), ENV_NULL))
+ const wcstring_list_t uni = uvars()->get_names(true, false);
+ for (i=0; i<uni.size(); i++)
{
- // Note that std::map::insert does NOT overwrite a value already in the map,
- // which we depend on here
- vals.insert(std::pair<wcstring, wcstring>(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<wcstring, wcstring>(key, val));
+ }
}
}
@@ -1443,6 +1376,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 7898a125..d1a40f7d 100644
--- a/env.h
+++ b/env.h
@@ -69,12 +69,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.
Memory policy: All keys and values are copied, the parameters can and should be freed by the caller afterwards
@@ -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
deleted file mode 100644
index 920139dd..00000000
--- a/env_universal.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-#include "config.h"
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <wchar.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <pwd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#if HAVE_NCURSES_H
-#include <ncurses.h>
-#else
-#include <curses.h>
-#endif
-
-#if HAVE_TERM_H
-#include <term.h>
-#elif HAVE_NCURSES_TERM_H
-#include <ncurses/term.h>
-#endif
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#include <signal.h>
-
-#include "fallback.h"
-#include "util.h"
-
-#include "common.h"
-#include "wutil.h"
-#include "env_universal_common.h"
-#include "env_universal.h"
-#include "env.h"
-
-/**
- Maximum number of times to try to get a new fishd socket
-*/
-
-#define RECONNECT_COUNT 32
-
-
-connection_t env_universal_server(-1);
-
-/**
- Set to true after initialization has been performed
-*/
-static bool s_env_univeral_inited = false;
-
-/**
- The number of attempts to start fishd
-*/
-static int get_socket_count = 0;
-
-#define DEFAULT_RETRY_COUNT 15
-#define DEFAULT_RETRY_DELAY 0.2
-
-static wchar_t * path;
-static wchar_t *user;
-static void (*start_fishd)();
-static void (*external_callback)(fish_message_type_t type, const wchar_t *name, const wchar_t *val);
-
-/**
- Flag set to 1 when a barrier reply is recieved
-*/
-static int barrier_reply = 0;
-
-void env_universal_barrier();
-
-static int is_dead()
-{
- return env_universal_server.fd < 0;
-}
-
-static int try_get_socket_once(void)
-{
- int s;
-
- wchar_t *wdir;
- wchar_t *wuname;
- char *dir = 0;
-
- wdir = path;
- wuname = user;
- uid_t seuid;
- gid_t segid;
-
- if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- {
- wperror(L"socket");
- return -1;
- }
-
- if (wdir)
- dir = wcs2str(wdir);
- else
- dir = strdup("/tmp");
-
- std::string uname;
- if (wuname)
- {
- uname = wcs2string(wuname);
- }
- else
- {
- struct passwd *pw = getpwuid(getuid());
- if (pw && pw->pw_name)
- {
- uname = pw->pw_name;
- }
- }
-
- std::string name;
- name.reserve(strlen(dir) + uname.size() + strlen(SOCK_FILENAME) + 2);
- name.append(dir);
- name.append("/");
- name.append(SOCK_FILENAME);
- name.append(uname);
-
- free(dir);
-
- debug(3, L"Connect to socket %s at fd %d", name.c_str(), s);
-
- struct sockaddr_un local = {};
- local.sun_family = AF_UNIX;
- strncpy(local.sun_path, name.c_str(), (sizeof local.sun_path) - 1);
-
- if (connect(s, (struct sockaddr *)&local, sizeof local) == -1)
- {
- close(s);
-
- /* If it fails on first try, it's probably no serious error, but fishd hasn't been launched yet.
- This happens (at least) on the first concurrent session. */
- if (get_socket_count > 1)
- wperror(L"connect");
-
- return -1;
- }
-
- if ((getpeereid(s, &seuid, &segid) != 0) || seuid != geteuid())
- {
- debug(1, L"Wrong credentials for socket %s at fd %d", name.c_str(), s);
- close(s);
- return -1;
- }
-
- if ((make_fd_nonblocking(s) != 0) || (fcntl(s, F_SETFD, FD_CLOEXEC) != 0))
- {
- wperror(L"fcntl");
- close(s);
-
- return -1;
- }
-
- debug(3, L"Connected to fd %d", s);
-
- return s;
-}
-
-/**
- Get a socket for reading from the server
-*/
-static int get_socket(void)
-{
- get_socket_count++;
-
- int s = try_get_socket_once();
- if (s < 0)
- {
- if (start_fishd)
- {
- debug(2, L"Could not connect to socket %d, starting fishd", s);
-
- start_fishd();
-
- for (size_t i=0; s < 0 && i < DEFAULT_RETRY_COUNT; i++)
- {
- if (i > 0)
- {
- // Wait before next try
- usleep((useconds_t)(DEFAULT_RETRY_DELAY * 1E6));
- }
- s = try_get_socket_once();
- }
- }
- }
-
- if (s < 0)
- {
- debug(1, L"Could not connect to universal variable server, already tried manual restart (or no command supplied). You will not be able to share variable values between fish sessions. Is fish properly installed?");
- return -1;
- }
-
- return s;
-}
-
-/**
- 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 (type == BARRIER_REPLY)
- {
- barrier_reply = 1;
- }
- else
- {
- if (external_callback)
- external_callback(type, name, val);
- }
-}
-
-/**
- Make sure the connection is healthy. If not, close it, and try to
- establish a new connection.
-*/
-static void check_connection(void)
-{
- if (! s_env_univeral_inited)
- return;
-
- if (env_universal_server.killme)
- {
- debug(3, L"Lost connection to universal variable server.");
-
- if (close(env_universal_server.fd))
- {
- wperror(L"close");
- }
-
- env_universal_server.fd = -1;
- env_universal_server.killme=0;
- env_universal_server.input.clear();
- env_universal_read_all();
- }
-}
-
-/**
- Remove all universal variables.
-*/
-static void env_universal_remove_all()
-{
- size_t i;
- wcstring_list_t lst;
- env_universal_common_get_names(lst, true, true);
- for (i=0; i<lst.size(); i++)
- {
- const wcstring &key = lst.at(i);
- env_universal_common_remove(key);
- }
-
-}
-
-
-/**
- Try to establish a new connection to fishd. If successfull, end
- with call to env_universal_barrier(), to make sure everything is in
- sync.
-*/
-static void reconnect()
-{
- assert(synchronizes_via_fishd());
-
- if (get_socket_count >= RECONNECT_COUNT)
- return;
-
- debug(3, L"Get new fishd connection");
-
- s_env_univeral_inited = false;
- env_universal_server.buffer_consumed = 0;
- env_universal_server.read_buffer.clear();
- env_universal_server.fd = get_socket();
- s_env_univeral_inited = true;
- if (env_universal_server.fd >= 0)
- {
- env_universal_remove_all();
- env_universal_barrier();
- }
-}
-
-void env_universal_init(wchar_t * p,
- wchar_t *u,
- void (*sf)(),
- void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val))
-{
- if (! synchronizes_via_fishd())
- {
- external_callback = cb;
- env_universal_common_init(&callback);
- s_env_univeral_inited = true;
- }
- else
- {
- path=p;
- user=u;
- start_fishd=sf;
- external_callback = cb;
-
- env_universal_server.fd = get_socket();
- env_universal_common_init(&callback);
- env_universal_read_all();
- s_env_univeral_inited = true;
- if (env_universal_server.fd >= 0)
- {
- env_universal_barrier();
- }
- }
-}
-
-void env_universal_destroy()
-{
- /*
- Go into blocking mode and send all data before exiting
- */
- if (env_universal_server.fd >= 0)
- {
- if (fcntl(env_universal_server.fd, F_SETFL, 0) != 0)
- {
- wperror(L"fcntl");
- }
- try_send_all(&env_universal_server);
- }
-
- connection_destroy(&env_universal_server);
- env_universal_server.fd =-1;
- s_env_univeral_inited = false;
-}
-
-
-/**
- Read all available messages from the server.
-*/
-int env_universal_read_all()
-{
- if (! s_env_univeral_inited)
- return 0;
-
- if (env_universal_server.fd == -1)
- {
- reconnect();
- if (env_universal_server.fd == -1)
- return 0;
- }
-
- if (env_universal_server.fd != -1)
- {
- read_message(&env_universal_server);
- check_connection();
- return 1;
- }
- else
- {
- debug(2, L"No connection to universal variable server");
- return 0;
- }
-}
-
-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");
- message_t *msg;
- fd_set fds;
-
- if (! synchronizes_via_fishd())
- {
- env_universal_common_sync();
- return;
- }
-
- if (!s_env_univeral_inited || is_dead())
- return;
-
- barrier_reply = 0;
-
- /*
- Create barrier request
- */
- msg= create_message(BARRIER, 0, 0);
- msg->count=1;
- env_universal_server.unsent.push(msg);
-
- /*
- Wait until barrier request has been sent
- */
- debug(3, L"Create barrier");
- while (1)
- {
- try_send_all(&env_universal_server);
- check_connection();
-
- if (env_universal_server.unsent.empty())
- break;
-
- if (env_universal_server.fd == -1)
- {
- reconnect();
- debug(2, L"barrier interrupted, exiting");
- return;
- }
-
- FD_ZERO(&fds);
- FD_SET(env_universal_server.fd, &fds);
- select(env_universal_server.fd+1, 0, &fds, 0, 0);
- }
-
- /*
- Wait for barrier reply
- */
- debug(3, L"Sent barrier request");
- while (!barrier_reply)
- {
- if (env_universal_server.fd == -1)
- {
- reconnect();
- debug(2, L"barrier interrupted, exiting (2)");
- return;
- }
- FD_ZERO(&fds);
- FD_SET(env_universal_server.fd, &fds);
- select(env_universal_server.fd+1, &fds, 0, 0, 0);
- env_universal_read_all();
- }
- debug(3, L"End barrier");
-}
-
-
-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());
-
- if (! synchronizes_via_fishd() || is_dead())
- {
- env_universal_common_set(name.c_str(), value.c_str(), exportv);
- env_universal_barrier();
- }
- else
- {
- message_t *msg = create_message(exportv?SET_EXPORT:SET,
- name.c_str(),
- value.c_str());
-
- if (!msg)
- {
- debug(1, L"Could not create universal variable message");
- return;
- }
-
- msg->count=1;
- env_universal_server.unsent.push(msg);
- env_universal_barrier();
- }
-}
-
-int env_universal_remove(const wchar_t *name)
-{
- int res;
-
- if (!s_env_univeral_inited)
- return 1;
-
- CHECK(name, 1);
-
- wcstring name_str = name;
- res = env_universal_common_get(name_str).missing();
- debug(3,
- L"env_universal_remove( \"%ls\" )",
- name);
-
- if (! synchronizes_via_fishd() || is_dead())
- {
- env_universal_common_remove(name_str);
- }
- else
- {
- message_t *msg = create_message(ERASE, name, 0);
- msg->count=1;
- env_universal_server.unsent.push(msg);
- env_universal_barrier();
- }
-
- return res;
-}
-
-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
deleted file mode 100644
index a77efb1f..00000000
--- a/env_universal.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/** \file env_universal.h
- Universal variable client library.
-*/
-
-#ifndef ENV_UNIVERSAL_H
-#define ENV_UNIVERSAL_H
-
-#include <wchar.h>
-
-#include "env_universal_common.h"
-#include "env.h"
-
-/**
- Data about the universal variable server.
-*/
-extern connection_t env_universal_server;
-
-/**
- Initialize the envuni library
-*/
-void env_universal_init(wchar_t * p,
- wchar_t *u,
- void (*sf)(),
- 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 zero if the variable existed, and non-zero if the variable did not exist
-*/
-int env_universal_remove(const wchar_t *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 0b73782d..49d26cdc 100644
--- a/env_universal_common.cpp
+++ b/env_universal_common.cpp
@@ -7,32 +7,14 @@
*/
#include "config.h"
+#include "env_universal_common.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <wchar.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
-#include <pwd.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <wctype.h>
-
-#include <errno.h>
-#include <locale.h>
-#include <dirent.h>
-#include <signal.h>
#include <fcntl.h>
-#include <sys/stat.h>
+#include <sys/un.h>
#include <sys/ioctl.h>
-#include <sys/file.h>
#include <sys/mman.h>
-#include <map>
+#include <sys/file.h>
+#include <arpa/inet.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
@@ -44,7 +26,6 @@
#include "common.h"
#include "wutil.h"
#include "utf8.h"
-#include "env_universal_common.h"
#include "path.h"
#include "iothread.h"
@@ -54,50 +35,31 @@
#endif
/**
- Non-wide version of the set command
+ The set command
*/
-#define SET_MBS "SET"
+#define SET_STR L"SET"
/**
- Non-wide version of the set_export command
+ The set_export command
*/
-#define SET_EXPORT_MBS "SET_EXPORT"
+#define SET_EXPORT_STR L"SET_EXPORT"
-/**
- Non-wide version of the erase command
-*/
-#define ERASE_MBS "ERASE"
/**
- Non-wide version of the barrier command
+ Non-wide version of the set command
*/
-#define BARRIER_MBS "BARRIER"
+#define SET_MBS "SET"
/**
- Non-wide version of the barrier_reply command
+ Non-wide version of the set_export command
*/
-#define BARRIER_REPLY_MBS "BARRIER_REPLY"
+#define SET_EXPORT_MBS "SET_EXPORT"
/**
Error message
*/
#define PARSE_ERR L"Unable to parse universal variable message: '%ls'"
-/**
- ERROR string for internal buffered reader
-*/
-#define ENV_UNIVERSAL_ERROR 0x100
-
-/**
- EAGAIN string for internal buffered reader
-*/
-#define ENV_UNIVERSAL_AGAIN 0x101
-
-/**
- EOF string for internal buffered reader
-*/
-#define ENV_UNIVERSAL_EOF 0x102
-
/** Small note about not editing ~/.fishd manually. Inserted at the top of all .fishd files. */
#define SAVE_MSG "# This file is automatically generated by the fish.\n# Do NOT edit it directly, your changes will be overwritten.\n"
@@ -125,120 +87,21 @@ 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());
- }
- }
-}
-
-/* UTF <-> wchar conversions. These return a string allocated with malloc. These call sites could be cleaned up substantially to eliminate the dependence on malloc. */
-static wchar_t *utf2wcs(const char *input)
-{
- wchar_t *result = NULL;
- wcstring converted;
- if (utf8_to_wchar_string(input, &converted))
- {
- result = wcsdup(converted.c_str());
- }
- return result;
-}
-
-static char *wcs2utf(const wchar_t *input)
-{
- char *result = NULL;
- std::string converted;
- if (wchar_to_utf8_string(input, &converted))
- {
- result = strdup(converted.c_str());
- }
- return result;
-}
-
void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val))
{
callback = cb;
}
-void read_message(connection_t *conn)
-{
- callback_data_list_t callbacks;
- default_universal_vars().read_message(conn, &callbacks);
- post_callbacks(callbacks);
-}
-
-/**
- Read one byte of date form the specified connection
- */
-static int read_byte(connection_t *src)
-{
-
- if (src->buffer_consumed >= src->read_buffer.size())
- {
- char local[ENV_UNIVERSAL_BUFFER_SIZE];
-
- ssize_t res = read(src->fd, local, sizeof local);
-
-// debug(4, L"Read chunk '%.*s'", res, src->buffer );
-
- if (res < 0)
- {
-
- if (errno == EAGAIN ||
- errno == EINTR)
- {
- return ENV_UNIVERSAL_AGAIN;
- }
-
- return ENV_UNIVERSAL_ERROR;
-
- }
- else if (res == 0)
- {
- return ENV_UNIVERSAL_EOF;
- }
- else
- {
- src->read_buffer.clear();
- src->read_buffer.insert(src->read_buffer.begin(), local, local + res);
- src->buffer_consumed = 0;
- }
- }
-
- return src->read_buffer.at(src->buffer_consumed++);
-
-}
-
/**
Remove variable with specified name
*/
-void env_universal_common_remove(const wcstring &name)
+bool env_universal_common_remove(const wcstring &name)
{
- default_universal_vars().remove(name);
+ return default_universal_vars().remove(name);
}
/**
@@ -269,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;
@@ -295,80 +146,6 @@ static void report_error(int err_code, const wchar_t *err_format, ...)
fwprintf(stderr, L"%s\n", strerror(err_code));
}
-/**
- Attempt to send the specified message to the specified file descriptor
-
- \return 1 on sucess, 0 if the message could not be sent without blocking and -1 on error
-*/
-static int try_send(message_t *msg,
- int fd)
-{
-
- debug(3,
- L"before write of %d chars to fd %d", msg->body.size(), fd);
-
- ssize_t res = write(fd, msg->body.c_str(), msg->body.size());
-
- if (res != -1)
- {
- debug(4, L"Wrote message '%s'", msg->body.c_str());
- }
- else
- {
- debug(4, L"Failed to write message '%s'", msg->body.c_str());
- }
-
- if (res == -1)
- {
- switch (errno)
- {
- case EAGAIN:
- return 0;
-
- default:
- debug(2,
- L"Error while sending universal variable message to fd %d. Closing connection",
- fd);
- if (debug_level > 2)
- wperror(L"write");
-
- return -1;
- }
- }
- msg->count--;
-
- if (!msg->count)
- {
- delete msg;
- }
- return 1;
-}
-
-void try_send_all(connection_t *c)
-{
- /* debug( 3,
- L"Send all updates to connection on fd %d",
- c->fd );*/
- while (!c->unsent.empty())
- {
- switch (try_send(c->unsent.front(), c->fd))
- {
- case 1:
- c->unsent.pop();
- break;
-
- case 0:
- debug(4,
- L"Socket full, send rest later");
- return;
-
- case -1:
- c->killme = 1;
- return;
- }
- }
-}
-
/* The universal variable format has some funny escaping requirements; here we try to be safe */
static bool is_universal_safe_to_encode_directly(wchar_t c)
{
@@ -408,117 +185,80 @@ static wcstring full_escape(const wchar_t *in)
return out;
}
-/* Sets the body of a message to the null-terminated list of null terminated const char *. */
-void set_body(message_t *msg, ...)
+/* Converts input to UTF-8 and appends it to receiver, using storage as temp storage */
+static bool append_utf8(const wcstring &input, std::string *receiver, std::string *storage)
{
- /* Start by counting the length of all the strings */
- size_t body_len = 0;
- const char *arg;
- va_list arg_list;
- va_start(arg_list, msg);
- while ((arg = va_arg(arg_list, const char *)) != NULL)
- body_len += strlen(arg);
- va_end(arg_list);
-
- /* Reserve that length in the string */
- msg->body.reserve(body_len + 1); //+1 for trailing NULL? Do I need that?
-
- /* Set the string contents */
- va_start(arg_list, msg);
- while ((arg = va_arg(arg_list, const char *)) != NULL)
- msg->body.append(arg);
- va_end(arg_list);
+ bool result = false;
+ if (wchar_to_utf8_string(input, storage))
+ {
+ receiver->append(*storage);
+ result = true;
+ }
+ return result;
}
-/* Returns an instance of message_t allocated via new */
-message_t *create_message(fish_message_type_t type,
- const wchar_t *key_in,
- const wchar_t *val_in)
+/* Creates a file entry like "SET fish_color_cwd:FF0". Appends the result to *result (as UTF8). Returns true on success. storage may be used for temporary storage, to avoid allocations */
+static bool append_file_entry(fish_message_type_t type, const wcstring &key_in, const wcstring &val_in, std::string *result, std::string *storage)
{
- char *key = NULL;
-
- // debug( 4, L"Crete message of type %d", type );
+ assert(storage != NULL);
+ assert(result != NULL);
+
+ // Record the length on entry, in case we need to back up
+ bool success = true;
+ const size_t result_length_on_entry = result->size();
+
+ // Append header like "SET "
+ result->append(type==SET ? SET_MBS : SET_EXPORT_MBS);
+ result->push_back(' ');
- if (key_in)
+ // Append variable name like "fish_color_cwd"
+ if (wcsvarname(key_in.c_str()))
{
- if (wcsvarname(key_in))
- {
- debug(0, L"Illegal variable name: '%ls'", key_in);
- return NULL;
- }
-
- key = wcs2utf(key_in);
- if (!key)
- {
- debug(0,
- L"Could not convert %ls to narrow character string",
- key_in);
- return NULL;
- }
+ debug(0, L"Illegal variable name: '%ls'", key_in.c_str());
+ success = false;
}
-
- message_t *msg = new message_t;
- msg->count = 0;
-
- switch (type)
+ if (success && ! append_utf8(key_in, result, storage))
{
- case SET:
- case SET_EXPORT:
- {
- if (!val_in)
- {
- val_in=L"";
- }
-
- wcstring esc = full_escape(val_in);
- char *val = wcs2utf(esc.c_str());
- set_body(msg, (type==SET?SET_MBS:SET_EXPORT_MBS), " ", key, ":", val, "\n", NULL);
- free(val);
- break;
- }
-
- case ERASE:
- {
- set_body(msg, ERASE_MBS, " ", key, "\n", NULL);
- break;
- }
-
- case BARRIER:
- {
- set_body(msg, BARRIER_MBS, "\n", NULL);
- break;
- }
-
- case BARRIER_REPLY:
- {
- set_body(msg, BARRIER_REPLY_MBS, "\n", NULL);
- break;
- }
-
- default:
- {
- debug(0, L"create_message: Unknown message type");
- }
+ debug(0, L"Could not convert %ls to narrow character string", key_in.c_str());
+ success = false;
}
-
- free(key);
-
- // debug( 4, L"Message body is '%s'", msg->body );
-
- return msg;
+
+ // Append ":"
+ if (success)
+ {
+ result->push_back(':');
+ }
+
+ // Append value
+ if (success && ! append_utf8(full_escape(val_in.c_str()), result, storage))
+ {
+ debug(0, L"Could not convert %ls to narrow character string", val_in.c_str());
+ success = false;
+ }
+
+ // Append newline
+ if (success)
+ {
+ result->push_back('\n');
+ }
+
+ // Don't modify result on failure. It's sufficient to simply resize it since all we ever did was append to it.
+ if (! success)
+ {
+ result->resize(result_length_on_entry);
+ }
+
+ 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);
}
@@ -528,33 +268,6 @@ bool env_universal_common_get_export(const wcstring &name)
return default_universal_vars().get_export(name);
}
-void enqueue_all(connection_t *c)
-{
- default_universal_vars().enqueue_all(c);
-}
-
-connection_t::connection_t(int input_fd) :
- fd(input_fd),
- killme(false),
- buffer_consumed(0)
-{
-}
-
-void connection_destroy(connection_t *c)
-{
- /*
- A connection need not always be open - we only try to close it
- if it is open.
- */
- if (c->fd >= 0)
- {
- if (close(c->fd))
- {
- wperror(L"close");
- }
- }
-}
-
env_universal_t::env_universal_t(const wcstring &path) : explicit_vars_path(path), tried_renaming(false), last_read_file(kInvalidFileID)
{
VOMIT_ON_FAILURE(pthread_mutex_init(&lock, NULL));
@@ -617,25 +330,21 @@ void env_universal_t::set(const wcstring &key, const wcstring &val, bool exportv
this->set_internal(key, val, exportv, true /* overwrite */);
}
-void env_universal_t::remove_internal(const wcstring &key, bool overwrite)
+bool env_universal_t::remove_internal(const wcstring &key)
{
ASSERT_IS_LOCKED(lock);
- if (! overwrite && this->modified.find(key) != modified.end())
- {
- /* This value has been modified and we're not overwriting it. Skip it. */
- return;
- }
size_t erased = this->vars.erase(key);
- if (erased > 0 && overwrite)
+ if (erased > 0)
{
this->modified.insert(key);
}
+ return erased > 0;
}
-void env_universal_t::remove(const wcstring &key)
+bool env_universal_t::remove(const wcstring &key)
{
scoped_lock locker(lock);
- this->remove_internal(key, true);
+ return this->remove_internal(key);
}
wcstring_list_t env_universal_t::get_names(bool show_exported, bool show_unexported) const
@@ -655,46 +364,76 @@ wcstring_list_t env_universal_t::get_names(bool show_exported, bool show_unexpor
return result;
}
-void env_universal_t::enqueue_all_internal(connection_t *c) const
+/* Given a variable table, generate callbacks representing the difference between our vars and the new vars */
+void env_universal_t::generate_callbacks(const var_table_t &new_vars, callback_data_list_t *callbacks) const
{
- ASSERT_IS_LOCKED(lock);
- var_table_t::const_iterator iter;
- for (iter = vars.begin(); iter != vars.end(); ++iter)
+ assert(callbacks != NULL);
+
+ /* Construct callbacks for erased values */
+ for (var_table_t::const_iterator iter = this->vars.begin(); iter != this->vars.end(); ++iter)
{
const wcstring &key = iter->first;
- const var_entry_t &entry = iter->second;
- message_t *msg = create_message(entry.exportv ? SET_EXPORT : SET, key.c_str(), entry.val.c_str());
- msg->count=1;
- c->unsent.push(msg);
+ /* Skip modified values */
+ if (this->modified.find(key) != this->modified.end())
+ {
+ continue;
+ }
+
+ /* If the value is not present in new_vars, it has been erased */
+ if (new_vars.find(key) == new_vars.end())
+ {
+ callbacks->push_back(callback_data_t(ERASE, key, L""));
+ }
+ }
+
+ /* Construct callbacks for newly inserted or changed values */
+ for (var_table_t::const_iterator iter = new_vars.begin(); iter != new_vars.end(); ++iter)
+ {
+ const wcstring &key = iter->first;
+
+ /* Skip modified values */
+ if (this->modified.find(key) != this->modified.end())
+ {
+ continue;
+ }
+
+ /* See if the value has changed */
+ const var_entry_t &new_entry = iter->second;
+ var_table_t::const_iterator existing = this->vars.find(key);
+ if (existing == this->vars.end() || existing->second.exportv != new_entry.exportv || existing->second.val != new_entry.val)
+ {
+ /* Value has changed */
+ callbacks->push_back(callback_data_t(new_entry.exportv ? SET_EXPORT : SET, key, new_entry.val));
+ }
}
- try_send_all(c);
}
-void env_universal_t::enqueue_all(connection_t *c) const
-{
- scoped_lock locker(lock);
- enqueue_all_internal(c);
-}
-void env_universal_t::erase_unmodified_values()
+void env_universal_t::acquire_variables(var_table_t *vars_to_acquire)
{
- /* Delete all non-modified keys. */
- var_table_t::iterator iter = vars.begin();
- while (iter != vars.end())
+ /* Copy modified values from existing vars to vars_to_acquire */
+ for (std::set<wcstring>::iterator iter = this->modified.begin(); iter != this->modified.end(); ++iter)
{
- const wcstring &key = iter->first;
- if (modified.find(key) == modified.end())
+ const wcstring &key = *iter;
+ var_table_t::iterator src_iter = this->vars.find(key);
+ if (src_iter == this->vars.end())
{
- // Unmodified key. Erase the old value.
- vars.erase(iter++);
+ /* The value has been deleted. */
+ vars_to_acquire->erase(key);
}
else
{
- // Modified key, retain the value.
- ++iter;
+ /* The value has been modified. Copy it over. Note we can destructively modify the source entry in vars since we are about to get rid of this->vars entirely. */
+ var_entry_t &src = src_iter->second;
+ var_entry_t &dst = (*vars_to_acquire)[key];
+ dst.val.swap(src.val);
+ dst.exportv = src.exportv;
}
}
+
+ /* We have constructed all the callbacks and updated vars_to_acquire. Acquire it! */
+ this->vars.swap(*vars_to_acquire);
}
void env_universal_t::load_from_fd(int fd, callback_data_list_t *callbacks)
@@ -709,11 +448,18 @@ void env_universal_t::load_from_fd(int fd, callback_data_list_t *callbacks)
}
else
{
- /* Unmodified values are sourced from the file. Since we are about to read a different file, erase them */
- this->erase_unmodified_values();
- connection_t c(fd);
- /* Read from the file. Do not destroy the connection; the caller is responsible for closing the fd. */
- this->read_message_internal(&c, callbacks);
+ /* Read a variables table from the file. */
+ var_table_t new_vars = this->read_message_internal(fd);
+
+ /* Announce changes */
+ if (callbacks != NULL)
+ {
+ this->generate_callbacks(new_vars, callbacks);
+ }
+
+ /* Acquire the new variables */
+ this->acquire_variables(&new_vars);
+
last_read_file = current_file;
}
}
@@ -729,7 +475,6 @@ bool env_universal_t::load_from_path(const wcstring &path, callback_data_list_t
return true;
}
- /* OK to not use CLO_EXEC here because fishd is single threaded */
bool result = false;
int fd = wopen_cloexec(path, O_RDONLY);
if (fd >= 0)
@@ -742,18 +487,52 @@ bool env_universal_t::load_from_path(const wcstring &path, callback_data_list_t
return result;
}
-void env_universal_t::write_to_fd(int fd)
+/* Writes our state to the fd. path is provided only for error reporting */
+bool env_universal_t::write_to_fd(int fd, const wcstring &path)
{
ASSERT_IS_LOCKED(lock);
assert(fd >= 0);
- connection_t conn(fd);
+ bool success = true;
+
+ // Stuff we output to fd
+ std::string contents;
+
+ // Temporary storage
+ std::string storage;
+
+ // Write the save message. If this fails, we don't bother complaining.
write_loop(fd, SAVE_MSG, strlen(SAVE_MSG));
- this->enqueue_all_internal(&conn);
+
+ var_table_t::const_iterator iter = vars.begin();
+ while (iter != vars.end())
+ {
+ // Append the entry. Note that append_file_entry may fail, but that only affects one variable; soldier on.
+ const wcstring &key = iter->first;
+ const var_entry_t &entry = iter->second;
+ append_file_entry(entry.exportv ? SET_EXPORT : SET, key, entry.val, &contents, &storage);
+
+ // Go to next
+ ++iter;
+
+ // Flush if this is the last iteration or we exceed a page
+ if (iter == vars.end() || contents.size() >= 4096)
+ {
+ if (write_loop(fd, contents.data(), contents.size()) < 0)
+ {
+ int err = errno;
+ report_error(err, L"Unable to write to universal variables file '%ls'", path.c_str());
+ success = false;
+ break;
+ }
+ contents.clear();
+ }
+ }
/* Since we just wrote out this file, it matches our internal state; pretend we read from it */
this->last_read_file = file_id_for_fd(fd);
- /* Do not destroy the connection; we don't close the file */
+ /* We don't close the file */
+ return success;
}
bool env_universal_t::move_new_vars_file_into_place(const wcstring &src, const wcstring &dst)
@@ -779,8 +558,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();
}
}
@@ -973,6 +751,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:
@@ -1000,13 +779,6 @@ bool env_universal_t::sync(callback_data_list_t *callbacks)
return false;
}
-#if 0
- for (std::set<wcstring>::iterator iter = modified.begin(); iter != modified.end(); ++iter)
- {
- fprintf(stderr, "Modified %ls\n", iter->c_str());
- }
-#endif
-
const wcstring directory = wdirname(vars_path);
bool success = true;
int vars_fd = -1;
@@ -1038,7 +810,7 @@ bool env_universal_t::sync(callback_data_list_t *callbacks)
if (success)
{
assert(private_fd >= 0);
- this->write_to_fd(private_fd);
+ success = this->write_to_fd(private_fd, private_file_path);
}
if (success)
@@ -1076,124 +848,96 @@ bool env_universal_t::sync(callback_data_list_t *callbacks)
return success;
}
-void env_universal_t::read_message_internal(connection_t *src, callback_data_list_t *callbacks)
+var_table_t env_universal_t::read_message_internal(int fd)
{
- ASSERT_IS_LOCKED(lock);
- while (1)
+ var_table_t result;
+
+ // Temp value used to avoid repeated allocations
+ wcstring storage;
+
+ // The line we construct (and then parse)
+ std::string line;
+ wcstring wide_line;
+ for (;;)
{
-
- int ib = read_byte(src);
- char b;
-
- switch (ib)
+ // Read into a buffer. Note this is NOT null-terminated!
+ char buffer[1024];
+ ssize_t amt = read_loop(fd, buffer, sizeof buffer);
+ if (amt <= 0)
{
- case ENV_UNIVERSAL_AGAIN:
- {
- return;
- }
-
- case ENV_UNIVERSAL_ERROR:
- {
- debug(2, L"Read error on fd %d, set killme flag", src->fd);
- if (debug_level > 2)
- wperror(L"read");
- src->killme = 1;
- return;
- }
-
- case ENV_UNIVERSAL_EOF:
- {
- src->killme = 1;
- debug(3, L"Fd %d has reached eof, set killme flag", src->fd);
- if (! src->input.empty())
- {
- char c = 0;
- src->input.push_back(c);
- debug(1,
- L"Universal variable connection closed while reading command. Partial command recieved: '%s'",
- &src->input.at(0));
- }
- return;
- }
+ break;
}
+ const size_t bufflen = (size_t)amt;
- b = (char)ib;
-
- if (b == '\n')
+ // 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 < amt)
{
- wchar_t *msg;
-
- b = 0;
- src->input.push_back(b);
-
- msg = utf2wcs(&src->input.at(0));
-
- /*
- Before calling parse_message, we must empty reset
- everything, since the callback function could
- potentially call read_message.
- */
- src->input.clear();
-
- if (msg)
+ // Run until we hit a newline
+ size_t cursor = line_start;
+ while (cursor < bufflen && buffer[cursor] != '\n')
{
- this->parse_message_internal(msg, src, callbacks);
+ cursor++;
}
- else
+
+ // Copy over what we read
+ 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 < bufflen && ! line.empty())
{
- debug(0, _(L"Could not convert message '%s' to wide character string"), &src->input.at(0));
+ if (utf8_to_wchar_string(line, &wide_line))
+ {
+ env_universal_t::parse_message_internal(wide_line, &result, &storage);
+ }
+ line.clear();
}
- free(msg);
-
- }
- else
- {
- src->input.push_back(b);
+ // Skip over the newline (or skip past the end)
+ line_start = cursor + 1;
}
}
-}
-
-void env_universal_t::read_message(connection_t *src, callback_data_list_t *callbacks)
-{
- scoped_lock locker(lock);
- return read_message_internal(src, callbacks);
+
+ // We make no effort to handle an unterminated last line
+ return result;
}
/**
Parse message msg
*/
-void env_universal_t::parse_message_internal(wchar_t *msg, connection_t *src, callback_data_list_t *callbacks)
+void env_universal_t::parse_message_internal(const wcstring &msgstr, var_table_t *vars, wcstring *storage)
{
- ASSERT_IS_LOCKED(lock);
+ const wchar_t *msg = msgstr.c_str();
// debug( 3, L"parse_message( %ls );", msg );
if (msg[0] == L'#')
return;
- if (match(msg, SET_STR) || match(msg, SET_EXPORT_STR))
+ bool is_set_export = match(msg, SET_EXPORT_STR);
+ bool is_set = ! is_set_export && match(msg, SET_STR);
+ if (is_set || is_set_export)
{
- wchar_t *name, *tmp;
- bool exportv = match(msg, SET_EXPORT_STR);
+ const wchar_t *name, *tmp;
+ const bool exportv = is_set_export;
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':');
if (tmp)
{
- const wcstring key(name, tmp - name);
+ /* Use 'storage' to hold our key to avoid allocations */
+ storage->assign(name, tmp - name);
+ const wcstring &key = *storage;
wcstring val;
if (unescape_string(tmp + 1, &val, 0))
{
- this->set_internal(key, val, exportv, false);
- if (callbacks != NULL)
- {
- callbacks->push_back(callback_data_t(exportv ? SET_EXPORT:SET, key, val));
- }
+ var_entry_t &entry = (*vars)[key];
+ entry.exportv = exportv;
+ entry.val.swap(val); //acquire the value
}
}
else
@@ -1201,45 +945,6 @@ void env_universal_t::parse_message_internal(wchar_t *msg, connection_t *src, ca
debug(1, PARSE_ERR, msg);
}
}
- else if (match(msg, ERASE_STR))
- {
- wchar_t *name, *tmp;
-
- name = msg+wcslen(ERASE_STR);
- while (wcschr(L"\t ", *name))
- name++;
-
- tmp = name;
- while (iswalnum(*tmp) || *tmp == L'_')
- tmp++;
-
- *tmp = 0;
-
- if (!wcslen(name))
- {
- debug(1, PARSE_ERR, msg);
- }
-
- this->remove_internal(name, false);
- if (callbacks != NULL)
- {
- callbacks->push_back(callback_data_t(ERASE, name, wcstring()));
- }
- }
- else if (match(msg, BARRIER_STR))
- {
- message_t *msg = create_message(BARRIER_REPLY, 0, 0);
- msg->count = 1;
- src->unsent.push(msg);
- try_send_all(src);
- }
- else if (match(msg, BARRIER_REPLY_STR))
- {
- if (callbacks != NULL)
- {
- callbacks->push_back(callback_data_t(BARRIER_REPLY, wcstring(), wcstring()));
- }
- }
else
{
debug(1, PARSE_ERR, msg);
@@ -1836,11 +1541,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 1dcf6ed4..207e4dba 100644
--- a/env_universal_common.h
+++ b/env_universal_common.h
@@ -5,207 +5,41 @@
#include <queue>
#include <string>
#include <set>
+#include "wutil.h"
#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 erase command
-*/
-#define ERASE_STR L"ERASE"
-
-/**
- The barrier command
-*/
-#define BARRIER_STR L"BARRIER"
-
-/**
- The barrier_reply command
-*/
-#define BARRIER_REPLY_STR L"BARRIER_REPLY"
-
-
-/**
- The filename to use for univeral variables. The username is appended
-*/
-#define SOCK_FILENAME "fishd.socket."
-
-/**
- The different types of commands that can be sent between client/server
+ The different types of messages found in the fishd file
*/
typedef enum
{
SET,
SET_EXPORT,
- ERASE,
- BARRIER,
- BARRIER_REPLY,
+ ERASE
} fish_message_type_t;
/**
- The size of the buffer used for reading from the socket
+ The size of the buffer used for reading from the file
*/
#define ENV_UNIVERSAL_BUFFER_SIZE 1024
-/**
- A struct representing a message to be sent between client and server
-*/
-typedef struct
-{
- /**
- Number of queues that contain this message. Once this reaches zero, the message should be deleted
- */
- int count;
-
- /**
- Message body. The message must be allocated using enough memory to actually contain the message.
- */
- std::string body;
-
-} message_t;
-
-typedef std::queue<message_t *> message_queue_t;
+typedef std::vector<struct callback_data_t> callback_data_list_t;
/**
- This struct represents a connection between a universal variable server/client
+ Callback data, reflecting a change in universal variables
*/
-class connection_t
+struct callback_data_t
{
-private:
- /* No assignment */
- connection_t &operator=(const connection_t &);
-
-public:
-
- /**
- The file descriptor this socket lives on
- */
- int fd;
-
- /**
- Queue of unsent messages
- */
- std::queue<message_t *> unsent;
-
- /**
- Set to one when this connection should be killed
- */
- bool killme;
- /**
- The input string. Input from the socket goes here. When a
- newline is encountered, the buffer is parsed and cleared.
- */
- std::vector<char> input;
-
- /**
- The read buffer.
- */
- std::vector<char> read_buffer;
-
- /**
- Number of bytes that have already been consumed.
- */
- size_t buffer_consumed;
-
- /* Constructor */
- connection_t(int input_fd);
+ 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)
+ {
+ }
};
-/**
- Read all available messages on this connection
-*/
-void read_message(connection_t *);
-
-/**
- Send as many messages as possible without blocking to the connection
-*/
-void try_send_all(connection_t *c);
-
-/**
- Create a messge with the specified properties
-*/
-message_t *create_message(fish_message_type_t type, const wchar_t *key, const wchar_t *val);
-
-/**
- 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.
-
- 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_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();
-
-/**
- Add messages about all existing variables to the specified connection
-*/
-void enqueue_all(connection_t *c);
-
-/**
- Close and destroy the specified connection struct. This frees
- allstructures allocated by the connection, such as ques of unsent
- messages.
-*/
-void connection_destroy(connection_t *c);
-
-typedef std::vector<struct callback_data_t> callback_data_list_t;
-
/** Class representing universal variables */
class env_universal_t
{
@@ -222,24 +56,27 @@ class env_universal_t
bool tried_renaming;
bool load_from_path(const wcstring &path, callback_data_list_t *callbacks);
void load_from_fd(int fd, callback_data_list_t *callbacks);
- void erase_unmodified_values();
-
- void parse_message_internal(wchar_t *msg, connection_t *src, callback_data_list_t *callbacks);
void set_internal(const wcstring &key, const wcstring &val, bool exportv, bool overwrite);
- void remove_internal(const wcstring &name, bool overwrite);
+ bool remove_internal(const wcstring &name);
/* Functions concerned with saving */
bool open_and_acquire_lock(const wcstring &path, int *out_fd);
bool open_temporary_file(const wcstring &directory, wcstring *out_path, int *out_fd);
- void write_to_fd(int fd);
+ bool write_to_fd(int fd, const wcstring &path);
bool move_new_vars_file_into_place(const wcstring &src, const wcstring &dst);
/* File id from which we last read */
file_id_t last_read_file;
- void read_message_internal(connection_t *src, callback_data_list_t *callbacks);
- void enqueue_all_internal(connection_t *c) const;
+ /* Given a variable table, generate callbacks representing the difference between our vars and the new vars */
+ void generate_callbacks(const var_table_t &new_vars, callback_data_list_t *callbacks) const;
+
+ /* Given a variable table, copy unmodified values into self. May destructively modified vars_to_acquire. */
+ void acquire_variables(var_table_t *vars_to_acquire);
+
+ static void parse_message_internal(const wcstring &msg, var_table_t *vars, wcstring *storage);
+ static var_table_t read_message_internal(int fd);
public:
env_universal_t(const wcstring &path);
@@ -254,23 +91,17 @@ public:
/* Sets a variable */
void set(const wcstring &key, const wcstring &val, bool exportv);
- /* Removes a variable */
- void remove(const wcstring &name);
+ /* Removes a variable. Returns true if it was found, false if not. */
+ bool remove(const wcstring &name);
/* Gets variable names */
wcstring_list_t get_names(bool show_exported, bool show_unexported) const;
- /* Writes variables to the connection */
- void enqueue_all(connection_t *c) const;
-
/** Loads variables at the correct path */
bool load();
/** Reads and writes variables at the correct path. Returns true if modified variables were written. */
bool sync(callback_data_list_t *callbacks);
-
- /* Internal use */
- void read_message(connection_t *src, callback_data_list_t *callbacks);
};
/** The "universal notifier" is an object responsible for broadcasting and receiving universal variable change notifications. These notifications do not contain the change, but merely indicate that the uvar file has changed. It is up to the uvar subsystem to re-read the file.
@@ -343,8 +174,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 12d70092..9f9b2ed2 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.xcodeproj/project.pbxproj b/fish.xcodeproj/project.pbxproj
index 762d73c2..0ed1dcd7 100644
--- a/fish.xcodeproj/project.pbxproj
+++ b/fish.xcodeproj/project.pbxproj
@@ -17,7 +17,6 @@
);
dependencies = (
D07D265715E33B86009E43F6 /* PBXTargetDependency */,
- D07D265915E33B86009E43F6 /* PBXTargetDependency */,
D07D265D15E33B86009E43F6 /* PBXTargetDependency */,
D0A56500168D257900AF6161 /* PBXTargetDependency */,
);
@@ -47,7 +46,6 @@
);
dependencies = (
D0F01A1315AA36280034B3B1 /* PBXTargetDependency */,
- D0F01A1515AA362E0034B3B1 /* PBXTargetDependency */,
D0F01A1715AA36300034B3B1 /* PBXTargetDependency */,
D0A564EF168D09C000AF6161 /* PBXTargetDependency */,
);
@@ -59,7 +57,6 @@
/* Begin PBXBuildFile section */
D00F63F119137E9D00FCCDEC /* fish_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D00F63F019137E9D00FCCDEC /* fish_version.cpp */; };
D00F63F219137E9D00FCCDEC /* fish_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D00F63F019137E9D00FCCDEC /* fish_version.cpp */; };
- D00F63F31914C5F800FCCDEC /* fish_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D00F63F019137E9D00FCCDEC /* fish_version.cpp */; };
D01A2D24169B736200767098 /* man1 in Copy Files */ = {isa = PBXBuildFile; fileRef = D01A2D23169B730A00767098 /* man1 */; };
D01A2D25169B737700767098 /* man1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = D01A2D23169B730A00767098 /* man1 */; };
D031890C15E36E4600D9CC39 /* base in Resources */ = {isa = PBXBuildFile; fileRef = D031890915E36D9800D9CC39 /* base */; };
@@ -100,7 +97,6 @@
D08A32A917B446A300F3A533 /* color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0B6B0FE14E88BA400AD6C10 /* color.cpp */; };
D08A32AA17B446A300F3A533 /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853613B3ACEE0099B651 /* common.cpp */; };
D08A32AB17B446A300F3A533 /* env_universal_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */; };
- D08A32AC17B446A300F3A533 /* env_universal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853913B3ACEE0099B651 /* env_universal.cpp */; };
D08A32AD17B446A300F3A533 /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853B13B3ACEE0099B651 /* event.cpp */; };
D08A32AE17B446A300F3A533 /* input_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854913B3ACEE0099B651 /* input_common.cpp */; };
D08A32AF17B446A300F3A533 /* intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854B13B3ACEE0099B651 /* intern.cpp */; };
@@ -120,7 +116,6 @@
D0A56501168D258300AF6161 /* man in Copy Files */ = {isa = PBXBuildFile; fileRef = D0A564F1168D0BAB00AF6161 /* man */; };
D0C52F371765284C00BFAB82 /* parse_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C52F351765284C00BFAB82 /* parse_tree.cpp */; };
D0C9733818DE5449002D7C81 /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C9733718DE5449002D7C81 /* utf8.cpp */; };
- D0C9733918DE5449002D7C81 /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C9733718DE5449002D7C81 /* utf8.cpp */; };
D0CBD587159EF0E10024809C /* launch_fish.scpt in Resources */ = {isa = PBXBuildFile; fileRef = D0CBD586159EF0E10024809C /* launch_fish.scpt */; };
D0D02A67159837AD008E62BD /* complete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853713B3ACEE0099B651 /* complete.cpp */; };
D0D02A69159837B2008E62BD /* env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853A13B3ACEE0099B651 /* env.cpp */; };
@@ -140,7 +135,6 @@
D0D02A7715983875008E62BD /* input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854A13B3ACEE0099B651 /* input.cpp */; };
D0D02A781598387E008E62BD /* output.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855113B3ACEE0099B651 /* output.cpp */; };
D0D02A7915983888008E62BD /* intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854B13B3ACEE0099B651 /* intern.cpp */; };
- D0D02A7A15983916008E62BD /* env_universal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853913B3ACEE0099B651 /* env_universal.cpp */; };
D0D02A7B15983928008E62BD /* env_universal_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */; };
D0D02A7C159839D5008E62BD /* autoload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */; };
D0D02A7D159839D5008E62BD /* builtin_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0F3373A1506DE3C00ECEFC0 /* builtin_test.cpp */; };
@@ -158,12 +152,6 @@
D0D02A89159839DF008E62BD /* fish.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854213B3ACEE0099B651 /* fish.cpp */; };
D0D02A8D15983CFA008E62BD /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D02A8C15983CFA008E62BD /* libncurses.dylib */; };
D0D02A8F15983D8F008E62BD /* parser_keywords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855313B3ACEE0099B651 /* parser_keywords.cpp */; };
- D0D02AC215985F3F008E62BD /* fishd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854313B3ACEE0099B651 /* fishd.cpp */; };
- D0D02AC315985F43008E62BD /* env_universal_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */; };
- D0D02AC415985F4D008E62BD /* wutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0856113B3ACEE0099B651 /* wutil.cpp */; };
- D0D02AC515985F5B008E62BD /* print_help.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855613B3ACEE0099B651 /* print_help.cpp */; };
- D0D02AC615985F65008E62BD /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853613B3ACEE0099B651 /* common.cpp */; };
- D0D02AC715985F9D008E62BD /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D02A8C15983CFA008E62BD /* libncurses.dylib */; };
D0D02AD615986492008E62BD /* fish_indent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853F13B3ACEE0099B651 /* fish_indent.cpp */; };
D0D02AD715986498008E62BD /* print_help.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0855613B3ACEE0099B651 /* print_help.cpp */; };
D0D02AD81598649E008E62BD /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853613B3ACEE0099B651 /* common.cpp */; };
@@ -174,7 +162,6 @@
D0D2694915983772005D9B9C /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0854413B3ACEE0099B651 /* function.cpp */; };
D0D2694A15983779005D9B9C /* builtin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A0853513B3ACEE0099B651 /* builtin.cpp */; };
D0F019F115A977140034B3B1 /* fish in CopyFiles */ = {isa = PBXBuildFile; fileRef = D0D2693C159835CA005D9B9C /* fish */; };
- D0F019F215A977270034B3B1 /* fishd in CopyFiles */ = {isa = PBXBuildFile; fileRef = D0D02ABC15985EF9008E62BD /* fishd */; };
D0F019F315A977290034B3B1 /* fish_indent in CopyFiles */ = {isa = PBXBuildFile; fileRef = D0D02AD01598642A008E62BD /* fish_indent */; };
D0F019F815A977AB0034B3B1 /* config.fish in CopyFiles */ = {isa = PBXBuildFile; fileRef = D0CBD580159EE48F0024809C /* config.fish */; };
D0F019FD15A977CA0034B3B1 /* config.fish in CopyFiles */ = {isa = PBXBuildFile; fileRef = D0C4FD9415A7D7EE00212EF1 /* config.fish */; };
@@ -198,13 +185,6 @@
remoteGlobalIDString = D0D2693B159835CA005D9B9C;
remoteInfo = fish_shell;
};
- D07D265A15E33B86009E43F6 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = D0A084F213B3AC130099B651 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D0D02ABB15985EF9008E62BD;
- remoteInfo = fishd;
- };
D07D265E15E33B86009E43F6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
@@ -233,13 +213,6 @@
remoteGlobalIDString = D0D2693B159835CA005D9B9C;
remoteInfo = fish_shell;
};
- D0F01A1415AA362E0034B3B1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = D0A084F213B3AC130099B651 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D0D02ABB15985EF9008E62BD;
- remoteInfo = fishd;
- };
D0F01A1615AA36300034B3B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D0A084F213B3AC130099B651 /* Project object */;
@@ -325,7 +298,6 @@
dstSubfolderSpec = 1;
files = (
D0F019F115A977140034B3B1 /* fish in CopyFiles */,
- D0F019F215A977270034B3B1 /* fishd in CopyFiles */,
D0F019F315A977290034B3B1 /* fish_indent in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -376,7 +348,6 @@
D0A0850513B3ACEE0099B651 /* complete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = complete.h; sourceTree = "<group>"; };
D0A0850613B3ACEE0099B651 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
D0A0850713B3ACEE0099B651 /* env_universal_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = env_universal_common.h; sourceTree = "<group>"; };
- D0A0850813B3ACEE0099B651 /* env_universal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = env_universal.h; sourceTree = "<group>"; };
D0A0850913B3ACEE0099B651 /* env.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = env.h; sourceTree = "<group>"; };
D0A0850A13B3ACEE0099B651 /* event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = event.h; sourceTree = "<group>"; };
D0A0850B13B3ACEE0099B651 /* exec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exec.h; sourceTree = "<group>"; };
@@ -423,7 +394,6 @@
D0A0853613B3ACEE0099B651 /* common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = common.cpp; sourceTree = "<group>"; };
D0A0853713B3ACEE0099B651 /* complete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = complete.cpp; sourceTree = "<group>"; };
D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = env_universal_common.cpp; sourceTree = "<group>"; };
- D0A0853913B3ACEE0099B651 /* env_universal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = env_universal.cpp; sourceTree = "<group>"; };
D0A0853A13B3ACEE0099B651 /* env.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = env.cpp; sourceTree = "<group>"; };
D0A0853B13B3ACEE0099B651 /* event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = event.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
D0A0853C13B3ACEE0099B651 /* exec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exec.cpp; sourceTree = "<group>"; };
@@ -432,7 +402,6 @@
D0A0853F13B3ACEE0099B651 /* fish_indent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish_indent.cpp; sourceTree = "<group>"; };
D0A0854113B3ACEE0099B651 /* fish_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish_tests.cpp; sourceTree = "<group>"; };
D0A0854213B3ACEE0099B651 /* fish.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fish.cpp; sourceTree = "<group>"; };
- D0A0854313B3ACEE0099B651 /* fishd.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fishd.cpp; sourceTree = "<group>"; };
D0A0854413B3ACEE0099B651 /* function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function.cpp; sourceTree = "<group>"; };
D0A0854713B3ACEE0099B651 /* highlight.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = highlight.cpp; sourceTree = "<group>"; };
D0A0854813B3ACEE0099B651 /* history.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = history.cpp; sourceTree = "<group>"; };
@@ -486,7 +455,6 @@
D0D02A8C15983CFA008E62BD /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = usr/lib/libncurses.dylib; sourceTree = SDKROOT; };
D0D02A9A15985A75008E62BD /* fish.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fish.app; sourceTree = BUILT_PRODUCTS_DIR; };
D0D02AA915985C0C008E62BD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = osx/Info.plist; sourceTree = "<group>"; };
- D0D02ABC15985EF9008E62BD /* fishd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fishd; sourceTree = BUILT_PRODUCTS_DIR; };
D0D02AD01598642A008E62BD /* fish_indent */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fish_indent; sourceTree = BUILT_PRODUCTS_DIR; };
D0D02AFA159871B2008E62BD /* osx_fish_launcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = osx_fish_launcher.m; path = osx/osx_fish_launcher.m; sourceTree = "<group>"; };
D0D2693C159835CA005D9B9C /* fish */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fish; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -506,14 +474,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- D0D02AB915985EF9008E62BD /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D0D02AC715985F9D008E62BD /* libncurses.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
D0D02ACD1598642A008E62BD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -611,8 +571,6 @@
D0A0850613B3ACEE0099B651 /* config.h */,
D0A0850713B3ACEE0099B651 /* env_universal_common.h */,
D0A0853813B3ACEE0099B651 /* env_universal_common.cpp */,
- D0A0850813B3ACEE0099B651 /* env_universal.h */,
- D0A0853913B3ACEE0099B651 /* env_universal.cpp */,
D0A0850913B3ACEE0099B651 /* env.h */,
D0A0853A13B3ACEE0099B651 /* env.cpp */,
D0A0850A13B3ACEE0099B651 /* event.h */,
@@ -635,7 +593,6 @@
D0A0853F13B3ACEE0099B651 /* fish_indent.cpp */,
D0A0854113B3ACEE0099B651 /* fish_tests.cpp */,
D0A0854213B3ACEE0099B651 /* fish.cpp */,
- D0A0854313B3ACEE0099B651 /* fishd.cpp */,
D00F63F019137E9D00FCCDEC /* fish_version.cpp */,
D0A0851113B3ACEE0099B651 /* highlight.h */,
D0A0854713B3ACEE0099B651 /* highlight.cpp */,
@@ -746,7 +703,6 @@
children = (
D0D2693C159835CA005D9B9C /* fish */,
D0D02A9A15985A75008E62BD /* fish.app */,
- D0D02ABC15985EF9008E62BD /* fishd */,
D0D02AD01598642A008E62BD /* fish_indent */,
D08A328D17B4455100F3A533 /* fish_tests */,
);
@@ -816,22 +772,6 @@
productReference = D0D02A9A15985A75008E62BD /* fish.app */;
productType = "com.apple.product-type.application";
};
- D0D02ABB15985EF9008E62BD /* fishd */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D0D02ABF15985EFA008E62BD /* Build configuration list for PBXNativeTarget "fishd" */;
- buildPhases = (
- D0D02AB815985EF9008E62BD /* Sources */,
- D0D02AB915985EF9008E62BD /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = fishd;
- productName = fishd;
- productReference = D0D02ABC15985EF9008E62BD /* fishd */;
- productType = "com.apple.product-type.tool";
- };
D0D02ACF1598642A008E62BD /* fish_indent */ = {
isa = PBXNativeTarget;
buildConfigurationList = D0D02AD31598642A008E62BD /* Build configuration list for PBXNativeTarget "fish_indent" */;
@@ -888,7 +828,6 @@
D0F019EC15A976F30034B3B1 /* base */,
D0D02A9915985A75008E62BD /* fish.app */,
D0D2693B159835CA005D9B9C /* fish_shell */,
- D0D02ABB15985EF9008E62BD /* fishd */,
D0D02ACF1598642A008E62BD /* fish_indent */,
D08A328C17B4455100F3A533 /* fish_tests */,
D0A564E6168CFDD800AF6161 /* man_pages */,
@@ -1080,7 +1019,6 @@
D08A32A917B446A300F3A533 /* color.cpp in Sources */,
D08A32AA17B446A300F3A533 /* common.cpp in Sources */,
D08A32AB17B446A300F3A533 /* env_universal_common.cpp in Sources */,
- D08A32AC17B446A300F3A533 /* env_universal.cpp in Sources */,
D08A32AD17B446A300F3A533 /* event.cpp in Sources */,
D08A32AE17B446A300F3A533 /* input_common.cpp in Sources */,
D08A32AF17B446A300F3A533 /* intern.cpp in Sources */,
@@ -1115,20 +1053,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- D0D02AB815985EF9008E62BD /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D00F63F31914C5F800FCCDEC /* fish_version.cpp in Sources */,
- D0D02AC215985F3F008E62BD /* fishd.cpp in Sources */,
- D0D02AC315985F43008E62BD /* env_universal_common.cpp in Sources */,
- D0C9733918DE5449002D7C81 /* utf8.cpp in Sources */,
- D0D02AC415985F4D008E62BD /* wutil.cpp in Sources */,
- D0D02AC515985F5B008E62BD /* print_help.cpp in Sources */,
- D0D02AC615985F65008E62BD /* common.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
D0D02ACC1598642A008E62BD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1184,7 +1108,6 @@
D0D02A7715983875008E62BD /* input.cpp in Sources */,
D0D02A781598387E008E62BD /* output.cpp in Sources */,
D0D02A7915983888008E62BD /* intern.cpp in Sources */,
- D0D02A7A15983916008E62BD /* env_universal.cpp in Sources */,
D0D02A7B15983928008E62BD /* env_universal_common.cpp in Sources */,
D032388B1849D1980032CF2C /* pager.cpp in Sources */,
D0D02A89159839DF008E62BD /* fish.cpp in Sources */,
@@ -1214,11 +1137,6 @@
target = D0D2693B159835CA005D9B9C /* fish_shell */;
targetProxy = D07D265815E33B86009E43F6 /* PBXContainerItemProxy */;
};
- D07D265915E33B86009E43F6 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D0D02ABB15985EF9008E62BD /* fishd */;
- targetProxy = D07D265A15E33B86009E43F6 /* PBXContainerItemProxy */;
- };
D07D265D15E33B86009E43F6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D0D02ACF1598642A008E62BD /* fish_indent */;
@@ -1239,11 +1157,6 @@
target = D0D2693B159835CA005D9B9C /* fish_shell */;
targetProxy = D0F01A1215AA36280034B3B1 /* PBXContainerItemProxy */;
};
- D0F01A1515AA362E0034B3B1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D0D02ABB15985EF9008E62BD /* fishd */;
- targetProxy = D0F01A1415AA362E0034B3B1 /* PBXContainerItemProxy */;
- };
D0F01A1715AA36300034B3B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D0D02ACF1598642A008E62BD /* fish_indent */;
@@ -1328,18 +1241,6 @@
};
name = "Release_C++11";
};
- D007FDDF17136EAA00A52BE6 /* Release_C++11 */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = "Release_C++11";
- };
D007FDE017136EAA00A52BE6 /* Release_C++11 */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -1596,30 +1497,6 @@
};
name = Release;
};
- D0D02AC015985EFA008E62BD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Debug;
- };
- D0D02AC115985EFA008E62BD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- COPY_PHASE_STRIP = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Release;
- };
D0D02AD41598642A008E62BD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -1755,16 +1632,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- D0D02ABF15985EFA008E62BD /* Build configuration list for PBXNativeTarget "fishd" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D0D02AC015985EFA008E62BD /* Debug */,
- D0D02AC115985EFA008E62BD /* Release */,
- D007FDDF17136EAA00A52BE6 /* Release_C++11 */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
D0D02AD31598642A008E62BD /* Build configuration list for PBXNativeTarget "fish_indent" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/fish.xcodeproj/xcshareddata/xcschemes/fishd.xcscheme b/fish.xcodeproj/xcshareddata/xcschemes/fishd.xcscheme
deleted file mode 100644
index a2741de2..00000000
--- a/fish.xcodeproj/xcshareddata/xcschemes/fishd.xcscheme
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0500"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "D0D02ABB15985EF9008E62BD"
- BuildableName = "fishd"
- BlueprintName = "fishd"
- ReferencedContainer = "container:fish.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- buildConfiguration = "Debug">
- <Testables>
- </Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "D0D02ABB15985EF9008E62BD"
- BuildableName = "fishd"
- BlueprintName = "fishd"
- ReferencedContainer = "container:fish.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- </TestAction>
- <LaunchAction
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Debug"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "D0D02ABB15985EF9008E62BD"
- BuildableName = "fishd"
- BlueprintName = "fishd"
- ReferencedContainer = "container:fish.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- buildConfiguration = "Release"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "D0D02ABB15985EF9008E62BD"
- BuildableName = "fishd"
- BlueprintName = "fishd"
- ReferencedContainer = "container:fish.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/fish_tests.cpp b/fish_tests.cpp
index 8fd773d5..b29f7124 100644
--- a/fish_tests.cpp
+++ b/fish_tests.cpp
@@ -2255,10 +2255,67 @@ static void test_universal()
}
}
- if (system("rm -Rf /tmp/fish_uvars_test")) err(L"rrm failed");
+ if (system("rm -Rf /tmp/fish_uvars_test")) err(L"rm failed");
putc('\n', stderr);
}
+static bool callback_data_less_than(const callback_data_t &a, const callback_data_t &b) {
+ return a.key < b.key;
+}
+
+static void test_universal_callbacks()
+{
+ say(L"Testing universal callbacks");
+ if (system("mkdir -p /tmp/fish_uvars_test/")) err(L"mkdir failed");
+ env_universal_t uvars1(UVARS_TEST_PATH);
+ env_universal_t uvars2(UVARS_TEST_PATH);
+
+ /* Put some variables into both */
+ uvars1.set(L"alpha", L"1", false);
+ uvars1.set(L"beta", L"1", false);
+ uvars1.set(L"delta", L"1", false);
+ uvars1.set(L"epsilon", L"1", false);
+ uvars1.set(L"lambda", L"1", false);
+ uvars1.set(L"kappa", L"1", false);
+ uvars1.set(L"omicron", L"1", false);
+
+ uvars1.sync(NULL);
+ uvars2.sync(NULL);
+
+ /* Change uvars1 */
+ uvars1.set(L"alpha", L"2", false); //changes value
+ uvars1.set(L"beta", L"1", true); //changes export
+ uvars1.remove(L"delta"); //erases value
+ uvars1.set(L"epsilon", L"1", false); //changes nothing
+ uvars1.sync(NULL);
+
+ /* Change uvars2. It should treat its value as correct and ignore changes from uvars1. */
+ uvars2.set(L"lambda", L"1", false); //same value
+ uvars2.set(L"kappa", L"2", false); //different value
+
+ /* Now see what uvars2 sees */
+ callback_data_list_t callbacks;
+ uvars2.sync(&callbacks);
+
+ /* Sort them to get them in a predictable order */
+ std::sort(callbacks.begin(), callbacks.end(), callback_data_less_than);
+
+ /* Should see exactly two changes */
+ do_test(callbacks.size() == 3);
+ do_test(callbacks.at(0).type == SET);
+ do_test(callbacks.at(0).key == L"alpha");
+ do_test(callbacks.at(0).val == L"2");
+ do_test(callbacks.at(1).type == SET_EXPORT);
+ do_test(callbacks.at(1).key == L"beta");
+ do_test(callbacks.at(1).val == L"1");
+ do_test(callbacks.at(2).type == ERASE);
+ do_test(callbacks.at(2).key == L"delta");
+ do_test(callbacks.at(2).val == L"");
+
+
+ if (system("rm -Rf /tmp/fish_uvars_test")) err(L"rm failed");
+}
+
bool poll_notifier(universal_notifier_t *note)
{
bool result = false;
@@ -3449,7 +3506,8 @@ int main(int argc, char **argv)
if (should_test_function("complete")) test_complete();
if (should_test_function("input")) test_input();
if (should_test_function("universal")) test_universal();
- if (should_test_function("universal_notifiers")) test_universal_notifiers();
+ if (should_test_function("universal")) test_universal_callbacks();
+ if (should_test_function("notifiers")) test_universal_notifiers();
if (should_test_function("completion_insertions")) test_completion_insertions();
if (should_test_function("autosuggestion_combining")) test_autosuggestion_combining();
if (should_test_function("autosuggest_suggest_special")) test_autosuggest_suggest_special();
@@ -3469,7 +3527,6 @@ int main(int argc, char **argv)
// say( L"Testing performance" );
// perf_complete();
- env_destroy();
reader_destroy();
builtin_destroy();
wutil_destroy();
diff --git a/fishd.cpp b/fishd.cpp
deleted file mode 100644
index 4bb80b50..00000000
--- a/fishd.cpp
+++ /dev/null
@@ -1,971 +0,0 @@
-/** \file fishd.c
-
-The universal variable server. fishd is automatically started by fish
-if a fishd server isn't already running. fishd reads any saved
-variables from ~/.fishd, and takes care of communication between fish
-instances. When no clients are running, fishd will automatically shut
-down and save.
-
-\section fishd-commands Commands
-
-Fishd works by sending and receiving commands. Each command is ended
-with a newline. These are the commands supported by fishd:
-
-<pre>set KEY:VALUE
-set_export KEY:VALUE
-</pre>
-
-These commands update the value of a variable. The only difference
-between the two is that <tt>set_export</tt>-variables should be
-exported to children of the process using them. When sending messages,
-all values below 32 or above 127 must be escaped using C-style
-backslash escapes. This means that the over the wire protocol is
-ASCII. However, any conforming reader must also accept non-ascii
-characters and interpret them as UTF-8. Lines containing invalid UTF-8
-escape sequences must be ignored entirely.
-
-<pre>erase KEY
-</pre>
-
-Erase the variable with the specified name.
-
-<pre>barrier
-barrier_reply
-</pre>
-
-A \c barrier command will result in a barrier_reply being added to
-the end of the senders queue of unsent messages. These commands are
-used to synchronize clients, since once the reply for a barrier
-message returns, the sender can know that any updates available at the
-time the original barrier request was sent have been received.
-
-*/
-
-#include "config.h"
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <wchar.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/un.h>
-#include <pwd.h>
-#include <fcntl.h>
-
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-#include <errno.h>
-#include <locale.h>
-#include <signal.h>
-#include <list>
-
-#include "fallback.h"
-#include "util.h"
-
-#include "common.h"
-#include "wutil.h"
-#include "env_universal_common.h"
-#include "path.h"
-#include "print_help.h"
-#include "fish_version.h"
-
-#ifndef HOST_NAME_MAX
-/**
- Maximum length of hostname return. It is ok if this is too short,
- getting the actual hostname is not critical, so long as the string
- is unique in the filesystem namespace.
- */
-#define HOST_NAME_MAX 255
-#endif
-
-/**
- Maximum length of socket filename
-*/
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 100
-#endif
-
-/**
- Fallback if MSG_DONTWAIT isn't defined. That's actually prerry bad,
- and may lead to strange fishd behaviour, but at least it should
- work most of the time.
-*/
-#ifndef MSG_DONTWAIT
-#define MSG_DONTWAIT 0
-#endif
-
-/**
- Small greeting to show that fishd is running
-*/
-#define GREETING "# Fish universal variable daemon\n"
-
-/**
- Small not about not editing ~/.fishd manually. Inserted at the top of all .fishd files.
-*/
-#define SAVE_MSG "# This file is automatically generated by the fishd universal variable daemon.\n# Do NOT edit it directly, your changes will be overwritten.\n"
-
-/**
- The name of the save file. The machine identifier is appended to this.
-*/
-#define FILE "fishd."
-
-/**
- Maximum length of hostname. Longer hostnames are truncated
-*/
-#define HOSTNAME_LEN 32
-
-/**
- The string to append to the socket name to name the lockfile
-*/
-#define LOCKPOSTFIX ".lock"
-
-/**
- The timeout in seconds on the lockfile for critical section
-*/
-#define LOCKTIMEOUT 1
-
-/**
- Getopt short switches for fishd
-*/
-#define GETOPT_STRING "hv"
-
-/**
- The list of connections to clients
-*/
-typedef std::list<connection_t> connection_list_t;
-static connection_list_t connections;
-
-/**
- The socket to accept new clients on
-*/
-static int sock;
-
-/**
- Set to one when fishd should save and exit
-*/
-static int quit=0;
-
-/**
- Constructs the fish socket filename
-*/
-static std::string get_socket_filename(void)
-{
- const char *dir = getenv("FISHD_SOCKET_DIR");
- char *uname = getenv("USER");
-
- if (dir == NULL)
- {
- dir = "/tmp";
- }
-
- if (uname == NULL)
- {
- const struct passwd *pw = getpwuid(getuid());
- uname = pw->pw_name;
- }
-
- std::string name;
- name.reserve(strlen(dir)+ strlen(uname)+ strlen(SOCK_FILENAME) + 1);
- name.append(dir);
- name.push_back('/');
- name.append(SOCK_FILENAME);
- name.append(uname);
-
- if (name.size() >= UNIX_PATH_MAX)
- {
- debug(1, L"Filename too long: '%s'", name.c_str());
- exit(EXIT_FAILURE);
- }
- return name;
-}
-
-/**
- Signal handler for the term signal.
-*/
-static void handle_term(int signal)
-{
- quit=1;
-}
-
-
-/**
- Writes a pseudo-random number (between one and maxlen) of pseudo-random
- digits into str.
- str must point to an allocated buffer of size of at least maxlen chars.
- Returns the number of digits written.
- Since the randomness in part depends on machine time it has _some_ extra
- strength but still not enough for use in concurrent locking schemes on a
- single machine because gettimeofday may not return a different value on
- consecutive calls when:
- a) the OS does not support fine enough resolution
- b) the OS is running on an SMP machine.
- Additionally, gettimeofday errors are ignored.
- Excludes chars other than digits since ANSI C only guarantees that digits
- are consecutive.
- */
-static void sprint_rand_digits(char *str, int maxlen)
-{
- int i, max;
- struct timeval tv;
-
- /*
- Seed the pseudo-random generator based on time - this assumes
- that consecutive calls to gettimeofday will return different values
- and ignores errors returned by gettimeofday.
- Cast to unsigned so that wrapping occurs on overflow as per ANSI C.
- */
- static bool seeded = false;
- if (! seeded)
- {
- (void)gettimeofday(&tv, NULL);
- unsigned long long seed = tv.tv_sec + tv.tv_usec * 1000000ULL;
- srand((unsigned int)seed);
- seeded = true;
- }
- max = (int)(1 + (maxlen - 1) * (rand() / (RAND_MAX + 1.0)));
- for (i = 0; i < max; i++)
- {
- str[i] = '0' + 10 * (rand() / (RAND_MAX + 1.0));
- }
- str[i] = 0;
-}
-
-
-
-/**
- Generate a filename unique in an NFS namespace by creating a copy of str and
- appending .{hostname}.{pid} to it. If gethostname() fails then a pseudo-
- random string is substituted for {hostname} - the randomness of the string
- should be strong enough across different machines. The main assumption
- though is that gethostname will not fail and this is just a "safe enough"
- fallback.
- The memory returned should be freed using free().
- */
-static std::string gen_unique_nfs_filename(const std::string &filename)
-{
- char hostname[HOST_NAME_MAX + 1];
- char pid_str[256];
- snprintf(pid_str, sizeof pid_str, "%ld", (long)getpid());
-
- if (gethostname(hostname, sizeof hostname) != 0)
- {
- sprint_rand_digits(hostname, HOST_NAME_MAX);
- }
-
- std::string newname(filename);
- newname.push_back('.');
- newname.append(hostname);
- newname.push_back('.');
- newname.append(pid_str);
- return newname;
-}
-
-/**
- The number of milliseconds to wait between polls when attempting to acquire
- a lockfile
- */
-#define LOCKPOLLINTERVAL 10
-
-/**
- Attempt to acquire a lock based on a lockfile, waiting LOCKPOLLINTERVAL
- milliseconds between polls and timing out after timeout seconds,
- thereafter forcibly attempting to obtain the lock if force is non-zero.
- Returns 1 on success, 0 on failure.
- To release the lock the lockfile must be unlinked.
- A unique temporary file named by appending characters to the lockfile name
- is used; any pre-existing file of the same name is subject to deletion.
- */
-static int acquire_lock_file(const std::string &lockfile_str, const int timeout, int force)
-{
- int fd, timed_out = 0;
- int ret = 0; /* early exit returns failure */
- struct timespec pollint;
- struct timeval start, end;
- double elapsed;
- struct stat statbuf;
- const char * const lockfile = lockfile_str.c_str();
-
- /*
- (Re)create a unique file and check that it has one only link.
- */
- const std::string linkfile_str = gen_unique_nfs_filename(lockfile);
- const char * const linkfile = linkfile_str.c_str();
- (void)unlink(linkfile);
- /* OK to not use CLO_EXEC here because fishd is single threaded */
- if ((fd = open(linkfile, O_CREAT|O_RDONLY, 0600)) == -1)
- {
- debug(1, L"acquire_lock_file: open: %s", strerror(errno));
- goto done;
- }
- /*
- Don't need to check exit status of close on read-only file descriptors
- */
- close(fd);
- if (stat(linkfile, &statbuf) != 0)
- {
- debug(1, L"acquire_lock_file: stat: %s", strerror(errno));
- goto done;
- }
- if (statbuf.st_nlink != 1)
- {
- debug(1, L"acquire_lock_file: number of hardlinks on unique "
- L"tmpfile is %d instead of 1.", (int)statbuf.st_nlink);
- goto done;
- }
- if (gettimeofday(&start, NULL) != 0)
- {
- debug(1, L"acquire_lock_file: gettimeofday: %s", strerror(errno));
- goto done;
- }
- end = start;
- pollint.tv_sec = 0;
- pollint.tv_nsec = LOCKPOLLINTERVAL * 1000000;
- do
- {
- /*
- Try to create a hard link to the unique file from the
- lockfile. This will only succeed if the lockfile does not
- already exist. It is guaranteed to provide race-free
- semantics over NFS which the alternative of calling
- open(O_EXCL|O_CREAT) on the lockfile is not. The lock
- succeeds if the call to link returns 0 or the link count on
- the unique file increases to 2.
- */
- if (link(linkfile, lockfile) == 0 ||
- (stat(linkfile, &statbuf) == 0 &&
- statbuf.st_nlink == 2))
- {
- /* Successful lock */
- ret = 1;
- break;
- }
- elapsed = end.tv_sec + end.tv_usec/1000000.0 -
- (start.tv_sec + start.tv_usec/1000000.0);
- /*
- The check for elapsed < 0 is to deal with the unlikely event
- that after the loop is entered the system time is set forward
- past the loop's end time. This would otherwise result in a
- (practically) infinite loop.
- */
- if (timed_out || elapsed >= timeout || elapsed < 0)
- {
- if (timed_out == 0 && force)
- {
- /*
- Timed out and force was specified - attempt to
- remove stale lock and try a final time
- */
- (void)unlink(lockfile);
- timed_out = 1;
- continue;
- }
- else
- {
- /*
- Timed out and final try was unsuccessful or
- force was not specified
- */
- debug(1, L"acquire_lock_file: timed out "
- L"trying to obtain lockfile %s using "
- L"linkfile %s", lockfile, linkfile);
- break;
- }
- }
- nanosleep(&pollint, NULL);
- }
- while (gettimeofday(&end, NULL) == 0);
-done:
- /* The linkfile is not needed once the lockfile has been created */
- (void)unlink(linkfile);
- return ret;
-}
-
-/**
- Acquire the lock for the socket
- Returns the name of the lock file if successful or
- NULL if unable to obtain lock.
- The returned string must be free()d after unlink()ing the file to release
- the lock
-*/
-static bool acquire_socket_lock(const std::string &sock_name, std::string *out_lockfile_name)
-{
- bool success = false;
- std::string lockfile;
- lockfile.reserve(sock_name.size() + strlen(LOCKPOSTFIX));
- lockfile = sock_name;
- lockfile.append(LOCKPOSTFIX);
- if (acquire_lock_file(lockfile, LOCKTIMEOUT, 1))
- {
- out_lockfile_name->swap(lockfile);
- success = true;
- }
- return success;
-}
-
-/**
- Connects to the fish socket and starts listening for connections
-*/
-static int get_socket(void)
-{
- // Cygwin has random problems involving sockets. When using Cygwin,
- // allow 20 attempts at making socket correctly.
-#ifdef __CYGWIN__
- int attempts = 0;
-repeat:
- attempts += 1;
-#endif
-
- int s, len, doexit = 0;
- int exitcode = EXIT_FAILURE;
- struct sockaddr_un local;
- const std::string sock_name = get_socket_filename();
-
- /*
- Start critical section protected by lock
- */
- std::string lockfile;
- if (! acquire_socket_lock(sock_name, &lockfile))
- {
- debug(0, L"Unable to obtain lock on socket, exiting");
- exit(EXIT_FAILURE);
- }
- debug(4, L"Acquired lockfile: %s", lockfile.c_str());
-
- local.sun_family = AF_UNIX;
- strcpy(local.sun_path, sock_name.c_str());
- len = sizeof(local);
-
- debug(1, L"Connect to socket at %s", sock_name.c_str());
-
- if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- {
- wperror(L"socket");
- doexit = 1;
- goto unlock;
- }
-
- /*
- First check whether the socket has been opened by another fishd;
- if so, exit with success status
- */
- if (connect(s, (struct sockaddr *)&local, len) == 0)
- {
- debug(1, L"Socket already exists, exiting");
- doexit = 1;
- exitcode = 0;
- goto unlock;
- }
-
- unlink(local.sun_path);
- if (bind(s, (struct sockaddr *)&local, len) == -1)
- {
- wperror(L"bind");
- doexit = 1;
- goto unlock;
- }
-
- if (make_fd_nonblocking(s) != 0)
- {
- wperror(L"fcntl");
- close(s);
- doexit = 1;
- }
- else if (listen(s, 64) == -1)
- {
- wperror(L"listen");
- doexit = 1;
- }
-
-unlock:
- (void)unlink(lockfile.c_str());
- debug(4, L"Released lockfile: %s", lockfile.c_str());
- /*
- End critical section protected by lock
- */
-
- if (doexit)
- {
- // If Cygwin, only allow normal quit when made lots of attempts.
-#ifdef __CYGWIN__
- if (exitcode && attempts < 20) goto repeat;
-#endif
- exit_without_destructors(exitcode);
- }
-
- return s;
-}
-
-/**
- Event handler. Broadcasts updates to all clients.
-*/
-static void broadcast(fish_message_type_t type, const wchar_t *key, const wchar_t *val)
-{
- message_t *msg;
-
- if (connections.empty())
- return;
-
- msg = create_message(type, key, val);
-
- /*
- Don't merge these loops, or try_send_all can free the message
- prematurely
- */
-
- for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
- {
- msg->count++;
- iter->unsent.push(msg);
- }
-
- for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
- {
- try_send_all(&*iter);
- }
-}
-
-/**
- Make program into a creature of the night.
-*/
-static void daemonize()
-{
- /*
- Fork, and let parent exit
- */
- switch (fork())
- {
- case -1:
- debug(0, L"Could not put fishd in background. Quitting");
- wperror(L"fork");
- exit(1);
-
- case 0:
- {
- /* Ordinarily there's very limited things we will do after fork, due to multithreading. But fishd is safe because it's single threaded. So don't die in is_forked_child. */
- setup_fork_guards();
-
- /*
- Make fishd ignore the HUP and PIPE signals.
- */
- struct sigaction act;
- sigemptyset(& act.sa_mask);
- act.sa_flags=0;
- act.sa_handler=SIG_IGN;
- sigaction(SIGHUP, &act, 0);
- sigaction(SIGPIPE, &act, 0);
-
- /*
- Make fishd save and exit on the TERM signal.
- */
- sigfillset(& act.sa_mask);
- act.sa_flags=0;
- act.sa_handler=&handle_term;
- sigaction(SIGTERM, &act, 0);
- break;
-
- }
-
- default:
- {
- debug(0, L"Parent process exiting (This is normal)");
- exit(0);
- }
- }
-
- /*
- Put ourself in our own process group
- */
- setsid();
-
- /*
- Close stdin and stdout. We only use stderr, anyway.
- */
- close(0);
- close(1);
-
-}
-
-/**
- Get environment variable value.
-*/
-static env_var_t fishd_env_get(const char *key)
-{
- const char *env = getenv(key);
- if (env != NULL)
- {
- return env_var_t(str2wcstring(env));
- }
- else
- {
- const wcstring wkey = str2wcstring(key);
- return env_universal_common_get(wkey);
- }
-}
-
-/**
- Get the configuration directory. The resulting string needs to be
- free'd. This is mostly the same code as path_get_config(), but had
- to be rewritten to avoid dragging in additional library
- dependencies.
-*/
-static wcstring fishd_get_config()
-{
- bool done = false;
- wcstring result;
-
- env_var_t xdg_dir = fishd_env_get("XDG_CONFIG_HOME");
- if (! xdg_dir.missing_or_empty())
- {
- result = xdg_dir;
- append_path_component(result, L"/fish");
- if (!create_directory(result))
- {
- done = true;
- }
- }
- else
- {
- env_var_t home = fishd_env_get("HOME");
- if (! home.missing_or_empty())
- {
- result = home;
- append_path_component(result, L"/.config/fish");
- if (!create_directory(result))
- {
- done = 1;
- }
- }
- }
-
- if (! done)
- {
- /* Bad juju */
- debug(0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access."));
- result.clear();
- }
-
- return result;
-}
-
-/**
- Load or save all variables
-*/
-static bool load_or_save_variables_at_path(bool save, const std::string &path)
-{
- bool result = false;
-
- debug(4, L"Open file for %s: '%s'",
- save?"saving":"loading",
- path.c_str());
-
- /* OK to not use CLO_EXEC here because fishd is single threaded */
- int fd = open(path.c_str(), save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
- if (fd >= 0)
- {
- /* Success */
- result = true;
- connection_t c(fd);
-
- if (save)
- {
- /* Save to the file */
- write_loop(c.fd, SAVE_MSG, strlen(SAVE_MSG));
- enqueue_all(&c);
- }
- else
- {
- /* Read from the file */
- read_message(&c);
- }
-
- connection_destroy(&c);
- }
- return result;
-}
-
-
-static std::string get_variables_file_path(const std::string &dir, const std::string &identifier)
-{
- std::string name;
- name.append(dir);
- name.append("/");
- name.append(FILE);
- name.append(identifier);
- return name;
-}
-
-
-static bool load_or_save_variables(bool save)
-{
- const wcstring wdir = fishd_get_config();
- const std::string dir = wcs2string(wdir);
- if (dir.empty())
- return false;
-
- const std::string machine_id = get_machine_identifier();
- const std::string machine_id_path = get_variables_file_path(dir, machine_id);
- bool success = load_or_save_variables_at_path(save, machine_id_path);
- if (! success && ! save && errno == ENOENT)
- {
- /* We failed to load, because the file was not found. Older fish used the hostname only. Try *moving* the filename based on the hostname into place; if that succeeds try again. Silently "upgraded." */
- std::string hostname_id;
- if (get_hostname_identifier(&hostname_id) && hostname_id != machine_id)
- {
- std::string hostname_path = get_variables_file_path(dir, hostname_id);
- if (0 == rename(hostname_path.c_str(), machine_id_path.c_str()))
- {
- /* We renamed - try again */
- success = load_or_save_variables_at_path(save, machine_id_path);
- }
- }
- }
- return success;
-}
-
-/**
- Load variables from disk
-*/
-static void load()
-{
- load_or_save_variables(false /* load, not save */);
-}
-
-/**
- Save variables to disk
-*/
-static void save()
-{
- load_or_save_variables(true /* save, not load */);
-}
-
-/**
- Do all sorts of boring initialization.
-*/
-static void init()
-{
-
- sock = get_socket();
- daemonize();
- env_universal_common_init(&broadcast);
-
- load();
-}
-
-/**
- Main function for fishd
-*/
-int main(int argc, char ** argv)
-{
- int child_socket;
- struct sockaddr_un remote;
- socklen_t t;
- uid_t sock_euid;
- gid_t sock_egid;
- int max_fd;
- int update_count=0;
-
- fd_set read_fd, write_fd;
-
- set_main_thread();
- setup_fork_guards();
-
- program_name=L"fishd";
- wsetlocale(LC_ALL, L"");
-
- /*
- Parse options
- */
- while (1)
- {
- static struct option
- long_options[] =
- {
- {
- "help", no_argument, 0, 'h'
- }
- ,
- {
- "version", no_argument, 0, 'v'
- }
- ,
- {
- 0, 0, 0, 0
- }
- }
- ;
-
- int opt_index = 0;
-
- int opt = getopt_long(argc,
- argv,
- GETOPT_STRING,
- long_options,
- &opt_index);
-
- if (opt == -1)
- break;
-
- switch (opt)
- {
- case 0:
- break;
-
- case 'h':
- print_help(argv[0], 1);
- exit(0);
-
- case 'v':
- debug(0, L"%ls, version %s\n", program_name, get_fish_version());
- exit(0);
-
- case '?':
- return 1;
-
- }
- }
-
- init();
- while (1)
- {
- int res;
-
- t = sizeof(remote);
-
- FD_ZERO(&read_fd);
- FD_ZERO(&write_fd);
- FD_SET(sock, &read_fd);
- max_fd = sock+1;
- for (connection_list_t::const_iterator iter = connections.begin(); iter != connections.end(); ++iter)
- {
- const connection_t &c = *iter;
- FD_SET(c.fd, &read_fd);
- max_fd = maxi(max_fd, c.fd+1);
-
- if (! c.unsent.empty())
- {
- FD_SET(c.fd, &write_fd);
- }
- }
-
- while (1)
- {
- res=select(max_fd, &read_fd, &write_fd, 0, 0);
-
- if (quit)
- {
- save();
- exit(0);
- }
-
- if (res != -1)
- break;
-
- if (errno != EINTR)
- {
- wperror(L"select");
- exit(1);
- }
- }
-
- if (FD_ISSET(sock, &read_fd))
- {
- if ((child_socket =
- accept(sock,
- (struct sockaddr *)&remote,
- &t)) == -1)
- {
- wperror(L"accept");
- exit(1);
- }
- else
- {
- debug(4, L"Connected with new child on fd %d", child_socket);
-
- if (((getpeereid(child_socket, &sock_euid, &sock_egid) != 0) || sock_euid != geteuid()))
- {
- debug(1, L"Wrong credentials for child on fd %d", child_socket);
- close(child_socket);
- }
- else if (make_fd_nonblocking(child_socket) != 0)
- {
- wperror(L"fcntl");
- close(child_socket);
- }
- else
- {
- connections.push_front(connection_t(child_socket));
- connection_t &newc = connections.front();
- send(newc.fd, GREETING, strlen(GREETING), MSG_DONTWAIT);
- enqueue_all(&newc);
- }
- }
- }
-
- for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
- {
- if (FD_ISSET(iter->fd, &write_fd))
- {
- try_send_all(&*iter);
- }
- }
-
- for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
- {
- if (FD_ISSET(iter->fd, &read_fd))
- {
- read_message(&*iter);
-
- /*
- Occasionally we save during normal use, so that we
- won't lose everything on a system crash
- */
- update_count++;
- if (update_count >= 64)
- {
- save();
- update_count = 0;
- }
- }
- }
-
- for (connection_list_t::iterator iter = connections.begin(); iter != connections.end();)
- {
- if (iter->killme)
- {
- debug(4, L"Close connection %d", iter->fd);
-
- while (! iter->unsent.empty())
- {
- message_t *msg = iter->unsent.front();
- iter->unsent.pop();
- msg->count--;
- if (! msg->count)
- free(msg);
- }
-
- connection_destroy(&*iter);
- iter = connections.erase(iter);
- }
- else
- {
- ++iter;
- }
- }
-
- if (connections.empty())
- {
- debug(0, L"No more clients. Quitting");
- save();
- break;
- }
-
- }
-}
-
diff --git a/input_common.cpp b/input_common.cpp
index 1252dc0d..513fd8e3 100644
--- a/input_common.cpp
+++ b/input_common.cpp
@@ -16,6 +16,7 @@ Implementation file for the low level input library
#include <wchar.h>
#include <stack>
#include <list>
+#include <queue>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
@@ -26,7 +27,7 @@ Implementation file for the low level input library
#include "common.h"
#include "wutil.h"
#include "input_common.h"
-#include "env_universal.h"
+#include "env_universal_common.h"
#include "iothread.h"
/**
@@ -37,9 +38,9 @@ Implementation file for the low level input library
#define WAIT_ON_ESCAPE 10
/** Characters that have been read and returned by the sequence matching code */
-static std::stack<wint_t, std::list<wint_t> > lookahead_list;
+static std::stack<wint_t, std::vector<wint_t> > lookahead_list;
-/* Queue of pairs of (function pointer, argument) to be invoked */
+/* Queue of pairs of (function pointer, argument) to be invoked. Expected to be mostly empty. */
typedef std::pair<void (*)(void *), void *> callback_info_t;
typedef std::queue<callback_info_t, std::list<callback_info_t> > callback_queue_t;
static callback_queue_t callback_queue;
@@ -102,11 +103,6 @@ static wint_t readb()
FD_ZERO(&fdset);
FD_SET(0, &fdset);
- if (env_universal_server.fd > 0)
- {
- FD_SET(env_universal_server.fd, &fdset);
- fd_max = maxi(fd_max, env_universal_server.fd);
- }
if (ioport > 0)
{
FD_SET(ioport, &fdset);
@@ -174,17 +170,7 @@ static wint_t readb()
/* Assume we loop unless we see a character in stdin */
do_loop = true;
- if (env_universal_server.fd > 0 && FD_ISSET(env_universal_server.fd, &fdset))
- {
- debug(3, L"Wake up on universal variable event");
- env_universal_read_all();
- if (has_lookahead())
- {
- return lookahead_pop();
- }
- }
-
- /* Check to see if we want a barrier */
+ /* Check to see if we want a universal variable barrier */
bool barrier_from_poll = notifier.poll();
bool barrier_from_readability = false;
if (notifier_fd > 0 && FD_ISSET(notifier_fd, &fdset))
diff --git a/parser.cpp b/parser.cpp
index 773cde6b..3740f1fb 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -37,7 +37,6 @@ The fish parser. Contains functions for parsing and evaluating code.
#include "expand.h"
#include "reader.h"
#include "sanity.h"
-#include "env_universal.h"
#include "event.h"
#include "intern.h"
#include "parse_util.h"