add support for single-quoting to our printf implementation

this is for escaping shell commands, which we'll make use of in a
moment.
This commit is contained in:
Oswald Buddenhagen
2025-03-25 18:02:20 +01:00
parent 3f84075715
commit ff04e2ae09
2 changed files with 27 additions and 1 deletions

View File

@@ -38,6 +38,9 @@ main( void )
"%!s", "foo \"\\\x1b\t\a\b\v\f\r\n" );
test( "double-quoted w/ escapes & linebreak", "foo \\\"\\\\\\x1b\\t\\a\\b\\v\\f\\r\\n\n",
"%!&s", "foo \"\\\x1b\t\a\b\v\f\r\n" );
test( "shell-quoted string", "foo '\\'' bar", "%'s", "foo ' bar" );
test( "cut shell-quoted string", "foo '\\'' b", "%.*'s", 7, "foo ' bar" );
test( "uncut shell-quoted string", "foo '\\'' bar", "%.*'s", 20, "foo ' bar" );
test( "unsigned", "4123567890", "%u", 4123567890U );
test( "positive signed", "13", "%d", 13 );
test( "negative signed", "-17", "%d", -17 );

View File

@@ -194,6 +194,8 @@ sys_error( const char *msg, ... )
// Same as %\\s, but non-ASCII characters are (hex-)escaped as well.
// - %!&s
// Same as %!s, but linefeeds are also printed verbatim for legibility.
// - %'s
// Print single-quote-escaped string literals. No outer quotes are added.
// TODO: Trade off segments vs. buffer capacity dynamically.
#define QPRINTF_SEGS 16
@@ -254,6 +256,9 @@ xvprintf_core( const char *fmt, va_list ap, printf_cb cb, void *cb_aux )
escaped = 3;
c = *++fmt;
}
} else if (c == '\'') {
escaped = 10;
c = *++fmt;
}
if (c == 'c') {
if (d + 1 > ed)
@@ -262,7 +267,25 @@ xvprintf_core( const char *fmt, va_list ap, printf_cb cb, void *cb_aux )
*d++ = (char)va_arg( ap, int );
} else if (c == 's') {
s = va_arg( ap, const char * );
if (escaped) {
if (escaped == 10) {
char *bd = d;
for (l = 0; l < maxlen && (c = *s); l++, s++) {
if (c == '\'') {
if (d + 3 >= ed)
oob();
*d++ = '\'';
*d++ = '\\';
*d++ = '\'';
} else {
if (d >= ed)
oob();
}
*d++ = c;
}
l = d - bd;
if (l)
ADD_SEG( bd, l );
} else if (escaped) {
char *bd = d;
for (l = 0; l < maxlen && (c = *s); l++, s++) {
if (c == '\\' || c == '"') {