diff options
Diffstat (limited to 'target/linux')
| -rw-r--r-- | target/linux/generic-2.6/patches-2.6.28/981-vsprintf_backport.patch | 888 | 
1 files changed, 888 insertions, 0 deletions
| 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 000000000..37589b188 --- /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 = "<NULL>"; +  +-	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); +  | 
