vici: Add some convenience getters on message
This commit is contained in:
@@ -304,6 +304,76 @@ START_TEST(test_builder_fmt)
|
|||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
static vici_message_t* build_getter_msg()
|
||||||
|
{
|
||||||
|
return vici_message_create_from_args(
|
||||||
|
VICI_KEY_VALUE, "key1", chunk_from_str("1"),
|
||||||
|
VICI_SECTION_START, "section1",
|
||||||
|
VICI_KEY_VALUE, "key2", chunk_from_str("0x12"),
|
||||||
|
VICI_SECTION_START, "section2",
|
||||||
|
VICI_KEY_VALUE, "key3", chunk_from_str("-1"),
|
||||||
|
VICI_SECTION_END,
|
||||||
|
VICI_KEY_VALUE, "key4", chunk_from_str("asdf"),
|
||||||
|
VICI_SECTION_END,
|
||||||
|
VICI_KEY_VALUE, "key5", chunk_from_str(""),
|
||||||
|
VICI_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_get_str)
|
||||||
|
{
|
||||||
|
vici_message_t *m;
|
||||||
|
|
||||||
|
m = build_getter_msg();
|
||||||
|
|
||||||
|
ck_assert_str_eq(m->get_str(m, "def", "key1"), "1");
|
||||||
|
ck_assert_str_eq(m->get_str(m, "def", "section1.key2"), "0x12");
|
||||||
|
ck_assert_str_eq(m->get_str(m, "def", "section%d.section2.key3", 1), "-1");
|
||||||
|
ck_assert_str_eq(m->get_str(m, "def", "section1.key4"), "asdf");
|
||||||
|
ck_assert_str_eq(m->get_str(m, "def", "key5"), "");
|
||||||
|
ck_assert_str_eq(m->get_str(m, "no", "nonexistent"), "no");
|
||||||
|
ck_assert_str_eq(m->get_str(m, "no", "n.o.n.e.x.i.s.t.e.n.t"), "no");
|
||||||
|
|
||||||
|
m->destroy(m);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_get_int)
|
||||||
|
{
|
||||||
|
vici_message_t *m;
|
||||||
|
|
||||||
|
m = build_getter_msg();
|
||||||
|
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "key1"), 1);
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "section1.key2"), 0x12);
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "section1.section2.key3"), -1);
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "section1.key4"), 2);
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "key5"), 0);
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "nonexistent"), 2);
|
||||||
|
ck_assert_int_eq(m->get_int(m, 2, "n.o.n.e.x.i.s.t.e.n.t"), 2);
|
||||||
|
|
||||||
|
m->destroy(m);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_get_value)
|
||||||
|
{
|
||||||
|
vici_message_t *m;
|
||||||
|
chunk_t d = chunk_from_chars('d','e','f');
|
||||||
|
|
||||||
|
m = build_getter_msg();
|
||||||
|
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "key1"), chunk_from_str("1"));
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "section1.key2"), chunk_from_str("0x12"));
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "section1.section2.key3"), chunk_from_str("-1"));
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "section1.key4"), chunk_from_str("asdf"));
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "key5"), chunk_empty);
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "nonexistent"), d);
|
||||||
|
ck_assert_chunk_eq(m->get_value(m, d, "n.o.n.e.x.i.s.t.e.n.t"), d);
|
||||||
|
|
||||||
|
m->destroy(m);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
Suite *message_suite_create()
|
Suite *message_suite_create()
|
||||||
{
|
{
|
||||||
Suite *s;
|
Suite *s;
|
||||||
@@ -327,5 +397,11 @@ Suite *message_suite_create()
|
|||||||
tcase_add_test(tc, test_builder_fmt);
|
tcase_add_test(tc, test_builder_fmt);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
tc = tcase_create("convenience getters");
|
||||||
|
tcase_add_test(tc, test_get_str);
|
||||||
|
tcase_add_test(tc, test_get_int);
|
||||||
|
tcase_add_test(tc, test_get_value);
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include <bio/bio_reader.h>
|
#include <bio/bio_reader.h>
|
||||||
#include <bio/bio_writer.h>
|
#include <bio/bio_writer.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
typedef struct private_vici_message_t private_vici_message_t;
|
typedef struct private_vici_message_t private_vici_message_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +42,11 @@ struct private_vici_message_t {
|
|||||||
* Free encoding during destruction?
|
* Free encoding during destruction?
|
||||||
*/
|
*/
|
||||||
bool cleanup;
|
bool cleanup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocated strings we maintain for get_str()
|
||||||
|
*/
|
||||||
|
linked_list_t *strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
ENUM(vici_type_names, VICI_SECTION_START, VICI_END,
|
ENUM(vici_type_names, VICI_SECTION_START, VICI_END,
|
||||||
@@ -129,7 +136,8 @@ METHOD(enumerator_t, parse_enumerate, bool,
|
|||||||
u_int8_t type;
|
u_int8_t type;
|
||||||
chunk_t data;
|
chunk_t data;
|
||||||
|
|
||||||
if (!this->reader->read_uint8(this->reader, &type))
|
if (!this->reader->remaining(this->reader) ||
|
||||||
|
!this->reader->read_uint8(this->reader, &type))
|
||||||
{
|
{
|
||||||
*out = VICI_END;
|
*out = VICI_END;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -215,6 +223,189 @@ METHOD(vici_message_t, create_enumerator, enumerator_t*,
|
|||||||
return &enumerator->public;
|
return &enumerator->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a value for given vararg key
|
||||||
|
*/
|
||||||
|
static bool find_value(private_vici_message_t *this, chunk_t *value,
|
||||||
|
char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
char buf[128], *name, *key, *dot, *next;
|
||||||
|
int section = 0, keysection = 0;
|
||||||
|
bool found = FALSE;
|
||||||
|
chunk_t current;
|
||||||
|
vici_type_t type;
|
||||||
|
|
||||||
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
|
next = buf;
|
||||||
|
|
||||||
|
enumerator = create_enumerator(this);
|
||||||
|
|
||||||
|
/* descent into section */
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
dot = strchr(next, '.');
|
||||||
|
if (!dot)
|
||||||
|
{
|
||||||
|
key = next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*dot = '\0';
|
||||||
|
key = next;
|
||||||
|
next = dot + 1;
|
||||||
|
keysection++;
|
||||||
|
|
||||||
|
while (enumerator->enumerate(enumerator, &type, &name, ¤t))
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case VICI_SECTION_START:
|
||||||
|
section++;
|
||||||
|
if (section == keysection && streq(name, key))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VICI_SECTION_END:
|
||||||
|
section--;
|
||||||
|
continue;
|
||||||
|
case VICI_END:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find key/value in current section */
|
||||||
|
while (enumerator->enumerate(enumerator, &type, &name, ¤t))
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case VICI_KEY_VALUE:
|
||||||
|
if (section == keysection && streq(key, name))
|
||||||
|
{
|
||||||
|
*value = current;
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case VICI_SECTION_START:
|
||||||
|
section++;
|
||||||
|
continue;
|
||||||
|
case VICI_SECTION_END:
|
||||||
|
section--;
|
||||||
|
continue;
|
||||||
|
case VICI_END:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_message_t, vget_str, char*,
|
||||||
|
private_vici_message_t *this, char *def, char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
chunk_t value;
|
||||||
|
bool found;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
found = find_value(this, &value, fmt, args);
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
if (chunk_printable(value, NULL, 0))
|
||||||
|
{
|
||||||
|
str = strndup(value.ptr, value.len);
|
||||||
|
/* keep a reference to string, so caller doesn't have to care */
|
||||||
|
this->strings->insert_last(this->strings, str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_message_t, get_str, char*,
|
||||||
|
private_vici_message_t *this, char *def, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
str = vget_str(this, def, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_message_t, vget_int, int,
|
||||||
|
private_vici_message_t *this, int def, char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
chunk_t value;
|
||||||
|
bool found;
|
||||||
|
char buf[32], *pos;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
found = find_value(this, &value, fmt, args);
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
if (chunk_printable(value, NULL, 0))
|
||||||
|
{
|
||||||
|
snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr);
|
||||||
|
errno = 0;
|
||||||
|
ret = strtol(buf, &pos, 0);
|
||||||
|
if (errno == 0 && pos == buf + strlen(buf))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_message_t, get_int, int,
|
||||||
|
private_vici_message_t *this, int def, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
val = vget_int(this, def, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_message_t, vget_value, chunk_t,
|
||||||
|
private_vici_message_t *this, chunk_t def, char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
chunk_t value;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
found = find_value(this, &value, fmt, args);
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_message_t, get_value, chunk_t,
|
||||||
|
private_vici_message_t *this, chunk_t def, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
chunk_t value;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
value = vget_value(this, def, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(vici_message_t, get_encoding, chunk_t,
|
METHOD(vici_message_t, get_encoding, chunk_t,
|
||||||
private_vici_message_t *this)
|
private_vici_message_t *this)
|
||||||
{
|
{
|
||||||
@@ -228,6 +419,7 @@ METHOD(vici_message_t, destroy, void,
|
|||||||
{
|
{
|
||||||
chunk_clear(&this->encoding);
|
chunk_clear(&this->encoding);
|
||||||
}
|
}
|
||||||
|
this->strings->destroy_function(this->strings, free);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,9 +433,16 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
|
|||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
.create_enumerator = _create_enumerator,
|
.create_enumerator = _create_enumerator,
|
||||||
|
.get_str = _get_str,
|
||||||
|
.vget_str = _vget_str,
|
||||||
|
.get_int = _get_int,
|
||||||
|
.vget_int = _vget_int,
|
||||||
|
.get_value = _get_value,
|
||||||
|
.vget_value = _vget_value,
|
||||||
.get_encoding = _get_encoding,
|
.get_encoding = _get_encoding,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
|
.strings = linked_list_create(),
|
||||||
.encoding = data,
|
.encoding = data,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -69,6 +69,67 @@ struct vici_message_t {
|
|||||||
*/
|
*/
|
||||||
enumerator_t* (*create_enumerator)(vici_message_t *this);
|
enumerator_t* (*create_enumerator)(vici_message_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a key/value pair as a string.
|
||||||
|
*
|
||||||
|
* @param def default value if not found
|
||||||
|
* @param fmt printf style format string for key, with sections
|
||||||
|
* @param ... arguments to fmt string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
char* (*get_str)(vici_message_t *this, char *def, char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a key/value pair as a string, va_list variant.
|
||||||
|
*
|
||||||
|
* @param def default value if not found
|
||||||
|
* @param fmt printf style format string for key, with sections
|
||||||
|
* @param args arguments to fmt string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
char* (*vget_str)(vici_message_t *this, char *def, char *fmt, va_list args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a key/value pair as integer.
|
||||||
|
*
|
||||||
|
* @param def default value if not found
|
||||||
|
* @param fmt printf style format string for key, with sections
|
||||||
|
* @param ... arguments to fmt string
|
||||||
|
* @return value
|
||||||
|
*/
|
||||||
|
int (*get_int)(vici_message_t *this, int def, char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a key/value pair as integer, va_list variant
|
||||||
|
*
|
||||||
|
* @param def default value if not found
|
||||||
|
* @param fmt printf style format string for key, with sections
|
||||||
|
* @param args arguments to fmt string
|
||||||
|
* @return value
|
||||||
|
*/
|
||||||
|
int (*vget_int)(vici_message_t *this, int def, char *fmt, va_list args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw value of a key/value pair.
|
||||||
|
*
|
||||||
|
* @param def default value if not found
|
||||||
|
* @param fmt printf style format string for key, with sections
|
||||||
|
* @param ... arguments to fmt string
|
||||||
|
* @return value
|
||||||
|
*/
|
||||||
|
chunk_t (*get_value)(vici_message_t *this, chunk_t def, char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw value of a key/value pair, va_list variant.
|
||||||
|
*
|
||||||
|
* @param def default value if not found
|
||||||
|
* @param fmt printf style format string for key, with sections
|
||||||
|
* @param args arguments to fmt string
|
||||||
|
* @return value
|
||||||
|
*/
|
||||||
|
chunk_t (*vget_value)(vici_message_t *this, chunk_t def,
|
||||||
|
char *fmt, va_list args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get encoded message.
|
* Get encoded message.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user