From e3fa570c1bcfec695db12194c472a6ee9a3cce48 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Mar 2019 13:52:52 +0100 Subject: [PATCH] shared: add "strip" argument to _nm_utils_unescape_spaces() It's usually not necessary, because _nm_utils_unescape_spaces() gets called after nm_utils_strsplit_set(), which already removes the non-escaped spaces. Still, for completeness, this should be here. Also, because with this the function is useful for individual options (not delimiter separate list values), to support automatically dropping leading or trailing whitespace, but also support escaping them. --- clients/common/nm-meta-setting-desc.c | 2 +- libnm-core/tests/test-general.c | 79 +++++++++++++++---- shared/nm-utils/nm-shared-utils.c | 24 +++++- shared/nm-utils/nm-shared-utils.h | 2 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 2 +- 5 files changed, 87 insertions(+), 22 deletions(-) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 664d596733..1009908ba4 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -3229,7 +3229,7 @@ _set_fcn_match_interface_name (ARGS_SET_FCN) if (strv) { for (i = 0; strv[i]; i++) { nm_setting_match_add_interface_name (NM_SETTING_MATCH (setting), - _nm_utils_unescape_spaces ((char *) strv[i])); + _nm_utils_unescape_spaces ((char *) strv[i], TRUE)); } } return TRUE; diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 9fcf7d006c..876e48388a 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -7733,24 +7733,73 @@ test_nm_utils_escape_spaces (void) g_free (to_free); } +static void +_do_test_unescape_spaces (const char *in, const char *out) +{ + nm_auto_free_gstring GString *str_out = g_string_new (NULL); + nm_auto_free_gstring GString *str_in = g_string_new (NULL); + guint i; + + for (i = 0; i < 10; i++) { + + g_string_set_size (str_in, 0); + + g_string_append (str_in, in); + + if (i == 0) + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, FALSE), ==, out); + else if (i == 1) + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, TRUE), ==, out); + else { + bool do_strip = nmtst_get_rand_bool (); + guint n = nmtst_get_rand_int () % 20; + guint j; + + g_string_set_size (str_out, 0); + if (!do_strip) + g_string_append (str_out, out); + + for (j = 0; j < n; j++) { + gboolean append = nmtst_get_rand_bool (); + char ch = nmtst_rand_select (' ', '\t'); + + if (append && out[strlen (out) - 1] == '\\') + append = FALSE; + + g_string_insert_c (str_in, append ? -1 : 0, ch); + if (!do_strip) + g_string_insert_c (str_out, append ? -1 : 0, ch); + } + + if (do_strip) + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, TRUE), ==, out); + else + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, FALSE), ==, str_out->str); + } + } +} + static void test_nm_utils_unescape_spaces (void) { -#define CHECK_STR(in, out) \ - G_STMT_START { \ - gs_free char *str = g_strdup (in); \ - \ - g_assert_cmpstr (_nm_utils_unescape_spaces (str), ==, out); \ - } G_STMT_END - - CHECK_STR ("\\a", "\\a"); - CHECK_STR ("foobar", "foobar"); - CHECK_STR ("foo bar", "foo bar"); - CHECK_STR ("foo\\ bar", "foo bar"); - CHECK_STR ("foo\\", "foo\\"); - CHECK_STR ("\\\\\t", "\\\t"); - -#undef CHECK_STR + _do_test_unescape_spaces ("", ""); + _do_test_unescape_spaces ("\\", "\\"); + _do_test_unescape_spaces ("\\ ", " "); + _do_test_unescape_spaces ("\\\t", "\t"); + _do_test_unescape_spaces ("a", "a"); + _do_test_unescape_spaces ("\\a", "\\a"); + _do_test_unescape_spaces ("foobar", "foobar"); + _do_test_unescape_spaces ("foo bar", "foo bar"); + _do_test_unescape_spaces ("foo\\ bar", "foo bar"); + _do_test_unescape_spaces ("foo\\", "foo\\"); + _do_test_unescape_spaces ("\\\\", "\\\\"); + _do_test_unescape_spaces ("foo bar", "foo bar"); + _do_test_unescape_spaces ("\\ foo bar", " foo bar"); + _do_test_unescape_spaces ("\\ foo bar\\ ", " foo bar "); + _do_test_unescape_spaces ("\\\tfoo bar\\\t", "\tfoo bar\t"); + _do_test_unescape_spaces ("\\\tfoo bar \\\t", "\tfoo bar \t"); + _do_test_unescape_spaces ("\\\t", "\t"); + _do_test_unescape_spaces ("\\\t \\ ", "\t "); } /*****************************************************************************/ diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index ae6262143c..7789034de5 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -2458,20 +2458,36 @@ _nm_utils_escape_spaces (const char *str, char **to_free) } char * -_nm_utils_unescape_spaces (char *str) +_nm_utils_unescape_spaces (char *str, gboolean do_strip) { - guint i, j = 0; + gsize i = 0; + gsize j = 0; + gsize preserve_space_at = 0; if (!str) return NULL; - for (i = 0; str[i]; i++) { - if (str[i] == '\\' && IS_SPACE (str[i+1])) + if (do_strip) { + while (str[i] && IS_SPACE (str[i])) i++; + } + + for (; str[i]; i++) { + if ( str[i] == '\\' + && IS_SPACE (str[i+1])) { + preserve_space_at = j; + i++; + } str[j++] = str[i]; } str[j] = '\0'; + if (do_strip && j > 0) { + while ( --j > preserve_space_at + && IS_SPACE (str[j])) + str[j] = '\0'; + } + return str; } diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 51e57ee03f..6ed1bc574e 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -1085,7 +1085,7 @@ void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...); /*****************************************************************************/ const char *_nm_utils_escape_spaces (const char *str, char **to_free); -char *_nm_utils_unescape_spaces (char *str); +char *_nm_utils_unescape_spaces (char *str, gboolean do_strip); /*****************************************************************************/ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 03d2cb6330..7779319b7f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -1449,7 +1449,7 @@ make_match_setting (shvarFile *ifcfg) if (!s_match) s_match = (NMSettingMatch *) nm_setting_match_new (); nm_setting_match_add_interface_name (s_match, - _nm_utils_unescape_spaces ((char *) strv[i])); + _nm_utils_unescape_spaces ((char *) strv[i], TRUE)); } }