extract-word.c revision 84ac7bea360cd369df26910e9685a7eed2327088
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2010 Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool backslash = false; /* whether we've just seen a backslash */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool separator = false; /* whether we've just seen a separator */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool start = true; /* false means we're looking at a value */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Bail early if called after last value or with no input */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Parses the first word of a string, and returns it in
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * *ret. Removes all quotes in the process. When parsing fails
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * (because of an uneven number of quotes or similar), leaves
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * the pointer *p at the first invalid character. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* We found a non-blank character, so we will always
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * want to return a string (even if it is empty),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * allocate it here. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If we find an unquoted trailing backslash and we're in
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Unbalanced quotes will only be allowed in EXTRACT_RELAX
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = cunescape_one(*p, (size_t) -1, &c, &u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (*p) += r - 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (quote) { /* inside either single or double quotes */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (c == quote) /* found the end quote */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (c == '\\')
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (c == '\\')
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char **p,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *rvalue) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Try to unquote it, if it fails, warn about it and try again but this
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * in invalid escape sequences. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = extract_first_word(p, ret, separators, flags);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int n = 0, i, c, r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Parses a number of words from a string, stripping any
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * quotes if necessary. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Count how many words are expected */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Read all words into a temporary array */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = newa0(char*, n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (c = 0; c < n; c++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = extract_first_word(p, &l[c], separators, flags);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (j = 0; j < c; j++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If we managed to parse all words, return them in the passed
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * in parameters */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < n; i++) {