cp: allow prefixing all console messages with the guest name
[hvf.git] / lib / vsprintf.c
blob808c14c87dcc1fdc7ebf4ab93ec7e484a003438a
1 /*
2 * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
7 * A number of things found in this file were borrowed from the Linux Kernel
8 */
10 #include <string.h>
11 #include <stdarg.h>
12 #include <vsprintf.h>
14 #define unlikely(x) (x)
17 * The following constants should not be available to any users outside this
18 * C file, as they are rather meaningless there.
21 /* borrowed from Linux */
22 #define ZEROPAD 1 /* pad with zero */
23 #define SIGN 2 /* unsigned/signed long */
24 #define PLUS 4 /* show plus */
25 #define SPACE 8 /* space if plus */
26 #define LEFT 16 /* left justified */
27 #define SPECIAL 32 /* 0x */
28 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
30 /* borrowed from Linux */
31 # define do_div(n,base) ({ \
32 u32 __base = (base); \
33 u32 __rem; \
34 __rem = ((u64)(n)) % __base; \
35 (n) = ((u64)(n)) / __base; \
36 __rem; \
39 /* borrowed from Linux */
40 static int skip_atoi(const char **s)
42 int i=0;
44 while (isdigit(**s))
45 i = i*10 + *((*s)++) - '0';
46 return i;
49 /* borrowed from Linux */
50 static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
52 char c,sign,tmp[66];
53 const char *digits;
54 static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
55 static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
56 int i;
58 digits = (type & LARGE) ? large_digits : small_digits;
59 if (type & LEFT)
60 type &= ~ZEROPAD;
61 if (base < 2 || base > 36)
62 return NULL;
63 c = (type & ZEROPAD) ? '0' : ' ';
64 sign = 0;
65 if (type & SIGN) {
66 if ((signed long long) num < 0) {
67 sign = '-';
68 num = - (signed long long) num;
69 size--;
70 } else if (type & PLUS) {
71 sign = '+';
72 size--;
73 } else if (type & SPACE) {
74 sign = ' ';
75 size--;
78 if (type & SPECIAL) {
79 if (base == 16)
80 size -= 2;
81 else if (base == 8)
82 size--;
84 i = 0;
85 if (num == 0)
86 tmp[i++]='0';
87 else while (num != 0)
88 tmp[i++] = digits[do_div(num,base)];
89 if (i > precision)
90 precision = i;
91 size -= precision;
92 if (!(type&(ZEROPAD+LEFT))) {
93 while(size-->0) {
94 if (buf < end)
95 *buf = ' ';
96 ++buf;
99 if (sign) {
100 if (buf < end)
101 *buf = sign;
102 ++buf;
104 if (type & SPECIAL) {
105 if (base==8) {
106 if (buf < end)
107 *buf = '0';
108 ++buf;
109 } else if (base==16) {
110 if (buf < end)
111 *buf = '0';
112 ++buf;
113 if (buf < end)
114 *buf = digits[33];
115 ++buf;
118 if (!(type & LEFT)) {
119 while (size-- > 0) {
120 if (buf < end)
121 *buf = c;
122 ++buf;
125 while (i < precision--) {
126 if (buf < end)
127 *buf = '0';
128 ++buf;
130 while (i-- > 0) {
131 if (buf < end)
132 *buf = tmp[i];
133 ++buf;
135 while (size-- > 0) {
136 if (buf < end)
137 *buf = ' ';
138 ++buf;
140 return buf;
144 * vsnprintf - Format a string and place it in a buffer
145 * @buf: The buffer to place the result into
146 * @size: The size of the buffer, including the trailing null space
147 * @fmt: The format string to use
148 * @args: Arguments for the format string
150 * The return value is the number of characters which would
151 * be generated for the given input, excluding the trailing
152 * '\0', as per ISO C99. If you want to have the exact
153 * number of characters written into @buf as return value
154 * (not including the trailing '\0'), use vscnprintf(). If the
155 * return is greater than or equal to @size, the resulting
156 * string is truncated.
158 * Call this function if you are already dealing with a va_list.
159 * You probably want snprintf() instead.
161 * NOTE: This function was borrowed from Linux's lib/vsprintf.c
163 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
165 int len;
166 unsigned long long num;
167 int i, base;
168 char *str, *end, c;
169 const char *s;
171 int flags; /* flags to number() */
173 int field_width; /* width of output field */
174 int precision; /* min. # of digits for integers; max
175 number of chars for from string */
176 int qualifier; /* 'h', 'l', or 'L' for integer fields */
177 /* 'z' support added 23/7/1999 S.H. */
178 /* 'z' changed to 'Z' --davidm 1/25/99 */
179 /* 't' added for ptrdiff_t */
181 /* Reject out-of-range values early. Large positive sizes are
182 used for unknown buffer sizes. */
183 if (unlikely((int) size < 0))
184 return 0;
186 str = buf;
187 end = buf + size;
189 /* Make sure end is always >= buf */
190 if (end < buf) {
191 end = ((void *)-1);
192 size = end - buf;
195 for (; *fmt ; ++fmt) {
196 if (*fmt != '%') {
197 if (str < end)
198 *str = *fmt;
199 ++str;
200 continue;
203 /* process flags */
204 flags = 0;
205 repeat:
206 ++fmt; /* this also skips first '%' */
207 switch (*fmt) {
208 case '-': flags |= LEFT; goto repeat;
209 case '+': flags |= PLUS; goto repeat;
210 case ' ': flags |= SPACE; goto repeat;
211 case '#': flags |= SPECIAL; goto repeat;
212 case '0': flags |= ZEROPAD; goto repeat;
215 /* get field width */
216 field_width = -1;
217 if (isdigit(*fmt))
218 field_width = skip_atoi(&fmt);
219 else if (*fmt == '*') {
220 ++fmt;
221 /* it's the next argument */
222 field_width = va_arg(args, int);
223 if (field_width < 0) {
224 field_width = -field_width;
225 flags |= LEFT;
229 /* get the precision */
230 precision = -1;
231 if (*fmt == '.') {
232 ++fmt;
233 if (isdigit(*fmt))
234 precision = skip_atoi(&fmt);
235 else if (*fmt == '*') {
236 ++fmt;
237 /* it's the next argument */
238 precision = va_arg(args, int);
240 if (precision < 0)
241 precision = 0;
244 /* get the conversion qualifier */
245 qualifier = -1;
246 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
247 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
248 qualifier = *fmt;
249 ++fmt;
250 if (qualifier == 'l' && *fmt == 'l') {
251 qualifier = 'L';
252 ++fmt;
256 /* default base */
257 base = 10;
259 switch (*fmt) {
260 case 'c':
261 if (!(flags & LEFT)) {
262 while (--field_width > 0) {
263 if (str < end)
264 *str = ' ';
265 ++str;
268 c = (unsigned char) va_arg(args, int);
269 if (str < end)
270 *str = c;
271 ++str;
272 while (--field_width > 0) {
273 if (str < end)
274 *str = ' ';
275 ++str;
277 continue;
279 case 's':
280 s = va_arg(args, char *);
281 if ((unsigned long)s < VSPRINTF_PAGE_SIZE)
282 s = "<NULL>";
284 len = strnlen(s, precision);
286 if (!(flags & LEFT)) {
287 while (len < field_width--) {
288 if (str < end)
289 *str = ' ';
290 ++str;
293 for (i = 0; i < len; ++i) {
294 if (str < end)
295 *str = *s;
296 ++str; ++s;
298 while (len < field_width--) {
299 if (str < end)
300 *str = ' ';
301 ++str;
303 continue;
305 case 'p':
306 if (field_width == -1) {
307 field_width = 2*sizeof(void *);
308 flags |= ZEROPAD;
310 str = number(str, end,
311 (unsigned long) va_arg(args, void *),
312 16, field_width, precision, flags);
313 continue;
316 case 'n':
317 /* FIXME:
318 * What does C99 say about the overflow case here? */
319 if (qualifier == 'l') {
320 long * ip = va_arg(args, long *);
321 *ip = (str - buf);
322 } else if (qualifier == 'Z' || qualifier == 'z') {
323 size_t * ip = va_arg(args, size_t *);
324 *ip = (str - buf);
325 } else {
326 int * ip = va_arg(args, int *);
327 *ip = (str - buf);
329 continue;
331 case '%':
332 if (str < end)
333 *str = '%';
334 ++str;
335 continue;
337 /* integer number formats - set up the flags and "break" */
338 case 'o':
339 base = 8;
340 break;
342 case 'X':
343 flags |= LARGE;
344 case 'x':
345 base = 16;
346 break;
348 case 'd':
349 case 'i':
350 flags |= SIGN;
351 case 'u':
352 break;
354 default:
355 if (str < end)
356 *str = '%';
357 ++str;
358 if (*fmt) {
359 if (str < end)
360 *str = *fmt;
361 ++str;
362 } else {
363 --fmt;
365 continue;
367 if (qualifier == 'L')
368 num = va_arg(args, long long);
369 else if (qualifier == 'l') {
370 num = va_arg(args, unsigned long);
371 if (flags & SIGN)
372 num = (signed long) num;
373 } else if (qualifier == 'Z' || qualifier == 'z') {
374 num = va_arg(args, size_t);
375 } else if (qualifier == 't') {
376 num = va_arg(args, ptrdiff_t);
377 } else if (qualifier == 'h') {
378 num = (unsigned short) va_arg(args, int);
379 if (flags & SIGN)
380 num = (signed short) num;
381 } else {
382 num = va_arg(args, unsigned int);
383 if (flags & SIGN)
384 num = (signed int) num;
386 str = number(str, end, num, base,
387 field_width, precision, flags);
389 if (size > 0) {
390 if (str < end)
391 *str = '\0';
392 else
393 end[-1] = '\0';
395 /* the trailing null byte doesn't count towards the total */
396 return str-buf;
399 int snprintf(char *buf, int len, const char *fmt, ...)
401 va_list args;
403 va_start(args, fmt);
404 len = vsnprintf(buf, len, fmt, args);
405 va_end(args);
407 return len;