From 59f855b39bcca43388ee718dcab9990641c68c2d Mon Sep 17 00:00:00 2001 From: djcb Date: Mon, 20 May 2013 05:14:35 +0300 Subject: [PATCH] * lib: add mu_str_parse_arglist + unit tests --- lib/mu-str.c | 119 ++++++++++++++++++++++++++++++++++++++++ lib/mu-str.h | 15 +++++ lib/tests/test-mu-str.c | 30 +++++++++- 3 files changed, 161 insertions(+), 3 deletions(-) diff --git a/lib/mu-str.c b/lib/mu-str.c index 85e040b0..feded3d0 100644 --- a/lib/mu-str.c +++ b/lib/mu-str.c @@ -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: '+:' (%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; +} diff --git a/lib/mu-str.h b/lib/mu-str.h index 0ab8bd18..99684d83 100644 --- a/lib/mu-str.h +++ b/lib/mu-str.h @@ -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 : arguments, where 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 * diff --git a/lib/tests/test-mu-str.c b/lib/tests/test-mu-str.c index 8cc84e4f..f23cc0a7 100644 --- a/lib/tests/test-mu-str.c +++ b/lib/tests/test-mu-str.c @@ -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);