core: add nm_match_spec_split() function

There are currently three device spec properties: 'main.ignore-carrier',
'main.no-auto-default' and 'keyfile.unmanaged-devices'.

The first two, called g_key_file_parse_value_as_string() to split
the string into individual device specs. This uses ',' as separator
and supports escaping using '\\'.

'keyfile.unmanaged-devices' is split using ',' or ';' as separator
without supporting escaping.

Add a new function nm_match_spec_split(), to unify these two behaviors
and support both formats. That is, both previous formats are mostly
supported, but obviously there are some behavioral changes if the string
contains one of '\\', ',', or ';'.

nm_match_spec_split() is copied from glibs g_key_file_parse_value_as_string()
and adjusted.
This commit is contained in:
Thomas Haller
2015-02-09 16:57:14 +01:00
parent 5c2e1afd1b
commit 3bcc5e4bd0
3 changed files with 85 additions and 9 deletions

View File

@@ -1061,6 +1061,74 @@ nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels)
return match; return match;
} }
GSList *
nm_match_spec_split (const char *value)
{
char *string_value, *p, *q0, *q;
GSList *pieces = NULL;
if (!value || !*value)
return NULL;
/* Copied from glibs g_key_file_parse_value_as_string() function
* and adjusted. */
string_value = g_new (gchar, strlen (value) + 1);
p = (gchar *) value;
q0 = q = string_value;
while (*p) {
if (*p == '\\') {
p++;
switch (*p) {
case 's':
*q = ' ';
break;
case 'n':
*q = '\n';
break;
case 't':
*q = '\t';
break;
case 'r':
*q = '\r';
break;
case '\\':
*q = '\\';
break;
case '\0':
break;
default:
if (NM_IN_SET (*p, ',', ';'))
*q = *p;
else {
*q++ = '\\';
*q = *p;
}
break;
}
} else {
*q = *p;
if (NM_IN_SET (*p, ',', ';')) {
if (q0 < q)
pieces = g_slist_prepend (pieces, g_strndup (q0, q - q0));
q0 = q + 1;
}
}
if (*p == '\0')
break;
q++;
p++;
}
*q = '\0';
if (q0 < q)
pieces = g_slist_prepend (pieces, g_strndup (q0, q - q0));
g_free (string_value);
return g_slist_reverse (pieces);
}
const char * const char *
nm_utils_get_shared_wifi_permission (NMConnection *connection) nm_utils_get_shared_wifi_permission (NMConnection *connection)
{ {

View File

@@ -105,6 +105,7 @@ typedef enum {
NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr);
NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels);
NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name); NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name);
GSList *nm_match_spec_split (const char *value);
const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); const char *nm_utils_get_shared_wifi_permission (NMConnection *connection);

View File

@@ -806,17 +806,13 @@ static void
test_match_spec_ifname (const char *spec_str, const char **matches, const char **neg_matches) test_match_spec_ifname (const char *spec_str, const char **matches, const char **neg_matches)
{ {
const char *m; const char *m;
char **spec_str_split;
GSList *specs, *specs_reverse = NULL; GSList *specs, *specs_reverse = NULL;
guint i; guint i;
g_assert (spec_str); g_assert (spec_str);
spec_str_split = g_strsplit_set (spec_str, ";,", -1);
for (i = 0; spec_str_split[i]; i++) { specs = nm_match_spec_split (spec_str);
if (spec_str_split[i]) specs_reverse = g_slist_reverse (g_slist_copy (specs));
specs_reverse = g_slist_prepend (specs_reverse, spec_str_split[i]);
}
specs = g_slist_reverse (g_slist_copy (specs_reverse));
for (i = 0; matches && matches[i]; i++) { for (i = 0; matches && matches[i]; i++) {
g_assert (nm_match_spec_interface_name (specs, matches[i]) == NM_MATCH_SPEC_MATCH); g_assert (nm_match_spec_interface_name (specs, matches[i]) == NM_MATCH_SPEC_MATCH);
@@ -836,8 +832,7 @@ test_match_spec_ifname (const char *spec_str, const char **matches, const char *
} }
g_slist_free (specs_reverse); g_slist_free (specs_reverse);
g_slist_free (specs); g_slist_free_full (specs, g_free);
g_strfreev (spec_str_split);
} }
static void static void
@@ -874,6 +869,18 @@ test_nm_match_spec_interface_name (void)
test_match_spec_ifname ("interface-name:em*,except:interface-name:=em*", test_match_spec_ifname ("interface-name:em*,except:interface-name:=em*",
S ("em", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"), S ("em", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"),
S ("em*")); S ("em*"));
test_match_spec_ifname ("aa,bb,cc\\,dd,e,,",
S ("aa", "bb", "cc,dd", "e"),
NULL);
test_match_spec_ifname ("aa;bb;cc\\;dd;e,;",
S ("aa", "bb", "cc;dd", "e"),
NULL);
test_match_spec_ifname ("interface-name:em\\;1,em\\,2,\\,,\\\\,,em\\\\x",
S ("em;1", "em,2", ",", "\\", "em\\x"),
NULL);
test_match_spec_ifname (" , interface-name:a, ,",
S (" ", " ", " interface-name:a"),
NULL);
#undef S #undef S
} }