xref: /kvm-unit-tests/lib/printf.c (revision 7516869fc7fbc175d18adb165117ba502050b160)
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 'd':
180 	    switch (nlong) {
181 	    case 0:
182 		print_int(&s, va_arg(va, int), 10, props);
183 		break;
184 	    case 1:
185 		print_int(&s, va_arg(va, long), 10, props);
186 		break;
187 	    default:
188 		print_int(&s, va_arg(va, long long), 10, props);
189 		break;
190 	    }
191 	    break;
192 	case 'u':
193 	    switch (nlong) {
194 	    case 0:
195 		print_unsigned(&s, va_arg(va, unsigned), 10, props);
196 		break;
197 	    case 1:
198 		print_unsigned(&s, va_arg(va, unsigned long), 10, props);
199 		break;
200 	    default:
201 		print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
202 		break;
203 	    }
204 	    break;
205 	case 'x':
206 	    switch (nlong) {
207 	    case 0:
208 		print_unsigned(&s, va_arg(va, unsigned), 16, props);
209 		break;
210 	    case 1:
211 		print_unsigned(&s, va_arg(va, unsigned long), 16, props);
212 		break;
213 	    default:
214 		print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
215 		break;
216 	    }
217 	    break;
218 	case 'p':
219 	    print_str(&s, "0x", props);
220 	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
221 	    break;
222 	case 's':
223 	    print_str(&s, va_arg(va, const char *), props);
224 	    break;
225 	default:
226 	    addchar(&s, f);
227 	    break;
228 	}
229     }
230     *s.buffer = 0;
231     return s.added;
232 }
233 
234 
235 int snprintf(char *buf, int size, const char *fmt, ...)
236 {
237     va_list va;
238     int r;
239 
240     va_start(va, fmt);
241     r = vsnprintf(buf, size, fmt, va);
242     va_end(va);
243     return r;
244 }
245 
246 int vprintf(const char *fmt, va_list va)
247 {
248     char buf[BUFSZ];
249     int r;
250 
251     r = vsnprintf(buf, sizeof(buf), fmt, va);
252     puts(buf);
253     return r;
254 }
255 
256 int printf(const char *fmt, ...)
257 {
258     va_list va;
259     char buf[BUFSZ];
260     int r;
261 
262     va_start(va, fmt);
263     r = vsnprintf(buf, sizeof buf, fmt, va);
264     va_end(va);
265     puts(buf);
266     return r;
267 }
268 
269 void binstr(unsigned long x, char out[BINSTR_SZ])
270 {
271 	int i;
272 	char *c;
273 	int n;
274 
275 	n = sizeof(unsigned long) * 8;
276 	i = 0;
277 	c = &out[0];
278 	for (;;) {
279 		*c++ = (x & (1ul << (n - i - 1))) ? '1' : '0';
280 		i++;
281 
282 		if (i == n) {
283 			*c = '\0';
284 			break;
285 		}
286 		if (i % 4 == 0)
287 			*c++ = '\'';
288 	}
289 	assert(c + 1 - &out[0] == BINSTR_SZ);
290 }
291 
292 void print_binstr(unsigned long x)
293 {
294 	char out[BINSTR_SZ];
295 	binstr(x, out);
296 	printf("%s", out);
297 }
298