84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering This file is part of systemd.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright 2010 Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is free software; you can redistribute it and/or modify it
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering under the terms of the GNU Lesser General Public License as published by
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering (at your option) any later version.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is distributed in the hope that it will be useful, but
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Lesser General Public License for more details.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering You should have received a copy of the GNU Lesser General Public License
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringint extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering bool backslash = false; /* whether we've just seen a backslash */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Bail early if called after last value or with no input */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Parses the first word of a string, and returns it in
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * *ret. Removes all quotes in the process. When parsing fails
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * (because of an uneven number of quotes or similar), leaves
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * the pointer *p at the first invalid character. */
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
b85e1c2534ca3b396c2aaa7de384995b42d12e1bFilipe Brandenburger if (!GREEDY_REALLOC(s, allocated, sz+1))
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger for (;; (*p) ++, c = **p) {
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* We found a non-blank character, so we will always
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * want to return a string (even if it is empty),
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * allocate it here. */
93de9eb76d628cf731120d97332e03600c167271Filipe Brandenburger for (;; (*p) ++, c = **p) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* If we find an unquoted trailing backslash and we're in
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Unbalanced quotes will only be allowed in EXTRACT_RELAX
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek r = cunescape_one(*p, (size_t) -1, &u, &eight_bit);
3ff13c298d6d53293680c383768c3054fb9fcc30Filipe Brandenburger (*p) += r - 1;
3565e09594a9cd2786b5682ad13812491e6781c1Zbigniew Jędrzejewski-Szmek sz += utf8_encode_unichar(s + sz, u);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering } else if (quote) { /* inside either single or double quotes */
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger for (;; (*p) ++, c = **p) {
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger } else if (c == quote) { /* found the end quote */
c89f52ac6938374972253d8752ed65f3af0b3ef4Lennart Poettering } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger if (!GREEDY_REALLOC(s, allocated, sz+2))
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger for (;; (*p) ++, c = **p) {
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
c89f52ac6938374972253d8752ed65f3af0b3ef4Lennart Poettering } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger /* Skip additional coalesced separators. */
0247447e96f1385cf0c48e3e6b696214fbe36802Filipe Brandenburger for (;; (*p) ++, c = **p) {
27fc921b658adc5baa988c4c213888b016a60b18Filipe Brandenburger if (!GREEDY_REALLOC(s, allocated, sz+2))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char **p,
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char *rvalue) {
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering /* Try to unquote it, if it fails, warn about it and try again
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering * backslashes verbatim in invalid escape sequences. */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = extract_first_word(p, ret, separators, flags);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering /* It worked this time, hence it must have been an invalid escape sequence we could correct. */
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering /* If it's still EINVAL; then it must be unbalanced quoting, report this. */
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering /* Can be any error, report it */
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringint extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering int n = 0, i, c, r;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Parses a number of words from a string, stripping any
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * quotes if necessary. */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Count how many words are expected */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* Read all words into a temporary array */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering l = newa0(char*, n);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (c = 0; c < n; c++) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering r = extract_first_word(p, &l[c], separators, flags);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (j = 0; j < c; j++)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* If we managed to parse all words, return them in the passed
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * in parameters */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (i = 0; i < n; i++) {