summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicm <nicm>2019-03-18 11:58:40 +0000
committernicm <nicm>2019-03-18 11:58:40 +0000
commitce6be7afd4d10b542f9cce8634d6bdd81754f775 (patch)
tree01a13843f212816c057069a13d02b46743ed8fd0
parentd2d43987d0f35af2bc012f1260fdb81c851fe390 (diff)
Make array options a sparse tree instead of an array of char * and
remove the size limit.
-rw-r--r--cmd-set-option.c10
-rw-r--r--cmd-show-options.c32
-rw-r--r--cmd.c38
-rw-r--r--environ.c20
-rw-r--r--options.c162
-rw-r--r--status.c19
-rw-r--r--tmux.h7
-rw-r--r--tty-keys.c11
-rw-r--r--tty-term.c15
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. */