libmm-common: new helper key/value parser
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
@@ -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 */
|
||||||
|
Reference in New Issue
Block a user