diff options
author | Filipe Brandenburger <filbranden@google.com> | 2015-06-02 21:08:24 -0700 |
---|---|---|
committer | Filipe Brandenburger <filbranden@google.com> | 2015-06-17 11:12:11 -0700 |
commit | d6293c070e6e4b83d8e7ec56e465b0b215d55d98 (patch) | |
tree | c30169db009cfe75bd8aa54e6c6ed3851738c5c8 /src/basic | |
parent | 05654e712f0ccfea7bbeb3e4de89861a670f974e (diff) |
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
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/util.c | 27 | ||||
-rw-r--r-- | src/basic/util.h | 5 |
2 files changed, 26 insertions, 6 deletions
diff --git a/src/basic/util.c b/src/basic/util.c index e0d1220153..46a48c4d60 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -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; diff --git a/src/basic/util.h b/src/basic/util.h index 7aca46d777..748f22f1a2 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -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); |