libnm-core/utils: add some special properties for the attributes

"no_value" indicates that the the attribute is a single word, not a
key=value pair. If the type is BOOLEAN then the attribute is considered
true, if it's a STRING then the key is used instead of a value.

"consumes_rest" indicates that the particular key takes the unparseable
tail of the string for a value.

This allows parsing tc-style strings. Consider this filter:

              ,------ regular key/value pair
       ,-----'----.
  root handle 1234: matchall action simple foo bar baz
    |                  |     `-----------.-----------'
    |                  |                 `- "", STRING, consumes_rest
    |                  `------------------- "kind", STRING, no_value
    `-------------------------------------- "root', BOOLEAN, no_value
This commit is contained in:
Lubomir Rintel 2017-12-04 11:40:32 +01:00
parent 48a619e62b
commit 47b1dc3828
3 changed files with 37 additions and 20 deletions

View file

@ -16,7 +16,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2007 - 2014 Red Hat, Inc.
* Copyright 2007 - 2017 Red Hat, Inc.
* Copyright 2007 - 2008 Novell, Inc.
*/
@ -1238,7 +1238,7 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
}
#define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \
&(NMVariantAttributeSpec) { name, type, v4, v6, str_type }
&(NMVariantAttributeSpec) { name, type, v4, v6, FALSE, FALSE, str_type }
static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = {
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),

View file

@ -15,7 +15,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2005 - 2014 Red Hat, Inc.
* Copyright 2005 - 2017 Red Hat, Inc.
*/
#ifndef __NM_UTILS_PRIVATE_H__
@ -33,6 +33,8 @@ struct _NMVariantAttributeSpec {
const GVariantType *type;
bool v4:1;
bool v6:1;
bool no_value:1;
bool consumes_rest:1;
char str_type;
};

View file

@ -5438,22 +5438,16 @@ nm_utils_parse_variant_attributes (const char *string,
break;
}
if (*sep != key_value_separator) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("missing key-value separator '%c'"), key_value_separator);
return NULL;
}
/* The attribute and key/value separators are the same. Look for the next one. */
if (ptr == sep)
goto next;
name = attribute_unescape (start, sep);
value = attribute_unescape (sep + 1, ptr);
for (s = spec; *s; s++) {
if (g_hash_table_contains (ht, (*s)->name))
continue;
if (nm_streq (name, (*s)->name))
break;
if ( (*s)->no_value
&& g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_STRING))
break;
}
if (!*s) {
@ -5466,12 +5460,33 @@ nm_utils_parse_variant_attributes (const char *string,
}
}
if ((*s)->no_value) {
if ((*s)->consumes_rest) {
value = g_strdup (start);
ptr = strchr (start, '\0');
} else {
value = g_steal_pointer (&name);
}
} else {
if (*sep != key_value_separator) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("missing key-value separator '%c' after '%s'"), key_value_separator, name);
return NULL;
}
/* The attribute and key/value separators are the same. Look for the next one. */
if (ptr == sep)
goto next;
value = attribute_unescape (sep + 1, ptr);
}
if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_UINT32)) {
gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
if (num == -1) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("invalid uint32 value '%s' for attribute '%s'"), value, name);
_("invalid uint32 value '%s' for attribute '%s'"), value, (*s)->name);
return NULL;
}
variant = g_variant_new_uint32 (num);
@ -5480,17 +5495,17 @@ nm_utils_parse_variant_attributes (const char *string,
if (num == -1) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("invalid uint8 value '%s' for attribute '%s'"), value, name);
_("invalid uint8 value '%s' for attribute '%s'"), value, (*s)->name);
return NULL;
}
variant = g_variant_new_byte ((guchar) num);
} else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BOOLEAN)) {
int b;
b = _nm_utils_ascii_str_to_bool (value, -1);
b = (*s)->no_value ? TRUE :_nm_utils_ascii_str_to_bool (value, -1);
if (b == -1) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("invalid boolean value '%s' for attribute '%s'"), value, name);
_("invalid boolean value '%s' for attribute '%s'"), value, (*s)->name);
return NULL;
}
variant = g_variant_new_boolean (b);
@ -5498,12 +5513,12 @@ nm_utils_parse_variant_attributes (const char *string,
variant = g_variant_new_take_string (g_steal_pointer (&value));
} else {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("unsupported attribute '%s' of type '%s'"), name,
_("unsupported attribute '%s' of type '%s'"), (*s)->name,
(char *) (*s)->type);
return NULL;
}
g_hash_table_insert (ht, g_steal_pointer (&name), variant);
g_hash_table_insert (ht, g_strdup ((*s)->name), variant);
start = NULL;
}
next: