}
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;
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;
}
#include <bio/bio_reader.h>
#include <bio/bio_writer.h>
+#include <errno.h>
+
typedef struct private_vici_message_t 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,
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;
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)
{
{
chunk_clear(&this->encoding);
}
+ this->strings->destroy_function(this->strings, free);
free(this);
}
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,
);
*/
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.
*