aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2015-05-03 18:40:51 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2015-05-03 18:40:51 +0200
commit3b5c3c3b4e7c24ef774f801c13b8b17d76c1ed94 (patch)
treeb51f4cf7f13035e1049eb53f592e0be891cc2435
parent4841ba5bd0117ca7b8dfc5d8eaa6ae8d58f5b92e (diff)
downloadxK-3b5c3c3b4e7c24ef774f801c13b8b17d76c1ed94.tar.gz
xK-3b5c3c3b4e7c24ef774f801c13b8b17d76c1ed94.tar.xz
xK-3b5c3c3b4e7c24ef774f801c13b8b17d76c1ed94.zip
degesch: implement /set += / -=
-rw-r--r--degesch.c160
1 files changed, 130 insertions, 30 deletions
diff --git a/degesch.c b/degesch.c
index ecc15d8..8d37622 100644
--- a/degesch.c
+++ b/degesch.c
@@ -3647,6 +3647,39 @@ config_dump (struct config_item_ *root, struct str_vector *output)
config_dump_item (root, &data);
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static int
+str_vector_sort_cb (const void *a, const void *b)
+{
+ return strcmp (*(const char **) a, *(const char **) b);
+}
+
+static void
+str_vector_sort (struct str_vector *self)
+{
+ qsort (self->vector, self->len, sizeof *self->vector, str_vector_sort_cb);
+}
+
+static void
+dump_matching_options
+ (struct app_context *ctx, const char *mask, struct str_vector *output)
+{
+ config_dump (ctx->config.root, output);
+ str_vector_sort (output);
+
+ // Filter out results by wildcard matching
+ for (size_t i = 0; i < output->len; i++)
+ {
+ // Yeah, I know
+ const char *line = output->vector[i];
+ char *key = xstrndup (line, strcspn (line, " "));
+ if (fnmatch (mask, key, 0))
+ str_vector_remove (output, i--);
+ free (key);
+ }
+}
+
// --- User input handling -----------------------------------------------------
static bool handle_command_help (struct app_context *, char *);
@@ -3773,6 +3806,78 @@ handle_command_buffer (struct app_context *ctx, char *arguments)
return true;
}
+static ssize_t
+str_vector_find (const struct str_vector *v, const char *s)
+{
+ for (size_t i = 0; i < v->len; i++)
+ if (!strcmp (v->vector[i], s))
+ return i;
+ return -1;
+}
+
+static bool
+replace_string_array
+ (struct config_item_ *item, struct str_vector *array, struct error **e)
+{
+ char *changed = join_str_vector (array, ',');
+ struct str tmp = { .str = changed, .len = strlen (changed) };
+ bool result = config_item_set_from (item,
+ config_item_string_array (&tmp), e);
+ free (changed);
+ return result;
+}
+
+static bool
+handle_command_set_add
+ (struct config_item_ *item, const char *value, struct error **e)
+{
+ bool result = false;
+ struct str_vector items;
+ str_vector_init (&items);
+ split_str (item->value.string.str, ',', &items);
+
+ if (str_vector_find (&items, value) != -1)
+ error_set (e, "already present in the array: %s", value);
+ else
+ {
+ str_vector_add (&items, value);
+ result = replace_string_array (item, &items, e);
+ }
+
+ str_vector_free (&items);
+ return result;
+}
+
+static bool
+handle_command_set_remove
+ (struct config_item_ *item, const char *value, struct error **e)
+{
+ bool result = false;
+ struct str_vector items;
+ str_vector_init (&items);
+ split_str (item->value.string.str, ',', &items);
+
+ ssize_t i = str_vector_find (&items, value);
+ if (i == -1)
+ error_set (e, "not present in the array: %s", value);
+ else
+ {
+ str_vector_remove (&items, i);
+ result = replace_string_array (item, &items, e);
+ }
+
+ str_vector_free (&items);
+ return result;
+}
+
+static bool
+handle_command_set_replace (struct app_context *ctx,
+ struct config_item_ *item, struct config_item_ *new_, struct error **e)
+{
+ // TODO: replace the item (or log error)
+ return false;
+}
+
static bool
handle_command_set_assign
(struct app_context *ctx, struct str_vector *all, char *arguments)
@@ -3815,53 +3920,48 @@ handle_command_set_assign
config_item_get (ctx->config.root, key, NULL);
hard_assert (item);
+ struct error *e = NULL;
if ((add | remove) && item->type != CONFIG_ITEM_STRING_ARRAY)
- buffer_send_error (ctx, ctx->global_buffer,
- "Option is not a string array: %s", key);
+ // FIXME: it can also be null, which makes this message confusing
+ error_set (&e, "not a string array");
else if (add)
- ; // TODO: add to string array (or log error)
+ handle_command_set_add (item, new_->value.string.str, &e);
else if (remove)
- ; // TODO: remove from string array (or log error)
+ handle_command_set_remove (item, new_->value.string.str, &e);
else
- ; // TODO: reset the value
+ handle_command_set_replace (ctx, item, new_, &e);
+
+ if (e)
+ {
+ buffer_send_error (ctx, ctx->global_buffer,
+ "Failed to set option \"%s\": %s", key, e->message);
+ error_free (e);
+ }
+ else
+ {
+ struct str_vector tmp;
+ str_vector_init (&tmp);
+ dump_matching_options (ctx, key, &tmp);
+ buffer_send_status (ctx, ctx->global_buffer,
+ "Option changed: %s", tmp.vector[0]);
+ str_vector_free (&tmp);
+ }
free (key);
}
config_item_destroy (new_);
return true;
}
-static int
-str_vector_sort_cb (const void *a, const void *b)
-{
- return strcmp (*(const char **) a, *(const char **) b);
-}
-
-static void
-str_vector_sort (struct str_vector *self)
-{
- qsort (self->vector, self->len, sizeof *self->vector, str_vector_sort_cb);
-}
-
static bool
handle_command_set (struct app_context *ctx, char *arguments)
{
- struct str_vector all;
- str_vector_init (&all);
- config_dump (ctx->config.root, &all);
- str_vector_sort (&all);
-
char *option = "*";
if (*arguments)
option = cut_word (&arguments);
- // Filter out results by wildcard matching
- for (size_t i = 0; i < all.len; i++)
- {
- char *key = xstrndup (all.vector[i], strcspn (all.vector[i], " "));
- if (fnmatch (option, key, 0))
- str_vector_remove (&all, i--);
- free (key);
- }
+ struct str_vector all;
+ str_vector_init (&all);
+ dump_matching_options (ctx, option, &all);
bool result = true;
if (!all.len)