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