libmm-common: new helper key/value parser

This commit is contained in:
Aleksander Morgado
2012-02-11 19:08:12 +01:00
parent 46cbee191c
commit 7df5874a88
2 changed files with 153 additions and 1 deletions

View File

@@ -10,9 +10,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details: * 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 <gio/gio.h>
#include <ModemManager.h> #include <ModemManager.h>
@@ -314,3 +315,145 @@ mm_common_build_bands_any (void)
g_variant_new_uint32 (MM_MODEM_BAND_ANY)); g_variant_new_uint32 (MM_MODEM_BAND_ANY));
return g_variant_builder_end (&builder); 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;
}

View File

@@ -46,4 +46,13 @@ GVariant *mm_common_bands_garray_to_variant (GArray *array);
GVariant *mm_common_build_bands_any (void); GVariant *mm_common_build_bands_any (void);
GVariant *mm_common_build_bands_unknown (void); GVariant *mm_common_build_bands_unknown (void);
typedef gboolean (*MMParseKeyValueForeachFn) (const gchar *key,
const gchar *value,
gpointer user_data);
gboolean mm_common_parse_key_value_string (const gchar *str,
GError **error,
MMParseKeyValueForeachFn callback,
gpointer user_data);
#endif /* MM_COMMON_HELPERS_H */ #endif /* MM_COMMON_HELPERS_H */