diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 1f6cda4f6..04ef2aa76 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1061,6 +1061,74 @@ nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels) 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 * nm_utils_get_shared_wifi_permission (NMConnection *connection) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index de691f138..4d797fafe 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -105,6 +105,7 @@ typedef enum { 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_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); diff --git a/src/tests/test-general.c b/src/tests/test-general.c index b26b0e2ae..21533cc74 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -806,17 +806,13 @@ static void test_match_spec_ifname (const char *spec_str, const char **matches, const char **neg_matches) { const char *m; - char **spec_str_split; GSList *specs, *specs_reverse = NULL; guint i; g_assert (spec_str); - spec_str_split = g_strsplit_set (spec_str, ";,", -1); - for (i = 0; spec_str_split[i]; i++) { - if (spec_str_split[i]) - specs_reverse = g_slist_prepend (specs_reverse, spec_str_split[i]); - } - specs = g_slist_reverse (g_slist_copy (specs_reverse)); + + specs = nm_match_spec_split (spec_str); + specs_reverse = g_slist_reverse (g_slist_copy (specs)); for (i = 0; matches && matches[i]; i++) { 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); - g_strfreev (spec_str_split); + g_slist_free_full (specs, g_free); } static void @@ -874,6 +869,18 @@ test_nm_match_spec_interface_name (void) 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*")); + 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 }