degesch: implement /set += / -=
This commit is contained in:
parent
4841ba5bd0
commit
3b5c3c3b4e
160
degesch.c
160
degesch.c
|
@ -3647,6 +3647,39 @@ config_dump (struct config_item_ *root, struct str_vector *output)
|
||||||
config_dump_item (root, &data);
|
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 -----------------------------------------------------
|
// --- User input handling -----------------------------------------------------
|
||||||
|
|
||||||
static bool handle_command_help (struct app_context *, char *);
|
static bool handle_command_help (struct app_context *, char *);
|
||||||
|
@ -3773,6 +3806,78 @@ handle_command_buffer (struct app_context *ctx, char *arguments)
|
||||||
return true;
|
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
|
static bool
|
||||||
handle_command_set_assign
|
handle_command_set_assign
|
||||||
(struct app_context *ctx, struct str_vector *all, char *arguments)
|
(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);
|
config_item_get (ctx->config.root, key, NULL);
|
||||||
hard_assert (item);
|
hard_assert (item);
|
||||||
|
|
||||||
|
struct error *e = NULL;
|
||||||
if ((add | remove) && item->type != CONFIG_ITEM_STRING_ARRAY)
|
if ((add | remove) && item->type != CONFIG_ITEM_STRING_ARRAY)
|
||||||
buffer_send_error (ctx, ctx->global_buffer,
|
// FIXME: it can also be null, which makes this message confusing
|
||||||
"Option is not a string array: %s", key);
|
error_set (&e, "not a string array");
|
||||||
else if (add)
|
else if (add)
|
||||||
; // TODO: add to string array (or log error)
|
handle_command_set_add (item, new_->value.string.str, &e);
|
||||||
else if (remove)
|
else if (remove)
|
||||||
; // TODO: remove from string array (or log error)
|
handle_command_set_remove (item, new_->value.string.str, &e);
|
||||||
else
|
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);
|
free (key);
|
||||||
}
|
}
|
||||||
config_item_destroy (new_);
|
config_item_destroy (new_);
|
||||||
return true;
|
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
|
static bool
|
||||||
handle_command_set (struct app_context *ctx, char *arguments)
|
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 = "*";
|
char *option = "*";
|
||||||
if (*arguments)
|
if (*arguments)
|
||||||
option = cut_word (&arguments);
|
option = cut_word (&arguments);
|
||||||
|
|
||||||
// Filter out results by wildcard matching
|
struct str_vector all;
|
||||||
for (size_t i = 0; i < all.len; i++)
|
str_vector_init (&all);
|
||||||
{
|
dump_matching_options (ctx, option, &all);
|
||||||
char *key = xstrndup (all.vector[i], strcspn (all.vector[i], " "));
|
|
||||||
if (fnmatch (option, key, 0))
|
|
||||||
str_vector_remove (&all, i--);
|
|
||||||
free (key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (!all.len)
|
if (!all.len)
|
||||||
|
|
Loading…
Reference in New Issue