From: Felix Fietkau Date: Mon, 9 Nov 2009 00:58:44 +0000 (+0000) Subject: backport a recent version of vsprintf to linux 2.6.28 to fix mac80211 wifi interface... X-Git-Tag: reboot~21928 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=ee937398f7919863625558d6a4b6a7fb5cee2186;p=oweals%2Fopenwrt.git backport a recent version of vsprintf to linux 2.6.28 to fix mac80211 wifi interface detection SVN-Revision: 18352 --- diff --git a/target/linux/generic-2.6/patches-2.6.28/981-vsprintf_backport.patch b/target/linux/generic-2.6/patches-2.6.28/981-vsprintf_backport.patch new file mode 100644 index 0000000000..37589b188f --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.28/981-vsprintf_backport.patch @@ -0,0 +1,888 @@ +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -170,6 +170,8 @@ int strict_strtoul(const char *cp, unsig + return -EINVAL; + + val = simple_strtoul(cp, &tail, base); ++ if (tail == cp) ++ return -EINVAL; + if ((*tail == '\0') || + ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { + *res = val; +@@ -241,6 +243,8 @@ int strict_strtoull(const char *cp, unsi + return -EINVAL; + + val = simple_strtoull(cp, &tail, base); ++ if (tail == cp) ++ return -EINVAL; + if ((*tail == '\0') || + ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { + *res = val; +@@ -392,7 +396,38 @@ static noinline char* put_dec(char *buf, + #define SMALL 32 /* Must be 32 == 0x20 */ + #define SPECIAL 64 /* 0x */ + +-static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) ++enum format_type { ++ FORMAT_TYPE_NONE, /* Just a string part */ ++ FORMAT_TYPE_WIDTH, ++ FORMAT_TYPE_PRECISION, ++ FORMAT_TYPE_CHAR, ++ FORMAT_TYPE_STR, ++ FORMAT_TYPE_PTR, ++ FORMAT_TYPE_PERCENT_CHAR, ++ FORMAT_TYPE_INVALID, ++ FORMAT_TYPE_LONG_LONG, ++ FORMAT_TYPE_ULONG, ++ FORMAT_TYPE_LONG, ++ FORMAT_TYPE_USHORT, ++ FORMAT_TYPE_SHORT, ++ FORMAT_TYPE_UINT, ++ FORMAT_TYPE_INT, ++ FORMAT_TYPE_NRCHARS, ++ FORMAT_TYPE_SIZE_T, ++ FORMAT_TYPE_PTRDIFF ++}; ++ ++struct printf_spec { ++ enum format_type type; ++ int flags; /* flags to number() */ ++ int field_width; /* width of output field */ ++ int base; ++ int precision; /* # of digits/chars */ ++ int qualifier; ++}; ++ ++static char *number(char *buf, char *end, unsigned long long num, ++ struct printf_spec spec) + { + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ +@@ -400,32 +435,32 @@ static char *number(char *buf, char *end + char tmp[66]; + char sign; + char locase; +- int need_pfx = ((type & SPECIAL) && base != 10); ++ int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); + int i; + + /* locase = 0 or 0x20. ORing digits or letters with 'locase' + * produces same digits or (maybe lowercased) letters */ +- locase = (type & SMALL); +- if (type & LEFT) +- type &= ~ZEROPAD; ++ locase = (spec.flags & SMALL); ++ if (spec.flags & LEFT) ++ spec.flags &= ~ZEROPAD; + sign = 0; +- if (type & SIGN) { ++ if (spec.flags & SIGN) { + if ((signed long long) num < 0) { + sign = '-'; + num = - (signed long long) num; +- size--; +- } else if (type & PLUS) { ++ spec.field_width--; ++ } else if (spec.flags & PLUS) { + sign = '+'; +- size--; +- } else if (type & SPACE) { ++ spec.field_width--; ++ } else if (spec.flags & SPACE) { + sign = ' '; +- size--; ++ spec.field_width--; + } + } + if (need_pfx) { +- size--; +- if (base == 16) +- size--; ++ spec.field_width--; ++ if (spec.base == 16) ++ spec.field_width--; + } + + /* generate full string in tmp[], in reverse order */ +@@ -437,10 +472,10 @@ static char *number(char *buf, char *end + tmp[i++] = (digits[do_div(num,base)] | locase); + } while (num != 0); + */ +- else if (base != 10) { /* 8 or 16 */ +- int mask = base - 1; ++ else if (spec.base != 10) { /* 8 or 16 */ ++ int mask = spec.base - 1; + int shift = 3; +- if (base == 16) shift = 4; ++ if (spec.base == 16) shift = 4; + do { + tmp[i++] = (digits[((unsigned char)num) & mask] | locase); + num >>= shift; +@@ -450,12 +485,12 @@ static char *number(char *buf, char *end + } + + /* printing 100 using %2d gives "100", not "00" */ +- if (i > precision) +- precision = i; ++ if (i > spec.precision) ++ spec.precision = i; + /* leading space padding */ +- size -= precision; +- if (!(type & (ZEROPAD+LEFT))) { +- while(--size >= 0) { ++ spec.field_width -= spec.precision; ++ if (!(spec.flags & (ZEROPAD+LEFT))) { ++ while(--spec.field_width >= 0) { + if (buf < end) + *buf = ' '; + ++buf; +@@ -472,23 +507,23 @@ static char *number(char *buf, char *end + if (buf < end) + *buf = '0'; + ++buf; +- if (base == 16) { ++ if (spec.base == 16) { + if (buf < end) + *buf = ('X' | locase); + ++buf; + } + } + /* zero or space padding */ +- if (!(type & LEFT)) { +- char c = (type & ZEROPAD) ? '0' : ' '; +- while (--size >= 0) { ++ if (!(spec.flags & LEFT)) { ++ char c = (spec.flags & ZEROPAD) ? '0' : ' '; ++ while (--spec.field_width >= 0) { + if (buf < end) + *buf = c; + ++buf; + } + } + /* hmm even more zero padding? */ +- while (i <= --precision) { ++ while (i <= --spec.precision) { + if (buf < end) + *buf = '0'; + ++buf; +@@ -500,7 +535,7 @@ static char *number(char *buf, char *end + ++buf; + } + /* trailing space padding */ +- while (--size >= 0) { ++ while (--spec.field_width >= 0) { + if (buf < end) + *buf = ' '; + ++buf; +@@ -508,17 +543,17 @@ static char *number(char *buf, char *end + return buf; + } + +-static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags) ++static char *string(char *buf, char *end, char *s, struct printf_spec spec) + { + int len, i; + + if ((unsigned long)s < PAGE_SIZE) + s = ""; + +- len = strnlen(s, precision); ++ len = strnlen(s, spec.precision); + +- if (!(flags & LEFT)) { +- while (len < field_width--) { ++ if (!(spec.flags & LEFT)) { ++ while (len < spec.field_width--) { + if (buf < end) + *buf = ' '; + ++buf; +@@ -529,7 +564,7 @@ static char *string(char *buf, char *end + *buf = *s; + ++buf; ++s; + } +- while (len < field_width--) { ++ while (len < spec.field_width--) { + if (buf < end) + *buf = ' '; + ++buf; +@@ -537,21 +572,24 @@ static char *string(char *buf, char *end + return buf; + } + +-static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags) ++static char *symbol_string(char *buf, char *end, void *ptr, ++ struct printf_spec spec) + { + unsigned long value = (unsigned long) ptr; + #ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; + sprint_symbol(sym, value); +- return string(buf, end, sym, field_width, precision, flags); ++ return string(buf, end, sym, spec); + #else +- field_width = 2*sizeof(void *); +- flags |= SPECIAL | SMALL | ZEROPAD; +- return number(buf, end, value, 16, field_width, precision, flags); ++ spec.field_width = 2*sizeof(void *); ++ spec.flags |= SPECIAL | SMALL | ZEROPAD; ++ spec.base = 16; ++ return number(buf, end, value, spec); + #endif + } + +-static char *resource_string(char *buf, char *end, struct resource *res, int field_width, int precision, int flags) ++static char *resource_string(char *buf, char *end, struct resource *res, ++ struct printf_spec spec) + { + #ifndef IO_RSRC_PRINTK_SIZE + #define IO_RSRC_PRINTK_SIZE 4 +@@ -560,7 +598,11 @@ static char *resource_string(char *buf, + #ifndef MEM_RSRC_PRINTK_SIZE + #define MEM_RSRC_PRINTK_SIZE 8 + #endif +- ++ struct printf_spec num_spec = { ++ .base = 16, ++ .precision = -1, ++ .flags = SPECIAL | SMALL | ZEROPAD, ++ }; + /* room for the actual numbers, the two "0x", -, [, ] and the final zero */ + char sym[4*sizeof(resource_size_t) + 8]; + char *p = sym, *pend = sym + sizeof(sym); +@@ -572,13 +614,73 @@ static char *resource_string(char *buf, + size = MEM_RSRC_PRINTK_SIZE; + + *p++ = '['; +- p = number(p, pend, res->start, 16, size, -1, SPECIAL | SMALL | ZEROPAD); ++ num_spec.field_width = size; ++ p = number(p, pend, res->start, num_spec); + *p++ = '-'; +- p = number(p, pend, res->end, 16, size, -1, SPECIAL | SMALL | ZEROPAD); ++ p = number(p, pend, res->end, num_spec); + *p++ = ']'; + *p = 0; + +- return string(buf, end, sym, field_width, precision, flags); ++ return string(buf, end, sym, spec); ++} ++ ++static char *mac_address_string(char *buf, char *end, u8 *addr, ++ struct printf_spec spec) ++{ ++ char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ ++ char *p = mac_addr; ++ int i; ++ ++ for (i = 0; i < 6; i++) { ++ p = pack_hex_byte(p, addr[i]); ++ if (!(spec.flags & SPECIAL) && i != 5) ++ *p++ = ':'; ++ } ++ *p = '\0'; ++ spec.flags &= ~SPECIAL; ++ ++ return string(buf, end, mac_addr, spec); ++} ++ ++static char *ip6_addr_string(char *buf, char *end, u8 *addr, ++ struct printf_spec spec) ++{ ++ char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ ++ char *p = ip6_addr; ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ p = pack_hex_byte(p, addr[2 * i]); ++ p = pack_hex_byte(p, addr[2 * i + 1]); ++ if (!(spec.flags & SPECIAL) && i != 7) ++ *p++ = ':'; ++ } ++ *p = '\0'; ++ spec.flags &= ~SPECIAL; ++ ++ return string(buf, end, ip6_addr, spec); ++} ++ ++static char *ip4_addr_string(char *buf, char *end, u8 *addr, ++ struct printf_spec spec) ++{ ++ char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ ++ char temp[3]; /* hold each IP quad in reverse order */ ++ char *p = ip4_addr; ++ int i, digits; ++ ++ for (i = 0; i < 4; i++) { ++ digits = put_dec_trunc(temp, addr[i]) - temp; ++ /* reverse the digits in the quad */ ++ while (digits--) ++ *p++ = temp[digits]; ++ if (i != 3) ++ *p++ = '.'; ++ } ++ *p = '\0'; ++ spec.flags &= ~SPECIAL; ++ ++ return string(buf, end, ip4_addr, spec); + } + + /* +@@ -592,28 +694,244 @@ static char *resource_string(char *buf, + * - 'S' For symbolic direct pointers + * - 'R' For a struct resource pointer, it prints the range of + * addresses (not the name nor the flags) ++ * - 'M' For a 6-byte MAC address, it prints the address in the ++ * usual colon-separated hex notation ++ * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated ++ * decimal for v4 and colon separated network-order 16 bit hex for v6) ++ * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is ++ * currently the same + * + * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 + * function pointers are really function descriptors, which contain a + * pointer to the real address. + */ +-static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags) ++static char *pointer(const char *fmt, char *buf, char *end, void *ptr, ++ struct printf_spec spec) + { ++ if (!ptr) ++ return string(buf, end, "(null)", spec); ++ + switch (*fmt) { + case 'F': + ptr = dereference_function_descriptor(ptr); + /* Fallthrough */ + case 'S': +- return symbol_string(buf, end, ptr, field_width, precision, flags); ++ return symbol_string(buf, end, ptr, spec); + case 'R': +- return resource_string(buf, end, ptr, field_width, precision, flags); ++ return resource_string(buf, end, ptr, spec); ++ case 'm': ++ spec.flags |= SPECIAL; ++ /* Fallthrough */ ++ case 'M': ++ return mac_address_string(buf, end, ptr, spec); ++ case 'i': ++ spec.flags |= SPECIAL; ++ /* Fallthrough */ ++ case 'I': ++ if (fmt[1] == '6') ++ return ip6_addr_string(buf, end, ptr, spec); ++ if (fmt[1] == '4') ++ return ip4_addr_string(buf, end, ptr, spec); ++ spec.flags &= ~SPECIAL; ++ break; + } +- flags |= SMALL; +- if (field_width == -1) { +- field_width = 2*sizeof(void *); +- flags |= ZEROPAD; ++ spec.flags |= SMALL; ++ if (spec.field_width == -1) { ++ spec.field_width = 2*sizeof(void *); ++ spec.flags |= ZEROPAD; + } +- return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags); ++ spec.base = 16; ++ ++ return number(buf, end, (unsigned long) ptr, spec); ++} ++ ++/* ++ * Helper function to decode printf style format. ++ * Each call decode a token from the format and return the ++ * number of characters read (or likely the delta where it wants ++ * to go on the next call). ++ * The decoded token is returned through the parameters ++ * ++ * 'h', 'l', or 'L' for integer fields ++ * 'z' support added 23/7/1999 S.H. ++ * 'z' changed to 'Z' --davidm 1/25/99 ++ * 't' added for ptrdiff_t ++ * ++ * @fmt: the format string ++ * @type of the token returned ++ * @flags: various flags such as +, -, # tokens.. ++ * @field_width: overwritten width ++ * @base: base of the number (octal, hex, ...) ++ * @precision: precision of a number ++ * @qualifier: qualifier of a number (long, size_t, ...) ++ */ ++static int format_decode(const char *fmt, struct printf_spec *spec) ++{ ++ const char *start = fmt; ++ ++ /* we finished early by reading the field width */ ++ if (spec->type == FORMAT_TYPE_WIDTH) { ++ if (spec->field_width < 0) { ++ spec->field_width = -spec->field_width; ++ spec->flags |= LEFT; ++ } ++ spec->type = FORMAT_TYPE_NONE; ++ goto precision; ++ } ++ ++ /* we finished early by reading the precision */ ++ if (spec->type == FORMAT_TYPE_PRECISION) { ++ if (spec->precision < 0) ++ spec->precision = 0; ++ ++ spec->type = FORMAT_TYPE_NONE; ++ goto qualifier; ++ } ++ ++ /* By default */ ++ spec->type = FORMAT_TYPE_NONE; ++ ++ for (; *fmt ; ++fmt) { ++ if (*fmt == '%') ++ break; ++ } ++ ++ /* Return the current non-format string */ ++ if (fmt != start || !*fmt) ++ return fmt - start; ++ ++ /* Process flags */ ++ spec->flags = 0; ++ ++ while (1) { /* this also skips first '%' */ ++ bool found = true; ++ ++ ++fmt; ++ ++ switch (*fmt) { ++ case '-': spec->flags |= LEFT; break; ++ case '+': spec->flags |= PLUS; break; ++ case ' ': spec->flags |= SPACE; break; ++ case '#': spec->flags |= SPECIAL; break; ++ case '0': spec->flags |= ZEROPAD; break; ++ default: found = false; ++ } ++ ++ if (!found) ++ break; ++ } ++ ++ /* get field width */ ++ spec->field_width = -1; ++ ++ if (isdigit(*fmt)) ++ spec->field_width = skip_atoi(&fmt); ++ else if (*fmt == '*') { ++ /* it's the next argument */ ++ spec->type = FORMAT_TYPE_WIDTH; ++ return ++fmt - start; ++ } ++ ++precision: ++ /* get the precision */ ++ spec->precision = -1; ++ if (*fmt == '.') { ++ ++fmt; ++ if (isdigit(*fmt)) { ++ spec->precision = skip_atoi(&fmt); ++ if (spec->precision < 0) ++ spec->precision = 0; ++ } else if (*fmt == '*') { ++ /* it's the next argument */ ++ spec->type = FORMAT_TYPE_PRECISION; ++ return ++fmt - start; ++ } ++ } ++ ++qualifier: ++ /* get the conversion qualifier */ ++ spec->qualifier = -1; ++ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || ++ *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { ++ spec->qualifier = *fmt; ++ ++fmt; ++ if (spec->qualifier == 'l' && *fmt == 'l') { ++ spec->qualifier = 'L'; ++ ++fmt; ++ } ++ } ++ ++ /* default base */ ++ spec->base = 10; ++ switch (*fmt) { ++ case 'c': ++ spec->type = FORMAT_TYPE_CHAR; ++ return ++fmt - start; ++ ++ case 's': ++ spec->type = FORMAT_TYPE_STR; ++ return ++fmt - start; ++ ++ case 'p': ++ spec->type = FORMAT_TYPE_PTR; ++ return fmt - start; ++ /* skip alnum */ ++ ++ case 'n': ++ spec->type = FORMAT_TYPE_NRCHARS; ++ return ++fmt - start; ++ ++ case '%': ++ spec->type = FORMAT_TYPE_PERCENT_CHAR; ++ return ++fmt - start; ++ ++ /* integer number formats - set up the flags and "break" */ ++ case 'o': ++ spec->base = 8; ++ break; ++ ++ case 'x': ++ spec->flags |= SMALL; ++ ++ case 'X': ++ spec->base = 16; ++ break; ++ ++ case 'd': ++ case 'i': ++ spec->flags |= SIGN; ++ case 'u': ++ break; ++ ++ default: ++ spec->type = FORMAT_TYPE_INVALID; ++ return fmt - start; ++ } ++ ++ if (spec->qualifier == 'L') ++ spec->type = FORMAT_TYPE_LONG_LONG; ++ else if (spec->qualifier == 'l') { ++ if (spec->flags & SIGN) ++ spec->type = FORMAT_TYPE_LONG; ++ else ++ spec->type = FORMAT_TYPE_ULONG; ++ } else if (spec->qualifier == 'Z' || spec->qualifier == 'z') { ++ spec->type = FORMAT_TYPE_SIZE_T; ++ } else if (spec->qualifier == 't') { ++ spec->type = FORMAT_TYPE_PTRDIFF; ++ } else if (spec->qualifier == 'h') { ++ if (spec->flags & SIGN) ++ spec->type = FORMAT_TYPE_SHORT; ++ else ++ spec->type = FORMAT_TYPE_USHORT; ++ } else { ++ if (spec->flags & SIGN) ++ spec->type = FORMAT_TYPE_INT; ++ else ++ spec->type = FORMAT_TYPE_UINT; ++ } ++ ++ return ++fmt - start; + } + + /** +@@ -642,18 +960,9 @@ static char *pointer(const char *fmt, ch + int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) + { + unsigned long long num; +- int base; + char *str, *end, c; +- +- int flags; /* flags to number() */ +- +- int field_width; /* width of output field */ +- int precision; /* min. # of digits for integers; max +- number of chars for from string */ +- int qualifier; /* 'h', 'l', or 'L' for integer fields */ +- /* 'z' support added 23/7/1999 S.H. */ +- /* 'z' changed to 'Z' --davidm 1/25/99 */ +- /* 't' added for ptrdiff_t */ ++ int read; ++ struct printf_spec spec = {0}; + + /* Reject out-of-range values early. Large positive sizes are + used for unknown buffer sizes. */ +@@ -674,184 +983,137 @@ int vsnprintf(char *buf, size_t size, co + size = end - buf; + } + +- for (; *fmt ; ++fmt) { +- if (*fmt != '%') { +- if (str < end) +- *str = *fmt; +- ++str; +- continue; +- } ++ while (*fmt) { ++ const char *old_fmt = fmt; + +- /* process flags */ +- flags = 0; +- repeat: +- ++fmt; /* this also skips first '%' */ +- switch (*fmt) { +- case '-': flags |= LEFT; goto repeat; +- case '+': flags |= PLUS; goto repeat; +- case ' ': flags |= SPACE; goto repeat; +- case '#': flags |= SPECIAL; goto repeat; +- case '0': flags |= ZEROPAD; goto repeat; +- } ++ read = format_decode(fmt, &spec); + +- /* get field width */ +- field_width = -1; +- if (isdigit(*fmt)) +- field_width = skip_atoi(&fmt); +- else if (*fmt == '*') { +- ++fmt; +- /* it's the next argument */ +- field_width = va_arg(args, int); +- if (field_width < 0) { +- field_width = -field_width; +- flags |= LEFT; +- } +- } ++ fmt += read; + +- /* get the precision */ +- precision = -1; +- if (*fmt == '.') { +- ++fmt; +- if (isdigit(*fmt)) +- precision = skip_atoi(&fmt); +- else if (*fmt == '*') { +- ++fmt; +- /* it's the next argument */ +- precision = va_arg(args, int); ++ switch (spec.type) { ++ case FORMAT_TYPE_NONE: { ++ int copy = read; ++ if (str < end) { ++ if (copy > end - str) ++ copy = end - str; ++ memcpy(str, old_fmt, copy); + } +- if (precision < 0) +- precision = 0; ++ str += read; ++ break; + } + +- /* get the conversion qualifier */ +- qualifier = -1; +- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || +- *fmt =='Z' || *fmt == 'z' || *fmt == 't') { +- qualifier = *fmt; +- ++fmt; +- if (qualifier == 'l' && *fmt == 'l') { +- qualifier = 'L'; +- ++fmt; +- } +- } ++ case FORMAT_TYPE_WIDTH: ++ spec.field_width = va_arg(args, int); ++ break; + +- /* default base */ +- base = 10; ++ case FORMAT_TYPE_PRECISION: ++ spec.precision = va_arg(args, int); ++ break; + +- switch (*fmt) { +- case 'c': +- if (!(flags & LEFT)) { +- while (--field_width > 0) { +- if (str < end) +- *str = ' '; +- ++str; +- } +- } +- c = (unsigned char) va_arg(args, int); +- if (str < end) +- *str = c; +- ++str; +- while (--field_width > 0) { ++ case FORMAT_TYPE_CHAR: ++ if (!(spec.flags & LEFT)) { ++ while (--spec.field_width > 0) { + if (str < end) + *str = ' '; + ++str; +- } +- continue; +- +- case 's': +- str = string(str, end, va_arg(args, char *), field_width, precision, flags); +- continue; +- +- case 'p': +- str = pointer(fmt+1, str, end, +- va_arg(args, void *), +- field_width, precision, flags); +- /* Skip all alphanumeric pointer suffixes */ +- while (isalnum(fmt[1])) +- fmt++; +- continue; + +- case 'n': +- /* FIXME: +- * What does C99 say about the overflow case here? */ +- if (qualifier == 'l') { +- long * ip = va_arg(args, long *); +- *ip = (str - buf); +- } else if (qualifier == 'Z' || qualifier == 'z') { +- size_t * ip = va_arg(args, size_t *); +- *ip = (str - buf); +- } else { +- int * ip = va_arg(args, int *); +- *ip = (str - buf); + } +- continue; +- +- case '%': ++ } ++ c = (unsigned char) va_arg(args, int); ++ if (str < end) ++ *str = c; ++ ++str; ++ while (--spec.field_width > 0) { + if (str < end) +- *str = '%'; ++ *str = ' '; + ++str; +- continue; ++ } ++ break; + +- /* integer number formats - set up the flags and "break" */ +- case 'o': +- base = 8; +- break; ++ case FORMAT_TYPE_STR: ++ str = string(str, end, va_arg(args, char *), spec); ++ break; + +- case 'x': +- flags |= SMALL; +- case 'X': +- base = 16; +- break; ++ case FORMAT_TYPE_PTR: ++ str = pointer(fmt+1, str, end, va_arg(args, void *), ++ spec); ++ while (isalnum(*fmt)) ++ fmt++; ++ break; + +- case 'd': +- case 'i': +- flags |= SIGN; +- case 'u': +- break; ++ case FORMAT_TYPE_PERCENT_CHAR: ++ if (str < end) ++ *str = '%'; ++ ++str; ++ break; + +- default: +- if (str < end) +- *str = '%'; +- ++str; +- if (*fmt) { +- if (str < end) +- *str = *fmt; +- ++str; +- } else { +- --fmt; +- } +- continue; ++ case FORMAT_TYPE_INVALID: ++ if (str < end) ++ *str = '%'; ++ ++str; ++ break; ++ ++ case FORMAT_TYPE_NRCHARS: { ++ int qualifier = spec.qualifier; ++ ++ if (qualifier == 'l') { ++ long *ip = va_arg(args, long *); ++ *ip = (str - buf); ++ } else if (qualifier == 'Z' || ++ qualifier == 'z') { ++ size_t *ip = va_arg(args, size_t *); ++ *ip = (str - buf); ++ } else { ++ int *ip = va_arg(args, int *); ++ *ip = (str - buf); ++ } ++ break; + } +- if (qualifier == 'L') +- num = va_arg(args, long long); +- else if (qualifier == 'l') { +- num = va_arg(args, unsigned long); +- if (flags & SIGN) +- num = (signed long) num; +- } else if (qualifier == 'Z' || qualifier == 'z') { +- num = va_arg(args, size_t); +- } else if (qualifier == 't') { +- num = va_arg(args, ptrdiff_t); +- } else if (qualifier == 'h') { +- num = (unsigned short) va_arg(args, int); +- if (flags & SIGN) +- num = (signed short) num; +- } else { +- num = va_arg(args, unsigned int); +- if (flags & SIGN) +- num = (signed int) num; ++ ++ default: ++ switch (spec.type) { ++ case FORMAT_TYPE_LONG_LONG: ++ num = va_arg(args, long long); ++ break; ++ case FORMAT_TYPE_ULONG: ++ num = va_arg(args, unsigned long); ++ break; ++ case FORMAT_TYPE_LONG: ++ num = va_arg(args, long); ++ break; ++ case FORMAT_TYPE_SIZE_T: ++ num = va_arg(args, size_t); ++ break; ++ case FORMAT_TYPE_PTRDIFF: ++ num = va_arg(args, ptrdiff_t); ++ break; ++ case FORMAT_TYPE_USHORT: ++ num = (unsigned short) va_arg(args, int); ++ break; ++ case FORMAT_TYPE_SHORT: ++ num = (short) va_arg(args, int); ++ break; ++ case FORMAT_TYPE_INT: ++ num = (int) va_arg(args, int); ++ break; ++ default: ++ num = va_arg(args, unsigned int); ++ } ++ ++ str = number(str, end, num, spec); + } +- str = number(str, end, num, base, +- field_width, precision, flags); + } ++ + if (size > 0) { + if (str < end) + *str = '\0'; + else + end[-1] = '\0'; + } ++ + /* the trailing null byte doesn't count towards the total */ + return str-buf; ++ + } + EXPORT_SYMBOL(vsnprintf); +