xref: /kvm-unit-tests/lib/printf.c (revision f1df865894dcab9e82f2dbcd642fa2423fa59a04)
1 #include "libcflat.h"
2 
3 #define BUFSZ 2000
4 
5 typedef struct pstream {
6     char *buffer;
7     int remain;
8     int added;
9 } pstream_t;
10 
11 typedef struct strprops {
12     char pad;
13     int npad;
14 } strprops_t;
15 
16 static void addchar(pstream_t *p, char c)
17 {
18     if (p->remain) {
19 	*p->buffer++ = c;
20 	--p->remain;
21     }
22     ++p->added;
23 }
24 
25 void print_str(pstream_t *p, const char *s, strprops_t props)
26 {
27     const char *s_orig = s;
28     int npad = props.npad;
29 
30     if (npad > 0) {
31 	npad -= strlen(s_orig);
32 	while (npad > 0) {
33 	    addchar(p, props.pad);
34 	    --npad;
35 	}
36     }
37 
38     while (*s)
39 	addchar(p, *s++);
40 
41     if (npad < 0) {
42 	props.pad = ' '; /* ignore '0' flag with '-' flag */
43 	npad += strlen(s_orig);
44 	while (npad < 0) {
45 	    addchar(p, props.pad);
46 	    ++npad;
47 	}
48     }
49 }
50 
51 static char digits[16] = "0123456789abcdef";
52 
53 void print_int(pstream_t *ps, long long n, int base, strprops_t props)
54 {
55     char buf[sizeof(long) * 3 + 2], *p = buf;
56     int s = 0, i;
57 
58     if (n < 0) {
59 	n = -n;
60 	s = 1;
61     }
62 
63     while (n) {
64 	*p++ = digits[n % base];
65 	n /= base;
66     }
67 
68     if (s)
69 	*p++ = '-';
70 
71     if (p == buf)
72 	*p++ = '0';
73 
74     for (i = 0; i < (p - buf) / 2; ++i) {
75 	char tmp;
76 
77 	tmp = buf[i];
78 	buf[i] = p[-1-i];
79 	p[-1-i] = tmp;
80     }
81 
82     *p = 0;
83 
84     print_str(ps, buf, props);
85 }
86 
87 void print_unsigned(pstream_t *ps, unsigned long long n, int base,
88 		    strprops_t props)
89 {
90     char buf[sizeof(long) * 3 + 1], *p = buf;
91     int i;
92 
93     while (n) {
94 	*p++ = digits[n % base];
95 	n /= base;
96     }
97 
98     if (p == buf)
99 	*p++ = '0';
100 
101     for (i = 0; i < (p - buf) / 2; ++i) {
102 	char tmp;
103 
104 	tmp = buf[i];
105 	buf[i] = p[-1-i];
106 	p[-1-i] = tmp;
107     }
108 
109     *p = 0;
110 
111     print_str(ps, buf, props);
112 }
113 
114 static int fmtnum(const char **fmt)
115 {
116     const char *f = *fmt;
117     int len = 0, num;
118 
119     if (*f == '-')
120 	++f, ++len;
121 
122     while (*f >= '0' && *f <= '9')
123 	++f, ++len;
124 
125     num = atol(*fmt);
126     *fmt += len;
127     return num;
128 }
129 
130 int vsnprintf(char *buf, int size, const char *fmt, va_list va)
131 {
132     pstream_t s;
133 
134     s.buffer = buf;
135     s.remain = size - 1;
136     s.added = 0;
137     while (*fmt) {
138 	char f = *fmt++;
139 	int nlong = 0;
140 	strprops_t props;
141 	memset(&props, 0, sizeof(props));
142 	props.pad = ' ';
143 
144 	if (f != '%') {
145 	    addchar(&s, f);
146 	    continue;
147 	}
148     morefmt:
149 	f = *fmt++;
150 	switch (f) {
151 	case '%':
152 	    addchar(&s, '%');
153 	    break;
154 	case 'c':
155             addchar(&s, va_arg(va, int));
156 	    break;
157 	case '\0':
158 	    --fmt;
159 	    break;
160 	case '0':
161 	    props.pad = '0';
162 	    ++fmt;
163 	    /* fall through */
164 	case '1'...'9':
165 	case '-':
166 	    --fmt;
167 	    props.npad = fmtnum(&fmt);
168 	    goto morefmt;
169 	case 'l':
170 	    ++nlong;
171 	    goto morefmt;
172 	case 'd':
173 	    switch (nlong) {
174 	    case 0:
175 		print_int(&s, va_arg(va, int), 10, props);
176 		break;
177 	    case 1:
178 		print_int(&s, va_arg(va, long), 10, props);
179 		break;
180 	    default:
181 		print_int(&s, va_arg(va, long long), 10, props);
182 		break;
183 	    }
184 	    break;
185 	case 'u':
186 	    switch (nlong) {
187 	    case 0:
188 		print_unsigned(&s, va_arg(va, unsigned), 10, props);
189 		break;
190 	    case 1:
191 		print_unsigned(&s, va_arg(va, unsigned long), 10, props);
192 		break;
193 	    default:
194 		print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
195 		break;
196 	    }
197 	    break;
198 	case 'x':
199 	    switch (nlong) {
200 	    case 0:
201 		print_unsigned(&s, va_arg(va, unsigned), 16, props);
202 		break;
203 	    case 1:
204 		print_unsigned(&s, va_arg(va, unsigned long), 16, props);
205 		break;
206 	    default:
207 		print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
208 		break;
209 	    }
210 	    break;
211 	case 'p':
212 	    print_str(&s, "0x", props);
213 	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
214 	    break;
215 	case 's':
216 	    print_str(&s, va_arg(va, const char *), props);
217 	    break;
218 	default:
219 	    addchar(&s, f);
220 	    break;
221 	}
222     }
223     *s.buffer = 0;
224     ++s.added;
225     return s.added;
226 }
227 
228 
229 int snprintf(char *buf, int size, const char *fmt, ...)
230 {
231     va_list va;
232     int r;
233 
234     va_start(va, fmt);
235     r = vsnprintf(buf, size, fmt, va);
236     va_end(va);
237     return r;
238 }
239 
240 int vprintf(const char *fmt, va_list va)
241 {
242     char buf[BUFSZ];
243     int r;
244 
245     r = vsnprintf(buf, sizeof(buf), fmt, va);
246     puts(buf);
247     return r;
248 }
249 
250 int printf(const char *fmt, ...)
251 {
252     va_list va;
253     char buf[BUFSZ];
254     int r;
255 
256     va_start(va, fmt);
257     r = vsnprintf(buf, sizeof buf, fmt, va);
258     va_end(va);
259     puts(buf);
260     return r;
261 }
262