From ce6be7afd4d10b542f9cce8634d6bdd81754f775 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 18 Mar 2019 11:58:40 +0000 Subject: [PATCH] Make array options a sparse tree instead of an array of char * and remove the size limit. --- cmd-set-option.c | 10 ++- cmd-show-options.c | 32 ++++----- cmd.c | 38 +++++------ environ.c | 20 +++--- options.c | 162 +++++++++++++++++++++++++++++++-------------- status.c | 19 ++++-- tmux.h | 7 +- tty-keys.c | 11 +-- tty-term.c | 15 +++-- 9 files changed, 197 insertions(+), 117 deletions(-) diff --git a/cmd-set-option.c b/cmd-set-option.c index a55472ca..ddbfc334 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -163,11 +163,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) parent = options_get(oo, name); /* Check that array options and indexes match up. */ - if (idx != -1) { - if (*name == '@' || options_array_size(parent, NULL) == -1) { - cmdq_error(item, "not an array: %s", argument); - goto fail; - } + if (idx != -1 && (*name == '@' || !options_isarray(parent))) { + cmdq_error(item, "not an array: %s", argument); + goto fail; } /* With -o, check this option is not already set. */ @@ -209,7 +207,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) goto fail; } options_set_string(oo, name, append, "%s", value); - } else if (idx == -1 && options_array_size(parent, NULL) == -1) { + } else if (idx == -1 && !options_isarray(parent)) { error = cmd_set_option_set(self, item, oo, parent, value); if (error != 0) goto fail; diff --git a/cmd-show-options.c b/cmd-show-options.c index f043beca..872f0c45 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -89,20 +89,20 @@ static void cmd_show_options_print(struct cmd *self, struct cmdq_item *item, struct options_entry *o, int idx) { - const char *name; - const char *value; - char *tmp, *escaped; - u_int size, i; + struct options_array_item *a; + const char *name, *value; + char *tmp, *escaped; if (idx != -1) { xasprintf(&tmp, "%s[%d]", options_name(o), idx); name = tmp; } else { - if (options_array_size(o, &size) != -1) { - for (i = 0; i < size; i++) { - if (options_array_get(o, i) == NULL) - continue; - cmd_show_options_print(self, item, o, i); + if (options_isarray(o)) { + a = options_array_first(o); + while (a != NULL) { + idx = options_array_item_index(a); + cmd_show_options_print(self, item, o, idx); + a = options_array_next(a); } return; } @@ -165,9 +165,10 @@ static enum cmd_retval cmd_show_options_all(struct cmd *self, struct cmdq_item *item, struct options *oo) { - struct options_entry *o; + struct options_entry *o; const struct options_table_entry *oe; - u_int size, idx; + struct options_array_item *a; + u_int idx; o = options_first(oo); while (o != NULL) { @@ -176,13 +177,14 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, o = options_next(o); continue; } - if (options_array_size(o, &size) == -1) + if (!options_isarray(o)) cmd_show_options_print(self, item, o, -1); else { - for (idx = 0; idx < size; idx++) { - if (options_array_get(o, idx) == NULL) - continue; + a = options_array_first(o); + while (a != NULL) { + idx = options_array_item_index(a); cmd_show_options_print(self, item, o, idx); + a = options_array_next(a); } } o = options_next(o); diff --git a/cmd.c b/cmd.c index 9226e6c2..eace4bbd 100644 --- a/cmd.c +++ b/cmd.c @@ -319,31 +319,31 @@ cmd_stringify_argv(int argc, char **argv) static int cmd_try_alias(int *argc, char ***argv) { - struct options_entry *o; - int old_argc = *argc, new_argc; - char **old_argv = *argv, **new_argv; - u_int size, idx; - int i; - size_t wanted; - const char *s, *cp = NULL; + struct options_entry *o; + struct options_array_item *a; + int old_argc = *argc, new_argc, i; + char **old_argv = *argv, **new_argv; + size_t wanted; + const char *s, *cp = NULL; o = options_get_only(global_options, "command-alias"); - if (o == NULL || options_array_size(o, &size) == -1 || size == 0) + if (o == NULL) return (-1); - wanted = strlen(old_argv[0]); - for (idx = 0; idx < size; idx++) { - s = options_array_get(o, idx); - if (s == NULL) - continue; - cp = strchr(s, '='); - if (cp == NULL || (size_t)(cp - s) != wanted) - continue; - if (strncmp(old_argv[0], s, wanted) == 0) - break; + a = options_array_first(o); + while (a != NULL) { + s = options_array_item_value(a); + if (s != NULL) { + cp = strchr(s, '='); + if (cp != NULL && + (size_t)(cp - s) == wanted && + strncmp(old_argv[0], s, wanted) == 0) + break; + } + a = options_array_next(a); } - if (idx == size) + if (a == NULL) return (-1); if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0) diff --git a/environ.c b/environ.c index 29191ee5..2764e027 100644 --- a/environ.c +++ b/environ.c @@ -174,22 +174,26 @@ environ_unset(struct environ *env, const char *name) void environ_update(struct options *oo, struct environ *src, struct environ *dst) { - struct environ_entry *envent; - struct options_entry *o; - u_int size, idx; - const char *value; + struct environ_entry *envent; + struct options_entry *o; + struct options_array_item *a; + const char *value; o = options_get(oo, "update-environment"); - if (o == NULL || options_array_size(o, &size) == -1) + if (o == NULL) return; - for (idx = 0; idx < size; idx++) { - value = options_array_get(o, idx); - if (value == NULL) + a = options_array_first(o); + while (a != NULL) { + value = options_array_item_value(a); + if (value == NULL) { + a = options_array_next(a); continue; + } if ((envent = environ_find(src, value)) == NULL) environ_clear(dst, value); else environ_set(dst, envent->name, "%s", envent->value); + a = options_array_next(a); } } diff --git a/options.c b/options.c index 9ea5c118..6a7c37d6 100644 --- a/options.c +++ b/options.c @@ -30,6 +30,23 @@ * a red-black tree. */ +struct options_array_item { + u_int index; + char *value; + RB_ENTRY(options_array_item) entry; +}; +RB_HEAD(options_array, options_array_item); +static int +options_array_cmp(struct options_array_item *a1, struct options_array_item *a2) +{ + if (a1->index < a2->index) + return (-1); + if (a1->index > a2->index) + return (1); + return (0); +} +RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp); + struct options_entry { struct options *owner; @@ -40,10 +57,7 @@ struct options_entry { char *string; long long number; struct style style; - struct { - const char **array; - u_int arraysize; - }; + struct options_array array; }; RB_ENTRY(options_entry) entry; @@ -56,8 +70,6 @@ struct options { static struct options_entry *options_add(struct options *, const char *); -#define OPTIONS_ARRAY_LIMIT 1000 - #define OPTIONS_IS_STRING(o) \ ((o)->tableentry == NULL || \ (o)->tableentry->type == OPTIONS_TABLE_STRING) @@ -163,6 +175,9 @@ options_empty(struct options *oo, const struct options_table_entry *oe) o = options_add(oo, oe->name); o->tableentry = oe; + if (oe->type == OPTIONS_TABLE_ARRAY) + RB_INIT(&o->array); + return (o); } @@ -210,15 +225,11 @@ void options_remove(struct options_entry *o) { struct options *oo = o->owner; - u_int i; if (OPTIONS_IS_STRING(o)) - free((void *)o->string); - else if (OPTIONS_IS_ARRAY(o)) { - for (i = 0; i < o->arraysize; i++) - free((void *)o->array[i]); - free(o->array); - } + free(o->string); + else if (OPTIONS_IS_ARRAY(o)) + options_array_clear(o); RB_REMOVE(options_tree, &oo->tree, o); free(o); @@ -236,62 +247,79 @@ options_table_entry(struct options_entry *o) return (o->tableentry); } +static struct options_array_item * +options_array_item(struct options_entry *o, u_int idx) +{ + struct options_array_item a; + + a.index = idx; + return (RB_FIND(options_array, &o->array, &a)); +} + +static void +options_array_free(struct options_entry *o, struct options_array_item *a) +{ + free(a->value); + RB_REMOVE(options_array, &o->array, a); + free(a); +} + void options_array_clear(struct options_entry *o) { - if (OPTIONS_IS_ARRAY(o)) - o->arraysize = 0; + struct options_array_item *a, *a1; + + if (!OPTIONS_IS_ARRAY(o)) + return; + + RB_FOREACH_SAFE(a, options_array, &o->array, a1) + options_array_free(o, a); } const char * options_array_get(struct options_entry *o, u_int idx) { + struct options_array_item *a; + if (!OPTIONS_IS_ARRAY(o)) return (NULL); - if (idx >= o->arraysize) + a = options_array_item(o, idx); + if (a == NULL) return (NULL); - return (o->array[idx]); + return (a->value); } int options_array_set(struct options_entry *o, u_int idx, const char *value, int append) { - char *new; - u_int i; + struct options_array_item *a; + char *new; if (!OPTIONS_IS_ARRAY(o)) return (-1); - if (idx >= OPTIONS_ARRAY_LIMIT) - return (-1); - if (idx >= o->arraysize) { - o->array = xreallocarray(o->array, idx + 1, sizeof *o->array); - for (i = o->arraysize; i < idx + 1; i++) - o->array[i] = NULL; - o->arraysize = idx + 1; + a = options_array_item(o, idx); + if (value == NULL) { + if (a != NULL) + options_array_free(o, a); + return (0); } - new = NULL; - if (value != NULL) { - if (o->array[idx] != NULL && append) - xasprintf(&new, "%s%s", o->array[idx], value); + if (a == NULL) { + a = xcalloc(1, sizeof *a); + a->index = idx; + a->value = xstrdup(value); + RB_INSERT(options_array, &o->array, a); + } else { + free(a->value); + if (a != NULL && append) + xasprintf(&new, "%s%s", a->value, value); else new = xstrdup(value); + a->value = new; } - free((void *)o->array[idx]); - o->array[idx] = new; - return (0); -} - -int -options_array_size(struct options_entry *o, u_int *size) -{ - if (!OPTIONS_IS_ARRAY(o)) - return (-1); - if (size != NULL) - *size = o->arraysize; return (0); } @@ -310,37 +338,69 @@ options_array_assign(struct options_entry *o, const char *s) while ((next = strsep(&string, separator)) != NULL) { if (*next == '\0') continue; - for (i = 0; i < OPTIONS_ARRAY_LIMIT; i++) { - if (i >= o->arraysize || o->array[i] == NULL) + for (i = 0; i < UINT_MAX; i++) { + if (options_array_item(o, i) == NULL) break; } - if (i == OPTIONS_ARRAY_LIMIT) + if (i == UINT_MAX) break; options_array_set(o, i, next, 0); } free(copy); } +struct options_array_item * +options_array_first(struct options_entry *o) +{ + if (!OPTIONS_IS_ARRAY(o)) + return (NULL); + return (RB_MIN(options_array, &o->array)); +} + +struct options_array_item * +options_array_next(struct options_array_item *a) +{ + return (RB_NEXT(options_array, &o->array, a)); +} + +u_int +options_array_item_index(struct options_array_item *a) +{ + return (a->index); +} + +const char * +options_array_item_value(struct options_array_item *a) +{ + return (a->value); +} + +int +options_isarray(struct options_entry *o) +{ + return (OPTIONS_IS_ARRAY(o)); +} + int options_isstring(struct options_entry *o) { - if (o->tableentry == NULL) - return (1); return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o)); } const char * options_tostring(struct options_entry *o, int idx, int numeric) { - static char s[1024]; - const char *tmp; + static char s[1024]; + const char *tmp; + struct options_array_item *a; if (OPTIONS_IS_ARRAY(o)) { if (idx == -1) return (NULL); - if ((u_int)idx >= o->arraysize || o->array[idx] == NULL) + a = options_array_item(o, idx); + if (a == NULL) return (""); - return (o->array[idx]); + return (a->value); } if (OPTIONS_IS_STYLE(o)) return (style_tostring(&o->style)); diff --git a/status.c b/status.c index 4a2eb19d..de6d2716 100644 --- a/status.c +++ b/status.c @@ -1510,9 +1510,10 @@ status_prompt_complete_list(u_int *size, const char *s) const char **layout, *value, *cp; const struct cmd_entry **cmdent; const struct options_table_entry *oe; - u_int items, idx; + u_int idx; size_t slen = strlen(s), valuelen; struct options_entry *o; + struct options_array_item *a; const char *layouts[] = { "even-horizontal", "even-vertical", "main-horizontal", "main-vertical", "tiled", NULL @@ -1538,16 +1539,22 @@ status_prompt_complete_list(u_int *size, const char *s) } } o = options_get_only(global_options, "command-alias"); - if (o != NULL && options_array_size(o, &items) != -1) { - for (idx = 0; idx < items; idx++) { - value = options_array_get(o, idx); + if (o != NULL) { + a = options_array_first(o); + while (a != NULL) { + value = options_array_item_value(a);; if (value == NULL || (cp = strchr(value, '=')) == NULL) - continue; + goto next; + valuelen = cp - value; if (slen > valuelen || strncmp(value, s, slen) != 0) - continue; + goto next; + list = xreallocarray(list, (*size) + 1, sizeof *list); list[(*size)++] = xstrndup(value, valuelen); + + next: + a = options_array_next(a); } } for (idx = 0; idx < (*size); idx++) diff --git a/tmux.h b/tmux.h index 2b083e44..a1ed1b46 100644 --- a/tmux.h +++ b/tmux.h @@ -50,6 +50,7 @@ struct mode_tree_data; struct mouse_event; struct options; struct options_entry; +struct options_array_item; struct session; struct tmuxpeer; struct tmuxproc; @@ -1642,8 +1643,12 @@ void options_array_clear(struct options_entry *); const char *options_array_get(struct options_entry *, u_int); int options_array_set(struct options_entry *, u_int, const char *, int); -int options_array_size(struct options_entry *, u_int *); void options_array_assign(struct options_entry *, const char *); +struct options_array_item *options_array_first(struct options_entry *); +struct options_array_item *options_array_next(struct options_array_item *); +u_int options_array_item_index(struct options_array_item *); +const char *options_array_item_value(struct options_array_item *); +int options_isarray(struct options_entry *); int options_isstring(struct options_entry *); const char *options_tostring(struct options_entry *, int, int); char *options_parse(const char *, int *); diff --git a/tty-keys.c b/tty-keys.c index 3eb8d428..da84077b 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -398,9 +398,10 @@ tty_keys_build(struct tty *tty) { const struct tty_default_key_raw *tdkr; const struct tty_default_key_code *tdkc; - u_int i, size; + u_int i; const char *s, *value; struct options_entry *o; + struct options_array_item *a; if (tty->key_tree != NULL) tty_keys_free(tty); @@ -423,11 +424,13 @@ tty_keys_build(struct tty *tty) } o = options_get(global_options, "user-keys"); - if (o != NULL && options_array_size(o, &size) != -1) { - for (i = 0; i < size; i++) { - value = options_array_get(o, i); + if (o != NULL) { + a = options_array_first(o); + while (a != NULL) { + value = options_array_item_value(a); if (value != NULL) tty_keys_add(tty, value, KEYC_USER + i); + a = options_array_next(a); } } } diff --git a/tty-term.c b/tty-term.c index 7df9a7d1..9e0bb63d 100644 --- a/tty-term.c +++ b/tty-term.c @@ -416,7 +416,8 @@ tty_term_find(char *name, int fd, char **cause) const struct tty_term_code_entry *ent; struct tty_code *code; struct options_entry *o; - u_int size, i; + struct options_array_item *a; + u_int i; int n, error; const char *s, *acs; @@ -491,12 +492,12 @@ tty_term_find(char *name, int fd, char **cause) /* Apply terminal overrides. */ o = options_get_only(global_options, "terminal-overrides"); - if (options_array_size(o, &size) != -1) { - for (i = 0; i < size; i++) { - s = options_array_get(o, i); - if (s != NULL) - tty_term_override(term, s); - } + a = options_array_first(o); + while (a != NULL) { + s = options_array_item_value(a); + if (s != NULL) + tty_term_override(term, s); + a = options_array_next(a); } /* Delete curses data. */