MINI2440: Auto probe for SDRAM size
[u-boot-openmoko/mini2440.git] / lib_generic / vsprintf.c
bloba1a5267ef3744eac7d2e9d6b3671b9ad74bcb8a9
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>
17 #include <common.h>
18 #if !defined (CONFIG_PANIC_HANG)
19 #include <command.h>
20 /*cmd_boot.c*/
21 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
22 #endif
24 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
26 unsigned long result = 0,value;
28 if (!base) {
29 base = 10;
30 if (*cp == '0') {
31 base = 8;
32 cp++;
33 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
34 cp++;
35 base = 16;
38 } else if (base == 16) {
39 if (cp[0] == '0' && toupper(cp[1]) == 'X')
40 cp += 2;
42 while (isxdigit(*cp) &&
43 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
44 result = result*base + value;
45 cp++;
47 if (endp)
48 *endp = (char *)cp;
49 return result;
52 long simple_strtol(const char *cp,char **endp,unsigned int base)
54 if(*cp=='-')
55 return -simple_strtoul(cp+1,endp,base);
56 return simple_strtoul(cp,endp,base);
59 #ifdef CFG_64BIT_STRTOUL
60 unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base)
62 unsigned long long result = 0, value;
64 if (*cp == '0') {
65 cp++;
66 if ((*cp == 'x') && isxdigit (cp[1])) {
67 base = 16;
68 cp++;
70 if (!base) {
71 base = 8;
74 if (!base) {
75 base = 10;
77 while (isxdigit (*cp) && (value = isdigit (*cp)
78 ? *cp - '0'
79 : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) {
80 result = result * base + value;
81 cp++;
83 if (endp)
84 *endp = (char *) cp;
85 return result;
87 #endif /* CFG_64BIT_STRTOUL */
89 /* we use this so that we can do without the ctype library */
90 #define is_digit(c) ((c) >= '0' && (c) <= '9')
92 static int skip_atoi(const char **s)
94 int i=0;
96 while (is_digit(**s))
97 i = i*10 + *((*s)++) - '0';
98 return i;
101 #define ZEROPAD 1 /* pad with zero */
102 #define SIGN 2 /* unsigned/signed long */
103 #define PLUS 4 /* show plus */
104 #define SPACE 8 /* space if plus */
105 #define LEFT 16 /* left justified */
106 #define SPECIAL 32 /* 0x */
107 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
109 #ifdef CFG_64BIT_VSPRINTF
110 #define do_div(n,base) ({ \
111 unsigned int __res; \
112 __res = ((unsigned long long) n) % base; \
113 n = ((unsigned long long) n) / base; \
114 __res; \
116 #else
117 #define do_div(n,base) ({ \
118 int __res; \
119 __res = ((unsigned long) n) % base; \
120 n = ((unsigned long) n) / base; \
121 __res; \
123 #endif
125 #ifdef CFG_64BIT_VSPRINTF
126 static char * number(char * str, long long num, unsigned int base, int size, int precision ,int type)
127 #else
128 static char * number(char * str, long num, unsigned int base, int size, int precision ,int type)
129 #endif
131 char c,sign,tmp[66];
132 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
133 int i;
135 if (type & LARGE)
136 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
137 if (type & LEFT)
138 type &= ~ZEROPAD;
139 if (base < 2 || base > 36)
140 return 0;
141 c = (type & ZEROPAD) ? '0' : ' ';
142 sign = 0;
143 if (type & SIGN) {
144 if (num < 0) {
145 sign = '-';
146 num = -num;
147 size--;
148 } else if (type & PLUS) {
149 sign = '+';
150 size--;
151 } else if (type & SPACE) {
152 sign = ' ';
153 size--;
156 if (type & SPECIAL) {
157 if (base == 16)
158 size -= 2;
159 else if (base == 8)
160 size--;
162 i = 0;
163 if (num == 0)
164 tmp[i++]='0';
165 else while (num != 0)
166 tmp[i++] = digits[do_div(num,base)];
167 if (i > precision)
168 precision = i;
169 size -= precision;
170 if (!(type&(ZEROPAD+LEFT)))
171 while(size-->0)
172 *str++ = ' ';
173 if (sign)
174 *str++ = sign;
175 if (type & SPECIAL) {
176 if (base==8)
177 *str++ = '0';
178 else if (base==16) {
179 *str++ = '0';
180 *str++ = digits[33];
183 if (!(type & LEFT))
184 while (size-- > 0)
185 *str++ = c;
186 while (i < precision--)
187 *str++ = '0';
188 while (i-- > 0)
189 *str++ = tmp[i];
190 while (size-- > 0)
191 *str++ = ' ';
192 return str;
195 /* Forward decl. needed for IP address printing stuff... */
196 int sprintf(char * buf, const char *fmt, ...);
198 int vsprintf(char *buf, const char *fmt, va_list args)
200 int len;
201 #ifdef CFG_64BIT_VSPRINTF
202 unsigned long long num;
203 #else
204 unsigned long num;
205 #endif
206 int i, base;
207 char * str;
208 const char *s;
210 int flags; /* flags to number() */
212 int field_width; /* width of output field */
213 int precision; /* min. # of digits for integers; max
214 number of chars for from string */
215 int qualifier; /* 'h', 'l', or 'q' for integer fields */
217 for (str=buf ; *fmt ; ++fmt) {
218 if (*fmt != '%') {
219 *str++ = *fmt;
220 continue;
223 /* process flags */
224 flags = 0;
225 repeat:
226 ++fmt; /* this also skips first '%' */
227 switch (*fmt) {
228 case '-': flags |= LEFT; goto repeat;
229 case '+': flags |= PLUS; goto repeat;
230 case ' ': flags |= SPACE; goto repeat;
231 case '#': flags |= SPECIAL; goto repeat;
232 case '0': flags |= ZEROPAD; goto repeat;
235 /* get field width */
236 field_width = -1;
237 if (is_digit(*fmt))
238 field_width = skip_atoi(&fmt);
239 else if (*fmt == '*') {
240 ++fmt;
241 /* it's the next argument */
242 field_width = va_arg(args, int);
243 if (field_width < 0) {
244 field_width = -field_width;
245 flags |= LEFT;
249 /* get the precision */
250 precision = -1;
251 if (*fmt == '.') {
252 ++fmt;
253 if (is_digit(*fmt))
254 precision = skip_atoi(&fmt);
255 else if (*fmt == '*') {
256 ++fmt;
257 /* it's the next argument */
258 precision = va_arg(args, int);
260 if (precision < 0)
261 precision = 0;
264 /* get the conversion qualifier */
265 qualifier = -1;
266 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'q') {
267 qualifier = *fmt;
268 if (qualifier == 'l' && *(fmt+1) == 'l') {
269 qualifier = 'q';
270 ++fmt;
272 ++fmt;
275 /* default base */
276 base = 10;
278 switch (*fmt) {
279 case 'c':
280 if (!(flags & LEFT))
281 while (--field_width > 0)
282 *str++ = ' ';
283 *str++ = (unsigned char) va_arg(args, int);
284 while (--field_width > 0)
285 *str++ = ' ';
286 continue;
288 case 's':
289 s = va_arg(args, char *);
290 if (!s)
291 s = "<NULL>";
293 len = strnlen(s, precision);
295 if (!(flags & LEFT))
296 while (len < field_width--)
297 *str++ = ' ';
298 for (i = 0; i < len; ++i)
299 *str++ = *s++;
300 while (len < field_width--)
301 *str++ = ' ';
302 continue;
304 case 'p':
305 if (field_width == -1) {
306 field_width = 2*sizeof(void *);
307 flags |= ZEROPAD;
309 str = number(str,
310 (unsigned long) va_arg(args, void *), 16,
311 field_width, precision, flags);
312 continue;
315 case 'n':
316 if (qualifier == 'l') {
317 long * ip = va_arg(args, long *);
318 *ip = (str - buf);
319 } else {
320 int * ip = va_arg(args, int *);
321 *ip = (str - buf);
323 continue;
325 case '%':
326 *str++ = '%';
327 continue;
329 /* integer number formats - set up the flags and "break" */
330 case 'o':
331 base = 8;
332 break;
334 case 'X':
335 flags |= LARGE;
336 case 'x':
337 base = 16;
338 break;
340 case 'd':
341 case 'i':
342 flags |= SIGN;
343 case 'u':
344 break;
346 default:
347 *str++ = '%';
348 if (*fmt)
349 *str++ = *fmt;
350 else
351 --fmt;
352 continue;
354 #ifdef CFG_64BIT_VSPRINTF
355 if (qualifier == 'q') /* "quad" for 64 bit variables */
356 num = va_arg(args, unsigned long long);
357 else
358 #endif
359 if (qualifier == 'l')
360 num = va_arg(args, unsigned long);
361 else if (qualifier == 'h') {
362 num = (unsigned short) va_arg(args, int);
363 if (flags & SIGN)
364 num = (short) num;
365 } else if (flags & SIGN)
366 num = va_arg(args, int);
367 else
368 num = va_arg(args, unsigned int);
369 str = number(str, num, base, field_width, precision, flags);
371 *str = '\0';
372 return str-buf;
375 int sprintf(char * buf, const char *fmt, ...)
377 va_list args;
378 int i;
380 va_start(args, fmt);
381 i=vsprintf(buf,fmt,args);
382 va_end(args);
383 return i;
386 void panic(const char *fmt, ...)
388 va_list args;
389 va_start(args, fmt);
390 vprintf(fmt, args);
391 putc('\n');
392 va_end(args);
393 #if defined (CONFIG_PANIC_HANG)
394 hang();
395 #else
396 udelay (100000); /* allow messages to go out */
397 do_reset (NULL, 0, 0, NULL);
398 #endif