mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-26 18:10:08 +01:00
shared: add nm_utils_escaped_tokens_escape()
This escapes strings so that they can be concatenated with a delimiter
and without loss tokenized with nm_utils_escaped_tokens_split().
Note that this is similar to _nm_utils_escape_plain() and
_nm_utils_escape_spaces(). The difference is that
nm_utils_escaped_tokens_escape() also escapes the last trailing
whitespace. That means, if delimiters contains all NM_ASCII_SPACES, then
it is identical to _nm_utils_escape_spaces(). Otherwise, the trailing
space is treated specially. That is, because
nm_utils_escaped_tokens_split() uses NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP,
to strip leading and trailing whitespace. To still express a trailing
whitespace, the last whitespace must be escaped. Note that
NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP also honors escaping any whitespace
(not only at the last position), but when escaping we don't need to
escape them, because unescaped (non-trailing) whitespace are taken just
fine.
The pair nm_utils_escaped_tokens_split() and
nm_utils_escaped_tokens_escape() are proposed as default way of
tokenizing a list of items. For example, with
$ nmcli connection modify "$PROFILE" +ipv4.routing-rules 'priority 5 from 192.168.7.5/32 table 5, priority 6 iif a\, from 192.168.7.5/32 table 6'
Here we implement a to/from string function to handle one item
(nm_ip_routing_rule_{from,to}_string()). When such elements are combined with ',',
then we need to support an additional layer of escaping on top of that.
The advantage is that the indvidual to/from string functions are agnostic
to this second layer of escaping/tokenizing that nmcli employs to handle
a list of these items.
The disadvantage is that we possibly get multiple layers of backslash
escapings. That is only mitigated by the fact that nm_utils_escaped_tokens_*()
supports a syntax for which *most* characters don't need any special escaping.
Only delimiters, backslash, and the trailing space needs escaping, and
these are cases are expected to be few.
This commit is contained in:
parent
9522aaf226
commit
e206e3d4d8
2 changed files with 107 additions and 0 deletions
|
|
@ -1216,6 +1216,82 @@ done2:
|
|||
return ptr;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const char *
|
||||
nm_utils_escaped_tokens_escape (const char *str,
|
||||
const char *delimiters,
|
||||
char **out_to_free)
|
||||
{
|
||||
guint8 ch_lookup[256];
|
||||
char *ret;
|
||||
gsize str_len;
|
||||
gsize alloc_len;
|
||||
gsize n_escapes;
|
||||
gsize i, j;
|
||||
gboolean escape_trailing_space;
|
||||
|
||||
if (!delimiters) {
|
||||
nm_assert (delimiters);
|
||||
delimiters = NM_ASCII_SPACES;
|
||||
}
|
||||
|
||||
if (!str || str[0] == '\0') {
|
||||
*out_to_free = NULL;
|
||||
return str;
|
||||
}
|
||||
|
||||
_char_lookup_table_init (ch_lookup, delimiters);
|
||||
|
||||
/* also mark '\\' as requiring escaping. */
|
||||
ch_lookup[((guint8) '\\')] = 1;
|
||||
|
||||
n_escapes = 0;
|
||||
for (i = 0; str[i] != '\0'; i++) {
|
||||
if (_char_lookup_has (ch_lookup, str[i]))
|
||||
n_escapes++;
|
||||
}
|
||||
|
||||
str_len = i;
|
||||
nm_assert (str_len > 0 && strlen (str) == str_len);
|
||||
|
||||
escape_trailing_space = !_char_lookup_has (ch_lookup, str[str_len - 1])
|
||||
&& g_ascii_isspace (str[str_len - 1]);
|
||||
|
||||
if ( n_escapes == 0
|
||||
&& !escape_trailing_space) {
|
||||
*out_to_free = NULL;
|
||||
return str;
|
||||
}
|
||||
|
||||
alloc_len = str_len + n_escapes + ((gsize) escape_trailing_space) + 1;
|
||||
ret = g_new (char, alloc_len);
|
||||
|
||||
j = 0;
|
||||
for (i = 0; str[i] != '\0'; i++) {
|
||||
if (_char_lookup_has (ch_lookup, str[i])) {
|
||||
nm_assert (j < alloc_len);
|
||||
ret[j++] = '\\';
|
||||
}
|
||||
nm_assert (j < alloc_len);
|
||||
ret[j++] = str[i];
|
||||
}
|
||||
if (escape_trailing_space) {
|
||||
nm_assert (!_char_lookup_has (ch_lookup, ret[j - 1]) && g_ascii_isspace (ret[j - 1]));
|
||||
ret[j] = ret[j - 1];
|
||||
ret[j - 1] = '\\';
|
||||
j++;
|
||||
}
|
||||
|
||||
nm_assert (j == alloc_len - 1);
|
||||
ret[j] = '\0';
|
||||
|
||||
*out_to_free = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* nm_utils_strv_find_first:
|
||||
* @list: the strv list to search
|
||||
|
|
|
|||
|
|
@ -409,6 +409,37 @@ char **_nm_utils_strv_cleanup (char **strv,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline const char **
|
||||
nm_utils_escaped_tokens_split (const char *str,
|
||||
const char *delimiters)
|
||||
{
|
||||
return nm_utils_strsplit_set_full (str,
|
||||
delimiters,
|
||||
NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED
|
||||
| NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
|
||||
}
|
||||
|
||||
const char *nm_utils_escaped_tokens_escape (const char *str,
|
||||
const char *delimiters,
|
||||
char **out_to_free);
|
||||
|
||||
static inline GString *
|
||||
nm_utils_escaped_tokens_escape_gstr (const char *str,
|
||||
const char *delimiters,
|
||||
GString *gstring)
|
||||
{
|
||||
gs_free char *str_to_free = NULL;
|
||||
|
||||
nm_assert (str);
|
||||
nm_assert (gstring);
|
||||
|
||||
g_string_append (gstring,
|
||||
nm_utils_escaped_tokens_escape (str, delimiters, &str_to_free));
|
||||
return gstring;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define NM_UTILS_CHECKSUM_LENGTH_MD5 16
|
||||
#define NM_UTILS_CHECKSUM_LENGTH_SHA1 20
|
||||
#define NM_UTILS_CHECKSUM_LENGTH_SHA256 32
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue