xref: /kvm-unit-tests/lib/printf.c (revision d31f6adb16fc88c51fa43a70a82eae79946f394d)
1 /*
2  * libc printf and friends
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Library General Public License version 2.
6  */
7 
8 #include "libcflat.h"
9 
10 #define BUFSZ 2000
11 
12 typedef struct pstream {
13     char *buffer;
14     int remain;
15     int added;
16 } pstream_t;
17 
18 typedef struct strprops {
19     char pad;
20     int npad;
21 } strprops_t;
22 
23 static void addchar(pstream_t *p, char c)
24 {
25     if (p->remain) {
26 	*p->buffer++ = c;
27 	--p->remain;
28     }
29     ++p->added;
30 }
31 
32 void print_str(pstream_t *p, const char *s, strprops_t props)
33 {
34     const char *s_orig = s;
35     int npad = props.npad;
36 
37     if (npad > 0) {
38 	npad -= strlen(s_orig);
39 	while (npad > 0) {
40 	    addchar(p, props.pad);
41 	    --npad;
42 	}
43     }
44 
45     while (*s)
46 	addchar(p, *s++);
47 
48     if (npad < 0) {
49 	props.pad = ' '; /* ignore '0' flag with '-' flag */
50 	npad += strlen(s_orig);
51 	while (npad < 0) {
52 	    addchar(p, props.pad);
53 	    ++npad;
54 	}
55     }
56 }
57 
58 static char digits[16] = "0123456789abcdef";
59 
60 void print_int(pstream_t *ps, long long n, int base, strprops_t props)
61 {
62     char buf[sizeof(long) * 3 + 2], *p = buf;
63     int s = 0, i;
64 
65     if (n < 0) {
66 	n = -n;
67 	s = 1;
68     }
69 
70     while (n) {
71 	*p++ = digits[n % base];
72 	n /= base;
73     }
74 
75     if (s)
76 	*p++ = '-';
77 
78     if (p == buf)
79 	*p++ = '0';
80 
81     for (i = 0; i < (p - buf) / 2; ++i) {
82 	char tmp;
83 
84 	tmp = buf[i];
85 	buf[i] = p[-1-i];
86 	p[-1-i] = tmp;
87     }
88 
89     *p = 0;
90 
91     print_str(ps, buf, props);
92 }
93 
94 void print_unsigned(pstream_t *ps, unsigned long long n, int base,
95 		    strprops_t props)
96 {
97     char buf[sizeof(long) * 3 + 1], *p = buf;
98     int i;
99 
100     while (n) {
101 	*p++ = digits[n % base];
102 	n /= base;
103     }
104 
105     if (p == buf)
106 	*p++ = '0';
107 
108     for (i = 0; i < (p - buf) / 2; ++i) {
109 	char tmp;
110 
111 	tmp = buf[i];
112 	buf[i] = p[-1-i];
113 	p[-1-i] = tmp;
114     }
115 
116     *p = 0;
117 
118     print_str(ps, buf, props);
119 }
120 
121 static int fmtnum(const char **fmt)
122 {
123     const char *f = *fmt;
124     int len = 0, num;
125 
126     if (*f == '-')
127 	++f, ++len;
128 
129     while (*f >= '0' && *f <= '9')
130 	++f, ++len;
131 
132     num = atol(*fmt);
133     *fmt += len;
134     return num;
135 }
136 
137 int vsnprintf(char *buf, int size, const char *fmt, va_list va)
138 {
139     pstream_t s;
140 
141     s.buffer = buf;
142     s.remain = size - 1;
143     s.added = 0;
144     while (*fmt) {
145 	char f = *fmt++;
146 	int nlong = 0;
147 	strprops_t props;
148 	memset(&props, 0, sizeof(props));
149 	props.pad = ' ';
150 
151 	if (f != '%') {
152 	    addchar(&s, f);
153 	    continue;
154 	}
155     morefmt:
156 	f = *fmt++;
157 	switch (f) {
158 	case '%':
159 	    addchar(&s, '%');
160 	    break;
161 	case 'c':
162             addchar(&s, va_arg(va, int));
163 	    break;
164 	case '\0':
165 	    --fmt;
166 	    break;
167 	case '0':
168 	    props.pad = '0';
169 	    ++fmt;
170 	    /* fall through */
171 	case '1'...'9':
172 	case '-':
173 	    --fmt;
174 	    props.npad = fmtnum(&fmt);
175 	    goto morefmt;
176 	case 'l':
177 	    ++nlong;
178 	    goto morefmt;
179 	case 't':
180 	case 'z':
181 	    /* Here we only care that sizeof(size_t) == sizeof(long).
182 	     * On a 32-bit platform it doesn't matter that size_t is
183 	     * typedef'ed to int or long; va_arg will work either way.
184 	     * Same for ptrdiff_t (%td).
185 	     */
186 	    nlong = 1;
187 	    goto morefmt;
188 	case 'd':
189 	    switch (nlong) {
190 	    case 0:
191 		print_int(&s, va_arg(va, int), 10, props);
192 		break;
193 	    case 1:
194 		print_int(&s, va_arg(va, long), 10, props);
195 		break;
196 	    default:
197 		print_int(&s, va_arg(va, long long), 10, props);
198 		break;
199 	    }
200 	    break;
201 	case 'u':
202 	    switch (nlong) {
203 	    case 0:
204 		print_unsigned(&s, va_arg(va, unsigned), 10, props);
205 		break;
206 	    case 1:
207 		print_unsigned(&s, va_arg(va, unsigned long), 10, props);
208 		break;
209 	    default:
210 		print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
211 		break;
212 	    }
213 	    break;
214 	case 'x':
215 	    switch (nlong) {
216 	    case 0:
217 		print_unsigned(&s, va_arg(va, unsigned), 16, props);
218 		break;
219 	    case 1:
220 		print_unsigned(&s, va_arg(va, unsigned long), 16, props);
221 		break;
222 	    default:
223 		print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
224 		break;
225 	    }
226 	    break;
227 	case 'p':
228 	    print_str(&s, "0x", props);
229 	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
230 	    break;
231 	case 's':
232 	    print_str(&s, va_arg(va, const char *), props);
233 	    break;
234 	default:
235 	    addchar(&s, f);
236 	    break;
237 	}
238     }
239     *s.buffer = 0;
240     return s.added;
241 }
242 
243 
244 int snprintf(char *buf, int size, const char *fmt, ...)
245 {
246     va_list va;
247     int r;
248 
249     va_start(va, fmt);
250     r = vsnprintf(buf, size, fmt, va);
251     va_end(va);
252     return r;
253 }
254 
255 int vprintf(const char *fmt, va_list va)
256 {
257     char buf[BUFSZ];
258     int r;
259 
260     r = vsnprintf(buf, sizeof(buf), fmt, va);
261     puts(buf);
262     return r;
263 }
264 
265 int printf(const char *fmt, ...)
266 {
267     va_list va;
268     char buf[BUFSZ];
269     int r;
270 
271     va_start(va, fmt);
272     r = vsnprintf(buf, sizeof buf, fmt, va);
273     va_end(va);
274     puts(buf);
275     return r;
276 }
277 
278 void binstr(unsigned long x, char out[BINSTR_SZ])
279 {
280 	int i;
281 	char *c;
282 	int n;
283 
284 	n = sizeof(unsigned long) * 8;
285 	i = 0;
286 	c = &out[0];
287 	for (;;) {
288 		*c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
289 		i++;
290 
291 		if (i == n) {
292 			*c = '\0';
293 			break;
294 		}
295 		if (i % 4 == 0)
296 			*c++ = '\'';
297 	}
298 	assert(c + 1 - &out[0] == BINSTR_SZ);
299 }
300 
301 void print_binstr(unsigned long x)
302 {
303 	char out[BINSTR_SZ];
304 	binstr(x, out);
305 	printf("%s", out);
306 }
307