commit 0079ec774a6e79b417a1f2daa1220d1c5df6e5b8
parent 57173bd289b370eeac8982bd2410144c3c1f87c3
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Tue, 3 May 2022 19:28:26 +0200
add escaping of non-printable & non-ASCII characters to xvasprintf()
Diffstat:
M | src/util.c | | | 46 | +++++++++++++++++++++++++++++++++++++++++++--- |
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/src/util.c b/src/util.c
@@ -189,6 +189,10 @@ sys_error( const char *msg, ... )
// Print backslash-escaped string literals. Note that this does not
// automatically add quotes around the printed string, so it is
// possible to concatenate multiple segments.
+// - %!s
+// Same as %\\s, but non-ASCII characters are (hex-)escaped as well.
+// - %!&s
+// Same as %!s, but linefeeds are also printed verbatim for legibility.
// TODO: Trade off segments vs. buffer capacity dynamically.
#define QPRINTF_SEGS 16
@@ -238,6 +242,13 @@ xvasprintf( const char *fmt, va_list ap )
if (c == '\\') {
escaped = 1;
c = *++fmt;
+ } else if (c == '!') {
+ escaped = 2;
+ c = *++fmt;
+ if (c == '&') {
+ escaped = 3;
+ c = *++fmt;
+ }
}
if (c == 'c') {
if (d + 1 > ed)
@@ -249,10 +260,39 @@ xvasprintf( const char *fmt, va_list ap )
if (escaped) {
char *bd = d;
for (l = 0; l < maxlen && (c = *s); l++, s++) {
- if (d + 2 > ed)
- oob();
- if (c == '\\' || c == '"')
+ if (c == '\\' || c == '"') {
+ if (d >= ed)
+ oob();
*d++ = '\\';
+ } else if (escaped >= 2 && (c < 32 || c > 126)) {
+ switch (c) {
+ case '\r': c = 'r'; break;
+ case '\t': c = 't'; break;
+ case '\a': c = 'a'; break;
+ case '\b': c = 'b'; break;
+ case '\v': c = 'v'; break;
+ case '\f': c = 'f'; break;
+ case '\n':
+ if (escaped == 2) {
+ c = 'n';
+ break;
+ }
+ if (d + 2 >= ed)
+ oob();
+ *d++ = '\\';
+ *d++ = 'n';
+ *d++ = c; // Keep the actual line break for legibility.
+ continue;
+ default:
+ d += nfsnprintf( d, ed - d, "\\x%02x", (uchar)c );
+ continue;
+ }
+ if (d >= ed)
+ oob();
+ *d++ = '\\';
+ }
+ if (d >= ed)
+ oob();
*d++ = c;
}
l = d - bd;