]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/escape.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
12 #include "alloc-util.h"
14 #include "hexdecoct.h"
18 int cescape_char(char c
, char *buf
) {
21 /* Needs space for 4 characters in the buffer */
67 /* For special chars we prefer octal over
68 * hexadecimal encoding, simply because glib's
69 * g_strescape() does the same */
70 if ((c
< ' ') || (c
>= 127)) {
72 *(buf
++) = octchar((unsigned char) c
>> 6);
73 *(buf
++) = octchar((unsigned char) c
>> 3);
74 *(buf
++) = octchar((unsigned char) c
);
83 char *cescape_length(const char *s
, size_t n
) {
89 /* Does C style string escaping. May be reversed with
92 r
= new(char, n
*4 + 1);
96 for (f
= s
, t
= r
; f
< s
+ n
; f
++)
97 t
+= cescape_char(*f
, t
);
104 char *cescape(const char *s
) {
107 return cescape_length(s
, strlen(s
));
110 int cunescape_one(const char *p
, size_t length
, char32_t
*ret
, bool *eight_bit
) {
117 /* Unescapes C style. Returns the unescaped character in ret.
118 * Sets *eight_bit to true if the escaped sequence either fits in
119 * one byte in UTF-8 or is a non-unicode literal byte and should
120 * instead be copied directly.
123 if (length
!= (size_t) -1 && length
< 1)
160 /* This is an extension of the XDG syntax files */
165 /* hexadecimal encoding */
168 if (length
!= (size_t) -1 && length
< 3)
179 /* Don't allow NUL bytes */
180 if (a
== 0 && b
== 0)
183 *ret
= (a
<< 4U) | b
;
190 /* C++11 style 16bit unicode */
196 if (length
!= (size_t) -1 && length
< 5)
199 for (i
= 0; i
< 4; i
++) {
200 a
[i
] = unhexchar(p
[1 + i
]);
205 c
= ((uint32_t) a
[0] << 12U) | ((uint32_t) a
[1] << 8U) | ((uint32_t) a
[2] << 4U) | (uint32_t) a
[3];
207 /* Don't allow 0 chars */
217 /* C++11 style 32bit unicode */
223 if (length
!= (size_t) -1 && length
< 9)
226 for (i
= 0; i
< 8; i
++) {
227 a
[i
] = unhexchar(p
[1 + i
]);
232 c
= ((uint32_t) a
[0] << 28U) | ((uint32_t) a
[1] << 24U) | ((uint32_t) a
[2] << 20U) | ((uint32_t) a
[3] << 16U) |
233 ((uint32_t) a
[4] << 12U) | ((uint32_t) a
[5] << 8U) | ((uint32_t) a
[6] << 4U) | (uint32_t) a
[7];
235 /* Don't allow 0 chars */
239 /* Don't allow invalid code points */
240 if (!unichar_is_valid(c
))
260 if (length
!= (size_t) -1 && length
< 3)
275 /* don't allow NUL bytes */
276 if (a
== 0 && b
== 0 && c
== 0)
279 /* Don't allow bytes above 255 */
280 m
= ((uint32_t) a
<< 6U) | ((uint32_t) b
<< 3U) | (uint32_t) c
;
297 int cunescape_length_with_prefix(const char *s
, size_t length
, const char *prefix
, UnescapeFlags flags
, char **ret
) {
305 /* Undoes C style string escaping, and optionally prefixes it. */
307 pl
= strlen_ptr(prefix
);
309 r
= new(char, pl
+length
+1);
314 memcpy(r
, prefix
, pl
);
316 for (f
= s
, t
= r
+ pl
; f
< s
+ length
; f
++) {
318 bool eight_bit
= false;
322 remaining
= s
+ length
- f
;
323 assert(remaining
> 0);
326 /* A literal, copy verbatim */
331 if (remaining
== 1) {
332 if (flags
& UNESCAPE_RELAX
) {
333 /* A trailing backslash, copy verbatim */
342 k
= cunescape_one(f
+ 1, remaining
- 1, &u
, &eight_bit
);
344 if (flags
& UNESCAPE_RELAX
) {
345 /* Invalid escape code, let's take it literal then */
356 /* One byte? Set directly as specified */
359 /* Otherwise encode as multi-byte UTF-8 */
360 t
+= utf8_encode_unichar(t
, u
);
369 int cunescape_length(const char *s
, size_t length
, UnescapeFlags flags
, char **ret
) {
370 return cunescape_length_with_prefix(s
, length
, NULL
, flags
, ret
);
373 int cunescape(const char *s
, UnescapeFlags flags
, char **ret
) {
374 return cunescape_length(s
, strlen(s
), flags
, ret
);
377 char *xescape(const char *s
, const char *bad
) {
381 /* Escapes all chars in bad, in addition to \ and all special
382 * chars, in \xFF style escaping. May be reversed with
385 r
= new(char, strlen(s
) * 4 + 1);
389 for (f
= s
, t
= r
; *f
; f
++) {
391 if ((*f
< ' ') || (*f
>= 127) ||
392 (*f
== '\\') || strchr(bad
, *f
)) {
395 *(t
++) = hexchar(*f
>> 4);
396 *(t
++) = hexchar(*f
);
406 char *octescape(const char *s
, size_t len
) {
410 /* Escapes all chars in bad, in addition to \ and " chars,
411 * in \nnn style escaping. */
413 r
= new(char, len
* 4 + 1);
417 for (f
= s
, t
= r
; f
< s
+ len
; f
++) {
419 if (*f
< ' ' || *f
>= 127 || IN_SET(*f
, '\\', '"')) {
421 *(t
++) = '0' + (*f
>> 6);
422 *(t
++) = '0' + ((*f
>> 3) & 8);
423 *(t
++) = '0' + (*f
& 8);
434 static char *strcpy_backslash_escaped(char *t
, const char *s
, const char *bad
, bool escape_tab_nl
) {
438 if (escape_tab_nl
&& IN_SET(*s
, '\n', '\t')) {
440 *(t
++) = *s
== '\n' ? 'n' : 't';
444 if (*s
== '\\' || strchr(bad
, *s
))
453 char *shell_escape(const char *s
, const char *bad
) {
456 r
= new(char, strlen(s
)*2+1);
460 t
= strcpy_backslash_escaped(r
, s
, bad
, false);
466 char* shell_maybe_quote(const char *s
, EscapeStyle style
) {
472 /* Encloses a string in quotes if necessary to make it OK as a shell
473 * string. Note that we treat benign UTF-8 characters as needing
474 * escaping too, but that should be OK. */
479 strchr(SHELL_NEED_QUOTES
, *p
))
485 r
= new(char, (style
== ESCAPE_POSIX
) + 1 + strlen(s
)*2 + 1 + 1);
490 if (style
== ESCAPE_BACKSLASH
)
492 else if (style
== ESCAPE_POSIX
) {
496 assert_not_reached("Bad EscapeStyle");
498 t
= mempcpy(t
, s
, p
- s
);
500 if (style
== ESCAPE_BACKSLASH
)
501 t
= strcpy_backslash_escaped(t
, p
, SHELL_NEED_ESCAPE
, false);
503 t
= strcpy_backslash_escaped(t
, p
, SHELL_NEED_ESCAPE_POSIX
, true);
505 if (style
== ESCAPE_BACKSLASH
)