util: change unquote_*_word to extract_*_word

It now takes a separators argument, which defaults to WHITESPACE if NULL
is passed.
This commit is contained in:
Richard Maw 2015-06-23 16:20:53 +00:00
parent 53f0db7177
commit 6868560773
11 changed files with 157 additions and 122 deletions

4
TODO
View File

@ -267,7 +267,7 @@ Features:
* maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment=
* code cleanup: retire FOREACH_WORD_QUOTED, port to unquote_first_word() loops instead
* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead
* introduce systemd-timesync-wait.service or so to sync on an NTP fix?
@ -303,7 +303,7 @@ Features:
* exponential backoff in timesyncd and resolved when we cannot reach a server
* unquote_many_words() should probably be used by a lot of code that
* extract_many_words() should probably be used by a lot of code that
currently uses FOREACH_WORD and friends. For example, most conf
parsing callbacks should use it.

View File

@ -550,7 +550,7 @@ char **replace_env_argv(char **argv, char **env) {
if (e) {
int r;
r = strv_split_quoted(&m, e, UNQUOTE_RELAX);
r = strv_split_quoted(&m, e, EXTRACT_RELAX);
if (r < 0) {
ret[k] = NULL;
strv_free(ret);

View File

@ -278,7 +278,7 @@ char **strv_split_newlines(const char *s) {
return l;
}
int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) {
int strv_split_quoted(char ***t, const char *s, ExtractFlags flags) {
size_t n = 0, allocated = 0;
_cleanup_strv_free_ char **l = NULL;
int r;
@ -289,7 +289,7 @@ int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) {
for (;;) {
_cleanup_free_ char *word = NULL;
r = unquote_first_word(&s, &word, flags);
r = extract_first_word(&s, &word, NULL, flags);
if (r < 0)
return r;
if (r == 0)

View File

@ -73,7 +73,7 @@ static inline bool strv_isempty(char * const *l) {
char **strv_split(const char *s, const char *separator);
char **strv_split_newlines(const char *s);
int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags);
int strv_split_quoted(char ***t, const char *s, ExtractFlags flags);
char *strv_join(char **l, const char *separator);
char *strv_join_quoted(char **l);

View File

@ -4843,7 +4843,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
_cleanup_free_ char *word = NULL;
char *value = NULL;
r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
r = extract_first_word(&p, &word, NULL, EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)
@ -4883,7 +4883,7 @@ int get_proc_cmdline_key(const char *key, char **value) {
_cleanup_free_ char *word = NULL;
const char *e;
r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
r = extract_first_word(&p, &word, NULL, EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)
@ -5698,7 +5698,7 @@ int is_device_node(const char *path) {
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
int r;
@ -5711,12 +5711,15 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
SINGLE_QUOTE_ESCAPE,
DOUBLE_QUOTE,
DOUBLE_QUOTE_ESCAPE,
SPACE,
SEPARATOR,
} state = START;
assert(p);
assert(ret);
if (!separators)
separators = WHITESPACE;
/* Bail early if called after last value or with no input */
if (!*p)
goto finish_force_terminate;
@ -5734,7 +5737,7 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
case START:
if (c == 0)
goto finish_force_terminate;
else if (strchr(WHITESPACE, c))
else if (strchr(separators, c))
break;
state = VALUE;
@ -5755,8 +5758,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -ENOMEM;
state = DOUBLE_QUOTE;
} else if (strchr(WHITESPACE, c))
state = SPACE;
} else if (strchr(separators, c))
state = SEPARATOR;
else {
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@ -5768,7 +5771,7 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
case SINGLE_QUOTE:
if (c == 0) {
if (flags & UNQUOTE_RELAX)
if (flags & EXTRACT_RELAX)
goto finish_force_terminate;
return -EINVAL;
} else if (c == '\'')
@ -5807,29 +5810,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -ENOMEM;
if (c == 0) {
if ((flags & UNQUOTE_CUNESCAPE_RELAX) &&
(state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) {
if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
(state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
/* If we find an unquoted trailing backslash and we're in
* UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the
* EXTRACT_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.
* Unbalanced quotes will only be allowed in EXTRACT_RELAX
* mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
*/
s[sz++] = '\\';
goto finish_force_terminate;
}
if (flags & UNQUOTE_RELAX)
if (flags & EXTRACT_RELAX)
goto finish_force_terminate;
return -EINVAL;
}
if (flags & UNQUOTE_CUNESCAPE) {
if (flags & EXTRACT_CUNESCAPE) {
uint32_t u;
r = cunescape_one(*p, (size_t) -1, &c, &u);
if (r < 0) {
if (flags & UNQUOTE_CUNESCAPE_RELAX) {
if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\';
s[sz++] = c;
goto end_escape;
@ -5852,10 +5855,10 @@ end_escape:
VALUE;
break;
case SPACE:
case SEPARATOR:
if (c == 0)
goto finish;
if (!strchr(WHITESPACE, c))
if (!strchr(separators, c))
goto finish;
break;
@ -5880,26 +5883,27 @@ finish:
return 1;
}
int unquote_first_word_and_warn(
int extract_first_word_and_warn(
const char **p,
char **ret,
UnquoteFlags flags,
const char *separators,
ExtractFlags flags,
const char *unit,
const char *filename,
unsigned line,
const char *rvalue) {
/* Try to unquote it, if it fails, warn about it and try again but this
* time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim
* time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
* in invalid escape sequences. */
const char *save;
int r;
save = *p;
r = unquote_first_word(p, ret, flags);
if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) {
/* Retry it with UNQUOTE_CUNESCAPE_RELAX. */
r = extract_first_word(p, ret, separators, flags);
if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
/* Retry it with EXTRACT_CUNESCAPE_RELAX. */
*p = save;
r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX);
r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
@ -5910,7 +5914,7 @@ int unquote_first_word_and_warn(
return r;
}
int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
va_list ap;
char **l;
int n = 0, i, c, r;
@ -5936,7 +5940,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
l = newa0(char*, n);
for (c = 0; c < n; c++) {
r = unquote_first_word(p, &l[c], flags);
r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) {
int j;

View File

@ -854,15 +854,15 @@ int is_symlink(const char *path);
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_CUNESCAPE_RELAX = 4,
} UnquoteFlags;
typedef enum ExtractFlags {
EXTRACT_RELAX = 1,
EXTRACT_CUNESCAPE = 2,
EXTRACT_CUNESCAPE_RELAX = 4,
} ExtractFlags;
int unquote_first_word(const char **p, char **ret, UnquoteFlags flags);
int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_;
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
static inline void free_and_replace(char **s, char *v) {
free(*s);

View File

@ -552,7 +552,7 @@ int config_parse_exec(
semicolon = false;
r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
if (r <= 0)
return 0;
@ -627,7 +627,7 @@ int config_parse_exec(
}
/* Check for \; explicitly, to not confuse it with \\;
* or "\;" or "\\;" etc. unquote_first_word would
* or "\;" or "\\;" etc. extract_first_word would
* return the same for all of those. */
if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
p += 2;
@ -642,7 +642,7 @@ int config_parse_exec(
continue;
}
r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
if (r == 0)
break;
else if (r < 0)

View File

@ -101,7 +101,7 @@ static int condition_test_kernel_command_line(Condition *c) {
_cleanup_free_ char *word = NULL;
bool found;
r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
r = extract_first_word(&p, &word, NULL, EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)

View File

@ -1380,7 +1380,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
/* Parse columns */
p = buffer;
r = unquote_many_words(&p, 0, &action, &name, &id, &description, &home, NULL);
r = extract_many_words(&p, NULL, 0, &action, &name, &id, &description, &home, NULL);
if (r < 0) {
log_error("[%s:%u] Syntax error.", fname, line);
return r;

View File

@ -1487,349 +1487,379 @@ static void test_execute_directory(void) {
(void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_unquote_first_word(void) {
static void test_extract_first_word(void) {
const char *p, *original;
char *t;
p = original = "foobar waldo";
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 7);
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(isempty(p));
assert_se(unquote_first_word(&p, &t, 0) == 0);
assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
assert_se(!t);
assert_se(isempty(p));
p = original = "\"foobar\" \'waldo\'";
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 9);
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(isempty(p));
assert_se(unquote_first_word(&p, &t, 0) == 0);
assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
assert_se(!t);
assert_se(isempty(p));
p = original = "\"";
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'";
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'fooo";
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
assert_se(p == original + 5);
p = original = "\'fooo";
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo"));
free(t);
assert_se(isempty(p));
p = original = "yay\'foo\'bar";
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "yayfoobar"));
free(t);
assert_se(isempty(p));
p = original = " foobar ";
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(isempty(p));
p = original = " foo\\ba\\x6ar ";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
assert_se(streq(t, "foo\ba\x6ar"));
free(t);
assert_se(isempty(p));
p = original = " foo\\ba\\x6ar ";
assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "foobax6ar"));
free(t);
assert_se(isempty(p));
p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
assert_se(streq(t, "föo"));
free(t);
assert_se(p == original + 13);
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
assert_se(streq(t, "pi\360\237\222\251le"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
assert_se(p == original + 5);
p = original = "\"foo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo"));
free(t);
assert_se(isempty(p));
p = original = "foo::bar";
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
assert_se(streq(t, "foo"));
free(t);
assert_se(p == original + 5);
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
assert_se(streq(t, "bar"));
free(t);
assert_se(isempty(p));
assert_se(extract_first_word(&p, &t, ":", 0) == 0);
assert_se(!t);
assert_se(isempty(p));
p = original = "foo\\:bar::waldo";
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
assert_se(streq(t, "foo:bar"));
free(t);
assert_se(p == original + 10);
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
assert_se(streq(t, "waldo"));
free(t);
assert_se(isempty(p));
assert_se(extract_first_word(&p, &t, ":", 0) == 0);
assert_se(!t);
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
assert_se(p == original + 5);
p = original = "\"foo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo\\"));
free(t);
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo\\"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
assert_se(p == original + 5);
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\ bar"));
free(t);
assert_se(p == original + 10);
p = original = "\\w+@\\K[\\d.]+";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
assert_se(p == original + 1);
p = original = "\\w+@\\K[\\d.]+";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
free(t);
assert_se(isempty(p));
p = original = "\\w+\\b";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "\\w+\b"));
free(t);
assert_se(isempty(p));
p = original = "-N ''";
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, "-N"));
free(t);
assert_se(p == original + 3);
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
assert_se(streq(t, ""));
free(t);
assert_se(isempty(p));
}
static void test_unquote_first_word_and_warn(void) {
static void test_extract_first_word_and_warn(void) {
const char *p, *original;
char *t;
p = original = "foobar waldo";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 7);
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(isempty(p));
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
assert_se(!t);
assert_se(isempty(p));
p = original = "\"foobar\" \'waldo\'";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 9);
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(isempty(p));
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
assert_se(!t);
assert_se(isempty(p));
p = original = "\"";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'fooo";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(p == original + 5);
p = original = "\'fooo";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo"));
free(t);
assert_se(isempty(p));
p = original = " foo\\ba\\x6ar ";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "foo\ba\x6ar"));
free(t);
assert_se(isempty(p));
p = original = " foo\\ba\\x6ar ";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "foobax6ar"));
free(t);
assert_se(isempty(p));
p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "föo"));
free(t);
assert_se(p == original + 13);
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "pi\360\237\222\251le"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == -EINVAL);
assert_se(p == original + 5);
p = original = "\"foo\\";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "foo"));
free(t);
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
assert_se(p == original + 5);
p = original = "\"foo\\";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "foo"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "fooo\\ bar"));
free(t);
assert_se(p == original + 10);
p = original = "\\w+@\\K[\\d.]+";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
free(t);
assert_se(isempty(p));
p = original = "\\w+\\b";
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
assert_se(streq(t, "\\w+\b"));
free(t);
assert_se(isempty(p));
}
static void test_unquote_many_words(void) {
static void test_extract_many_words(void) {
const char *p, *original;
char *a, *b, *c;
p = original = "foobar waldi piep";
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 3);
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
assert_se(isempty(p));
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
@ -1839,7 +1869,7 @@ static void test_unquote_many_words(void) {
free(c);
p = original = "'foobar' wa\"ld\"i ";
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 2);
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
assert_se(isempty(p));
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
@ -1848,31 +1878,31 @@ static void test_unquote_many_words(void) {
free(b);
p = original = "";
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0);
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
assert_se(isempty(p));
assert_se(streq_ptr(a, NULL));
assert_se(streq_ptr(b, NULL));
assert_se(streq_ptr(c, NULL));
p = original = " ";
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0);
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
assert_se(isempty(p));
assert_se(streq_ptr(a, NULL));
assert_se(streq_ptr(b, NULL));
assert_se(streq_ptr(c, NULL));
p = original = "foobar";
assert_se(unquote_many_words(&p, 0, NULL) == 0);
assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
assert_se(p == original);
p = original = "foobar waldi";
assert_se(unquote_many_words(&p, 0, &a, NULL) == 1);
assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
assert_se(p == original+7);
assert_se(streq_ptr(a, "foobar"));
free(a);
p = original = " foobar ";
assert_se(unquote_many_words(&p, 0, &a, NULL) == 1);
assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
assert_se(isempty(p));
assert_se(streq_ptr(a, "foobar"));
free(a);
@ -2149,9 +2179,9 @@ int main(int argc, char *argv[]) {
test_search_and_fopen_nulstr();
test_glob_exists();
test_execute_directory();
test_unquote_first_word();
test_unquote_first_word_and_warn();
test_unquote_many_words();
test_extract_first_word();
test_extract_first_word_and_warn();
test_extract_many_words();
test_parse_proc_cmdline();
test_raw_clone();
test_same_fd();

View File

@ -662,7 +662,7 @@ static int parse_xattrs_from_arg(Item *i) {
for (;;) {
_cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL, *xattr_replaced = NULL;
r = unquote_first_word(&p, &xattr, UNQUOTE_CUNESCAPE);
r = extract_first_word(&p, &xattr, NULL, EXTRACT_CUNESCAPE);
if (r < 0)
log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
if (r <= 0)
@ -1760,8 +1760,9 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
assert(line >= 1);
assert(buffer);
r = unquote_many_words(
r = extract_many_words(
&buffer,
NULL,
0,
&action,
&path,