|
@@ -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);
|
|
|
|
|
+
|