]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - lib_generic/vsprintf.c
Add support for CompactFlash on ATC board
[karo-tx-uboot.git] / lib_generic / vsprintf.c
1 /*
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>
20 #include <cmd_boot.h>           /* for do_reset() prototype */
21 #endif
22
23 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
24 {
25         unsigned long result = 0,value;
26
27         if (*cp == '0') {
28                 cp++;
29                 if ((*cp == 'x') && isxdigit(cp[1])) {
30                         base = 16;
31                         cp++;
32                 }
33                 if (!base) {
34                         base = 8;
35                 }
36         }
37         if (!base) {
38                 base = 10;
39         }
40         while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
41             ? toupper(*cp) : *cp)-'A'+10) < base) {
42                 result = result*base + value;
43                 cp++;
44         }
45         if (endp)
46                 *endp = (char *)cp;
47         return result;
48 }
49
50 long simple_strtol(const char *cp,char **endp,unsigned int base)
51 {
52         if(*cp=='-')
53                 return -simple_strtoul(cp+1,endp,base);
54         return simple_strtoul(cp,endp,base);
55 }
56
57 /* we use this so that we can do without the ctype library */
58 #define is_digit(c)     ((c) >= '0' && (c) <= '9')
59
60 static int skip_atoi(const char **s)
61 {
62         int i=0;
63
64         while (is_digit(**s))
65                 i = i*10 + *((*s)++) - '0';
66         return i;
67 }
68
69 #define ZEROPAD 1               /* pad with zero */
70 #define SIGN    2               /* unsigned/signed long */
71 #define PLUS    4               /* show plus */
72 #define SPACE   8               /* space if plus */
73 #define LEFT    16              /* left justified */
74 #define SPECIAL 32              /* 0x */
75 #define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
76
77 #define do_div(n,base) ({ \
78 int __res; \
79 __res = ((unsigned long) n) % (unsigned) base; \
80 n = ((unsigned long) n) / (unsigned) base; \
81 __res; })
82
83 static char * number(char * str, long num, int base, int size, int precision
84         ,int type)
85 {
86         char c,sign,tmp[66];
87         const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
88         int i;
89
90         if (type & LARGE)
91                 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
92         if (type & LEFT)
93                 type &= ~ZEROPAD;
94         if (base < 2 || base > 36)
95                 return 0;
96         c = (type & ZEROPAD) ? '0' : ' ';
97         sign = 0;
98         if (type & SIGN) {
99                 if (num < 0) {
100                         sign = '-';
101                         num = -num;
102                         size--;
103                 } else if (type & PLUS) {
104                         sign = '+';
105                         size--;
106                 } else if (type & SPACE) {
107                         sign = ' ';
108                         size--;
109                 }
110         }
111         if (type & SPECIAL) {
112                 if (base == 16)
113                         size -= 2;
114                 else if (base == 8)
115                         size--;
116         }
117         i = 0;
118         if (num == 0)
119                 tmp[i++]='0';
120         else while (num != 0)
121                 tmp[i++] = digits[do_div(num,base)];
122         if (i > precision)
123                 precision = i;
124         size -= precision;
125         if (!(type&(ZEROPAD+LEFT)))
126                 while(size-->0)
127                         *str++ = ' ';
128         if (sign)
129                 *str++ = sign;
130         if (type & SPECIAL) {
131                 if (base==8)
132                         *str++ = '0';
133                 else if (base==16) {
134                         *str++ = '0';
135                         *str++ = digits[33];
136                 }
137         }
138         if (!(type & LEFT))
139                 while (size-- > 0)
140                         *str++ = c;
141         while (i < precision--)
142                 *str++ = '0';
143         while (i-- > 0)
144                 *str++ = tmp[i];
145         while (size-- > 0)
146                 *str++ = ' ';
147         return str;
148 }
149
150 /* Forward decl. needed for IP address printing stuff... */
151 int sprintf(char * buf, const char *fmt, ...);
152
153 int vsprintf(char *buf, const char *fmt, va_list args)
154 {
155         int len;
156         unsigned long num;
157         int i, base;
158         char * str;
159         const char *s;
160
161         int flags;              /* flags to number() */
162
163         int field_width;        /* width of output field */
164         int precision;          /* min. # of digits for integers; max
165                                    number of chars for from string */
166         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
167
168         for (str=buf ; *fmt ; ++fmt) {
169                 if (*fmt != '%') {
170                         *str++ = *fmt;
171                         continue;
172                 }
173
174                 /* process flags */
175                 flags = 0;
176                 repeat:
177                         ++fmt;          /* this also skips first '%' */
178                         switch (*fmt) {
179                                 case '-': flags |= LEFT; goto repeat;
180                                 case '+': flags |= PLUS; goto repeat;
181                                 case ' ': flags |= SPACE; goto repeat;
182                                 case '#': flags |= SPECIAL; goto repeat;
183                                 case '0': flags |= ZEROPAD; goto repeat;
184                                 }
185
186                 /* get field width */
187                 field_width = -1;
188                 if (is_digit(*fmt))
189                         field_width = skip_atoi(&fmt);
190                 else if (*fmt == '*') {
191                         ++fmt;
192                         /* it's the next argument */
193                         field_width = va_arg(args, int);
194                         if (field_width < 0) {
195                                 field_width = -field_width;
196                                 flags |= LEFT;
197                         }
198                 }
199
200                 /* get the precision */
201                 precision = -1;
202                 if (*fmt == '.') {
203                         ++fmt;
204                         if (is_digit(*fmt))
205                                 precision = skip_atoi(&fmt);
206                         else if (*fmt == '*') {
207                                 ++fmt;
208                                 /* it's the next argument */
209                                 precision = va_arg(args, int);
210                         }
211                         if (precision < 0)
212                                 precision = 0;
213                 }
214
215                 /* get the conversion qualifier */
216                 qualifier = -1;
217                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
218                         qualifier = *fmt;
219                         ++fmt;
220                 }
221
222                 /* default base */
223                 base = 10;
224
225                 switch (*fmt) {
226                 case 'c':
227                         if (!(flags & LEFT))
228                                 while (--field_width > 0)
229                                         *str++ = ' ';
230                         *str++ = (unsigned char) va_arg(args, int);
231                         while (--field_width > 0)
232                                 *str++ = ' ';
233                         continue;
234
235                 case 's':
236                         s = va_arg(args, char *);
237                         if (!s)
238                                 s = "<NULL>";
239
240                         len = strnlen(s, precision);
241
242                         if (!(flags & LEFT))
243                                 while (len < field_width--)
244                                         *str++ = ' ';
245                         for (i = 0; i < len; ++i)
246                                 *str++ = *s++;
247                         while (len < field_width--)
248                                 *str++ = ' ';
249                         continue;
250
251                 case 'p':
252                         if (field_width == -1) {
253                                 field_width = 2*sizeof(void *);
254                                 flags |= ZEROPAD;
255                         }
256                         str = number(str,
257                                 (unsigned long) va_arg(args, void *), 16,
258                                 field_width, precision, flags);
259                         continue;
260
261
262                 case 'n':
263                         if (qualifier == 'l') {
264                                 long * ip = va_arg(args, long *);
265                                 *ip = (str - buf);
266                         } else {
267                                 int * ip = va_arg(args, int *);
268                                 *ip = (str - buf);
269                         }
270                         continue;
271
272                 case '%':
273                         *str++ = '%';
274                         continue;
275
276                 /* integer number formats - set up the flags and "break" */
277                 case 'o':
278                         base = 8;
279                         break;
280
281                 case 'X':
282                         flags |= LARGE;
283                 case 'x':
284                         base = 16;
285                         break;
286
287                 case 'd':
288                 case 'i':
289                         flags |= SIGN;
290                 case 'u':
291                         break;
292
293                 default:
294                         *str++ = '%';
295                         if (*fmt)
296                                 *str++ = *fmt;
297                         else
298                                 --fmt;
299                         continue;
300                 }
301                 if (qualifier == 'l')
302                         num = va_arg(args, unsigned long);
303                 else if (qualifier == 'h') {
304                         num = (unsigned short) va_arg(args, int);
305                         if (flags & SIGN)
306                                 num = (short) num;
307                 } else if (flags & SIGN)
308                         num = va_arg(args, int);
309                 else
310                         num = va_arg(args, unsigned int);
311                 str = number(str, num, base, field_width, precision, flags);
312         }
313         *str = '\0';
314         return str-buf;
315 }
316
317 int sprintf(char * buf, const char *fmt, ...)
318 {
319         va_list args;
320         int i;
321
322         va_start(args, fmt);
323         i=vsprintf(buf,fmt,args);
324         va_end(args);
325         return i;
326 }
327
328 void panic(const char *fmt, ...)
329 {
330         va_list args;
331         va_start(args, fmt);
332         printf(fmt);
333         putc('\n');
334         va_end(args);
335 #if defined (CONFIG_PANIC_HANG)
336         hang();
337 #else
338         udelay (100000);        /* allow messages to go out */
339         do_reset (NULL, 0, 0, NULL);
340 #endif
341 }