2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
26 #include "hexdecoct.h"
30 size_t cescape_char(char c, char *buf) {
77 /* For special chars we prefer octal over
78 * hexadecimal encoding, simply because glib's
79 * g_strescape() does the same */
80 if ((c < ' ') || (c >= 127)) {
82 *(buf++) = octchar((unsigned char) c >> 6);
83 *(buf++) = octchar((unsigned char) c >> 3);
84 *(buf++) = octchar((unsigned char) c);
93 char *cescape_length(const char *s, size_t n) {
99 /* Does C style string escaping. May be reversed with
102 r = new(char, n*4 + 1);
106 for (f = s, t = r; f < s + n; f++)
107 t += cescape_char(*f, t);
114 char *cescape(const char *s) {
117 return cescape_length(s, strlen(s));
120 int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) {
127 /* Unescapes C style. Returns the unescaped character in ret.
128 * Sets *eight_bit to true if the escaped sequence either fits in
129 * one byte in UTF-8 or is a non-unicode literal byte and should
130 * instead be copied directly.
133 if (length != (size_t) -1 && length < 1)
170 /* This is an extension of the XDG syntax files */
175 /* hexadecimal encoding */
178 if (length != (size_t) -1 && length < 3)
189 /* Don't allow NUL bytes */
190 if (a == 0 && b == 0)
193 *ret = (a << 4U) | b;
200 /* C++11 style 16bit unicode */
206 if (length != (size_t) -1 && length < 5)
209 for (i = 0; i < 4; i++) {
210 a[i] = unhexchar(p[1 + i]);
215 c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
217 /* Don't allow 0 chars */
227 /* C++11 style 32bit unicode */
233 if (length != (size_t) -1 && length < 9)
236 for (i = 0; i < 8; i++) {
237 a[i] = unhexchar(p[1 + i]);
242 c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
243 ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
245 /* Don't allow 0 chars */
249 /* Don't allow invalid code points */
250 if (!unichar_is_valid(c))
270 if (length != (size_t) -1 && length < 3)
285 /* don't allow NUL bytes */
286 if (a == 0 && b == 0 && c == 0)
289 /* Don't allow bytes above 255 */
290 m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
307 int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
315 /* Undoes C style string escaping, and optionally prefixes it. */
317 pl = prefix ? strlen(prefix) : 0;
319 r = new(char, pl+length+1);
324 memcpy(r, prefix, pl);
326 for (f = s, t = r + pl; f < s + length; f++) {
328 bool eight_bit = false;
332 remaining = s + length - f;
333 assert(remaining > 0);
336 /* A literal literal, copy verbatim */
341 if (remaining == 1) {
342 if (flags & UNESCAPE_RELAX) {
343 /* A trailing backslash, copy verbatim */
352 k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit);
354 if (flags & UNESCAPE_RELAX) {
355 /* Invalid escape code, let's take it literal then */
366 /* One byte? Set directly as specified */
369 /* Otherwise encode as multi-byte UTF-8 */
370 t += utf8_encode_unichar(t, u);
379 int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
380 return cunescape_length_with_prefix(s, length, NULL, flags, ret);
383 int cunescape(const char *s, UnescapeFlags flags, char **ret) {
384 return cunescape_length(s, strlen(s), flags, ret);
387 char *xescape(const char *s, const char *bad) {
391 /* Escapes all chars in bad, in addition to \ and all special
392 * chars, in \xFF style escaping. May be reversed with
395 r = new(char, strlen(s) * 4 + 1);
399 for (f = s, t = r; *f; f++) {
401 if ((*f < ' ') || (*f >= 127) ||
402 (*f == '\\') || strchr(bad, *f)) {
405 *(t++) = hexchar(*f >> 4);
406 *(t++) = hexchar(*f);
416 static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
420 if (*s == '\\' || strchr(bad, *s))
429 char *shell_escape(const char *s, const char *bad) {
432 r = new(char, strlen(s)*2+1);
436 t = strcpy_backslash_escaped(r, s, bad);
442 char *shell_maybe_quote(const char *s) {
448 /* Encloses a string in double quotes if necessary to make it
449 * OK as shell string. */
454 strchr(SHELL_NEED_QUOTES, *p))
460 r = new(char, 1+strlen(s)*2+1+1);
466 t = mempcpy(t, s, p - s);
468 t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);