xref: /kvm-unit-tests/lib/printf.c (revision 23b8916bf11daa5a147be0f31ae8fbfa81ae4713)
14b6da826SThomas Huth /*
24b6da826SThomas Huth  * libc printf and friends
34b6da826SThomas Huth  *
44b6da826SThomas Huth  * This code is free software; you can redistribute it and/or modify it
54b6da826SThomas Huth  * under the terms of the GNU Library General Public License version 2.
64b6da826SThomas Huth  */
74b6da826SThomas Huth 
87d36db35SAvi Kivity #include "libcflat.h"
97d36db35SAvi Kivity 
10cb12ecccSAndrew Jones #define BUFSZ 2000
11cb12ecccSAndrew Jones 
127d36db35SAvi Kivity typedef struct pstream {
137d36db35SAvi Kivity     char *buffer;
147d36db35SAvi Kivity     int remain;
157d36db35SAvi Kivity     int added;
167d36db35SAvi Kivity } pstream_t;
177d36db35SAvi Kivity 
182c978d9bSAndrew Jones typedef struct strprops {
192c978d9bSAndrew Jones     char pad;
202c978d9bSAndrew Jones     int npad;
218ef44442SRadim Krčmář     bool alternate;
222c978d9bSAndrew Jones } strprops_t;
232c978d9bSAndrew Jones 
247d36db35SAvi Kivity static void addchar(pstream_t *p, char c)
257d36db35SAvi Kivity {
267d36db35SAvi Kivity     if (p->remain) {
277d36db35SAvi Kivity 	*p->buffer++ = c;
287d36db35SAvi Kivity 	--p->remain;
297d36db35SAvi Kivity     }
307d36db35SAvi Kivity     ++p->added;
317d36db35SAvi Kivity }
327d36db35SAvi Kivity 
33*23b8916bSThomas Huth static void print_str(pstream_t *p, const char *s, strprops_t props)
347d36db35SAvi Kivity {
352c978d9bSAndrew Jones     const char *s_orig = s;
362c978d9bSAndrew Jones     int npad = props.npad;
372c978d9bSAndrew Jones 
382c978d9bSAndrew Jones     if (npad > 0) {
392c978d9bSAndrew Jones 	npad -= strlen(s_orig);
402c978d9bSAndrew Jones 	while (npad > 0) {
412c978d9bSAndrew Jones 	    addchar(p, props.pad);
422c978d9bSAndrew Jones 	    --npad;
432c978d9bSAndrew Jones 	}
442c978d9bSAndrew Jones     }
452c978d9bSAndrew Jones 
467d36db35SAvi Kivity     while (*s)
477d36db35SAvi Kivity 	addchar(p, *s++);
482c978d9bSAndrew Jones 
492c978d9bSAndrew Jones     if (npad < 0) {
502c978d9bSAndrew Jones 	props.pad = ' '; /* ignore '0' flag with '-' flag */
512c978d9bSAndrew Jones 	npad += strlen(s_orig);
522c978d9bSAndrew Jones 	while (npad < 0) {
532c978d9bSAndrew Jones 	    addchar(p, props.pad);
542c978d9bSAndrew Jones 	    ++npad;
552c978d9bSAndrew Jones 	}
562c978d9bSAndrew Jones     }
577d36db35SAvi Kivity }
587d36db35SAvi Kivity 
597d36db35SAvi Kivity static char digits[16] = "0123456789abcdef";
607d36db35SAvi Kivity 
61*23b8916bSThomas Huth static void print_int(pstream_t *ps, long long n, int base, strprops_t props)
627d36db35SAvi Kivity {
637d36db35SAvi Kivity     char buf[sizeof(long) * 3 + 2], *p = buf;
647d36db35SAvi Kivity     int s = 0, i;
657d36db35SAvi Kivity 
667d36db35SAvi Kivity     if (n < 0) {
677d36db35SAvi Kivity 	n = -n;
687d36db35SAvi Kivity 	s = 1;
697d36db35SAvi Kivity     }
707d36db35SAvi Kivity 
717d36db35SAvi Kivity     while (n) {
727d36db35SAvi Kivity 	*p++ = digits[n % base];
737d36db35SAvi Kivity 	n /= base;
747d36db35SAvi Kivity     }
757d36db35SAvi Kivity 
767d36db35SAvi Kivity     if (s)
777d36db35SAvi Kivity 	*p++ = '-';
787d36db35SAvi Kivity 
797d36db35SAvi Kivity     if (p == buf)
807d36db35SAvi Kivity 	*p++ = '0';
817d36db35SAvi Kivity 
827d36db35SAvi Kivity     for (i = 0; i < (p - buf) / 2; ++i) {
837d36db35SAvi Kivity 	char tmp;
847d36db35SAvi Kivity 
857d36db35SAvi Kivity 	tmp = buf[i];
867d36db35SAvi Kivity 	buf[i] = p[-1-i];
877d36db35SAvi Kivity 	p[-1-i] = tmp;
887d36db35SAvi Kivity     }
897d36db35SAvi Kivity 
907d36db35SAvi Kivity     *p = 0;
917d36db35SAvi Kivity 
922c978d9bSAndrew Jones     print_str(ps, buf, props);
937d36db35SAvi Kivity }
947d36db35SAvi Kivity 
95*23b8916bSThomas Huth static void print_unsigned(pstream_t *ps, unsigned long long n, int base,
962c978d9bSAndrew Jones 			   strprops_t props)
977d36db35SAvi Kivity {
988ef44442SRadim Krčmář     char buf[sizeof(long) * 3 + 3], *p = buf;
997d36db35SAvi Kivity     int i;
1007d36db35SAvi Kivity 
1017d36db35SAvi Kivity     while (n) {
1027d36db35SAvi Kivity 	*p++ = digits[n % base];
1037d36db35SAvi Kivity 	n /= base;
1047d36db35SAvi Kivity     }
1057d36db35SAvi Kivity 
1067d36db35SAvi Kivity     if (p == buf)
1077d36db35SAvi Kivity 	*p++ = '0';
1088ef44442SRadim Krčmář     else if (props.alternate && base == 16) {
109c9af8739SRadim Krčmář 	if (props.pad == '0') {
110c9af8739SRadim Krčmář 	    addchar(ps, '0');
111c9af8739SRadim Krčmář 	    addchar(ps, 'x');
112c9af8739SRadim Krčmář 
113c9af8739SRadim Krčmář 	    if (props.npad > 0)
114c9af8739SRadim Krčmář 		props.npad = MAX(props.npad - 2, 0);
115c9af8739SRadim Krčmář 	} else {
1168ef44442SRadim Krčmář 	    *p++ = 'x';
1178ef44442SRadim Krčmář 	    *p++ = '0';
1188ef44442SRadim Krčmář 	}
119c9af8739SRadim Krčmář     }
1207d36db35SAvi Kivity 
1217d36db35SAvi Kivity     for (i = 0; i < (p - buf) / 2; ++i) {
1227d36db35SAvi Kivity 	char tmp;
1237d36db35SAvi Kivity 
1247d36db35SAvi Kivity 	tmp = buf[i];
1257d36db35SAvi Kivity 	buf[i] = p[-1-i];
1267d36db35SAvi Kivity 	p[-1-i] = tmp;
1277d36db35SAvi Kivity     }
1287d36db35SAvi Kivity 
1297d36db35SAvi Kivity     *p = 0;
1307d36db35SAvi Kivity 
1312c978d9bSAndrew Jones     print_str(ps, buf, props);
1322c978d9bSAndrew Jones }
1332c978d9bSAndrew Jones 
1342c978d9bSAndrew Jones static int fmtnum(const char **fmt)
1352c978d9bSAndrew Jones {
1362c978d9bSAndrew Jones     const char *f = *fmt;
1372c978d9bSAndrew Jones     int len = 0, num;
1382c978d9bSAndrew Jones 
1392c978d9bSAndrew Jones     if (*f == '-')
1402c978d9bSAndrew Jones 	++f, ++len;
1412c978d9bSAndrew Jones 
1422c978d9bSAndrew Jones     while (*f >= '0' && *f <= '9')
1432c978d9bSAndrew Jones 	++f, ++len;
1442c978d9bSAndrew Jones 
1452c978d9bSAndrew Jones     num = atol(*fmt);
1462c978d9bSAndrew Jones     *fmt += len;
1472c978d9bSAndrew Jones     return num;
1487d36db35SAvi Kivity }
1497d36db35SAvi Kivity 
1507d36db35SAvi Kivity int vsnprintf(char *buf, int size, const char *fmt, va_list va)
1517d36db35SAvi Kivity {
1527d36db35SAvi Kivity     pstream_t s;
1537d36db35SAvi Kivity 
1547d36db35SAvi Kivity     s.buffer = buf;
1557d36db35SAvi Kivity     s.remain = size - 1;
1567d36db35SAvi Kivity     s.added = 0;
1577d36db35SAvi Kivity     while (*fmt) {
1587d36db35SAvi Kivity 	char f = *fmt++;
1597d36db35SAvi Kivity 	int nlong = 0;
1602c978d9bSAndrew Jones 	strprops_t props;
1612c978d9bSAndrew Jones 	memset(&props, 0, sizeof(props));
1622c978d9bSAndrew Jones 	props.pad = ' ';
1637d36db35SAvi Kivity 
1647d36db35SAvi Kivity 	if (f != '%') {
1657d36db35SAvi Kivity 	    addchar(&s, f);
1667d36db35SAvi Kivity 	    continue;
1677d36db35SAvi Kivity 	}
1687d36db35SAvi Kivity     morefmt:
1697d36db35SAvi Kivity 	f = *fmt++;
1707d36db35SAvi Kivity 	switch (f) {
1717d36db35SAvi Kivity 	case '%':
1727d36db35SAvi Kivity 	    addchar(&s, '%');
1737d36db35SAvi Kivity 	    break;
1743d7d5195SMichael S. Tsirkin 	case 'c':
1753d7d5195SMichael S. Tsirkin             addchar(&s, va_arg(va, int));
1763d7d5195SMichael S. Tsirkin 	    break;
1777d36db35SAvi Kivity 	case '\0':
1787d36db35SAvi Kivity 	    --fmt;
1797d36db35SAvi Kivity 	    break;
180c9af8739SRadim Krčmář 	case '#':
181c9af8739SRadim Krčmář 	    props.alternate = true;
182c9af8739SRadim Krčmář 	    goto morefmt;
1832c978d9bSAndrew Jones 	case '0':
1842c978d9bSAndrew Jones 	    props.pad = '0';
1852c978d9bSAndrew Jones 	    ++fmt;
1862c978d9bSAndrew Jones 	    /* fall through */
1872c978d9bSAndrew Jones 	case '1'...'9':
1882c978d9bSAndrew Jones 	case '-':
1892c978d9bSAndrew Jones 	    --fmt;
1902c978d9bSAndrew Jones 	    props.npad = fmtnum(&fmt);
1912c978d9bSAndrew Jones 	    goto morefmt;
1927d36db35SAvi Kivity 	case 'l':
1937d36db35SAvi Kivity 	    ++nlong;
1947d36db35SAvi Kivity 	    goto morefmt;
195cda042caSPaolo Bonzini 	case 't':
196cda042caSPaolo Bonzini 	case 'z':
197cda042caSPaolo Bonzini 	    /* Here we only care that sizeof(size_t) == sizeof(long).
198cda042caSPaolo Bonzini 	     * On a 32-bit platform it doesn't matter that size_t is
199cda042caSPaolo Bonzini 	     * typedef'ed to int or long; va_arg will work either way.
200cda042caSPaolo Bonzini 	     * Same for ptrdiff_t (%td).
201cda042caSPaolo Bonzini 	     */
202cda042caSPaolo Bonzini 	    nlong = 1;
203cda042caSPaolo Bonzini 	    goto morefmt;
2047d36db35SAvi Kivity 	case 'd':
2057d36db35SAvi Kivity 	    switch (nlong) {
2067d36db35SAvi Kivity 	    case 0:
2072c978d9bSAndrew Jones 		print_int(&s, va_arg(va, int), 10, props);
2087d36db35SAvi Kivity 		break;
2097d36db35SAvi Kivity 	    case 1:
2102c978d9bSAndrew Jones 		print_int(&s, va_arg(va, long), 10, props);
2117d36db35SAvi Kivity 		break;
2127d36db35SAvi Kivity 	    default:
2132c978d9bSAndrew Jones 		print_int(&s, va_arg(va, long long), 10, props);
2147d36db35SAvi Kivity 		break;
2157d36db35SAvi Kivity 	    }
2167d36db35SAvi Kivity 	    break;
2173a08f439SAlex Bennée 	case 'u':
2183a08f439SAlex Bennée 	    switch (nlong) {
2193a08f439SAlex Bennée 	    case 0:
2203a08f439SAlex Bennée 		print_unsigned(&s, va_arg(va, unsigned), 10, props);
2213a08f439SAlex Bennée 		break;
2223a08f439SAlex Bennée 	    case 1:
2233a08f439SAlex Bennée 		print_unsigned(&s, va_arg(va, unsigned long), 10, props);
2243a08f439SAlex Bennée 		break;
2253a08f439SAlex Bennée 	    default:
2263a08f439SAlex Bennée 		print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
2273a08f439SAlex Bennée 		break;
2283a08f439SAlex Bennée 	    }
2293a08f439SAlex Bennée 	    break;
2307d36db35SAvi Kivity 	case 'x':
2317d36db35SAvi Kivity 	    switch (nlong) {
2327d36db35SAvi Kivity 	    case 0:
2332c978d9bSAndrew Jones 		print_unsigned(&s, va_arg(va, unsigned), 16, props);
2347d36db35SAvi Kivity 		break;
2357d36db35SAvi Kivity 	    case 1:
2362c978d9bSAndrew Jones 		print_unsigned(&s, va_arg(va, unsigned long), 16, props);
2377d36db35SAvi Kivity 		break;
2387d36db35SAvi Kivity 	    default:
2392c978d9bSAndrew Jones 		print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
2407d36db35SAvi Kivity 		break;
2417d36db35SAvi Kivity 	    }
2427d36db35SAvi Kivity 	    break;
2437d36db35SAvi Kivity 	case 'p':
2448ef44442SRadim Krčmář 	    props.alternate = true;
2452c978d9bSAndrew Jones 	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
2467d36db35SAvi Kivity 	    break;
2477d36db35SAvi Kivity 	case 's':
2482c978d9bSAndrew Jones 	    print_str(&s, va_arg(va, const char *), props);
2497d36db35SAvi Kivity 	    break;
2507d36db35SAvi Kivity 	default:
2517d36db35SAvi Kivity 	    addchar(&s, f);
2527d36db35SAvi Kivity 	    break;
2537d36db35SAvi Kivity 	}
2547d36db35SAvi Kivity     }
2557d36db35SAvi Kivity     *s.buffer = 0;
2567d36db35SAvi Kivity     return s.added;
2577d36db35SAvi Kivity }
2587d36db35SAvi Kivity 
2597d36db35SAvi Kivity 
2607d36db35SAvi Kivity int snprintf(char *buf, int size, const char *fmt, ...)
2617d36db35SAvi Kivity {
2627d36db35SAvi Kivity     va_list va;
2637d36db35SAvi Kivity     int r;
2647d36db35SAvi Kivity 
2657d36db35SAvi Kivity     va_start(va, fmt);
2667d36db35SAvi Kivity     r = vsnprintf(buf, size, fmt, va);
2677d36db35SAvi Kivity     va_end(va);
2687d36db35SAvi Kivity     return r;
2697d36db35SAvi Kivity }
2707d36db35SAvi Kivity 
271cb12ecccSAndrew Jones int vprintf(const char *fmt, va_list va)
272cb12ecccSAndrew Jones {
273cb12ecccSAndrew Jones     char buf[BUFSZ];
274cb12ecccSAndrew Jones     int r;
275cb12ecccSAndrew Jones 
276cb12ecccSAndrew Jones     r = vsnprintf(buf, sizeof(buf), fmt, va);
277cb12ecccSAndrew Jones     puts(buf);
278cb12ecccSAndrew Jones     return r;
279cb12ecccSAndrew Jones }
280cb12ecccSAndrew Jones 
2817d36db35SAvi Kivity int printf(const char *fmt, ...)
2827d36db35SAvi Kivity {
2837d36db35SAvi Kivity     va_list va;
284cb12ecccSAndrew Jones     char buf[BUFSZ];
2857d36db35SAvi Kivity     int r;
2867d36db35SAvi Kivity 
2877d36db35SAvi Kivity     va_start(va, fmt);
2887d36db35SAvi Kivity     r = vsnprintf(buf, sizeof buf, fmt, va);
2897d36db35SAvi Kivity     va_end(va);
2907d36db35SAvi Kivity     puts(buf);
2917d36db35SAvi Kivity     return r;
2927d36db35SAvi Kivity }
293840375e1SPeter Feiner 
294840375e1SPeter Feiner void binstr(unsigned long x, char out[BINSTR_SZ])
295840375e1SPeter Feiner {
296840375e1SPeter Feiner 	int i;
297840375e1SPeter Feiner 	char *c;
298840375e1SPeter Feiner 	int n;
299840375e1SPeter Feiner 
300840375e1SPeter Feiner 	n = sizeof(unsigned long) * 8;
301840375e1SPeter Feiner 	i = 0;
302840375e1SPeter Feiner 	c = &out[0];
303840375e1SPeter Feiner 	for (;;) {
304840375e1SPeter Feiner 		*c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
305840375e1SPeter Feiner 		i++;
306840375e1SPeter Feiner 
307840375e1SPeter Feiner 		if (i == n) {
308840375e1SPeter Feiner 			*c = '\0';
309840375e1SPeter Feiner 			break;
310840375e1SPeter Feiner 		}
311840375e1SPeter Feiner 		if (i % 4 == 0)
312840375e1SPeter Feiner 			*c++ = '\'';
313840375e1SPeter Feiner 	}
314840375e1SPeter Feiner 	assert(c + 1 - &out[0] == BINSTR_SZ);
315840375e1SPeter Feiner }
316840375e1SPeter Feiner 
317840375e1SPeter Feiner void print_binstr(unsigned long x)
318840375e1SPeter Feiner {
319840375e1SPeter Feiner 	char out[BINSTR_SZ];
320840375e1SPeter Feiner 	binstr(x, out);
321840375e1SPeter Feiner 	printf("%s", out);
322840375e1SPeter Feiner }
323