1bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* 2bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Taken from Linux kernel's linux/lib/vsprintf.c 3bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * and somewhat simplified. 4bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 5bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Copyright (C) 1991, 1992 Linus Torvalds 6bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 7bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 8bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* 9bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Wirzenius wrote this portably, Torvalds fucked it up :-) 10bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 11bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 12bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#include "defs.h" 13bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 145dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#if USE_CUSTOM_PRINTF 15bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 16bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#include <stdarg.h> 17bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#include <limits.h> 18bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 195dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#ifndef HAVE_FPUTS_UNLOCKED 205dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes# define fputs_unlocked fputs 215dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#endif 225dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 23bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define noinline_for_stack /*nothing*/ 24bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define likely(expr) (expr) 25bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define unlikely(expr) (expr) 26bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 27bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define do_div(n, d) ({ __typeof(num) t = n % d; n /= d; t; }) 28bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 29bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#undef isdigit 30bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define isdigit(a) ((unsigned char)((a) - '0') <= 9) 31bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 32bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic inline 33bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesint skip_atoi(const char **s) 34bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 35bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int i = 0; 36bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes const char *p = *s; 37bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 38bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (isdigit(*p)) 39bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = i*10 + *p++ - '0'; 40bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 41bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *s = p; 42bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return i; 43bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 44bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 45bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* Decimal conversion is by far the most typical, and is used 46bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * for /proc and /sys data. This directly impacts e.g. top performance 47bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * with many processes running. We optimize it for speed 48bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html> 49bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (with permission from the author, Douglas W. Jones). 50bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 51bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 52bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#if LONG_MAX != 0x7fffffffUL || LLONG_MAX != 0x7fffffffffffffffULL 53bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* Formats correctly any integer in [0, 999999999] */ 54bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 55bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *put_dec_full9(char *buf, unsigned q) 56bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 57bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes unsigned r; 58bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 59bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* Possible ways to approx. divide by 10 60bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit) 61bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0xcccd) >> 19 x < 81920 (x < 262149 when 64-bit mul) 62bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x6667) >> 18 x < 43699 63bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x3334) >> 17 x < 16389 64bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x199a) >> 16 x < 16389 65bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x0ccd) >> 15 x < 16389 66bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x0667) >> 14 x < 2739 67bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x0334) >> 13 x < 1029 68bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x019a) >> 12 x < 1029 69bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x00cd) >> 11 x < 1029 shorter code than * 0x67 (on i386) 70bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x0067) >> 10 x < 179 71bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x0034) >> 9 x < 69 same 72bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x001a) >> 8 x < 69 same 73bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x000d) >> 7 x < 69 same, shortest code (on i386) 74bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (x * 0x0007) >> 6 x < 19 75bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html> 76bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 77bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * (uint64_t)0x1999999a) >> 32; 78bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 1 */ 79bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * (uint64_t)0x1999999a) >> 32; 80bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 2 */ 81bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * (uint64_t)0x1999999a) >> 32; 82bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 3 */ 83bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * (uint64_t)0x1999999a) >> 32; 84bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 4 */ 85bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * (uint64_t)0x1999999a) >> 32; 86bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 5 */ 87bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* Now value is under 10000, can avoid 64-bit multiply */ 88bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * 0x199a) >> 16; 89bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 6 */ 90bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * 0xcd) >> 11; 91bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 7 */ 92bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * 0xcd) >> 11; 93bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 8 */ 94bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = q + '0'; /* 9 */ 95bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf; 96bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 97bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#endif 98bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 99bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* Similar to above but do not pad with zeros. 100bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Code can be easily arranged to print 9 digits too, but our callers 101bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * always call put_dec_full9() instead when the number has 9 decimal digits. 102bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 103bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 104bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *put_dec_trunc8(char *buf, unsigned r) 105bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 106bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes unsigned q; 107bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 108bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* Copy of previous function's body with added early returns */ 109bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * (uint64_t)0x1999999a) >> 32; 110bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 2 */ 111bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (q == 0) return buf; 112bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * (uint64_t)0x1999999a) >> 32; 113bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 3 */ 114bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (r == 0) return buf; 115bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * (uint64_t)0x1999999a) >> 32; 116bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 4 */ 117bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (q == 0) return buf; 118bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * (uint64_t)0x1999999a) >> 32; 119bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 5 */ 120bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (r == 0) return buf; 121bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * 0x199a) >> 16; 122bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 6 */ 123bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (q == 0) return buf; 124bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * 0xcd) >> 11; 125bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; /* 7 */ 126bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (r == 0) return buf; 127bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * 0xcd) >> 11; 128bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; /* 8 */ 129bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (q == 0) return buf; 130bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = q + '0'; /* 9 */ 131bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf; 132bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 133bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 134bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* There are two algorithms to print larger numbers. 135bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * One is generic: divide by 1000000000 and repeatedly print 136bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * groups of (up to) 9 digits. It's conceptually simple, 137bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * but requires a (unsigned long long) / 1000000000 division. 138bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 139bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, 140bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * manipulates them cleverly and generates groups of 4 decimal digits. 141bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * It so happens that it does NOT require long long division. 142bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 143bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * If long is > 32 bits, division of 64-bit values is relatively easy, 144bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * and we will use the first algorithm. 145bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * If long long is > 64 bits (strange architecture with VERY large long long), 146bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * second algorithm can't be used, and we again use the first one. 147bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 148bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Else (if long is 32 bits and long long is 64 bits) we use second one. 149bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 150bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 151bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#if LONG_MAX != 0x7fffffffUL || LLONG_MAX != 0x7fffffffffffffffULL 152bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 153bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* First algorithm: generic */ 154bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 155bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic 156bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *put_dec(char *buf, unsigned long long n) 157bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 158bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (n >= 100*1000*1000) { 159bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (n >= 1000*1000*1000) 160bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = put_dec_full9(buf, do_div(n, 1000*1000*1000)); 161bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (n >= 100*1000*1000) 162bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return put_dec_full9(buf, n); 163bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 164bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return put_dec_trunc8(buf, n); 165bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 166bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 167bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#else 168bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 169bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* Second algorithm: valid only for 64-bit long longs */ 170bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 171bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 172bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *put_dec_full4(char *buf, unsigned q) 173bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 174bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes unsigned r; 175bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * 0xcccd) >> 19; 176bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; 177bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = (r * 0x199a) >> 16; 178bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (r - 10 * q) + '0'; 179bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = (q * 0xcd) >> 11; 180bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = (q - 10 * r) + '0'; 181bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf++ = r + '0'; 182bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf; 183bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 184bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 185bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* Based on code by Douglas W. Jones found at 186bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> 187bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (with permission from the author). 188bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Performs no 64-bit division and hence should be fast on 32-bit machines. 189bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 190bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic 191bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *put_dec(char *buf, unsigned long long n) 192bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 193bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes uint32_t d3, d2, d1, q, h; 194bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 195bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (n < 100*1000*1000) 196bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return put_dec_trunc8(buf, n); 197bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 198bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ 199bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes h = (n >> 32); 200bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes d2 = (h ) & 0xffff; 201bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes d3 = (h >> 16); /* implicit "& 0xffff" */ 202bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 203bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); 204bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 205bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = put_dec_full4(buf, q % 10000); 206bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = q / 10000; 207bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 208bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes d1 = q + 7671 * d3 + 9496 * d2 + 6 * d1; 209bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = put_dec_full4(buf, d1 % 10000); 210bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = d1 / 10000; 211bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 212bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes d2 = q + 4749 * d3 + 42 * d2; 213bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = put_dec_full4(buf, d2 % 10000); 214bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = d2 / 10000; 215bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 216bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes d3 = q + 281 * d3; 217bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!d3) 218bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes goto done; 219bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = put_dec_full4(buf, d3 % 10000); 220bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes q = d3 / 10000; 221bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!q) 222bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes goto done; 223bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = put_dec_full4(buf, q); 224bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes done: 225bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (buf[-1] == '0') 226bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes --buf; 227bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 228bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf; 229bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 230bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 231bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#endif 232bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 233bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* 234bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * For strace, the following formats are not supported: 235bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * %h[h]u, %zu, %tu - use [unsigned] int/long/long long fmt instead 236bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * %8.4u - no precision field for integers allowed (ok for strings) 237bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * %+d, % d - no forced sign or force "space positive" sign 238bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * %-07u - use %-7u instead 239bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * %X - works as %x 240bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 241bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 242bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define ZEROPAD 1 /* pad with zero */ 243bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define SIGN 2 /* unsigned/signed long */ 244bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes//#define PLUS 4 /* show plus */ 245bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes//#define SPACE 8 /* space if plus */ 246bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define LEFT 16 /* left justified */ 247bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes//#deefine SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ 248bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ 249bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 250bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesenum format_type { 251bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_NONE, /* Just a string part */ 252bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_WIDTH, 253bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_PRECISION, 254bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_CHAR, 255bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_STR, 256bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_PTR, 257bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_PERCENT_CHAR, 258bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_INVALID, 259bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_LONG_LONG, 260bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_ULONG, 261bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_LONG, 262bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_UINT, 263bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes FORMAT_TYPE_INT, 264bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes}; 265bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 266bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstruct printf_spec { 267bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes uint8_t type; /* format_type enum */ 268bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes uint8_t flags; /* flags to number() */ 269bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes uint8_t base; /* number base, 8, 10 or 16 only */ 270bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes uint8_t qualifier; /* number qualifier, one of 'hHlLtzZ' */ 271bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int field_width; /* width of output field */ 272bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int precision; /* # of digits/chars */ 273bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes}; 274bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 275bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 276bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *number(char *buf, char *end, unsigned long long num, 277bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes struct printf_spec spec) 278bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 279bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 280bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes static const char digits[16] = "0123456789abcdef"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 281bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 282bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes char tmp[sizeof(long long)*3 + 4]; 283bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes char sign; 284bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); 285bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int i; 286bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 287bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* We may overflow the buf. Crudely check for it */ 288bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = sizeof(long long)*3 + 4; 289bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (i < spec.field_width) 290bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = spec.field_width; 291bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if ((end - buf) <= i) 292bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf + i; 293bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 294bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes//we don't use formats like "%-07u" 295bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// if (spec.flags & LEFT) 296bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec.flags &= ~ZEROPAD; 297bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes sign = 0; 298bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec.flags & SIGN) { 299bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if ((signed long long)num < 0) { 300bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes sign = '-'; 301bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num = -(signed long long)num; 302bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.field_width--; 303bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// } else if (spec.flags & PLUS) { 304bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// sign = '+'; 305bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec.field_width--; 306bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// } else if (spec.flags & SPACE) { 307bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// sign = ' '; 308bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec.field_width--; 309bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 310bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 311bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (need_pfx) { 312bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.field_width--; 313bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec.base == 16) 314bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.field_width--; 315bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 316bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 317bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* generate full string in tmp[], in reverse order */ 318bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = 0; 319bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (num < spec.base) 320bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes tmp[i++] = digits[num]; 321bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* Generic code, for any base: 322bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes else do { 323bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes tmp[i++] = (digits[do_div(num,base)]); 324bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } while (num != 0); 325bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 326bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes else if (spec.base != 10) { /* 8 or 16 */ 327bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int mask = spec.base - 1; 328bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int shift = 3; 329bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 330bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec.base == 16) 331bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes shift = 4; 332bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes do { 333bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes tmp[i++] = digits[((unsigned char)num) & mask]; 334bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num >>= shift; 335bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } while (num); 336bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } else { /* base 10 */ 337bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = put_dec(tmp, num) - tmp; 338bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 339bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 340bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes//spec.precision is assumed 0 ("not specified") 341bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// /* printing 100 using %2d gives "100", not "00" */ 342bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// if (i > spec.precision) 343bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec.precision = i; 344bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// /* leading space padding */ 345bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec.field_width -= spec.precision; 346bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.field_width -= i; 347bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!(spec.flags & (ZEROPAD+LEFT))) { 348bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (--spec.field_width >= 0) { 349bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 350bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = ' '; 351bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 352bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 353bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 354bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* sign */ 355bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (sign) { 356bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 357bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = sign; 358bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 359bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 360bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* "0x" / "0" prefix */ 361bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (need_pfx) { 362bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 363bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = '0'; 364bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 365bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec.base == 16) { 366bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 367bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = 'x'; 368bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 369bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 370bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 371bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* zero or space padding */ 372bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!(spec.flags & LEFT)) { 373bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes char c = (spec.flags & ZEROPAD) ? '0' : ' '; 374bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (--spec.field_width >= 0) { 375bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 376bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = c; 377bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 378bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 379bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 380bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// /* hmm even more zero padding? */ 381bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// while (i <= --spec.precision) { 382bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// ///if (buf < end) 383bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// *buf = '0'; 384bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// ++buf; 385bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// } 386bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* actual digits of result */ 387bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (--i >= 0) { 388bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 389bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = tmp[i]; 390bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 391bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 392bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* trailing space padding */ 393bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (--spec.field_width >= 0) { 394bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 395bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = ' '; 396bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 397bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 398bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 399bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf; 400bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 401bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 402bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 403bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *string(char *buf, char *end, const char *s, struct printf_spec spec) 404bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 405bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int len, i; 406bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 407bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!s) 408bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes s = "(null)"; 409bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 410bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes len = strnlen(s, spec.precision); 411bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 412bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* We may overflow the buf. Crudely check for it */ 413bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = len; 414bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (i < spec.field_width) 415bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes i = spec.field_width; 416bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if ((end - buf) <= i) 417bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf + i; 418bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 419bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!(spec.flags & LEFT)) { 420bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (len < spec.field_width--) { 421bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 422bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = ' '; 423bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 424bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 425bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 426bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes for (i = 0; i < len; ++i) { 427bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 428bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = *s; 429bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; ++s; 430bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 431bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (len < spec.field_width--) { 432bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ///if (buf < end) 433bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *buf = ' '; 434bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++buf; 435bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 436bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 437bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return buf; 438bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 439bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 440bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 441bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hugheschar *pointer(const char *fmt, char *buf, char *end, void *ptr, 442bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes struct printf_spec spec) 443bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 444bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec.flags |= SMALL; 445bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec.field_width == -1) { 446bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.field_width = 2 * sizeof(void *); 447bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.flags |= ZEROPAD; 448bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 449bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.base = 16; 450bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 451bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return number(buf, end, (unsigned long) ptr, spec); 452bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 453bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 454bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/* 455bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Helper function to decode printf style format. 456bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * Each call decode a token from the format and return the 457bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * number of characters read (or likely the delta where it wants 458bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * to go on the next call). 459bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * The decoded token is returned through the parameters 460bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 461bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 'h', 'l', or 'L' for integer fields 462bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 'z' support added 23/7/1999 S.H. 463bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 'z' changed to 'Z' --davidm 1/25/99 464bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 't' added for ptrdiff_t 465bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 466bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @fmt: the format string 467bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @type of the token returned 468bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @flags: various flags such as +, -, # tokens.. 469bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @field_width: overwritten width 470bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @base: base of the number (octal, hex, ...) 471bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @precision: precision of a number 472bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @qualifier: qualifier of a number (long, size_t, ...) 473bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 474bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic noinline_for_stack 475bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesint format_decode(const char *fmt, struct printf_spec *spec) 476bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 477bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes const char *start = fmt; 478bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 479bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* we finished early by reading the field width */ 480bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->type == FORMAT_TYPE_WIDTH) { 481bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->field_width < 0) { 482bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->field_width = -spec->field_width; 483bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->flags |= LEFT; 484bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 485bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_NONE; 486bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes goto precision; 487bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 488bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 489bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* we finished early by reading the precision */ 490bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->type == FORMAT_TYPE_PRECISION) { 491bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->precision < 0) 492bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->precision = 0; 493bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 494bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_NONE; 495bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes goto qualifier; 496bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 497bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 498bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* By default */ 499bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_NONE; 500bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 501bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes for (;;) { 502bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (*fmt == '\0') 503bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return fmt - start; 504bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (*fmt == '%') 505bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 506bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++fmt; 507bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 508bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 509bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* Return the current non-format string */ 510bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (fmt != start) 511bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return fmt - start; 512bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 513bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* Process flags */ 514bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->flags = 0; 515bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 516bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (1) { /* this also skips first '%' */ 517bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes bool found = true; 518bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 519bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++fmt; 520bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 521bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes switch (*fmt) { 522bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case '-': spec->flags |= LEFT; break; 523bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// case '+': spec->flags |= PLUS; break; 524bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// case ' ': spec->flags |= SPACE; break; 525bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case '#': spec->flags |= SPECIAL; break; 526bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case '0': spec->flags |= ZEROPAD; break; 527bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes default: found = false; 528bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 529bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 530bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!found) 531bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 532bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 533bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 534bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* get field width */ 535bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->field_width = -1; 536bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 537bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (isdigit(*fmt)) 538bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->field_width = skip_atoi(&fmt); 539bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes else if (*fmt == '*') { 540bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* it's the next argument */ 541bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_WIDTH; 542bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 543bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 544bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 545bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesprecision: 546bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* get the precision */ 547bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->precision = -1; 548bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (*fmt == '.') { 549bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++fmt; 550bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (isdigit(*fmt)) { 551bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->precision = skip_atoi(&fmt); 552bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// if (spec->precision < 0) 553bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec->precision = 0; 554bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } else if (*fmt == '*') { 555bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* it's the next argument */ 556bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_PRECISION; 557bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 558bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 559bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 560bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 561bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesqualifier: 562bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* get the conversion qualifier */ 563bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->qualifier = -1; 564bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (*fmt == 'l') { 565bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->qualifier = *fmt++; 566bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (unlikely(spec->qualifier == *fmt)) { 567bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->qualifier = 'L'; 568bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++fmt; 569bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 570bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 571bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 572bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* default base */ 573bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->base = 10; 574bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes switch (*fmt) { 575bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'c': 576bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_CHAR; 577bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 578bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 579bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 's': 580bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_STR; 581bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 582bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 583bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'p': 584bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_PTR; 585bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 586bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 587bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case '%': 588bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_PERCENT_CHAR; 589bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 590bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 591bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* integer number formats - set up the flags and "break" */ 592bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'o': 593bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->base = 8; 594bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 595bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 596bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'x': 597bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// spec->flags |= SMALL; 598bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 599bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'X': 600bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->base = 16; 601bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 602bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 603bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'd': 604bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'i': 605bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->flags |= SIGN; 606bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case 'u': 607bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 608bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 609bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes default: 610bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_INVALID; 611bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return fmt - start; 612bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 613bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 614bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->qualifier == 'L') 615bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_LONG_LONG; 616bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes else if (spec->qualifier == 'l') { 617bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->flags & SIGN) 618bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_LONG; 619bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes else 620bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_ULONG; 621bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } else { 622bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (spec->flags & SIGN) 623bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_INT; 624bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes else 625bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec->type = FORMAT_TYPE_UINT; 626bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 627bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 628bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return ++fmt - start; 629bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 630bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 631bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes/** 632bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * vsnprintf - Format a string and place it in a buffer 633bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @buf: The buffer to place the result into 634bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @size: The size of the buffer, including the trailing null space 635bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @fmt: The format string to use 636bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * @args: Arguments for the format string 637bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 638bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * The return value is the number of characters which would 639bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * be generated for the given input, excluding the trailing 640bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * '\0', as per ISO C99. If you want to have the exact 641bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * number of characters written into @buf as return value 642bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * (not including the trailing '\0'), use vscnprintf(). If the 643bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * return is greater than or equal to @size, the resulting 644bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * string is truncated. 645bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * 646bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes * If you're not already dealing with a va_list consider using snprintf(). 647bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes */ 648bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesstatic 649bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesint kernel_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) 650bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 651bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes unsigned long long num; 652bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes char *str, *end; 653bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes struct printf_spec spec = {0}; 654bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 655bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes str = buf; 656bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes end = buf + size; 657bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 658bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (*fmt) { 659bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes const char *old_fmt = fmt; 660bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int read = format_decode(fmt, &spec); 661bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 662bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes fmt += read; 663bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 664bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes switch (spec.type) { 665bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_NONE: { 666bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int copy = read; 667bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) { 668bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (copy > end - str) 669bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes copy = end - str; 670bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes memcpy(str, old_fmt, copy); 671bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 672bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes str += read; 673bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 674bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 675bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 676bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_WIDTH: 677bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.field_width = va_arg(args, int); 678bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 679bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 680bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_PRECISION: 681bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec.precision = va_arg(args, int); 682bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 683bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 684bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_CHAR: { 685bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes char c; 686bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 687bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (!(spec.flags & LEFT)) { 688bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (--spec.field_width > 0) { 689bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) 690bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *str = ' '; 691bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++str; 692bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 693bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 694bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 695bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes c = (unsigned char) va_arg(args, int); 696bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) 697bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *str = c; 698bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++str; 699bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes while (--spec.field_width > 0) { 700bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) 701bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *str = ' '; 702bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++str; 703bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 704bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 705bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 706bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 707bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_STR: 708bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes str = string(str, end, va_arg(args, char *), spec); 709bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 710bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 711bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_PTR: 712bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes str = pointer(fmt+1, str, end, va_arg(args, void *), 713bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes spec); 714bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// while (isalnum(*fmt)) 715bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// fmt++; 716bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 717bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 718bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_PERCENT_CHAR: 719bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) 720bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *str = '%'; 721bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++str; 722bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 723bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 724bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_INVALID: 725bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) 726bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *str = '%'; 727bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes ++str; 728bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 729bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 730bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes default: 731bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes switch (spec.type) { 732bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_LONG_LONG: 733bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num = va_arg(args, long long); 734bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 735bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_ULONG: 736bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num = va_arg(args, unsigned long); 737bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 738bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_LONG: 739bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num = va_arg(args, long); 740bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 741bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes case FORMAT_TYPE_INT: 742bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num = (int) va_arg(args, int); 743bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes break; 744bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes default: 745bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes num = va_arg(args, unsigned int); 746bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 747bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 748bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes str = number(str, end, num, spec); 749bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 750bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 751bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 752bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// if (size > 0) { 753bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (str < end) 754bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes *str = '\0'; 755bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// else 756bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// end[-1] = '\0'; 757bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes// } 758bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 759bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /* the trailing null byte doesn't count towards the total */ 760bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return str-buf; 761bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 762bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 763bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 764bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughesint strace_vfprintf(FILE *fp, const char *fmt, va_list args) 765bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes{ 76615fc6a2add5cc636435b120075d2c27637528b11Elliott Hughes static char *buf = NULL; 76715fc6a2add5cc636435b120075d2c27637528b11Elliott Hughes static unsigned buflen = 0; 768bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 769bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes int r; 770bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes va_list a1; 771bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 772bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes va_copy(a1, args); 773bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes unsigned len = kernel_vsnprintf(buf, buflen, fmt, a1); 774bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes va_end(a1); 775bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 776bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (len >= buflen) { 777bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buflen = len + 256; 778bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes free(buf); 779bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes buf = malloc(buflen); 78015fc6a2add5cc636435b120075d2c27637528b11Elliott Hughes if (!buf) 78115fc6a2add5cc636435b120075d2c27637528b11Elliott Hughes die_out_of_memory(); 782bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes /*len =*/ kernel_vsnprintf(buf, buflen, fmt, args); 783bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes } 784bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 785bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes r = fputs_unlocked(buf, fp); 786bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes if (r < 0) return r; 787bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes return len; 788bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes} 789bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes 790bb0c2d52fc596f5e21652486c0b6a0b3e3b7e4cbElliott Hughes#endif /* USE_CUSTOM_PRINTF */ 791