/* * linux/lib/vsprintf.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. *//* * Wirzenius wrote this portably, Torvalds fucked it up :-) */ /* * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> * - changed to provide snprintf and vsnprintf functions * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> * - scnprintf and vscnprintf */ #include <stdarg.h>#include <linux/module.h> /* for KSYM_SYMBOL_LEN */#include <linux/types.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/kernel.h>#include <linux/kallsyms.h>#include <linux/math64.h>#include <linux/uaccess.h>#include <linux/ioport.h>#include <linux/dcache.h>#include <linux/cred.h>#include <net/addrconf.h> #include <asm/page.h> /* for PAGE_SIZE */#include <asm/sections.h> /* for dereference_function_descriptor() */ #include "kstrtox.h" /** * simple_strtoull - convert a string to an unsigned long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoull instead. */unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base){ unsigned long long result; unsigned int rv; cp = _parse_integer_fixup_radix(cp, &base); rv = _parse_integer(cp, base, &result); /* FIXME */ cp += (rv & ~KSTRTOX_OVERFLOW); if (endp) *endp = (char *)cp; return result;}EXPORT_SYMBOL(simple_strtoull); /** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoul instead. */unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base){ return simple_strtoull(cp, endp, base);}EXPORT_SYMBOL(simple_strtoul); /** * simple_strtol - convert a string to a signed long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtol instead. */long simple_strtol(const char *cp, char **endp, unsigned int base){ if (*cp == '-') return -simple_strtoul(cp + 1, endp, base); return simple_strtoul(cp, endp, base);}EXPORT_SYMBOL(simple_strtol); /** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoll instead. */long long simple_strtoll(const char *cp, char **endp, unsigned int base){ if (*cp == '-') return -simple_strtoull(cp + 1, endp, base); return simple_strtoull(cp, endp, base);}EXPORT_SYMBOL(simple_strtoll); static noinline_for_stackint skip_atoi(const char **s){ int i = 0; while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; return i;} /* Decimal conversion is by far the most typical, and is used * for /proc and /sys data. This directly impacts e.g. top performance * with many processes running. We optimize it for speed * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html> * (with permission from the author, Douglas W. Jones). */ #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64/* Formats correctly any integer in [0, 999999999] */static noinline_for_stackchar *put_dec_full9(char *buf, unsigned q){ unsigned r; /* * Possible ways to approx. divide by 10 * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit) * (x * 0xcccd) >> 19 x < 81920 (x < 262149 when 64-bit mul) * (x * 0x6667) >> 18 x < 43699 * (x * 0x3334) >> 17 x < 16389 * (x * 0x199a) >> 16 x < 16389 * (x * 0x0ccd) >> 15 x < 16389 * (x * 0x0667) >> 14 x < 2739 * (x * 0x0334) >> 13 x < 1029 * (x * 0x019a) >> 12 x < 1029 * (x * 0x00cd) >> 11 x < 1029 shorter code than * 0x67 (on i386) * (x * 0x0067) >> 10 x < 179 * (x * 0x0034) >> 9 x < 69 same * (x * 0x001a) >> 8 x < 69 same * (x * 0x000d) >> 7 x < 69 same, shortest code (on i386) * (x * 0x0007) >> 6 x < 19 * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html> */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 1 */ q = (r * (uint64_t)0x1999999a) >> 32; *buf++ = (r - 10 * q) + '0'; /* 2 */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 3 */ q = (r * (uint64_t)0x1999999a) >> 32; *buf++ = (r - 10 * q) + '0'; /* 4 */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 5 */ /* Now value is under 10000, can avoid 64-bit multiply */ q = (r * 0x199a) >> 16; *buf++ = (r - 10 * q) + '0'; /* 6 */ r = (q * 0xcd) >> 11; *buf++ = (q - 10 * r) + '0'; /* 7 */ q = (r * 0xcd) >> 11; *buf++ = (r - 10 * q) + '0'; /* 8 */ *buf++ = q + '0'; /* 9 */ return buf;}#endif /* Similar to above but do not pad with zeros. * Code can be easily arranged to print 9 digits too, but our callers * always call put_dec_full9() instead when the number has 9 decimal digits. */static noinline_for_stackchar *put_dec_trunc8(char *buf, unsigned r){ unsigned q; /* Copy of previous function's body with added early returns */ while (r >= 10000) { q = r + '0'; r = (r * (uint64_t)0x1999999a) >> 32; *buf++ = q - 10*r; } q = (r * 0x199a) >> 16; /* r <= 9999 */ *buf++ = (r - 10 * q) + '0'; if (q == 0) return buf; r = (q * 0xcd) >> 11; /* q <= 999 */ *buf++ = (q - 10 * r) + '0'; if (r == 0) return buf; q = (r * 0xcd) >> 11; /* r <= 99 */ *buf++ = (r - 10 * q) + '0'; if (q == 0) return buf; *buf++ = q + '0'; /* q <= 9 */ return buf;} /* There are two algorithms to print larger numbers. * One is generic: divide by 1000000000 and repeatedly print * groups of (up to) 9 digits. It's conceptually simple, * but requires a (unsigned long long) / 1000000000 division. * * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, * manipulates them cleverly and generates groups of 4 decimal digits. * It so happens that it does NOT require long long division. * * If long is > 32 bits, division of 64-bit values is relatively easy, * and we will use the first algorithm. * If long long is > 64 bits (strange architecture with VERY large long long), * second algorithm can't be used, and we again use the first one. * * Else (if long is 32 bits and long long is 64 bits) we use second one. */ #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 /* First algorithm: generic */ staticchar *put_dec(char *buf, unsigned long long n){ if (n >= 100*1000*1000) { while (n >= 1000*1000*1000) buf = put_dec_full9(buf, do_div(n, 1000*1000*1000)); if (n >= 100*1000*1000) return put_dec_full9(buf, n); } return put_dec_trunc8(buf, n);} #else /* Second algorithm: valid only for 64-bit long longs */ /* See comment in put_dec_full9 for choice of constants */static noinline_for_stackvoid put_dec_full4(char *buf, unsigned q){ unsigned r; r = (q * 0xccd) >> 15; buf[0] = (q - 10 * r) + '0'; q = (r * 0xcd) >> 11; buf[1] = (r - 10 * q) + '0'; r = (q * 0xcd) >> 11; buf[2] = (q - 10 * r) + '0'; buf[3] = r + '0';} /* * Call put_dec_full4 on x % 10000, return x / 10000. * The approximation x/10000 == (x * 0x346DC5D7) >> 43 * holds for all x < 1,128,869,999. The largest value this * helper will ever be asked to convert is 1,125,520,955. * (d1 in the put_dec code, assuming n is all-ones). */staticunsigned put_dec_helper4(char *buf, unsigned x){ uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; put_dec_full4(buf, x - q * 10000); return q;} /* Based on code by Douglas W. Jones found at * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> * (with permission from the author). * Performs no 64-bit division and hence should be fast on 32-bit machines. */staticchar *put_dec(char *buf, unsigned long long n){ uint32_t d3, d2, d1, q, h; if (n < 100*1000*1000) return put_dec_trunc8(buf, n); d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ h = (n >> 32); d2 = (h ) & 0xffff; d3 = (h >> 16); /* implicit "& 0xffff" */ q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); q = put_dec_helper4(buf, q); q += 7671 * d3 + 9496 * d2 + 6 * d1; q = put_dec_helper4(buf+4, q); q += 4749 * d3 + 42 * d2; q = put_dec_helper4(buf+8, q); q += 281 * d3; buf += 12; if (q) buf = put_dec_trunc8(buf, q); else while (buf[-1] == '0') --buf; return buf;} #endif /* * Convert passed number to decimal string. * Returns the length of string. On buffer overflow, returns 0. * * If speed is not important, use snprintf(). It's easy to read the code. */int num_to_str(char *buf, int size, unsigned long long num){ char tmp[sizeof(num) * 3]; int idx, len; /* put_dec() may work incorrectly for num = 0 (generate "", not "0") */ if (num <= 9) { tmp[0] = '0' + num; len = 1; } else { len = put_dec(tmp, num) - tmp; } if (len > size) return 0; for (idx = 0; idx < len; ++idx) buf[idx] = tmp[len - idx - 1]; return len;} #define ZEROPAD 1 /* pad with zero */#define SIGN 2 /* unsigned/signed long */#define PLUS 4 /* show plus */#define SPACE 8 /* space if plus */#define LEFT 16 /* left justified */#define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */#define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ 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_UBYTE, FORMAT_TYPE_BYTE, FORMAT_TYPE_USHORT, FORMAT_TYPE_SHORT, FORMAT_TYPE_UINT, FORMAT_TYPE_INT, FORMAT_TYPE_SIZE_T, FORMAT_TYPE_PTRDIFF}; struct printf_spec { u8 type; /* format_type enum */ u8 flags; /* flags to number() */ u8 base; /* number base, 8, 10 or 16 only */ u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ s16 field_width; /* width of output field */ s16 precision; /* # of digits/chars */}; static noinline_for_stackchar *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"; */ char tmp[66]; char sign; char locase; int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); int i; bool is_zero = num == 0LL; /* locase = 0 or 0x20. ORing digits or letters with 'locase' * produces same digits or (maybe lowercased) letters */ locase = (spec.flags & SMALL); if (spec.flags & LEFT) spec.flags &= ~ZEROPAD; sign = 0; if (spec.flags & SIGN) { if ((signed long long)num < 0) { sign = '-'; num = -(signed long long)num; spec.field_width--; } else if (spec.flags & PLUS) { sign = '+'; spec.field_width--; } else if (spec.flags & SPACE) { sign = ' '; spec.field_width--; } } if (need_pfx) { if (spec.base == 16) spec.field_width -= 2; else if (!is_zero) spec.field_width--; } /* generate full string in tmp[], in reverse order */ i = 0; if (num < spec.base) tmp[i++] = digits[num] | locase; /* Generic code, for any base: else do { tmp[i++] = (digits[do_div(num,base)] | locase); } while (num != 0); */ else if (spec.base != 10) { /* 8 or 16 */ int mask = spec.base - 1; int shift = 3; if (spec.base == 16) shift = 4; do { tmp[i++] = (digits[((unsigned char)num) & mask] | locase); num >>= shift; } while (num); } else { /* base 10 */ i = put_dec(tmp, num) - tmp; } /* printing 100 using %2d gives "100", not "00" */ if (i > spec.precision) spec.precision = i; /* leading space padding */ spec.field_width -= spec.precision; if (!(spec.flags & (ZEROPAD+LEFT))) { while (--spec.field_width >= 0) { if (buf < end) *buf = ' '; ++buf; } } /* sign */ if (sign) { if (buf < end) *buf = sign; ++buf; } /* "0x" / "0" prefix */ if (need_pfx) { if (spec.base == 16 || !is_zero) { if (buf < end) *buf = '0'; ++buf; } if (spec.base == 16) { if (buf < end) *buf = ('X' | locase); ++buf; } } /* zero or space padding */ 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 <= --spec.precision) { if (buf < end) *buf = '0'; ++buf; } /* actual digits of result */ while (--i >= 0) { if (buf < end) *buf = tmp[i]; ++buf; } /* trailing space padding */ while (--spec.field_width >= 0) { if (buf < end) *buf = ' '; ++buf; }Lines 1–500 of 2503. Load more
/* * linux/lib/vsprintf.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ /* * Wirzenius wrote this portably, Torvalds fucked it up :-) */ /* * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> * - changed to provide snprintf and vsnprintf functions * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> * - scnprintf and vscnprintf */ #include <stdarg.h> #include <linux/module.h> /* for KSYM_SYMBOL_LEN */ #include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #include <linux/kernel.h> #include <linux/kallsyms.h> #include <linux/math64.h> #include <linux/uaccess.h> #include <linux/ioport.h> #include <linux/dcache.h> #include <linux/cred.h> #include <net/addrconf.h> #include <asm/page.h> /* for PAGE_SIZE */ #include <asm/sections.h> /* for dereference_function_descriptor() */ #include "kstrtox.h" /** * simple_strtoull - convert a string to an unsigned long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoull instead. */ unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) { unsigned long long result; unsigned int rv; cp = _parse_integer_fixup_radix(cp, &base); rv = _parse_integer(cp, base, &result); /* FIXME */ cp += (rv & ~KSTRTOX_OVERFLOW); if (endp) *endp = (char *)cp; return result; } EXPORT_SYMBOL(simple_strtoull); /** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoul instead. */ unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) { return simple_strtoull(cp, endp, base); } EXPORT_SYMBOL(simple_strtoul); /** * simple_strtol - convert a string to a signed long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtol instead. */ long simple_strtol(const char *cp, char **endp, unsigned int base) { if (*cp == '-') return -simple_strtoul(cp + 1, endp, base); return simple_strtoul(cp, endp, base); } EXPORT_SYMBOL(simple_strtol); /** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoll instead. */ long long simple_strtoll(const char *cp, char **endp, unsigned int base) { if (*cp == '-') return -simple_strtoull(cp + 1, endp, base); return simple_strtoull(cp, endp, base); } EXPORT_SYMBOL(simple_strtoll); static noinline_for_stack int skip_atoi(const char **s) { int i = 0; while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; return i; } /* Decimal conversion is by far the most typical, and is used * for /proc and /sys data. This directly impacts e.g. top performance * with many processes running. We optimize it for speed * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html> * (with permission from the author, Douglas W. Jones). */ #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 /* Formats correctly any integer in [0, 999999999] */ static noinline_for_stack char *put_dec_full9(char *buf, unsigned q) { unsigned r; /* * Possible ways to approx. divide by 10 * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit) * (x * 0xcccd) >> 19 x < 81920 (x < 262149 when 64-bit mul) * (x * 0x6667) >> 18 x < 43699 * (x * 0x3334) >> 17 x < 16389 * (x * 0x199a) >> 16 x < 16389 * (x * 0x0ccd) >> 15 x < 16389 * (x * 0x0667) >> 14 x < 2739 * (x * 0x0334) >> 13 x < 1029 * (x * 0x019a) >> 12 x < 1029 * (x * 0x00cd) >> 11 x < 1029 shorter code than * 0x67 (on i386) * (x * 0x0067) >> 10 x < 179 * (x * 0x0034) >> 9 x < 69 same * (x * 0x001a) >> 8 x < 69 same * (x * 0x000d) >> 7 x < 69 same, shortest code (on i386) * (x * 0x0007) >> 6 x < 19 * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html> */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 1 */ q = (r * (uint64_t)0x1999999a) >> 32; *buf++ = (r - 10 * q) + '0'; /* 2 */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 3 */ q = (r * (uint64_t)0x1999999a) >> 32; *buf++ = (r - 10 * q) + '0'; /* 4 */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 5 */ /* Now value is under 10000, can avoid 64-bit multiply */ q = (r * 0x199a) >> 16; *buf++ = (r - 10 * q) + '0'; /* 6 */ r = (q * 0xcd) >> 11; *buf++ = (q - 10 * r) + '0'; /* 7 */ q = (r * 0xcd) >> 11; *buf++ = (r - 10 * q) + '0'; /* 8 */ *buf++ = q + '0'; /* 9 */ return buf; } #endif /* Similar to above but do not pad with zeros. * Code can be easily arranged to print 9 digits too, but our callers * always call put_dec_full9() instead when the number has 9 decimal digits. */ static noinline_for_stack char *put_dec_trunc8(char *buf, unsigned r) { unsigned q; /* Copy of previous function's body with added early returns */ while (r >= 10000) { q = r + '0'; r = (r * (uint64_t)0x1999999a) >> 32; *buf++ = q - 10*r; } q = (r * 0x199a) >> 16; /* r <= 9999 */ *buf++ = (r - 10 * q) + '0'; if (q == 0) return buf; r = (q * 0xcd) >> 11; /* q <= 999 */ *buf++ = (q - 10 * r) + '0'; if (r == 0) return buf; q = (r * 0xcd) >> 11; /* r <= 99 */ *buf++ = (r - 10 * q) + '0'; if (q == 0) return buf; *buf++ = q + '0'; /* q <= 9 */ return buf; } /* There are two algorithms to print larger numbers. * One is generic: divide by 1000000000 and repeatedly print * groups of (up to) 9 digits. It's conceptually simple, * but requires a (unsigned long long) / 1000000000 division. * * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, * manipulates them cleverly and generates groups of 4 decimal digits. * It so happens that it does NOT require long long division. * * If long is > 32 bits, division of 64-bit values is relatively easy, * and we will use the first algorithm. * If long long is > 64 bits (strange architecture with VERY large long long), * second algorithm can't be used, and we again use the first one. * * Else (if long is 32 bits and long long is 64 bits) we use second one. */ #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 /* First algorithm: generic */ static char *put_dec(char *buf, unsigned long long n) { if (n >= 100*1000*1000) { while (n >= 1000*1000*1000) buf = put_dec_full9(buf, do_div(n, 1000*1000*1000)); if (n >= 100*1000*1000) return put_dec_full9(buf, n); } return put_dec_trunc8(buf, n); } #else /* Second algorithm: valid only for 64-bit long longs */ /* See comment in put_dec_full9 for choice of constants */ static noinline_for_stack void put_dec_full4(char *buf, unsigned q) { unsigned r; r = (q * 0xccd) >> 15; buf[0] = (q - 10 * r) + '0'; q = (r * 0xcd) >> 11; buf[1] = (r - 10 * q) + '0'; r = (q * 0xcd) >> 11; buf[2] = (q - 10 * r) + '0'; buf[3] = r + '0'; } /* * Call put_dec_full4 on x % 10000, return x / 10000. * The approximation x/10000 == (x * 0x346DC5D7) >> 43 * holds for all x < 1,128,869,999. The largest value this * helper will ever be asked to convert is 1,125,520,955. * (d1 in the put_dec code, assuming n is all-ones). */ static unsigned put_dec_helper4(char *buf, unsigned x) { uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; put_dec_full4(buf, x - q * 10000); return q; } /* Based on code by Douglas W. Jones found at * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> * (with permission from the author). * Performs no 64-bit division and hence should be fast on 32-bit machines. */ static char *put_dec(char *buf, unsigned long long n) { uint32_t d3, d2, d1, q, h; if (n < 100*1000*1000) return put_dec_trunc8(buf, n); d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ h = (n >> 32); d2 = (h ) & 0xffff; d3 = (h >> 16); /* implicit "& 0xffff" */ q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); q = put_dec_helper4(buf, q); q += 7671 * d3 + 9496 * d2 + 6 * d1; q = put_dec_helper4(buf+4, q); q += 4749 * d3 + 42 * d2; q = put_dec_helper4(buf+8, q); q += 281 * d3; buf += 12; if (q) buf = put_dec_trunc8(buf, q); else while (buf[-1] == '0') --buf; return buf; } #endif /* * Convert passed number to decimal string. * Returns the length of string. On buffer overflow, returns 0. * * If speed is not important, use snprintf(). It's easy to read the code. */ int num_to_str(char *buf, int size, unsigned long long num) { char tmp[sizeof(num) * 3]; int idx, len; /* put_dec() may work incorrectly for num = 0 (generate "", not "0") */ if (num <= 9) { tmp[0] = '0' + num; len = 1; } else { len = put_dec(tmp, num) - tmp; } if (len > size) return 0; for (idx = 0; idx < len; ++idx) buf[idx] = tmp[len - idx - 1]; return len; } #define ZEROPAD 1 /* pad with zero */ #define SIGN 2 /* unsigned/signed long */ #define PLUS 4 /* show plus */ #define SPACE 8 /* space if plus */ #define LEFT 16 /* left justified */ #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ 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_UBYTE, FORMAT_TYPE_BYTE, FORMAT_TYPE_USHORT, FORMAT_TYPE_SHORT, FORMAT_TYPE_UINT, FORMAT_TYPE_INT, FORMAT_TYPE_SIZE_T, FORMAT_TYPE_PTRDIFF }; struct printf_spec { u8 type; /* format_type enum */ u8 flags; /* flags to number() */ u8 base; /* number base, 8, 10 or 16 only */ u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ s16 field_width; /* width of output field */ s16 precision; /* # of digits/chars */ }; static noinline_for_stack 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"; */ char tmp[66]; char sign; char locase; int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); int i; bool is_zero = num == 0LL; /* locase = 0 or 0x20. ORing digits or letters with 'locase' * produces same digits or (maybe lowercased) letters */ locase = (spec.flags & SMALL); if (spec.flags & LEFT) spec.flags &= ~ZEROPAD; sign = 0; if (spec.flags & SIGN) { if ((signed long long)num < 0) { sign = '-'; num = -(signed long long)num; spec.field_width--; } else if (spec.flags & PLUS) { sign = '+'; spec.field_width--; } else if (spec.flags & SPACE) { sign = ' '; spec.field_width--; } } if (need_pfx) { if (spec.base == 16) spec.field_width -= 2; else if (!is_zero) spec.field_width--; } /* generate full string in tmp[], in reverse order */ i = 0; if (num < spec.base) tmp[i++] = digits[num] | locase; /* Generic code, for any base: else do { tmp[i++] = (digits[do_div(num,base)] | locase); } while (num != 0); */ else if (spec.base != 10) { /* 8 or 16 */ int mask = spec.base - 1; int shift = 3; if (spec.base == 16) shift = 4; do { tmp[i++] = (digits[((unsigned char)num) & mask] | locase); num >>= shift; } while (num); } else { /* base 10 */ i = put_dec(tmp, num) - tmp; } /* printing 100 using %2d gives "100", not "00" */ if (i > spec.precision) spec.precision = i; /* leading space padding */ spec.field_width -= spec.precision; if (!(spec.flags & (ZEROPAD+LEFT))) { while (--spec.field_width >= 0) { if (buf < end) *buf = ' '; ++buf; } } /* sign */ if (sign) { if (buf < end) *buf = sign; ++buf; } /* "0x" / "0" prefix */ if (need_pfx) { if (spec.base == 16 || !is_zero) { if (buf < end) *buf = '0'; ++buf; } if (spec.base == 16) { if (buf < end) *buf = ('X' | locase); ++buf; } } /* zero or space padding */ 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 <= --spec.precision) { if (buf < end) *buf = '0'; ++buf; } /* actual digits of result */ while (--i >= 0) { if (buf < end) *buf = tmp[i]; ++buf; } /* trailing space padding */ while (--spec.field_width >= 0) { if (buf < end) *buf = ' '; ++buf; }