vici: Add some convenience getters on message
This commit is contained in:
@@ -304,6 +304,76 @@ START_TEST(test_builder_fmt)
|
||||
}
|
||||
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 *s;
|
||||
@@ -327,5 +397,11 @@ Suite *message_suite_create()
|
||||
tcase_add_test(tc, test_builder_fmt);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <bio/bio_reader.h>
|
||||
#include <bio/bio_writer.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct private_vici_message_t private_vici_message_t;
|
||||
|
||||
/**
|
||||
@@ -40,6 +42,11 @@ struct private_vici_message_t {
|
||||
* Free encoding during destruction?
|
||||
*/
|
||||
bool cleanup;
|
||||
|
||||
/**
|
||||
* Allocated strings we maintain for get_str()
|
||||
*/
|
||||
linked_list_t *strings;
|
||||
};
|
||||
|
||||
ENUM(vici_type_names, VICI_SECTION_START, VICI_END,
|
||||
@@ -129,7 +136,8 @@ METHOD(enumerator_t, parse_enumerate, bool,
|
||||
u_int8_t type;
|
||||
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;
|
||||
return TRUE;
|
||||
@@ -215,6 +223,189 @@ METHOD(vici_message_t, create_enumerator, enumerator_t*,
|
||||
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,
|
||||
private_vici_message_t *this)
|
||||
{
|
||||
@@ -228,6 +419,7 @@ METHOD(vici_message_t, destroy, void,
|
||||
{
|
||||
chunk_clear(&this->encoding);
|
||||
}
|
||||
this->strings->destroy_function(this->strings, free);
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -241,9 +433,16 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
|
||||
INIT(this,
|
||||
.public = {
|
||||
.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,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.strings = linked_list_create(),
|
||||
.encoding = data,
|
||||
.cleanup = cleanup,
|
||||
);
|
||||
|
||||
@@ -69,6 +69,67 @@ struct vici_message_t {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user