blob: 2740f2e769be35347805218919db4631df221312 [file] [log] [blame]
wdenk153d5112002-08-30 11:07:04 +00001/*
2 * linux/lib/vsprintf.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8/*
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
10 */
11
12#include <stdarg.h>
13#include <linux/types.h>
14#include <linux/string.h>
15#include <linux/ctype.h>
16
17#include <common.h>
18#if !defined (CONFIG_PANIC_HANG)
19#include <command.h>
wdenk8bde7f72003-06-27 21:31:46 +000020/*cmd_boot.c*/
21extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
wdenk153d5112002-08-30 11:07:04 +000022#endif
23
24unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
25{
26 unsigned long result = 0,value;
27
28 if (*cp == '0') {
29 cp++;
30 if ((*cp == 'x') && isxdigit(cp[1])) {
31 base = 16;
32 cp++;
33 }
34 if (!base) {
35 base = 8;
36 }
37 }
38 if (!base) {
39 base = 10;
40 }
41 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
42 ? toupper(*cp) : *cp)-'A'+10) < base) {
43 result = result*base + value;
44 cp++;
45 }
46 if (endp)
47 *endp = (char *)cp;
48 return result;
49}
50
51long simple_strtol(const char *cp,char **endp,unsigned int base)
52{
53 if(*cp=='-')
54 return -simple_strtoul(cp+1,endp,base);
55 return simple_strtoul(cp,endp,base);
56}
57
wdenk42dfe7a2004-03-14 22:25:36 +000058#ifdef CFG_64BIT_STRTOUL
wdenkc40b2952004-03-13 23:29:43 +000059unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base)
60{
61 unsigned long long result = 0, value;
62
63 if (*cp == '0') {
64 cp++;
65 if ((*cp == 'x') && isxdigit (cp[1])) {
66 base = 16;
67 cp++;
68 }
69 if (!base) {
70 base = 8;
71 }
72 }
73 if (!base) {
74 base = 10;
75 }
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++;
81 }
82 if (endp)
83 *endp = (char *) cp;
84 return result;
85}
86#endif /* CFG_64BIT_STRTOUL */
87
wdenk153d5112002-08-30 11:07:04 +000088/* we use this so that we can do without the ctype library */
89#define is_digit(c) ((c) >= '0' && (c) <= '9')
90
91static int skip_atoi(const char **s)
92{
93 int i=0;
94
95 while (is_digit(**s))
96 i = i*10 + *((*s)++) - '0';
97 return i;
98}
99
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 SPECIAL 32 /* 0x */
106#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
107
108#define do_div(n,base) ({ \
wdenkc40b2952004-03-13 23:29:43 +0000109 int __res; \
110 __res = ((unsigned long) n) % (unsigned) base; \
111 n = ((unsigned long) n) / (unsigned) base; \
112 __res; \
113})
wdenk153d5112002-08-30 11:07:04 +0000114
wdenk42dfe7a2004-03-14 22:25:36 +0000115#ifdef CFG_64BIT_VSPRINTF
wdenkc40b2952004-03-13 23:29:43 +0000116static char * number(char * str, long long num, int base, int size, int precision ,int type)
117#else
118static char * number(char * str, long num, int base, int size, int precision ,int type)
119#endif
wdenk153d5112002-08-30 11:07:04 +0000120{
121 char c,sign,tmp[66];
122 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
123 int i;
124
125 if (type & LARGE)
126 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
127 if (type & LEFT)
128 type &= ~ZEROPAD;
129 if (base < 2 || base > 36)
130 return 0;
131 c = (type & ZEROPAD) ? '0' : ' ';
132 sign = 0;
133 if (type & SIGN) {
134 if (num < 0) {
135 sign = '-';
136 num = -num;
137 size--;
138 } else if (type & PLUS) {
139 sign = '+';
140 size--;
141 } else if (type & SPACE) {
142 sign = ' ';
143 size--;
144 }
145 }
146 if (type & SPECIAL) {
147 if (base == 16)
148 size -= 2;
149 else if (base == 8)
150 size--;
151 }
152 i = 0;
153 if (num == 0)
154 tmp[i++]='0';
155 else while (num != 0)
156 tmp[i++] = digits[do_div(num,base)];
157 if (i > precision)
158 precision = i;
159 size -= precision;
160 if (!(type&(ZEROPAD+LEFT)))
161 while(size-->0)
162 *str++ = ' ';
163 if (sign)
164 *str++ = sign;
165 if (type & SPECIAL) {
166 if (base==8)
167 *str++ = '0';
168 else if (base==16) {
169 *str++ = '0';
170 *str++ = digits[33];
171 }
172 }
173 if (!(type & LEFT))
174 while (size-- > 0)
175 *str++ = c;
176 while (i < precision--)
177 *str++ = '0';
178 while (i-- > 0)
179 *str++ = tmp[i];
180 while (size-- > 0)
181 *str++ = ' ';
182 return str;
183}
184
185/* Forward decl. needed for IP address printing stuff... */
186int sprintf(char * buf, const char *fmt, ...);
187
188int vsprintf(char *buf, const char *fmt, va_list args)
189{
190 int len;
wdenk42dfe7a2004-03-14 22:25:36 +0000191#ifdef CFG_64BIT_VSPRINTF
wdenkc40b2952004-03-13 23:29:43 +0000192 unsigned long long num;
193#else
wdenk153d5112002-08-30 11:07:04 +0000194 unsigned long num;
wdenkc40b2952004-03-13 23:29:43 +0000195#endif
wdenk153d5112002-08-30 11:07:04 +0000196 int i, base;
197 char * str;
198 const char *s;
199
200 int flags; /* flags to number() */
201
202 int field_width; /* width of output field */
203 int precision; /* min. # of digits for integers; max
204 number of chars for from string */
wdenkc40b2952004-03-13 23:29:43 +0000205 int qualifier; /* 'h', 'l', or 'q' for integer fields */
wdenk153d5112002-08-30 11:07:04 +0000206
207 for (str=buf ; *fmt ; ++fmt) {
208 if (*fmt != '%') {
209 *str++ = *fmt;
210 continue;
211 }
212
213 /* process flags */
214 flags = 0;
215 repeat:
216 ++fmt; /* this also skips first '%' */
217 switch (*fmt) {
218 case '-': flags |= LEFT; goto repeat;
219 case '+': flags |= PLUS; goto repeat;
220 case ' ': flags |= SPACE; goto repeat;
221 case '#': flags |= SPECIAL; goto repeat;
222 case '0': flags |= ZEROPAD; goto repeat;
223 }
224
225 /* get field width */
226 field_width = -1;
227 if (is_digit(*fmt))
228 field_width = skip_atoi(&fmt);
229 else if (*fmt == '*') {
230 ++fmt;
231 /* it's the next argument */
232 field_width = va_arg(args, int);
233 if (field_width < 0) {
234 field_width = -field_width;
235 flags |= LEFT;
236 }
237 }
238
239 /* get the precision */
240 precision = -1;
241 if (*fmt == '.') {
242 ++fmt;
243 if (is_digit(*fmt))
244 precision = skip_atoi(&fmt);
245 else if (*fmt == '*') {
246 ++fmt;
247 /* it's the next argument */
248 precision = va_arg(args, int);
249 }
250 if (precision < 0)
251 precision = 0;
252 }
253
254 /* get the conversion qualifier */
255 qualifier = -1;
wdenkc40b2952004-03-13 23:29:43 +0000256 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'q') {
wdenk153d5112002-08-30 11:07:04 +0000257 qualifier = *fmt;
258 ++fmt;
259 }
260
261 /* default base */
262 base = 10;
263
264 switch (*fmt) {
265 case 'c':
266 if (!(flags & LEFT))
267 while (--field_width > 0)
268 *str++ = ' ';
269 *str++ = (unsigned char) va_arg(args, int);
270 while (--field_width > 0)
271 *str++ = ' ';
272 continue;
273
274 case 's':
275 s = va_arg(args, char *);
276 if (!s)
277 s = "<NULL>";
278
279 len = strnlen(s, precision);
280
281 if (!(flags & LEFT))
282 while (len < field_width--)
283 *str++ = ' ';
284 for (i = 0; i < len; ++i)
285 *str++ = *s++;
286 while (len < field_width--)
287 *str++ = ' ';
288 continue;
289
290 case 'p':
291 if (field_width == -1) {
292 field_width = 2*sizeof(void *);
293 flags |= ZEROPAD;
294 }
295 str = number(str,
296 (unsigned long) va_arg(args, void *), 16,
297 field_width, precision, flags);
298 continue;
299
300
301 case 'n':
302 if (qualifier == 'l') {
303 long * ip = va_arg(args, long *);
304 *ip = (str - buf);
305 } else {
306 int * ip = va_arg(args, int *);
307 *ip = (str - buf);
308 }
309 continue;
310
311 case '%':
312 *str++ = '%';
313 continue;
314
315 /* integer number formats - set up the flags and "break" */
316 case 'o':
317 base = 8;
318 break;
319
320 case 'X':
321 flags |= LARGE;
322 case 'x':
323 base = 16;
324 break;
325
326 case 'd':
327 case 'i':
328 flags |= SIGN;
329 case 'u':
330 break;
331
332 default:
333 *str++ = '%';
334 if (*fmt)
335 *str++ = *fmt;
336 else
337 --fmt;
338 continue;
339 }
wdenk42dfe7a2004-03-14 22:25:36 +0000340#ifdef CFG_64BIT_VSPRINTF
wdenkc40b2952004-03-13 23:29:43 +0000341 if (qualifier == 'q') /* "quad" for 64 bit variables */
342 num = va_arg(args, unsigned long long);
343 else
344#endif
wdenk153d5112002-08-30 11:07:04 +0000345 if (qualifier == 'l')
346 num = va_arg(args, unsigned long);
347 else if (qualifier == 'h') {
348 num = (unsigned short) va_arg(args, int);
349 if (flags & SIGN)
350 num = (short) num;
351 } else if (flags & SIGN)
352 num = va_arg(args, int);
353 else
354 num = va_arg(args, unsigned int);
355 str = number(str, num, base, field_width, precision, flags);
356 }
357 *str = '\0';
358 return str-buf;
359}
360
361int sprintf(char * buf, const char *fmt, ...)
362{
363 va_list args;
364 int i;
365
366 va_start(args, fmt);
367 i=vsprintf(buf,fmt,args);
368 va_end(args);
369 return i;
370}
371
372void panic(const char *fmt, ...)
373{
374 va_list args;
375 va_start(args, fmt);
wdenk6dd652f2003-06-19 23:40:20 +0000376 vprintf(fmt, args);
wdenk153d5112002-08-30 11:07:04 +0000377 putc('\n');
378 va_end(args);
379#if defined (CONFIG_PANIC_HANG)
380 hang();
381#else
382 udelay (100000); /* allow messages to go out */
383 do_reset (NULL, 0, 0, NULL);
384#endif
385}