version 1.38, 2019/03/15 21:54:47 |
version 1.39, 2019/03/18 11:58:40 |
|
|
* a red-black tree. |
* 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_entry { |
struct options *owner; |
struct options *owner; |
|
|
|
|
char *string; |
char *string; |
long long number; |
long long number; |
struct style style; |
struct style style; |
struct { |
struct options_array array; |
const char **array; |
|
u_int arraysize; |
|
}; |
|
}; |
}; |
|
|
RB_ENTRY(options_entry) entry; |
RB_ENTRY(options_entry) entry; |
|
|
|
|
static struct options_entry *options_add(struct options *, const char *); |
static struct options_entry *options_add(struct options *, const char *); |
|
|
#define OPTIONS_ARRAY_LIMIT 1000 |
|
|
|
#define OPTIONS_IS_STRING(o) \ |
#define OPTIONS_IS_STRING(o) \ |
((o)->tableentry == NULL || \ |
((o)->tableentry == NULL || \ |
(o)->tableentry->type == OPTIONS_TABLE_STRING) |
(o)->tableentry->type == OPTIONS_TABLE_STRING) |
|
|
o = options_add(oo, oe->name); |
o = options_add(oo, oe->name); |
o->tableentry = oe; |
o->tableentry = oe; |
|
|
|
if (oe->type == OPTIONS_TABLE_ARRAY) |
|
RB_INIT(&o->array); |
|
|
return (o); |
return (o); |
} |
} |
|
|
|
|
options_remove(struct options_entry *o) |
options_remove(struct options_entry *o) |
{ |
{ |
struct options *oo = o->owner; |
struct options *oo = o->owner; |
u_int i; |
|
|
|
if (OPTIONS_IS_STRING(o)) |
if (OPTIONS_IS_STRING(o)) |
free((void *)o->string); |
free(o->string); |
else if (OPTIONS_IS_ARRAY(o)) { |
else if (OPTIONS_IS_ARRAY(o)) |
for (i = 0; i < o->arraysize; i++) |
options_array_clear(o); |
free((void *)o->array[i]); |
|
free(o->array); |
|
} |
|
|
|
RB_REMOVE(options_tree, &oo->tree, o); |
RB_REMOVE(options_tree, &oo->tree, o); |
free(o); |
free(o); |
|
|
return (o->tableentry); |
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 |
void |
options_array_clear(struct options_entry *o) |
options_array_clear(struct options_entry *o) |
{ |
{ |
if (OPTIONS_IS_ARRAY(o)) |
struct options_array_item *a, *a1; |
o->arraysize = 0; |
|
|
if (!OPTIONS_IS_ARRAY(o)) |
|
return; |
|
|
|
RB_FOREACH_SAFE(a, options_array, &o->array, a1) |
|
options_array_free(o, a); |
} |
} |
|
|
const char * |
const char * |
options_array_get(struct options_entry *o, u_int idx) |
options_array_get(struct options_entry *o, u_int idx) |
{ |
{ |
|
struct options_array_item *a; |
|
|
if (!OPTIONS_IS_ARRAY(o)) |
if (!OPTIONS_IS_ARRAY(o)) |
return (NULL); |
return (NULL); |
if (idx >= o->arraysize) |
a = options_array_item(o, idx); |
|
if (a == NULL) |
return (NULL); |
return (NULL); |
return (o->array[idx]); |
return (a->value); |
} |
} |
|
|
int |
int |
options_array_set(struct options_entry *o, u_int idx, const char *value, |
options_array_set(struct options_entry *o, u_int idx, const char *value, |
int append) |
int append) |
{ |
{ |
char *new; |
struct options_array_item *a; |
u_int i; |
char *new; |
|
|
if (!OPTIONS_IS_ARRAY(o)) |
if (!OPTIONS_IS_ARRAY(o)) |
return (-1); |
return (-1); |
|
|
if (idx >= OPTIONS_ARRAY_LIMIT) |
a = options_array_item(o, idx); |
return (-1); |
if (value == NULL) { |
if (idx >= o->arraysize) { |
if (a != NULL) |
o->array = xreallocarray(o->array, idx + 1, sizeof *o->array); |
options_array_free(o, a); |
for (i = o->arraysize; i < idx + 1; i++) |
return (0); |
o->array[i] = NULL; |
|
o->arraysize = idx + 1; |
|
} |
} |
|
|
new = NULL; |
if (a == NULL) { |
if (value != NULL) { |
a = xcalloc(1, sizeof *a); |
if (o->array[idx] != NULL && append) |
a->index = idx; |
xasprintf(&new, "%s%s", o->array[idx], value); |
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 |
else |
new = xstrdup(value); |
new = xstrdup(value); |
|
a->value = new; |
} |
} |
|
|
free((void *)o->array[idx]); |
|
o->array[idx] = new; |
|
return (0); |
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); |
|
} |
|
|
|
void |
void |
options_array_assign(struct options_entry *o, const char *s) |
options_array_assign(struct options_entry *o, const char *s) |
{ |
{ |
|
|
while ((next = strsep(&string, separator)) != NULL) { |
while ((next = strsep(&string, separator)) != NULL) { |
if (*next == '\0') |
if (*next == '\0') |
continue; |
continue; |
for (i = 0; i < OPTIONS_ARRAY_LIMIT; i++) { |
for (i = 0; i < UINT_MAX; i++) { |
if (i >= o->arraysize || o->array[i] == NULL) |
if (options_array_item(o, i) == NULL) |
break; |
break; |
} |
} |
if (i == OPTIONS_ARRAY_LIMIT) |
if (i == UINT_MAX) |
break; |
break; |
options_array_set(o, i, next, 0); |
options_array_set(o, i, next, 0); |
} |
} |
free(copy); |
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 |
int |
|
options_isarray(struct options_entry *o) |
|
{ |
|
return (OPTIONS_IS_ARRAY(o)); |
|
} |
|
|
|
int |
options_isstring(struct options_entry *o) |
options_isstring(struct options_entry *o) |
{ |
{ |
if (o->tableentry == NULL) |
|
return (1); |
|
return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o)); |
return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o)); |
} |
} |
|
|
const char * |
const char * |
options_tostring(struct options_entry *o, int idx, int numeric) |
options_tostring(struct options_entry *o, int idx, int numeric) |
{ |
{ |
static char s[1024]; |
static char s[1024]; |
const char *tmp; |
const char *tmp; |
|
struct options_array_item *a; |
|
|
if (OPTIONS_IS_ARRAY(o)) { |
if (OPTIONS_IS_ARRAY(o)) { |
if (idx == -1) |
if (idx == -1) |
return (NULL); |
return (NULL); |
if ((u_int)idx >= o->arraysize || o->array[idx] == NULL) |
a = options_array_item(o, idx); |
|
if (a == NULL) |
return (""); |
return (""); |
return (o->array[idx]); |
return (a->value); |
} |
} |
if (OPTIONS_IS_STYLE(o)) |
if (OPTIONS_IS_STYLE(o)) |
return (style_tostring(&o->style)); |
return (style_tostring(&o->style)); |