* lib: add mu_str_parse_arglist + unit tests

This commit is contained in:
djcb 2013-05-20 05:14:35 +03:00
parent 2f5d6e246b
commit 59f855b39b
3 changed files with 161 additions and 3 deletions

View File

@ -840,3 +840,122 @@ mu_str_quoted_from_strv (const gchar **params)
return g_string_free (str, FALSE);
}
static char*
read_key (const char *str, const char **val, GError **err)
{
const char *cur;
GString *gstr;
cur = str;
gstr = g_string_sized_new (strlen(cur));
while (*cur && *cur != ':') {
g_string_append_c (gstr, *cur);
++cur;
}
if (*cur != ':' || gstr->len == 0) {
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR,
"expected: '<alphanum>+:' (%s)",
str);
g_string_free (gstr, TRUE);
*val = NULL;
return NULL;
} else {
*val = cur + 1;
return g_string_free (gstr, FALSE);
}
}
static char*
read_val (const char *str, const char **endval, GError **err)
{
const char *cur;
gboolean quoted;
GString *gstr;
gstr = g_string_sized_new (strlen(str));
for (quoted = FALSE, cur = str; *cur; ++cur) {
if (*cur == '\\') {
if (cur[1] != '"' && cur[1] != '\\') {
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR,
"invalid escaping");
goto errexit;
} else {
++cur;
g_string_append_c (gstr, *cur);
continue;
}
} else if (*cur == '"') {
quoted = !quoted;
continue;
} else if (isblank(*cur) && !quoted)
break;
else
g_string_append_c (gstr, *cur);
}
if (quoted) {
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR,
"error in quoting");
goto errexit;
}
*endval = cur;
return g_string_free (gstr, FALSE);
errexit:
g_string_free (gstr, TRUE);
return NULL;
}
GHashTable*
mu_str_parse_arglist (const char *args, GError **err)
{
GHashTable *hash;
const char *cur;
g_return_val_if_fail (args, NULL);
hash = g_hash_table_new_full (
g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
cur = args;
while ((isblank(*cur)))
++cur;
do {
char *key, *val;
const char *valstart, *valend;
key = read_key (cur, &valstart, err);
if (!key)
goto errexit;
val = read_val (valstart, &valend, err);
if (!val)
goto errexit;
g_print ("%s->%s\n", key, val);
g_hash_table_insert (hash, key, val);
cur = valend;
while ((isblank(*cur)))
++cur;
} while (*cur);
return hash;
errexit:
g_hash_table_destroy (hash);
return NULL;
}

View File

@ -281,6 +281,21 @@ GSList* mu_str_to_list (const char *str, char sepa, gboolean strip);
GSList* mu_str_esc_to_list (const char *str);
/**
* Parse a list of <key>:<value> arguments, where <value> supports
* quoting and escaping.
*
* @param args a list of arguments
* @param err receives error information
*
* @return a hash table with key->value, or NULL in case of
* error. Free with g_hash_table_destroy.
*/
GHashTable* mu_str_parse_arglist (const char *args, GError **err)
G_GNUC_WARN_UNUSED_RESULT;
/**
* free a GSList consisting of allocated strings
*

View File

@ -129,6 +129,30 @@ test_mu_str_flatten (void)
}
}
static void
test_parse_arglist (void)
{
const char *args;
GHashTable *hash;
GError *err;
args = "cmd:find query:\"maildir:\\\"/sent items\\\"\" maxnum:500";
err = NULL;
hash = mu_str_parse_arglist (args, &err);
g_assert_no_error (err);
g_assert (hash);
g_assert_cmpstr (g_hash_table_lookup (hash, "cmd"), ==,
"find");
g_assert_cmpstr (g_hash_table_lookup (hash, "query"), ==,
"maildir:\"/sent items\"");
g_assert_cmpstr (g_hash_table_lookup (hash, "maxnum"), ==,
"500");
g_hash_table_destroy (hash);
}
static void
@ -403,9 +427,6 @@ test_mu_term_fixups (void)
int
main (int argc, char *argv[])
{
@ -443,6 +464,9 @@ main (int argc, char *argv[])
g_test_add_func ("/mu-str/mu-str-to-list-strip",
test_mu_str_to_list_strip);
g_test_add_func ("/mu-str/mu-str-esc-to-list",
test_parse_arglist);
g_test_add_func ("/mu-str/mu-str-esc-to-list",
test_mu_str_esc_to_list);