menu: simplify usage for clients
[barebox-mini2440.git] / lib / vsprintf.c
blob6066845c5b00e5312b7b76db239a3abb4ef4ecd1
1 /*
2 * linux/lib/vsprintf.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8 /*
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
12 #include <stdarg.h>
13 #include <linux/types.h>
14 #include <linux/string.h>
15 #include <linux/ctype.h>
16 #include <asm-generic/div64.h>
17 #include <malloc.h>
19 #include <common.h>
20 #include <reloc.h>
22 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
24 unsigned long result = 0,value;
26 if (*cp == '0') {
27 cp++;
28 if ((*cp == 'x') && isxdigit(cp[1])) {
29 base = 16;
30 cp++;
32 if (!base) {
33 base = 8;
36 if (!base) {
37 base = 10;
39 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
40 ? toupper(*cp) : *cp)-'A'+10) < base) {
41 result = result*base + value;
42 cp++;
44 if (endp)
45 *endp = (char *)cp;
46 return result;
48 EXPORT_SYMBOL(simple_strtoul);
50 long simple_strtol(const char *cp,char **endp,unsigned int base)
52 if(*cp=='-')
53 return -simple_strtoul(cp+1,endp,base);
54 return simple_strtoul(cp,endp,base);
56 EXPORT_SYMBOL(simple_strtol);
58 #ifdef CFG_64BIT_STRTOUL
59 unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base)
61 unsigned long long result = 0, value;
63 if (*cp == '0') {
64 cp++;
65 if ((*cp == 'x') && isxdigit (cp[1])) {
66 base = 16;
67 cp++;
69 if (!base) {
70 base = 8;
73 if (!base) {
74 base = 10;
76 while (isxdigit (*cp) && (value = isdigit (*cp)
77 ? *cp - '0'
78 : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) {
79 result = result * base + value;
80 cp++;
82 if (endp)
83 *endp = (char *) cp;
84 return result;
86 #endif /* CFG_64BIT_STRTOUL */
88 /* we use this so that we can do without the ctype library */
89 #define is_digit(c) ((c) >= '0' && (c) <= '9')
91 static int skip_atoi(const char **s)
93 int i=0;
95 while (is_digit(**s))
96 i = i*10 + *((*s)++) - '0';
97 return i;
100 #define ZEROPAD 1 /* pad with zero */
101 #define SIGN 2 /* unsigned/signed long */
102 #define PLUS 4 /* show plus */
103 #define SPACE 8 /* space if plus */
104 #define LEFT 16 /* left justified */
105 #define SMALL 32 /* Must be 32 == 0x20 */
106 #define SPECIAL 64 /* 0x */
108 static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
110 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
111 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
113 char tmp[66];
114 char sign;
115 char locase;
116 int need_pfx = ((type & SPECIAL) && base != 10);
117 int i;
119 /* locase = 0 or 0x20. ORing digits or letters with 'locase'
120 * produces same digits or (maybe lowercased) letters */
121 locase = (type & SMALL);
122 if (type & LEFT)
123 type &= ~ZEROPAD;
124 sign = 0;
125 if (type & SIGN) {
126 if ((signed long long) num < 0) {
127 sign = '-';
128 num = - (signed long long) num;
129 size--;
130 } else if (type & PLUS) {
131 sign = '+';
132 size--;
133 } else if (type & SPACE) {
134 sign = ' ';
135 size--;
138 if (need_pfx) {
139 size--;
140 if (base == 16)
141 size--;
143 /* generate full string in tmp[], in reverse order */
144 i = 0;
145 if (num == 0)
146 tmp[i++] = '0';
147 else do {
148 tmp[i++] = (digits[do_div(num,base)] | locase);
149 } while (num != 0);
151 /* printing 100 using %2d gives "100", not "00" */
152 if (i > precision)
153 precision = i;
154 size -= precision;
155 if (!(type & (ZEROPAD+LEFT))) {
156 while(--size >= 0) {
157 if (buf < end)
158 *buf = ' ';
159 ++buf;
162 /* sign */
163 if (sign) {
164 if (buf < end)
165 *buf = sign;
166 ++buf;
168 /* "0x" / "0" prefix */
169 if (need_pfx) {
170 if (buf < end)
171 *buf = '0';
172 ++buf;
173 if (base == 16) {
174 if (buf < end)
175 *buf = ('X' | locase);
176 ++buf;
179 /* zero or space padding */
180 if (!(type & LEFT)) {
181 char c = (type & ZEROPAD) ? '0' : ' ';
182 while (--size >= 0) {
183 if (buf < end)
184 *buf = c;
185 ++buf;
188 /* hmm even more zero padding? */
189 while (i <= --precision) {
190 if (buf < end)
191 *buf = '0';
192 ++buf;
194 /* actual digits of result */
195 while (--i >= 0) {
196 if (buf < end)
197 *buf = tmp[i];
198 ++buf;
200 /* trailing space padding */
201 while (--size >= 0) {
202 if (buf < end)
203 *buf = ' ';
204 ++buf;
206 return buf;
209 #ifndef PAGE_SIZE
210 #define PAGE_SIZE 4096
211 #endif
213 static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags)
215 int len, i;
217 if ((unsigned long)s < PAGE_SIZE)
218 s = "<NULL>";
220 len = strnlen(s, precision);
222 if (!(flags & LEFT)) {
223 while (len < field_width--) {
224 if (buf < end)
225 *buf = ' ';
226 ++buf;
229 for (i = 0; i < len; ++i) {
230 if (buf < end)
231 *buf = *s;
232 ++buf; ++s;
234 while (len < field_width--) {
235 if (buf < end)
236 *buf = ' ';
237 ++buf;
239 return buf;
242 static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
244 unsigned long value = (unsigned long) ptr;
245 #ifdef CONFIG_KALLSYMS
246 char sym[KSYM_SYMBOL_LEN];
247 sprint_symbol(sym, value);
248 return string(buf, end, sym, field_width, precision, flags);
249 #else
250 field_width = 2*sizeof(void *);
251 flags |= SPECIAL | SMALL | ZEROPAD;
252 return number(buf, end, value, 16, field_width, precision, flags);
253 #endif
257 * Show a '%p' thing. A kernel extension is that the '%p' is followed
258 * by an extra set of alphanumeric characters that are extended format
259 * specifiers.
261 * Right now we handle:
263 * - 'S' For symbolic direct pointers
265 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
266 * function pointers are really function descriptors, which contain a
267 * pointer to the real address.
269 static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags)
271 switch (*fmt) {
272 case 'S':
273 return symbol_string(buf, end, ptr, field_width, precision, flags);
275 flags |= SMALL;
276 if (field_width == -1) {
277 field_width = 2*sizeof(void *);
278 flags |= ZEROPAD;
280 return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags);
284 * vsnprintf - Format a string and place it in a buffer
285 * @buf: The buffer to place the result into
286 * @size: The size of the buffer, including the trailing null space
287 * @fmt: The format string to use
288 * @args: Arguments for the format string
290 * This function follows C99 vsnprintf, but has some extensions:
291 * %pS output the name of a text symbol
292 * %pF output the name of a function pointer
293 * %pR output the address range in a struct resource
295 * The return value is the number of characters which would
296 * be generated for the given input, excluding the trailing
297 * '\0', as per ISO C99. If you want to have the exact
298 * number of characters written into @buf as return value
299 * (not including the trailing '\0'), use vscnprintf(). If the
300 * return is greater than or equal to @size, the resulting
301 * string is truncated.
303 * Call this function if you are already dealing with a va_list.
304 * You probably want snprintf() instead.
306 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
308 unsigned long long num;
309 int base;
310 char *str, *end, c;
312 int flags; /* flags to number() */
314 int field_width; /* width of output field */
315 int precision; /* min. # of digits for integers; max
316 number of chars for from string */
317 int qualifier; /* 'h', 'l', or 'L' for integer fields */
318 /* 'z' support added 23/7/1999 S.H. */
319 /* 'z' changed to 'Z' --davidm 1/25/99 */
320 /* 't' added for ptrdiff_t */
322 /* Reject out-of-range values early. Large positive sizes are
323 used for unknown buffer sizes. */
324 if (unlikely((int) size < 0))
325 return 0;
327 str = buf;
328 end = buf + size;
330 /* Make sure end is always >= buf */
331 if (end < buf) {
332 end = ((void *)-1);
333 size = end - buf;
336 for (; *fmt ; ++fmt) {
337 if (*fmt != '%') {
338 if (str < end)
339 *str = *fmt;
340 ++str;
341 continue;
344 /* process flags */
345 flags = 0;
346 repeat:
347 ++fmt; /* this also skips first '%' */
348 switch (*fmt) {
349 case '-': flags |= LEFT; goto repeat;
350 case '+': flags |= PLUS; goto repeat;
351 case ' ': flags |= SPACE; goto repeat;
352 case '#': flags |= SPECIAL; goto repeat;
353 case '0': flags |= ZEROPAD; goto repeat;
356 /* get field width */
357 field_width = -1;
358 if (isdigit(*fmt))
359 field_width = skip_atoi(&fmt);
360 else if (*fmt == '*') {
361 ++fmt;
362 /* it's the next argument */
363 field_width = va_arg(args, int);
364 if (field_width < 0) {
365 field_width = -field_width;
366 flags |= LEFT;
370 /* get the precision */
371 precision = -1;
372 if (*fmt == '.') {
373 ++fmt;
374 if (isdigit(*fmt))
375 precision = skip_atoi(&fmt);
376 else if (*fmt == '*') {
377 ++fmt;
378 /* it's the next argument */
379 precision = va_arg(args, int);
381 if (precision < 0)
382 precision = 0;
385 /* get the conversion qualifier */
386 qualifier = -1;
387 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
388 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
389 qualifier = *fmt;
390 ++fmt;
391 if (qualifier == 'l' && *fmt == 'l') {
392 qualifier = 'L';
393 ++fmt;
397 /* default base */
398 base = 10;
400 switch (*fmt) {
401 case 'c':
402 if (!(flags & LEFT)) {
403 while (--field_width > 0) {
404 if (str < end)
405 *str = ' ';
406 ++str;
409 c = (unsigned char) va_arg(args, int);
410 if (str < end)
411 *str = c;
412 ++str;
413 while (--field_width > 0) {
414 if (str < end)
415 *str = ' ';
416 ++str;
418 continue;
420 case 's':
421 str = string(str, end, va_arg(args, char *), field_width, precision, flags);
422 continue;
424 case 'p':
425 str = pointer(fmt+1, str, end,
426 va_arg(args, void *),
427 field_width, precision, flags);
428 /* Skip all alphanumeric pointer suffixes */
429 while (isalnum(fmt[1]))
430 fmt++;
431 continue;
433 case 'n':
434 /* FIXME:
435 * What does C99 say about the overflow case here? */
436 if (qualifier == 'l') {
437 long * ip = va_arg(args, long *);
438 *ip = (str - buf);
439 } else if (qualifier == 'Z' || qualifier == 'z') {
440 size_t * ip = va_arg(args, size_t *);
441 *ip = (str - buf);
442 } else {
443 int * ip = va_arg(args, int *);
444 *ip = (str - buf);
446 continue;
448 case '%':
449 if (str < end)
450 *str = '%';
451 ++str;
452 continue;
454 /* integer number formats - set up the flags and "break" */
455 case 'o':
456 base = 8;
457 break;
459 case 'x':
460 flags |= SMALL;
461 case 'X':
462 base = 16;
463 break;
465 case 'd':
466 case 'i':
467 flags |= SIGN;
468 case 'u':
469 break;
471 default:
472 if (str < end)
473 *str = '%';
474 ++str;
475 if (*fmt) {
476 if (str < end)
477 *str = *fmt;
478 ++str;
479 } else {
480 --fmt;
482 continue;
484 if (qualifier == 'L')
485 num = va_arg(args, long long);
486 else if (qualifier == 'l') {
487 num = va_arg(args, unsigned long);
488 if (flags & SIGN)
489 num = (signed long) num;
490 } else if (qualifier == 'Z' || qualifier == 'z') {
491 num = va_arg(args, size_t);
492 } else if (qualifier == 't') {
493 num = va_arg(args, ptrdiff_t);
494 } else if (qualifier == 'h') {
495 num = (unsigned short) va_arg(args, int);
496 if (flags & SIGN)
497 num = (signed short) num;
498 } else {
499 num = va_arg(args, unsigned int);
500 if (flags & SIGN)
501 num = (signed int) num;
503 str = number(str, end, num, base,
504 field_width, precision, flags);
506 if (size > 0) {
507 if (str < end)
508 *str = '\0';
509 else
510 end[-1] = '\0';
512 /* the trailing null byte doesn't count towards the total */
513 return str-buf;
515 EXPORT_SYMBOL(vsnprintf);
518 * vscnprintf - Format a string and place it in a buffer
519 * @buf: The buffer to place the result into
520 * @size: The size of the buffer, including the trailing null space
521 * @fmt: The format string to use
522 * @args: Arguments for the format string
524 * The return value is the number of characters which have been written into
525 * the @buf not including the trailing '\0'. If @size is <= 0 the function
526 * returns 0.
528 * Call this function if you are already dealing with a va_list.
529 * You probably want scnprintf() instead.
531 * See the vsnprintf() documentation for format string extensions over C99.
533 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
535 int i;
537 i=vsnprintf(buf,size,fmt,args);
538 return (i >= size) ? (size - 1) : i;
540 EXPORT_SYMBOL(vscnprintf);
543 * vsprintf - Format a string and place it in a buffer
544 * @buf: The buffer to place the result into
545 * @fmt: The format string to use
546 * @args: Arguments for the format string
548 * The function returns the number of characters written
549 * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
550 * buffer overflows.
552 * Call this function if you are already dealing with a va_list.
553 * You probably want sprintf() instead.
555 * See the vsnprintf() documentation for format string extensions over C99.
557 int vsprintf(char *buf, const char *fmt, va_list args)
559 return vsnprintf(buf, INT_MAX, fmt, args);
561 EXPORT_SYMBOL(vsprintf);
563 int sprintf(char * buf, const char *fmt, ...)
565 va_list args;
566 int i;
568 va_start(args, fmt);
569 i=vsprintf(buf,fmt,args);
570 va_end(args);
571 return i;
573 EXPORT_SYMBOL(sprintf);
575 int snprintf(char * buf, size_t size, const char *fmt, ...)
577 va_list args;
578 int i;
580 va_start(args, fmt);
581 i = vsnprintf(buf, size, fmt, args);
582 va_end(args);
583 return i;
585 EXPORT_SYMBOL(sprintf);
587 /* Simplified asprintf. */
588 char *vasprintf(const char *fmt, va_list ap)
590 unsigned int len;
591 char *p;
592 va_list aq;
594 va_copy(aq, ap);
595 len = vsnprintf(NULL, 0, fmt, aq);
596 va_end(aq);
598 p = malloc(len + 1);
599 if (!p)
600 return NULL;
602 vsnprintf(p, len + 1, fmt, ap);
604 return p;
606 EXPORT_SYMBOL(vasprintf);
608 char *asprintf(const char *fmt, ...)
610 va_list ap;
611 char *p;
613 va_start(ap, fmt);
614 p = vasprintf(fmt, ap);
615 va_end(ap);
617 return p;
619 EXPORT_SYMBOL(asprintf);
621 void __noreturn panic(const char *fmt, ...)
623 va_list args;
624 va_start(args, fmt);
625 vprintf(fmt, args);
626 putchar('\n');
627 va_end(args);
628 #if defined (CONFIG_PANIC_HANG)
629 hang();
630 #else
631 udelay(100000); /* allow messages to go out */
632 reset_cpu(0);
633 #endif
635 EXPORT_SYMBOL(panic);