mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-31 20:31:19 -03:00
Removed connection_t and associated functions
This commit is contained in:
@@ -47,21 +47,6 @@
|
||||
*/
|
||||
#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"
|
||||
|
||||
@@ -120,83 +105,11 @@ static void post_callbacks(const callback_data_list_t &callbacks)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
@@ -259,80 +172,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)
|
||||
{
|
||||
@@ -372,28 +211,6 @@ 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, ...)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -460,66 +277,6 @@ static bool append_file_entry(fish_message_type_t type, const wcstring &key_in,
|
||||
return success;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
char *key = NULL;
|
||||
|
||||
// debug( 4, L"Crete message of type %d", type );
|
||||
|
||||
if (key_in)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
message_t *msg = new message_t;
|
||||
msg->count = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
debug(0, L"create_message: Unknown message type");
|
||||
}
|
||||
}
|
||||
|
||||
free(key);
|
||||
|
||||
// debug( 4, L"Message body is '%s'", msg->body );
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
Put exported or unexported variables in a string list
|
||||
*/
|
||||
@@ -540,19 +297,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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
@@ -653,28 +397,6 @@ 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
|
||||
{
|
||||
ASSERT_IS_LOCKED(lock);
|
||||
var_table_t::const_iterator iter;
|
||||
for (iter = vars.begin(); iter != 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);
|
||||
fprintf(stderr, "%s", msg->body.c_str());
|
||||
}
|
||||
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()
|
||||
{
|
||||
@@ -710,9 +432,8 @@ void env_universal_t::load_from_fd(int fd, callback_data_list_t *callbacks)
|
||||
{
|
||||
/* 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 from the file. */
|
||||
this->read_message_internal(fd, callbacks);
|
||||
last_read_file = current_file;
|
||||
}
|
||||
}
|
||||
@@ -1109,94 +830,61 @@ 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)
|
||||
void env_universal_t::read_message_internal(int fd, callback_data_list_t *callbacks)
|
||||
{
|
||||
ASSERT_IS_LOCKED(lock);
|
||||
while (1)
|
||||
|
||||
// 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:
|
||||
break;
|
||||
}
|
||||
|
||||
// Walk over it by lines. The contents of an unterminated line will be left in 'line' for the next iteration.
|
||||
size_t line_start = 0;
|
||||
while (line_start < sizeof buffer)
|
||||
{
|
||||
// Run until we hit a newline
|
||||
size_t cursor = line_start;
|
||||
while (cursor < sizeof buffer && buffer[cursor] != '\n')
|
||||
{
|
||||
return;
|
||||
cursor++;
|
||||
}
|
||||
|
||||
case ENV_UNIVERSAL_ERROR:
|
||||
|
||||
// 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 < sizeof buffer && ! line.empty())
|
||||
{
|
||||
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())
|
||||
if (utf8_to_wchar_string(line, &wide_line))
|
||||
{
|
||||
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));
|
||||
wchar_t *tmp = wcsdup(wide_line.c_str());
|
||||
this->parse_message_internal(tmp, callbacks);
|
||||
free(tmp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
b = (char)ib;
|
||||
|
||||
if (b == '\n')
|
||||
{
|
||||
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)
|
||||
{
|
||||
this->parse_message_internal(msg, src, callbacks);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug(0, _(L"Could not convert message '%s' to wide character string"), &src->input.at(0));
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
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(wchar_t *msg, callback_data_list_t *callbacks)
|
||||
{
|
||||
ASSERT_IS_LOCKED(lock);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user