driver: add dev_name inline
[barebox-mini2440.git] / lib / vsprintf.c
blobb04694f25f7fe3bbbd732d32762c04fffd086651
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 #define PAGE_SIZE 4096
211 static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags)
213 int len, i;
215 if ((unsigned long)s < PAGE_SIZE)
216 s = "<NULL>";
218 len = strnlen(s, precision);
220 if (!(flags & LEFT)) {
221 while (len < field_width--) {
222 if (buf < end)
223 *buf = ' ';
224 ++buf;
227 for (i = 0; i < len; ++i) {
228 if (buf < end)
229 *buf = *s;
230 ++buf; ++s;
232 while (len < field_width--) {
233 if (buf < end)
234 *buf = ' ';
235 ++buf;
237 return buf;
240 static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
242 unsigned long value = (unsigned long) ptr;
243 #ifdef CONFIG_KALLSYMS
244 char sym[KSYM_SYMBOL_LEN];
245 sprint_symbol(sym, value);
246 return string(buf, end, sym, field_width, precision, flags);
247 #else
248 field_width = 2*sizeof(void *);
249 flags |= SPECIAL | SMALL | ZEROPAD;
250 return number(buf, end, value, 16, field_width, precision, flags);
251 #endif
255 * Show a '%p' thing. A kernel extension is that the '%p' is followed
256 * by an extra set of alphanumeric characters that are extended format
257 * specifiers.
259 * Right now we handle:
261 * - 'S' For symbolic direct pointers
263 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
264 * function pointers are really function descriptors, which contain a
265 * pointer to the real address.
267 static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags)
269 switch (*fmt) {
270 case 'S':
271 return symbol_string(buf, end, ptr, field_width, precision, flags);
273 flags |= SMALL;
274 if (field_width == -1) {
275 field_width = 2*sizeof(void *);
276 flags |= ZEROPAD;
278 return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags);
282 * vsnprintf - Format a string and place it in a buffer
283 * @buf: The buffer to place the result into
284 * @size: The size of the buffer, including the trailing null space
285 * @fmt: The format string to use
286 * @args: Arguments for the format string
288 * This function follows C99 vsnprintf, but has some extensions:
289 * %pS output the name of a text symbol
290 * %pF output the name of a function pointer
291 * %pR output the address range in a struct resource
293 * The return value is the number of characters which would
294 * be generated for the given input, excluding the trailing
295 * '\0', as per ISO C99. If you want to have the exact
296 * number of characters written into @buf as return value
297 * (not including the trailing '\0'), use vscnprintf(). If the
298 * return is greater than or equal to @size, the resulting
299 * string is truncated.
301 * Call this function if you are already dealing with a va_list.
302 * You probably want snprintf() instead.
304 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
306 unsigned long long num;
307 int base;
308 char *str, *end, c;
310 int flags; /* flags to number() */
312 int field_width; /* width of output field */
313 int precision; /* min. # of digits for integers; max
314 number of chars for from string */
315 int qualifier; /* 'h', 'l', or 'L' for integer fields */
316 /* 'z' support added 23/7/1999 S.H. */
317 /* 'z' changed to 'Z' --davidm 1/25/99 */
318 /* 't' added for ptrdiff_t */
320 /* Reject out-of-range values early. Large positive sizes are
321 used for unknown buffer sizes. */
322 if (unlikely((int) size < 0))
323 return 0;
325 str = buf;
326 end = buf + size;
328 /* Make sure end is always >= buf */
329 if (end < buf) {
330 end = ((void *)-1);
331 size = end - buf;
334 for (; *fmt ; ++fmt) {
335 if (*fmt != '%') {
336 if (str < end)
337 *str = *fmt;
338 ++str;
339 continue;
342 /* process flags */
343 flags = 0;
344 repeat:
345 ++fmt; /* this also skips first '%' */
346 switch (*fmt) {
347 case '-': flags |= LEFT; goto repeat;
348 case '+': flags |= PLUS; goto repeat;
349 case ' ': flags |= SPACE; goto repeat;
350 case '#': flags |= SPECIAL; goto repeat;
351 case '0': flags |= ZEROPAD; goto repeat;
354 /* get field width */
355 field_width = -1;
356 if (isdigit(*fmt))
357 field_width = skip_atoi(&fmt);
358 else if (*fmt == '*') {
359 ++fmt;
360 /* it's the next argument */
361 field_width = va_arg(args, int);
362 if (field_width < 0) {
363 field_width = -field_width;
364 flags |= LEFT;
368 /* get the precision */
369 precision = -1;
370 if (*fmt == '.') {
371 ++fmt;
372 if (isdigit(*fmt))
373 precision = skip_atoi(&fmt);
374 else if (*fmt == '*') {
375 ++fmt;
376 /* it's the next argument */
377 precision = va_arg(args, int);
379 if (precision < 0)
380 precision = 0;
383 /* get the conversion qualifier */
384 qualifier = -1;
385 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
386 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
387 qualifier = *fmt;
388 ++fmt;
389 if (qualifier == 'l' && *fmt == 'l') {
390 qualifier = 'L';
391 ++fmt;
395 /* default base */
396 base = 10;
398 switch (*fmt) {
399 case 'c':
400 if (!(flags & LEFT)) {
401 while (--field_width > 0) {
402 if (str < end)
403 *str = ' ';
404 ++str;
407 c = (unsigned char) va_arg(args, int);
408 if (str < end)
409 *str = c;
410 ++str;
411 while (--field_width > 0) {
412 if (str < end)
413 *str = ' ';
414 ++str;
416 continue;
418 case 's':
419 str = string(str, end, va_arg(args, char *), field_width, precision, flags);
420 continue;
422 case 'p':
423 str = pointer(fmt+1, str, end,
424 va_arg(args, void *),
425 field_width, precision, flags);
426 /* Skip all alphanumeric pointer suffixes */
427 while (isalnum(fmt[1]))
428 fmt++;
429 continue;
431 case 'n':
432 /* FIXME:
433 * What does C99 say about the overflow case here? */
434 if (qualifier == 'l') {
435 long * ip = va_arg(args, long *);
436 *ip = (str - buf);
437 } else if (qualifier == 'Z' || qualifier == 'z') {
438 size_t * ip = va_arg(args, size_t *);
439 *ip = (str - buf);
440 } else {
441 int * ip = va_arg(args, int *);
442 *ip = (str - buf);
444 continue;
446 case '%':
447 if (str < end)
448 *str = '%';
449 ++str;
450 continue;
452 /* integer number formats - set up the flags and "break" */
453 case 'o':
454 base = 8;
455 break;
457 case 'x':
458 flags |= SMALL;
459 case 'X':
460 base = 16;
461 break;
463 case 'd':
464 case 'i':
465 flags |= SIGN;
466 case 'u':
467 break;
469 default:
470 if (str < end)
471 *str = '%';
472 ++str;
473 if (*fmt) {
474 if (str < end)
475 *str = *fmt;
476 ++str;
477 } else {
478 --fmt;
480 continue;
482 if (qualifier == 'L')
483 num = va_arg(args, long long);
484 else if (qualifier == 'l') {
485 num = va_arg(args, unsigned long);
486 if (flags & SIGN)
487 num = (signed long) num;
488 } else if (qualifier == 'Z' || qualifier == 'z') {
489 num = va_arg(args, size_t);
490 } else if (qualifier == 't') {
491 num = va_arg(args, ptrdiff_t);
492 } else if (qualifier == 'h') {
493 num = (unsigned short) va_arg(args, int);
494 if (flags & SIGN)
495 num = (signed short) num;
496 } else {
497 num = va_arg(args, unsigned int);
498 if (flags & SIGN)
499 num = (signed int) num;
501 str = number(str, end, num, base,
502 field_width, precision, flags);
504 if (size > 0) {
505 if (str < end)
506 *str = '\0';
507 else
508 end[-1] = '\0';
510 /* the trailing null byte doesn't count towards the total */
511 return str-buf;
513 EXPORT_SYMBOL(vsnprintf);
516 * vsprintf - Format a string and place it in a buffer
517 * @buf: The buffer to place the result into
518 * @fmt: The format string to use
519 * @args: Arguments for the format string
521 * The function returns the number of characters written
522 * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
523 * buffer overflows.
525 * Call this function if you are already dealing with a va_list.
526 * You probably want sprintf() instead.
528 * See the vsnprintf() documentation for format string extensions over C99.
530 int vsprintf(char *buf, const char *fmt, va_list args)
532 return vsnprintf(buf, INT_MAX, fmt, args);
534 EXPORT_SYMBOL(vsprintf);
536 int sprintf(char * buf, const char *fmt, ...)
538 va_list args;
539 int i;
541 va_start(args, fmt);
542 i=vsprintf(buf,fmt,args);
543 va_end(args);
544 return i;
546 EXPORT_SYMBOL(sprintf);
548 /* Simplified asprintf. */
549 char *vasprintf(const char *fmt, va_list ap)
551 unsigned int len;
552 char *p;
553 va_list aq;
555 va_copy(aq, ap);
556 len = vsnprintf(NULL, 0, fmt, aq);
557 va_end(aq);
559 p = malloc(len + 1);
560 if (!p)
561 return NULL;
563 vsnprintf(p, len + 1, fmt, ap);
565 return p;
567 EXPORT_SYMBOL(vasprintf);
569 char *asprintf(const char *fmt, ...)
571 va_list ap;
572 char *p;
574 va_start(ap, fmt);
575 p = vasprintf(fmt, ap);
576 va_end(ap);
578 return p;
580 EXPORT_SYMBOL(asprintf);
582 void panic(const char *fmt, ...)
584 va_list args;
585 va_start(args, fmt);
586 vprintf(fmt, args);
587 putchar('\n');
588 va_end(args);
589 #if defined (CONFIG_PANIC_HANG)
590 hang();
591 #else
592 udelay(100000); /* allow messages to go out */
593 reset_cpu(0);
594 #endif
596 EXPORT_SYMBOL(panic);