unsigned int i;
int rc;
- rc = vsnprintf(buf, sizeof(buf), fmt, args);
+ rc = vsnprintf_internal(buf, sizeof(buf), fmt, args, LF_TO_CRLF);
if ( rc > (int)sizeof(buf) )
panic("vprintk() buffer overflow\n");
/* Conversions */
#define UPPER (1u << 5)
#define SIGNED (1u << 6)
+/* Careful not to overlap with vsnprintf_internal() flags. */
/* Shorthand for ensuring str moves forwards, but not overruning the buffer. */
#define PUT(c) \
PUT(' ');
for ( i = 0; i < len; ++i )
+ {
+ if ( (flags & LF_TO_CRLF) && val[i] == '\n' )
+ PUT('\r');
PUT(val[i]);
+ }
while ( len < width-- )
PUT(' ');
width, precision, flags);
}
-int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+int vsnprintf_internal(char *buf, size_t size, const char *fmt, va_list args,
+ unsigned int caller_flags)
{
char *str = buf, *end = buf + size;
const char *spec_start = fmt; /* For rewinding on error. */
unsigned long long num;
- unsigned int base, flags = 0;
+ unsigned int base, flags = caller_flags;
int width = -1, precision = -1;
- char length_mod = 'i';
+ char c, length_mod = 'i';
/* Put regular characters into the destination. */
if ( *fmt != '%' )
{
- PUT(*fmt);
- continue;
+ c = *fmt;
+ goto put_char;
}
next_flag: /* Process any flags. */
continue;
case 'c': /* Unsigned char. */
- {
- unsigned char c = va_arg(args, int);
+ c = va_arg(args, int);
if ( !(flags & LEFT) )
while ( --width > 0 )
PUT(' ');
+ put_char:
+ if ( (flags & LF_TO_CRLF) && c == '\n' )
+ PUT('\r');
PUT(c);
while ( --width > 0 )
PUT(' ');
continue;
- }
case 's': /* String. */
str = fmt_string(str, end, va_arg(args, const char *),
size_t strnlen(const char *str, size_t max);
+/*
+ * Internal version of vsnprintf(), taking extra control flags.
+ *
+ * LF_TO_CRLF causes "\n" to be expanded to "\r\n" in the output buffer.
+ */
+#define LF_TO_CRLF (1u << 7)
int __printf(3, 0)
- vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+ vsnprintf_internal(char *buf, size_t size, const char *fmt, va_list args,
+ unsigned int flags);
+
+static inline int __printf(3, 0)
+ vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ return vsnprintf_internal(buf, size, fmt, args, 0);
+}
int __printf(3, 4)
snprintf(char *buf, size_t size, const char *fmt, ...);
xtf_failure("Fail: xtf_init_grant_table(2) returned %d\n", rc);
}
+static void test_vsnprintf_crlf_one(const char *fmt, ...)
+{
+ va_list args;
+
+ char buf[4];
+ int rc;
+
+ va_start(args, fmt);
+ rc = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ if ( rc != 1 )
+ return xtf_failure("Fail: '%s', expected length 1, got %d\n", fmt, rc);
+ if ( strcmp(buf, "\n") )
+ return xtf_failure("Fail: '%s', expected \"\\n\", got %*ph\n",
+ fmt, (int)sizeof(buf), buf);
+
+ va_start(args, fmt);
+ rc = vsnprintf_internal(buf, sizeof(buf), fmt, args, LF_TO_CRLF);
+ va_end(args);
+
+ if ( rc != 2 )
+ return xtf_failure("Fail: '%s', expected length 2, got %d\n", fmt, rc);
+ if ( strcmp(buf, "\r\n") )
+ return xtf_failure("Fail: '%s', expected \"\\r\\n\", got %*ph\n",
+ fmt, (int)sizeof(buf), buf);
+}
+
+static void test_vsnprintf_crlf(void)
+{
+ printk("Test: vsnprintf() with CRLF expansion\n");
+
+ test_vsnprintf_crlf_one("\n");
+ test_vsnprintf_crlf_one("%c", '\n');
+ test_vsnprintf_crlf_one("%s", "\n");
+}
+
void test_main(void)
{
/*
test_extable_handler();
test_custom_idte();
test_driver_init();
+ test_vsnprintf_crlf();
if ( has_xenstore )
test_xenstore();