ar71xx: fix random wireless mac address on the TEW-632BRP/DIR-615 boards
[openwrt/svn-archive/archive.git] / target / linux / generic-2.6 / patches-2.6.28 / 981-vsprintf_backport.patch
1 --- a/lib/vsprintf.c
2 +++ b/lib/vsprintf.c
3 @@ -170,6 +170,8 @@ int strict_strtoul(const char *cp, unsig
4 return -EINVAL;
5
6 val = simple_strtoul(cp, &tail, base);
7 + if (tail == cp)
8 + return -EINVAL;
9 if ((*tail == '\0') ||
10 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
11 *res = val;
12 @@ -241,6 +243,8 @@ int strict_strtoull(const char *cp, unsi
13 return -EINVAL;
14
15 val = simple_strtoull(cp, &tail, base);
16 + if (tail == cp)
17 + return -EINVAL;
18 if ((*tail == '\0') ||
19 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
20 *res = val;
21 @@ -392,7 +396,38 @@ static noinline char* put_dec(char *buf,
22 #define SMALL 32 /* Must be 32 == 0x20 */
23 #define SPECIAL 64 /* 0x */
24
25 -static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
26 +enum format_type {
27 + FORMAT_TYPE_NONE, /* Just a string part */
28 + FORMAT_TYPE_WIDTH,
29 + FORMAT_TYPE_PRECISION,
30 + FORMAT_TYPE_CHAR,
31 + FORMAT_TYPE_STR,
32 + FORMAT_TYPE_PTR,
33 + FORMAT_TYPE_PERCENT_CHAR,
34 + FORMAT_TYPE_INVALID,
35 + FORMAT_TYPE_LONG_LONG,
36 + FORMAT_TYPE_ULONG,
37 + FORMAT_TYPE_LONG,
38 + FORMAT_TYPE_USHORT,
39 + FORMAT_TYPE_SHORT,
40 + FORMAT_TYPE_UINT,
41 + FORMAT_TYPE_INT,
42 + FORMAT_TYPE_NRCHARS,
43 + FORMAT_TYPE_SIZE_T,
44 + FORMAT_TYPE_PTRDIFF
45 +};
46 +
47 +struct printf_spec {
48 + enum format_type type;
49 + int flags; /* flags to number() */
50 + int field_width; /* width of output field */
51 + int base;
52 + int precision; /* # of digits/chars */
53 + int qualifier;
54 +};
55 +
56 +static char *number(char *buf, char *end, unsigned long long num,
57 + struct printf_spec spec)
58 {
59 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
60 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
61 @@ -400,32 +435,32 @@ static char *number(char *buf, char *end
62 char tmp[66];
63 char sign;
64 char locase;
65 - int need_pfx = ((type & SPECIAL) && base != 10);
66 + int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
67 int i;
68
69 /* locase = 0 or 0x20. ORing digits or letters with 'locase'
70 * produces same digits or (maybe lowercased) letters */
71 - locase = (type & SMALL);
72 - if (type & LEFT)
73 - type &= ~ZEROPAD;
74 + locase = (spec.flags & SMALL);
75 + if (spec.flags & LEFT)
76 + spec.flags &= ~ZEROPAD;
77 sign = 0;
78 - if (type & SIGN) {
79 + if (spec.flags & SIGN) {
80 if ((signed long long) num < 0) {
81 sign = '-';
82 num = - (signed long long) num;
83 - size--;
84 - } else if (type & PLUS) {
85 + spec.field_width--;
86 + } else if (spec.flags & PLUS) {
87 sign = '+';
88 - size--;
89 - } else if (type & SPACE) {
90 + spec.field_width--;
91 + } else if (spec.flags & SPACE) {
92 sign = ' ';
93 - size--;
94 + spec.field_width--;
95 }
96 }
97 if (need_pfx) {
98 - size--;
99 - if (base == 16)
100 - size--;
101 + spec.field_width--;
102 + if (spec.base == 16)
103 + spec.field_width--;
104 }
105
106 /* generate full string in tmp[], in reverse order */
107 @@ -437,10 +472,10 @@ static char *number(char *buf, char *end
108 tmp[i++] = (digits[do_div(num,base)] | locase);
109 } while (num != 0);
110 */
111 - else if (base != 10) { /* 8 or 16 */
112 - int mask = base - 1;
113 + else if (spec.base != 10) { /* 8 or 16 */
114 + int mask = spec.base - 1;
115 int shift = 3;
116 - if (base == 16) shift = 4;
117 + if (spec.base == 16) shift = 4;
118 do {
119 tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
120 num >>= shift;
121 @@ -450,12 +485,12 @@ static char *number(char *buf, char *end
122 }
123
124 /* printing 100 using %2d gives "100", not "00" */
125 - if (i > precision)
126 - precision = i;
127 + if (i > spec.precision)
128 + spec.precision = i;
129 /* leading space padding */
130 - size -= precision;
131 - if (!(type & (ZEROPAD+LEFT))) {
132 - while(--size >= 0) {
133 + spec.field_width -= spec.precision;
134 + if (!(spec.flags & (ZEROPAD+LEFT))) {
135 + while(--spec.field_width >= 0) {
136 if (buf < end)
137 *buf = ' ';
138 ++buf;
139 @@ -472,23 +507,23 @@ static char *number(char *buf, char *end
140 if (buf < end)
141 *buf = '0';
142 ++buf;
143 - if (base == 16) {
144 + if (spec.base == 16) {
145 if (buf < end)
146 *buf = ('X' | locase);
147 ++buf;
148 }
149 }
150 /* zero or space padding */
151 - if (!(type & LEFT)) {
152 - char c = (type & ZEROPAD) ? '0' : ' ';
153 - while (--size >= 0) {
154 + if (!(spec.flags & LEFT)) {
155 + char c = (spec.flags & ZEROPAD) ? '0' : ' ';
156 + while (--spec.field_width >= 0) {
157 if (buf < end)
158 *buf = c;
159 ++buf;
160 }
161 }
162 /* hmm even more zero padding? */
163 - while (i <= --precision) {
164 + while (i <= --spec.precision) {
165 if (buf < end)
166 *buf = '0';
167 ++buf;
168 @@ -500,7 +535,7 @@ static char *number(char *buf, char *end
169 ++buf;
170 }
171 /* trailing space padding */
172 - while (--size >= 0) {
173 + while (--spec.field_width >= 0) {
174 if (buf < end)
175 *buf = ' ';
176 ++buf;
177 @@ -508,17 +543,17 @@ static char *number(char *buf, char *end
178 return buf;
179 }
180
181 -static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags)
182 +static char *string(char *buf, char *end, char *s, struct printf_spec spec)
183 {
184 int len, i;
185
186 if ((unsigned long)s < PAGE_SIZE)
187 s = "<NULL>";
188
189 - len = strnlen(s, precision);
190 + len = strnlen(s, spec.precision);
191
192 - if (!(flags & LEFT)) {
193 - while (len < field_width--) {
194 + if (!(spec.flags & LEFT)) {
195 + while (len < spec.field_width--) {
196 if (buf < end)
197 *buf = ' ';
198 ++buf;
199 @@ -529,7 +564,7 @@ static char *string(char *buf, char *end
200 *buf = *s;
201 ++buf; ++s;
202 }
203 - while (len < field_width--) {
204 + while (len < spec.field_width--) {
205 if (buf < end)
206 *buf = ' ';
207 ++buf;
208 @@ -537,21 +572,24 @@ static char *string(char *buf, char *end
209 return buf;
210 }
211
212 -static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
213 +static char *symbol_string(char *buf, char *end, void *ptr,
214 + struct printf_spec spec)
215 {
216 unsigned long value = (unsigned long) ptr;
217 #ifdef CONFIG_KALLSYMS
218 char sym[KSYM_SYMBOL_LEN];
219 sprint_symbol(sym, value);
220 - return string(buf, end, sym, field_width, precision, flags);
221 + return string(buf, end, sym, spec);
222 #else
223 - field_width = 2*sizeof(void *);
224 - flags |= SPECIAL | SMALL | ZEROPAD;
225 - return number(buf, end, value, 16, field_width, precision, flags);
226 + spec.field_width = 2*sizeof(void *);
227 + spec.flags |= SPECIAL | SMALL | ZEROPAD;
228 + spec.base = 16;
229 + return number(buf, end, value, spec);
230 #endif
231 }
232
233 -static char *resource_string(char *buf, char *end, struct resource *res, int field_width, int precision, int flags)
234 +static char *resource_string(char *buf, char *end, struct resource *res,
235 + struct printf_spec spec)
236 {
237 #ifndef IO_RSRC_PRINTK_SIZE
238 #define IO_RSRC_PRINTK_SIZE 4
239 @@ -560,7 +598,11 @@ static char *resource_string(char *buf,
240 #ifndef MEM_RSRC_PRINTK_SIZE
241 #define MEM_RSRC_PRINTK_SIZE 8
242 #endif
243 -
244 + struct printf_spec num_spec = {
245 + .base = 16,
246 + .precision = -1,
247 + .flags = SPECIAL | SMALL | ZEROPAD,
248 + };
249 /* room for the actual numbers, the two "0x", -, [, ] and the final zero */
250 char sym[4*sizeof(resource_size_t) + 8];
251 char *p = sym, *pend = sym + sizeof(sym);
252 @@ -572,13 +614,73 @@ static char *resource_string(char *buf,
253 size = MEM_RSRC_PRINTK_SIZE;
254
255 *p++ = '[';
256 - p = number(p, pend, res->start, 16, size, -1, SPECIAL | SMALL | ZEROPAD);
257 + num_spec.field_width = size;
258 + p = number(p, pend, res->start, num_spec);
259 *p++ = '-';
260 - p = number(p, pend, res->end, 16, size, -1, SPECIAL | SMALL | ZEROPAD);
261 + p = number(p, pend, res->end, num_spec);
262 *p++ = ']';
263 *p = 0;
264
265 - return string(buf, end, sym, field_width, precision, flags);
266 + return string(buf, end, sym, spec);
267 +}
268 +
269 +static char *mac_address_string(char *buf, char *end, u8 *addr,
270 + struct printf_spec spec)
271 +{
272 + char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
273 + char *p = mac_addr;
274 + int i;
275 +
276 + for (i = 0; i < 6; i++) {
277 + p = pack_hex_byte(p, addr[i]);
278 + if (!(spec.flags & SPECIAL) && i != 5)
279 + *p++ = ':';
280 + }
281 + *p = '\0';
282 + spec.flags &= ~SPECIAL;
283 +
284 + return string(buf, end, mac_addr, spec);
285 +}
286 +
287 +static char *ip6_addr_string(char *buf, char *end, u8 *addr,
288 + struct printf_spec spec)
289 +{
290 + char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
291 + char *p = ip6_addr;
292 + int i;
293 +
294 + for (i = 0; i < 8; i++) {
295 + p = pack_hex_byte(p, addr[2 * i]);
296 + p = pack_hex_byte(p, addr[2 * i + 1]);
297 + if (!(spec.flags & SPECIAL) && i != 7)
298 + *p++ = ':';
299 + }
300 + *p = '\0';
301 + spec.flags &= ~SPECIAL;
302 +
303 + return string(buf, end, ip6_addr, spec);
304 +}
305 +
306 +static char *ip4_addr_string(char *buf, char *end, u8 *addr,
307 + struct printf_spec spec)
308 +{
309 + char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
310 + char temp[3]; /* hold each IP quad in reverse order */
311 + char *p = ip4_addr;
312 + int i, digits;
313 +
314 + for (i = 0; i < 4; i++) {
315 + digits = put_dec_trunc(temp, addr[i]) - temp;
316 + /* reverse the digits in the quad */
317 + while (digits--)
318 + *p++ = temp[digits];
319 + if (i != 3)
320 + *p++ = '.';
321 + }
322 + *p = '\0';
323 + spec.flags &= ~SPECIAL;
324 +
325 + return string(buf, end, ip4_addr, spec);
326 }
327
328 /*
329 @@ -592,28 +694,244 @@ static char *resource_string(char *buf,
330 * - 'S' For symbolic direct pointers
331 * - 'R' For a struct resource pointer, it prints the range of
332 * addresses (not the name nor the flags)
333 + * - 'M' For a 6-byte MAC address, it prints the address in the
334 + * usual colon-separated hex notation
335 + * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
336 + * decimal for v4 and colon separated network-order 16 bit hex for v6)
337 + * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
338 + * currently the same
339 *
340 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
341 * function pointers are really function descriptors, which contain a
342 * pointer to the real address.
343 */
344 -static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags)
345 +static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
346 + struct printf_spec spec)
347 {
348 + if (!ptr)
349 + return string(buf, end, "(null)", spec);
350 +
351 switch (*fmt) {
352 case 'F':
353 ptr = dereference_function_descriptor(ptr);
354 /* Fallthrough */
355 case 'S':
356 - return symbol_string(buf, end, ptr, field_width, precision, flags);
357 + return symbol_string(buf, end, ptr, spec);
358 case 'R':
359 - return resource_string(buf, end, ptr, field_width, precision, flags);
360 + return resource_string(buf, end, ptr, spec);
361 + case 'm':
362 + spec.flags |= SPECIAL;
363 + /* Fallthrough */
364 + case 'M':
365 + return mac_address_string(buf, end, ptr, spec);
366 + case 'i':
367 + spec.flags |= SPECIAL;
368 + /* Fallthrough */
369 + case 'I':
370 + if (fmt[1] == '6')
371 + return ip6_addr_string(buf, end, ptr, spec);
372 + if (fmt[1] == '4')
373 + return ip4_addr_string(buf, end, ptr, spec);
374 + spec.flags &= ~SPECIAL;
375 + break;
376 }
377 - flags |= SMALL;
378 - if (field_width == -1) {
379 - field_width = 2*sizeof(void *);
380 - flags |= ZEROPAD;
381 + spec.flags |= SMALL;
382 + if (spec.field_width == -1) {
383 + spec.field_width = 2*sizeof(void *);
384 + spec.flags |= ZEROPAD;
385 }
386 - return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags);
387 + spec.base = 16;
388 +
389 + return number(buf, end, (unsigned long) ptr, spec);
390 +}
391 +
392 +/*
393 + * Helper function to decode printf style format.
394 + * Each call decode a token from the format and return the
395 + * number of characters read (or likely the delta where it wants
396 + * to go on the next call).
397 + * The decoded token is returned through the parameters
398 + *
399 + * 'h', 'l', or 'L' for integer fields
400 + * 'z' support added 23/7/1999 S.H.
401 + * 'z' changed to 'Z' --davidm 1/25/99
402 + * 't' added for ptrdiff_t
403 + *
404 + * @fmt: the format string
405 + * @type of the token returned
406 + * @flags: various flags such as +, -, # tokens..
407 + * @field_width: overwritten width
408 + * @base: base of the number (octal, hex, ...)
409 + * @precision: precision of a number
410 + * @qualifier: qualifier of a number (long, size_t, ...)
411 + */
412 +static int format_decode(const char *fmt, struct printf_spec *spec)
413 +{
414 + const char *start = fmt;
415 +
416 + /* we finished early by reading the field width */
417 + if (spec->type == FORMAT_TYPE_WIDTH) {
418 + if (spec->field_width < 0) {
419 + spec->field_width = -spec->field_width;
420 + spec->flags |= LEFT;
421 + }
422 + spec->type = FORMAT_TYPE_NONE;
423 + goto precision;
424 + }
425 +
426 + /* we finished early by reading the precision */
427 + if (spec->type == FORMAT_TYPE_PRECISION) {
428 + if (spec->precision < 0)
429 + spec->precision = 0;
430 +
431 + spec->type = FORMAT_TYPE_NONE;
432 + goto qualifier;
433 + }
434 +
435 + /* By default */
436 + spec->type = FORMAT_TYPE_NONE;
437 +
438 + for (; *fmt ; ++fmt) {
439 + if (*fmt == '%')
440 + break;
441 + }
442 +
443 + /* Return the current non-format string */
444 + if (fmt != start || !*fmt)
445 + return fmt - start;
446 +
447 + /* Process flags */
448 + spec->flags = 0;
449 +
450 + while (1) { /* this also skips first '%' */
451 + bool found = true;
452 +
453 + ++fmt;
454 +
455 + switch (*fmt) {
456 + case '-': spec->flags |= LEFT; break;
457 + case '+': spec->flags |= PLUS; break;
458 + case ' ': spec->flags |= SPACE; break;
459 + case '#': spec->flags |= SPECIAL; break;
460 + case '0': spec->flags |= ZEROPAD; break;
461 + default: found = false;
462 + }
463 +
464 + if (!found)
465 + break;
466 + }
467 +
468 + /* get field width */
469 + spec->field_width = -1;
470 +
471 + if (isdigit(*fmt))
472 + spec->field_width = skip_atoi(&fmt);
473 + else if (*fmt == '*') {
474 + /* it's the next argument */
475 + spec->type = FORMAT_TYPE_WIDTH;
476 + return ++fmt - start;
477 + }
478 +
479 +precision:
480 + /* get the precision */
481 + spec->precision = -1;
482 + if (*fmt == '.') {
483 + ++fmt;
484 + if (isdigit(*fmt)) {
485 + spec->precision = skip_atoi(&fmt);
486 + if (spec->precision < 0)
487 + spec->precision = 0;
488 + } else if (*fmt == '*') {
489 + /* it's the next argument */
490 + spec->type = FORMAT_TYPE_PRECISION;
491 + return ++fmt - start;
492 + }
493 + }
494 +
495 +qualifier:
496 + /* get the conversion qualifier */
497 + spec->qualifier = -1;
498 + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
499 + *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
500 + spec->qualifier = *fmt;
501 + ++fmt;
502 + if (spec->qualifier == 'l' && *fmt == 'l') {
503 + spec->qualifier = 'L';
504 + ++fmt;
505 + }
506 + }
507 +
508 + /* default base */
509 + spec->base = 10;
510 + switch (*fmt) {
511 + case 'c':
512 + spec->type = FORMAT_TYPE_CHAR;
513 + return ++fmt - start;
514 +
515 + case 's':
516 + spec->type = FORMAT_TYPE_STR;
517 + return ++fmt - start;
518 +
519 + case 'p':
520 + spec->type = FORMAT_TYPE_PTR;
521 + return fmt - start;
522 + /* skip alnum */
523 +
524 + case 'n':
525 + spec->type = FORMAT_TYPE_NRCHARS;
526 + return ++fmt - start;
527 +
528 + case '%':
529 + spec->type = FORMAT_TYPE_PERCENT_CHAR;
530 + return ++fmt - start;
531 +
532 + /* integer number formats - set up the flags and "break" */
533 + case 'o':
534 + spec->base = 8;
535 + break;
536 +
537 + case 'x':
538 + spec->flags |= SMALL;
539 +
540 + case 'X':
541 + spec->base = 16;
542 + break;
543 +
544 + case 'd':
545 + case 'i':
546 + spec->flags |= SIGN;
547 + case 'u':
548 + break;
549 +
550 + default:
551 + spec->type = FORMAT_TYPE_INVALID;
552 + return fmt - start;
553 + }
554 +
555 + if (spec->qualifier == 'L')
556 + spec->type = FORMAT_TYPE_LONG_LONG;
557 + else if (spec->qualifier == 'l') {
558 + if (spec->flags & SIGN)
559 + spec->type = FORMAT_TYPE_LONG;
560 + else
561 + spec->type = FORMAT_TYPE_ULONG;
562 + } else if (spec->qualifier == 'Z' || spec->qualifier == 'z') {
563 + spec->type = FORMAT_TYPE_SIZE_T;
564 + } else if (spec->qualifier == 't') {
565 + spec->type = FORMAT_TYPE_PTRDIFF;
566 + } else if (spec->qualifier == 'h') {
567 + if (spec->flags & SIGN)
568 + spec->type = FORMAT_TYPE_SHORT;
569 + else
570 + spec->type = FORMAT_TYPE_USHORT;
571 + } else {
572 + if (spec->flags & SIGN)
573 + spec->type = FORMAT_TYPE_INT;
574 + else
575 + spec->type = FORMAT_TYPE_UINT;
576 + }
577 +
578 + return ++fmt - start;
579 }
580
581 /**
582 @@ -642,18 +960,9 @@ static char *pointer(const char *fmt, ch
583 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
584 {
585 unsigned long long num;
586 - int base;
587 char *str, *end, c;
588 -
589 - int flags; /* flags to number() */
590 -
591 - int field_width; /* width of output field */
592 - int precision; /* min. # of digits for integers; max
593 - number of chars for from string */
594 - int qualifier; /* 'h', 'l', or 'L' for integer fields */
595 - /* 'z' support added 23/7/1999 S.H. */
596 - /* 'z' changed to 'Z' --davidm 1/25/99 */
597 - /* 't' added for ptrdiff_t */
598 + int read;
599 + struct printf_spec spec = {0};
600
601 /* Reject out-of-range values early. Large positive sizes are
602 used for unknown buffer sizes. */
603 @@ -674,184 +983,137 @@ int vsnprintf(char *buf, size_t size, co
604 size = end - buf;
605 }
606
607 - for (; *fmt ; ++fmt) {
608 - if (*fmt != '%') {
609 - if (str < end)
610 - *str = *fmt;
611 - ++str;
612 - continue;
613 - }
614 + while (*fmt) {
615 + const char *old_fmt = fmt;
616
617 - /* process flags */
618 - flags = 0;
619 - repeat:
620 - ++fmt; /* this also skips first '%' */
621 - switch (*fmt) {
622 - case '-': flags |= LEFT; goto repeat;
623 - case '+': flags |= PLUS; goto repeat;
624 - case ' ': flags |= SPACE; goto repeat;
625 - case '#': flags |= SPECIAL; goto repeat;
626 - case '0': flags |= ZEROPAD; goto repeat;
627 - }
628 + read = format_decode(fmt, &spec);
629
630 - /* get field width */
631 - field_width = -1;
632 - if (isdigit(*fmt))
633 - field_width = skip_atoi(&fmt);
634 - else if (*fmt == '*') {
635 - ++fmt;
636 - /* it's the next argument */
637 - field_width = va_arg(args, int);
638 - if (field_width < 0) {
639 - field_width = -field_width;
640 - flags |= LEFT;
641 - }
642 - }
643 + fmt += read;
644
645 - /* get the precision */
646 - precision = -1;
647 - if (*fmt == '.') {
648 - ++fmt;
649 - if (isdigit(*fmt))
650 - precision = skip_atoi(&fmt);
651 - else if (*fmt == '*') {
652 - ++fmt;
653 - /* it's the next argument */
654 - precision = va_arg(args, int);
655 + switch (spec.type) {
656 + case FORMAT_TYPE_NONE: {
657 + int copy = read;
658 + if (str < end) {
659 + if (copy > end - str)
660 + copy = end - str;
661 + memcpy(str, old_fmt, copy);
662 }
663 - if (precision < 0)
664 - precision = 0;
665 + str += read;
666 + break;
667 }
668
669 - /* get the conversion qualifier */
670 - qualifier = -1;
671 - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
672 - *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
673 - qualifier = *fmt;
674 - ++fmt;
675 - if (qualifier == 'l' && *fmt == 'l') {
676 - qualifier = 'L';
677 - ++fmt;
678 - }
679 - }
680 + case FORMAT_TYPE_WIDTH:
681 + spec.field_width = va_arg(args, int);
682 + break;
683
684 - /* default base */
685 - base = 10;
686 + case FORMAT_TYPE_PRECISION:
687 + spec.precision = va_arg(args, int);
688 + break;
689
690 - switch (*fmt) {
691 - case 'c':
692 - if (!(flags & LEFT)) {
693 - while (--field_width > 0) {
694 - if (str < end)
695 - *str = ' ';
696 - ++str;
697 - }
698 - }
699 - c = (unsigned char) va_arg(args, int);
700 - if (str < end)
701 - *str = c;
702 - ++str;
703 - while (--field_width > 0) {
704 + case FORMAT_TYPE_CHAR:
705 + if (!(spec.flags & LEFT)) {
706 + while (--spec.field_width > 0) {
707 if (str < end)
708 *str = ' ';
709 ++str;
710 - }
711 - continue;
712 -
713 - case 's':
714 - str = string(str, end, va_arg(args, char *), field_width, precision, flags);
715 - continue;
716 -
717 - case 'p':
718 - str = pointer(fmt+1, str, end,
719 - va_arg(args, void *),
720 - field_width, precision, flags);
721 - /* Skip all alphanumeric pointer suffixes */
722 - while (isalnum(fmt[1]))
723 - fmt++;
724 - continue;
725
726 - case 'n':
727 - /* FIXME:
728 - * What does C99 say about the overflow case here? */
729 - if (qualifier == 'l') {
730 - long * ip = va_arg(args, long *);
731 - *ip = (str - buf);
732 - } else if (qualifier == 'Z' || qualifier == 'z') {
733 - size_t * ip = va_arg(args, size_t *);
734 - *ip = (str - buf);
735 - } else {
736 - int * ip = va_arg(args, int *);
737 - *ip = (str - buf);
738 }
739 - continue;
740 -
741 - case '%':
742 + }
743 + c = (unsigned char) va_arg(args, int);
744 + if (str < end)
745 + *str = c;
746 + ++str;
747 + while (--spec.field_width > 0) {
748 if (str < end)
749 - *str = '%';
750 + *str = ' ';
751 ++str;
752 - continue;
753 + }
754 + break;
755
756 - /* integer number formats - set up the flags and "break" */
757 - case 'o':
758 - base = 8;
759 - break;
760 + case FORMAT_TYPE_STR:
761 + str = string(str, end, va_arg(args, char *), spec);
762 + break;
763
764 - case 'x':
765 - flags |= SMALL;
766 - case 'X':
767 - base = 16;
768 - break;
769 + case FORMAT_TYPE_PTR:
770 + str = pointer(fmt+1, str, end, va_arg(args, void *),
771 + spec);
772 + while (isalnum(*fmt))
773 + fmt++;
774 + break;
775
776 - case 'd':
777 - case 'i':
778 - flags |= SIGN;
779 - case 'u':
780 - break;
781 + case FORMAT_TYPE_PERCENT_CHAR:
782 + if (str < end)
783 + *str = '%';
784 + ++str;
785 + break;
786
787 - default:
788 - if (str < end)
789 - *str = '%';
790 - ++str;
791 - if (*fmt) {
792 - if (str < end)
793 - *str = *fmt;
794 - ++str;
795 - } else {
796 - --fmt;
797 - }
798 - continue;
799 + case FORMAT_TYPE_INVALID:
800 + if (str < end)
801 + *str = '%';
802 + ++str;
803 + break;
804 +
805 + case FORMAT_TYPE_NRCHARS: {
806 + int qualifier = spec.qualifier;
807 +
808 + if (qualifier == 'l') {
809 + long *ip = va_arg(args, long *);
810 + *ip = (str - buf);
811 + } else if (qualifier == 'Z' ||
812 + qualifier == 'z') {
813 + size_t *ip = va_arg(args, size_t *);
814 + *ip = (str - buf);
815 + } else {
816 + int *ip = va_arg(args, int *);
817 + *ip = (str - buf);
818 + }
819 + break;
820 }
821 - if (qualifier == 'L')
822 - num = va_arg(args, long long);
823 - else if (qualifier == 'l') {
824 - num = va_arg(args, unsigned long);
825 - if (flags & SIGN)
826 - num = (signed long) num;
827 - } else if (qualifier == 'Z' || qualifier == 'z') {
828 - num = va_arg(args, size_t);
829 - } else if (qualifier == 't') {
830 - num = va_arg(args, ptrdiff_t);
831 - } else if (qualifier == 'h') {
832 - num = (unsigned short) va_arg(args, int);
833 - if (flags & SIGN)
834 - num = (signed short) num;
835 - } else {
836 - num = va_arg(args, unsigned int);
837 - if (flags & SIGN)
838 - num = (signed int) num;
839 +
840 + default:
841 + switch (spec.type) {
842 + case FORMAT_TYPE_LONG_LONG:
843 + num = va_arg(args, long long);
844 + break;
845 + case FORMAT_TYPE_ULONG:
846 + num = va_arg(args, unsigned long);
847 + break;
848 + case FORMAT_TYPE_LONG:
849 + num = va_arg(args, long);
850 + break;
851 + case FORMAT_TYPE_SIZE_T:
852 + num = va_arg(args, size_t);
853 + break;
854 + case FORMAT_TYPE_PTRDIFF:
855 + num = va_arg(args, ptrdiff_t);
856 + break;
857 + case FORMAT_TYPE_USHORT:
858 + num = (unsigned short) va_arg(args, int);
859 + break;
860 + case FORMAT_TYPE_SHORT:
861 + num = (short) va_arg(args, int);
862 + break;
863 + case FORMAT_TYPE_INT:
864 + num = (int) va_arg(args, int);
865 + break;
866 + default:
867 + num = va_arg(args, unsigned int);
868 + }
869 +
870 + str = number(str, end, num, spec);
871 }
872 - str = number(str, end, num, base,
873 - field_width, precision, flags);
874 }
875 +
876 if (size > 0) {
877 if (str < end)
878 *str = '\0';
879 else
880 end[-1] = '\0';
881 }
882 +
883 /* the trailing null byte doesn't count towards the total */
884 return str-buf;
885 +
886 }
887 EXPORT_SYMBOL(vsnprintf);
888