/* $OpenBSD$ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <fnmatch.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Option handling; each option has a name, type and value and is stored in
* a red-black tree.
*/
struct options_array_item {
u_int index;
union options_value value;
RB_ENTRY(options_array_item) entry;
};
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;
const char *name;
const struct options_table_entry *tableentry;
union options_value value;
int cached;
struct style style;
RB_ENTRY(options_entry) entry;
};
struct options {
RB_HEAD(options_tree, options_entry) tree;
struct options *parent;
};
static struct options_entry *options_add(struct options *, const char *);
static void options_remove(struct options_entry *);
#define OPTIONS_IS_STRING(o) \
((o)->tableentry == NULL || \
(o)->tableentry->type == OPTIONS_TABLE_STRING)
#define OPTIONS_IS_NUMBER(o) \
((o)->tableentry != NULL && \
((o)->tableentry->type == OPTIONS_TABLE_NUMBER || \
(o)->tableentry->type == OPTIONS_TABLE_KEY || \
(o)->tableentry->type == OPTIONS_TABLE_COLOUR || \
(o)->tableentry->type == OPTIONS_TABLE_FLAG || \
(o)->tableentry->type == OPTIONS_TABLE_CHOICE))
#define OPTIONS_IS_COMMAND(o) \
((o)->tableentry != NULL && \
(o)->tableentry->type == OPTIONS_TABLE_COMMAND)
#define OPTIONS_IS_ARRAY(o) \
((o)->tableentry != NULL && \
((o)->tableentry->flags & OPTIONS_TABLE_IS_ARRAY))
static int options_cmp(struct options_entry *, struct options_entry *);
RB_GENERATE_STATIC(options_tree, options_entry, entry, options_cmp);
static int
options_cmp(struct options_entry *lhs, struct options_entry *rhs)
{
return (strcmp(lhs->name, rhs->name));
}
static const char *
options_map_name(const char *name)
{
const struct options_name_map *map;
for (map = options_other_names; map->from != NULL; map++) {
if (strcmp(map->from, name) == 0)
return (map->to);
}
return (name);
}
static const struct options_table_entry *
options_parent_table_entry(struct options *oo, const char *s)
{
struct options_entry *o;
if (oo->parent == NULL)
fatalx("no parent options for %s", s);
o = options_get(oo->parent, s);
if (o == NULL)
fatalx("%s not in parent options", s);
return (o->tableentry);
}
static void
options_value_free(struct options_entry *o, union options_value *ov)
{
if (OPTIONS_IS_STRING(o))
free(ov->string);
if (OPTIONS_IS_COMMAND(o) && ov->cmdlist != NULL