xref: /kvm-unit-tests/lib/printf.c (revision 4b6da8266e20882f41cdbbe254b08b900a5b9fbe)
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     ++s.added;
232     return s.added;
233 }
234 
235 
236 int snprintf(char *buf, int size, const char *fmt, ...)
237 {
238     va_list va;
239     int r;
240 
241     va_start(va, fmt);
242     r = vsnprintf(buf, size, fmt, va);
243     va_end(va);
244     return r;
245 }
246 
247 int vprintf(const char *fmt, va_list va)
248 {
249     char buf[BUFSZ];
250     int r;
251 
252     r = vsnprintf(buf, sizeof(buf), fmt, va);
253     puts(buf);
254     return r;
255 }
256 
257 int printf(const char *fmt, ...)
258 {
259     va_list va;
260     char buf[BUFSZ];
261     int r;
262 
263     va_start(va, fmt);
264     r = vsnprintf(buf, sizeof buf, fmt, va);
265     va_end(va);
266     puts(buf);
267     return r;
268 }
269