util: New flag UNQUOTE_UNESCAPE_RELAX for unquote_first_word
The new flag UNQUOTE_UNESCAPE_RELAX preserves unrecognized escape sequences verbatim in unquote_first_word, either when it's a trailing backslash (similar to UNQUOTE_RELAX, but in this case keep the extra backslash in the output) or in the middle of a sequence string. Add unit test cases to ensure the new flag works as expected and to prevent regressions from being introduced. Tested with a follow up commit converting config_parse_exec() to start using unquote_first_word, in which case this flags makes it possible to preserve unrecognized escape sequences. Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
This commit is contained in:
+23
-4
@@ -5246,21 +5246,39 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
case SINGLE_QUOTE_ESCAPE:
|
||||
case DOUBLE_QUOTE_ESCAPE:
|
||||
case VALUE_ESCAPE:
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+7))
|
||||
return -ENOMEM;
|
||||
|
||||
if (c == 0) {
|
||||
if ((flags & UNQUOTE_CUNESCAPE_RELAX) &&
|
||||
(state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) {
|
||||
/* If we find an unquoted trailing backslash and we're in
|
||||
* UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the
|
||||
* output.
|
||||
*
|
||||
* Unbalanced quotes will only be allowed in UNQUOTE_RELAX
|
||||
* mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them.
|
||||
*/
|
||||
s[sz++] = '\\';
|
||||
goto finish;
|
||||
}
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
goto finish;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+7))
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags & UNQUOTE_CUNESCAPE) {
|
||||
uint32_t u;
|
||||
|
||||
r = cunescape_one(*p, (size_t) -1, &c, &u);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
if (flags & UNQUOTE_CUNESCAPE_RELAX) {
|
||||
s[sz++] = '\\';
|
||||
s[sz++] = c;
|
||||
goto end_escape;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
(*p) += r - 1;
|
||||
|
||||
@@ -5271,6 +5289,7 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
} else
|
||||
s[sz++] = c;
|
||||
|
||||
end_escape:
|
||||
state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE :
|
||||
(state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE :
|
||||
VALUE;
|
||||
|
||||
+3
-2
@@ -839,8 +839,9 @@ int is_dir(const char *path, bool follow);
|
||||
int is_device_node(const char *path);
|
||||
|
||||
typedef enum UnquoteFlags {
|
||||
UNQUOTE_RELAX = 1,
|
||||
UNQUOTE_CUNESCAPE = 2,
|
||||
UNQUOTE_RELAX = 1,
|
||||
UNQUOTE_CUNESCAPE = 2,
|
||||
UNQUOTE_CUNESCAPE_RELAX = 4,
|
||||
} UnquoteFlags;
|
||||
|
||||
int unquote_first_word(const char **p, char **ret, UnquoteFlags flags);
|
||||
|
||||
Reference in New Issue
Block a user