diff options
Diffstat (limited to 'libmm-common/mm-common-helpers.c')
-rw-r--r-- | libmm-common/mm-common-helpers.c | 145 |
1 files changed, 144 insertions, 1 deletions
diff --git a/libmm-common/mm-common-helpers.c b/libmm-common/mm-common-helpers.c index 1d3361e1..98f85bc5 100644 --- a/libmm-common/mm-common-helpers.c +++ b/libmm-common/mm-common-helpers.c @@ -10,9 +10,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * - * Copyright (C) 2011 - Google, Inc. + * Copyright (C) 2011 - 2012 Google, Inc. */ +#include <string.h> #include <gio/gio.h> #include <ModemManager.h> @@ -314,3 +315,145 @@ mm_common_build_bands_any (void) g_variant_new_uint32 (MM_MODEM_BAND_ANY)); return g_variant_builder_end (&builder); } + +/* Expecting input as: + * key1=string,key2=true,key3=false... + * Strings may also be passed enclosed between double or single quotes, like: + * key1="this is a string", key2='and so is this' + */ +gboolean +mm_common_parse_key_value_string (const gchar *str, + GError **error, + MMParseKeyValueForeachFn callback, + gpointer user_data) +{ + GError *inner_error = NULL; + gchar *dup, *p, *key, *key_end, *value, *value_end, quote; + + g_return_val_if_fail (callback != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + dup = g_strdup (str); + + p = dup; + + while (TRUE) { + gboolean keep_iteration = FALSE; + + /* Skip leading spaces */ + while (*p && g_ascii_isspace (*p)) + p++; + + /* Key start */ + key = p; + if (!g_ascii_isalnum (*key)) { + inner_error = g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Key must start with alpha/num, starts with '%c'", + *key); + break; + } + + /* Key end */ + while (g_ascii_isalnum (*p) || (*p == '-') || (*p == '_')) + p++; + key_end = p; + if (key_end == key) { + inner_error = g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't find a proper key"); + break; + } + + /* Skip whitespaces, if any */ + while (*p && g_ascii_isspace (*p)) + p++; + + /* Equal sign must be here */ + if (*p != '=') { + inner_error = g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Couldn't find equal sign separator"); + break; + } + /* Skip the equal */ + p++; + + /* Skip whitespaces, if any */ + while (*p && g_ascii_isspace (*p)) + p++; + + /* Do we have a quote-enclosed string? */ + if (*p == '\"' || *p == '\'') { + quote = *p; + /* Skip the quote */ + p++; + /* Value start */ + value = p; + /* Find the closing quote */ + p = strchr (p, quote); + if (!p) { + inner_error = g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unmatched quotes in string value"); + break; + } + + /* Value end */ + value_end = p; + /* Skip the quote */ + p++; + } else { + /* Value start */ + value = p; + + /* Value end */ + while ((*p != ',') && (*p != '\0') && !g_ascii_isspace (*p)) + p++; + value_end = p; + } + + /* Note that we allow value == value_end here */ + + /* Skip whitespaces, if any */ + while (*p && g_ascii_isspace (*p)) + p++; + + /* If a comma is found, we should keep the iteration */ + if (*p == ',') { + /* skip the comma */ + p++; + keep_iteration = TRUE; + } + + /* Got key and value, prepare them and run the callback */ + *value_end = '\0'; + *key_end = '\0'; + if (!callback (key, value, user_data)) { + /* We were told to abort */ + break; + } + + if (keep_iteration) + continue; + + /* Check if no more key/value pairs expected */ + if (*p == '\0') + break; + + inner_error = g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unexpected content (%s) after value", + p); + break; + } + + g_free (dup); + + if (inner_error) { + g_propagate_error (error, inner_error); + return FALSE; + } + + return TRUE; +} |