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)