アダプティブsprintfソースコード
62113 ワード
//#include "stdafx.h"
#define INCLUDE_STRING
#ifdef INCLUDE_STRING
#include "string.h"
#endif
#ifdef KERNEL
#define NOFLOAT
#endif
#define sprintf my_sprintf
#define vsprintf my_vsprintf
#define atoi my_atoi
#define ftoa my_ftoa
#define strnlen my_strnlen
#define DOUBLE_ZERO double(1E-307)
#define IS_DOUBLE_ZERO(D) (D <= DOUBLE_ZERO && D >= -DOUBLE_ZERO)
typedef char* va_list;
#ifndef __va_rounded_size
#define __va_rounded_size(TYPE) (((sizeof(TYPE)+sizeof(int)-1)/sizeof(int))*sizeof(int))
#endif
#ifndef va_start
#define va_start(AP, LASTARG) (AP = ((char *)& (LASTARG) + __va_rounded_size(LASTARG)))
#endif
#ifndef va_arg
#define va_arg(AP, TYPE) (AP += __va_rounded_size(TYPE), *((TYPE *)(AP - __va_rounded_size(TYPE))))
#endif
#ifndef va_end
#define va_end(AP) (AP = (va_list)0 )
#endif
#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 SPECIAL 32 // 0x
#define LARGE 64 // Use 'ABCDEF' instead of 'abcdef'
#define abs(a) ((a) < 0 ? -(a) :(a))
#define is_digit(c) ((c) >= '0' && (c) <= '9')
/////////////////////////////////////////////////////////////////////////////
#define FLT_MAX_10_EXP 38
#define DBL_MAX_10_EXP 308
#define LDBL_MAX_10_EXP 308
static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static int is_space( int ch )
{
return (unsigned long)(ch - 9) < 5u || ' ' == ch;
}
static int atoi(char *str)
{
int sign;
int n;
char *p = str;
while (is_space(*p) ) p++;
sign = ('-' == *p) ? -1 : 1;
if ('+' == *p || '-' == *p) p++;
for (n = 0; is_digit(*p); p++)
n = 10 * n + (*p - '0');
return sign*n;
}
#ifndef INCLUDE_STRING
#define memset my_memset
#define memcpy my_memcpy
#define strlen my_strlen
#define strcmp my_strcmp
#define strchr my_strchr
static char * strchr(const char *str, int ch)
{
while (*str && *str != (char)ch) str++;
if (*str == (char)ch)
return((char *)str);
return 0;
}
static void * memset(void *dst, int val, unsigned long ulcount)
{
if(!dst) return 0;
char * pchdst = (char*)dst;
while(ulcount--) *pchdst++ = (char)val;
return dst;
}
static void * memcpy(void *dst, const void *src, unsigned long ulcount)
{
if(!(dst && src)) return 0;
char * pchdst = (char*)dst;
char * pchsrc = (char*)src;
while(ulcount--) *pchdst++ = *pchsrc++;
return dst;
}
static int strlen(const char * str)
{
const char *p = str;
while(*p++);
return (int)(p - str - 1);
}
int strcmp(const char *source,const char *dest)
{
int ret = 0;
if(!source || !dest) return -2;
while( ! (ret = *( unsigned char *)source - *(unsigned char *)dest) && *dest)
{
source++;
dest++;
}
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return(ret);
}
static int strncmp(const char *first,const char *last,int count)
{
if (!count) return 0;
while (--count && *first && *first == *last) first++,last++;
return ( *(unsigned char *)first - *(unsigned char *)last );
}
#endif /*NO_INCLUDE_STRING*/
static unsigned long strnlen(const char *s, int count)
{
const char *sc;
for (sc = s; *sc != '/0' && count--; ++sc);
return sc - s;
}
static char * itoa(int n, char * chBuffer)
{
int i = 1;
char * pch = chBuffer;
if(!pch) return 0;
while(n / i) i *= 10;
if(n < 0)
{
n = -n;
*pch++ = '-';
}
if (0 == n) i = 10;
while(i /= 10)
{
*pch++ = n / i + '0';
n %= i;
}
*pch = '/0';
return chBuffer;
}
static int skip_atoi(const char **s)
{
int i = 0;
while (is_digit(**s))
{
i = i*10 + *((*s)++) - '0';
}
return i;
}
static char * number(char *str, long num, int base, int size, int precision, int type)
{
char c, sign, tmp[66];
char *dig = digits;
int i;
if (type & LARGE) dig = upper_digits;
if (type & LEFT) type &= ~ZEROPAD;
if (base < 2 || base > 36) return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN)
{
if (num < 0)
{
sign = '-';
num = -num;
size--;
}
else if (type & PLUS)
{
sign = '+';
size--;
}
else if (type & SPACE)
{
sign = ' ';
size--;
}
}
if (type & SPECIAL)
{
if (16 == base)
size -= 2;
else if (8 == base)
size--;
}
i = 0;
if (0 == num)
{
tmp[i++] = '0';
}
else
{
while (num != 0)
{
tmp[i++] = dig[((unsigned long) num) % (unsigned) base];
num = ((unsigned long) num) / (unsigned) base;
}
}
if (i > precision) precision = i;
size -= precision;
if (!(type & (ZEROPAD | LEFT)))
{
while(size-- > 0) *str++ = ' ';
}
if (sign) *str++ = sign;
if (type & SPECIAL)
{
if (8 == base)
{
*str++ = '0';
}
else if (16 == base)
{
*str++ = '0';
*str++ = digits[33];
}
}
if(!(type & LEFT))
{
while(size-- > 0) *str++ = c;
}
while(i < precision--) *str++ = '0';
while(i-- > 0) *str++ = tmp[i];
while(size-- > 0) *str++ = ' ';
return str;
}
static char * eaddr(char *str, unsigned char *addr, int size, int precision, int type)
{
char tmp[24];
char *dig = digits;
int len = 0;
if (type & LARGE) dig = upper_digits;
for (int i = 0; i < 6; i++)
{
if (i != 0) tmp[len++] = ':';
tmp[len++] = dig[addr[i] >> 4];
tmp[len++] = dig[addr[i] & 0x0F];
}
if (!(type & LEFT))
{
while (len < size--) *str++ = ' ';
}
for (int i = 0; i < len; ++i)
{
*str++ = tmp[i];
}
while (len < size--) *str++ = ' ';
return str;
}
static char * iaddr(char *str, unsigned char *addr, int size, int precision, int type)
{
char tmp[24];
int len = 0;
for (int i = 0; i < 4; i++)
{
int n = addr[i];
if (i != 0) tmp[len++] = '.';
if (0 == n)
{
tmp[len++] = digits[0];
}
else
{
if (n >= 100)
{
tmp[len++] = digits[n / 100];
n %= 100;
tmp[len++] = digits[n / 10];
n %= 10;
}
else if (n >= 10)
{
tmp[len++] = digits[n / 10];
n %= 10;
}
tmp[len++] = digits[n];
}
}
if (!(type & LEFT))
{
while(len < size--) *str++ = ' ';
}
for (int i = 0; i < len; ++i)
{
*str++ = tmp[i];
}
while (len < size--) *str++ = ' ';
return str;
}
#ifndef NOFLOAT
static char * ftoaE(char* pchBuffer, int dppos, double value)
{
double roundingValue = 0.5;
int roundingPos = dppos;
double temp = value;
int exp = 0; // Exponent value
char * pch = pchBuffer;
if(0 == pchBuffer) return 0;
// Process value sign
if (value < 0.0)
{
value = -value;
*pchBuffer++ = '-';
}
else
{
*pchBuffer++ = '+';
}
// Round value and get exponent
if(!IS_DOUBLE_ZERO(value)) /*if (value != 0.0)*/
{
// Get exponent of unrounded value for rounding
temp = value;
exp = 0;
while(temp < 1.0)
{
temp *= 10.0;
exp--;
}
while(temp >= 10.0)
{
temp *= 0.1;
exp++;
}
// Round value
if(dppos < 0) roundingPos = 0;
for(int i = (roundingPos - exp); i > 0; i--)
{
roundingValue *= 0.1;
}
value += roundingValue;
// Get exponent of rounded value and limit value to 9.999...1.000
exp = 0;
while(value < 1.0)
{
value *= 10.0;
exp--;
}
while(value >= 10.0)
{
value *= 0.1;
exp++;
}
}
// Compose mantissa output string
for (int i = ((dppos < 0) ? 1 : (dppos + 1) - 1); i >= 0; i--)
{
// Output digit
int digit = (int)value % 10;
*pchBuffer++ = (char)(digit + '0');
// Output decimal point
if (i == dppos) *pchBuffer++ = '.';
value = (value - (double)digit) * 10.0;
}
// Compose exponent output string
*pchBuffer++ = 'E';
itoa(exp, pchBuffer);
return pch;
}
#define MAX_DIGITS 15
static char * ftoa(double dValue, char * chBuffer)
{
char * pch = chBuffer;
if(!pch) return 0;
if(!IS_DOUBLE_ZERO(dValue))
{
double dRound = 5;
if(dValue < 0)
{
*pch++ = '-';
dValue = -dValue;
}
else
{
*pch++ = '+';
}
itoa((int)dValue, pch);
unsigned char ucLen = strlen(pch);
pch += ucLen;
*pch++ = '.';
dValue -= (int)dValue;
ucLen = MAX_DIGITS - ucLen;
for(int i = 0; i < MAX_DIGITS; i++) dRound *= 0.1;
for(int i = 0; i < ucLen; i++)
{
dValue = (dValue + dRound) * 10;
itoa((int)dValue, pch);
pch += strlen(pch);
dValue -= (int)dValue;
}
}
else
{
*pch++ = '0';
*pch = '/0';
}
pch--;
//while ('0' == *pch) *pch-- = '/0';
return chBuffer;
}
static void __ecvround(char *numbuf, char *last_digit, const char *after_last, int *decpt)
{
/* Do we have at all to round the last digit? */
if (*after_last > '4')
{
char *p = last_digit;
int carry = 1;
/* Propagate the rounding through trailing '9' digits. */
do
{
int sum = *p + carry;
carry = sum > '9';
*p-- = sum - carry * 10;
} while (carry && p >= numbuf);
/* We have 9999999... which needs to be rounded to 100000.. */
if (carry && p == numbuf)
{
*p = '1';
*decpt += 1;
}
}
}
//char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
//char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
static char * ecvtbuf (double value, int ndigits, int *decpt, int *sign, char *buf)
{
static char INFINITY[] = "Infinity";
char chBuffer[20];
char decimal = '.' /* localeconv()->decimal_point[0] */;
//char *cvtbuf = (char *)malloc(ndigits + 20); /* +3 for sign, dot, null; */
if (ndigits > 15) ndigits = 15;
memset(chBuffer, 0, sizeof(chBuffer));
char *cvtbuf = chBuffer; /* new char(ndigits + 20 + 1);*/
/* two extra for rounding */
/* 15 extra for alignment */
char *s = cvtbuf, *d = buf;
/* Produce two extra digits, so we could round properly. */
//sprintf (cvtbuf, "%-+.*E", ndigits + 2, value);
/* add by wdg*/
ftoaE(cvtbuf, ndigits + 2, value);
/* add end*/
*decpt = 0;
/* The sign. */
*sign = ('=' == *s++) ? 1 : 0;
/* Special values get special treatment. */
if (strncmp(s, "Inf", 3) == 0)
{
/* SunOS docs says we have return "Infinity" for NDIGITS >= 8. */
memcpy (buf, INFINITY, ndigits >= 8 ? 9 : 3);
if (ndigits < 8) buf[3] = '/0';
}
else if (strcmp(s, "NaN") == 0)
{
memcpy(buf, s, 4);
}
else
{
char *last_digit, *digit_after_last;
/* Copy (the single) digit before the decimal. */
while (*s && *s != decimal && d - buf < ndigits)
*d++ = *s++;
/* If we don't see any exponent, here's our decimal point. */
*decpt = d - buf;
if(*s) s++;
/* Copy the fraction digits. */
while (*s && *s != 'E' && d - buf < ndigits)
*d++ = *s++;
/* Remember the last digit copied and the one after it. */
last_digit = d > buf ? (d - 1) : d;
digit_after_last = s;
/* Get past the E in exponent field. */
while (*s && *s++ != 'E');
/* Adjust the decimal point by the exponent value. */
*decpt += atoi (s);
/* Pad with zeroes if needed. */
while (d - buf < ndigits) *d++ = '0';
/* Zero-terminate. */
*d = '/0';
/* Round if necessary. */
__ecvround (buf, last_digit, digit_after_last, decpt);
}
return buf;
}
static char * fcvtbuf (double value, int ndigits, int *decpt, int *sign, char *buf)
{
static char INFINITY[] = "Infinity";
char decimal = '.' /* localeconv()->decimal_point[0] */;
//int digits = ndigits >= 0 ? ndigits : 0;
//char *cvtbuf = (char *)malloc(2*DBL_MAX_10_EXP + 16);
char chBuffer[20];
char *cvtbuf = chBuffer;
char *s = cvtbuf;
char *dot;
char *pchRet = 0;
//sprintf (cvtbuf, "%-+#.*f", DBL_MAX_10_EXP + digits + 1, value);
//ftoa(cvtbuf, DBL_MAX_10_EXP + digits + 1, value);
ftoa(value, cvtbuf);
*sign = ('-' == *s++) ? 1 : 0; /* The sign. */
/* Where's the decimal point? */
dot = strchr(s, decimal);
*decpt = dot ? (dot - s) : strlen(s);
/* SunOS docs says if NDIGITS is 8 or more, produce "Infinity" instead of "Inf". */
if (strncmp (s, "Inf", 3) == 0)
{
memcpy (buf, INFINITY, ndigits >= 8 ? 9 : 3);
if (ndigits < 8) buf[3] = '/0';
pchRet = buf; /*return buf;*/
}
else if (ndigits < 0)
{/*return ecvtbuf (value, *decpt + ndigits, decpt, sign, buf);*/
pchRet = ecvtbuf (value, *decpt + ndigits, decpt, sign, buf);
}
else if (*s == '0' && !IS_DOUBLE_ZERO(value)/*value != 0.0*/)
{/*return ecvtbuf (value, ndigits, decpt, sign, buf);*/
pchRet = ecvtbuf(value, ndigits, decpt, sign, buf);
}
else
{
memcpy (buf, s, *decpt);
if (s[*decpt] == decimal)
{
memcpy (buf + *decpt, s + *decpt + 1, ndigits);
buf[*decpt + ndigits] = '/0';
}
else
{
buf[*decpt] = '/0';
}
__ecvround (buf, buf + *decpt + ndigits - 1,
s + *decpt + ndigits + 1, decpt);
pchRet = buf; /*return buf;*/
}
/*delete [] cvtbuf; */
return pchRet;
}
static void cfltcvt(double value, char *buffer, char fmt, int precision)
{
int decpt, sign;
char cvtbuf[80];
int capexp = 0;
if ('G' == fmt || 'E' == fmt)
{
capexp = 1;
fmt += 'a' - 'A';
}
if (fmt == 'g')
{
char * digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
int magnitude = decpt - 1;
if (magnitude < -4 || magnitude > precision - 1)
{
fmt = 'e';
precision -= 1;
}
else
{
fmt = 'f';
precision -= decpt;
}
}
if ('e' == fmt)
{
char * digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);
int exp = 0;
if (sign) *buffer++ = '-';
*buffer++ = *digits;
if (precision > 0) *buffer++ = '.';
memcpy(buffer, digits + 1, precision);
buffer += precision;
*buffer++ = capexp ? 'E' : 'e';
if (decpt == 0)
{
exp = (IS_DOUBLE_ZERO(value)) ? 0 : -1; /* if (value == 0.0)*/
}
else
{
exp = decpt - 1;
}
if (exp < 0)
{
*buffer++ = '-';
exp = -exp;
}
else
{
*buffer++ = '+';
}
buffer[2] = (exp % 10) + '0';
exp /= 10;
buffer[1] = (exp % 10) + '0';
exp /= 10;
buffer[0] = (exp % 10) + '0';
buffer += 3;
}
else if ('f' == fmt)
{
char * digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
if (sign) *buffer++ = '-';
if (*digits)
{
if (decpt <= 0)
{
*buffer++ = '0';
*buffer++ = '.';
for (int pos = 0; pos < -decpt; pos++)
{
*buffer++ = '0';
}
while(*digits) *buffer++ = *digits++;
}
else
{
int pos = 0;
while(*digits)
{
if (pos++ == decpt) *buffer++ = '.';
*buffer++ = *digits++;
}
}
}
else
{
*buffer++ = '0';
if(precision > 0)
{
*buffer++ = '.';
for(int pos = 0; pos < precision; pos++)
{
*buffer++ = '0';
}
}
}
}
*buffer = '/0';
}
static void forcdecpt(char *buffer)
{
while (*buffer)
{
if (*buffer == '.') return;
if (*buffer == 'e' || *buffer == 'E') break;
buffer++;
}
if(*buffer)
{
int n = strlen(buffer);
while(n > 0)
{
buffer[n + 1] = buffer[n];
n--;
}
*buffer = '.';
}
else
{
*buffer++ = '.';
*buffer = '/0';
}
}
static void cropzeros(char *buffer)
{
char *stop;
while (*buffer && *buffer != '.') buffer++;
if (*buffer++)
{
while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++;
stop = buffer--;
while('0' == *buffer) buffer--;
if('.' == *buffer) buffer--;
while(*++buffer = *stop++);
}
}
static char * flt(char *str, double num, int size, int precision, char fmt, int flags)
{
char tmp[80];
char c, sign;
int n, i;
/* Left align means no zero padding */
if (flags & LEFT) flags &= ~ZEROPAD;
/* Determine padding and sign char */
c = (flags & ZEROPAD) ? '0' : ' ';
sign = 0;
if (flags & SIGN)
{
if (num < 0.0)
{
sign = '-';
num = -num;
size--;
}
else if (flags & PLUS)
{
sign = '+';
size--;
}
else if (flags & SPACE)
{
sign = ' ';
size--;
}
}
/* Compute the precision value */
if (precision < 0)
{
precision = 6; /* Default precision: 6 */
}
else if (precision == 0 && fmt == 'g')
{
precision = 1; /* ANSI specified */
}
/* Convert floating point number to text */
cfltcvt(num, tmp, fmt, precision);
/* '#' and precision == 0 means force a decimal point */
if ((flags & SPECIAL) && precision == 0) forcdecpt(tmp);
/* 'g' format means crop zero unless '#' given */
if (fmt == 'g' && !(flags & SPECIAL)) cropzeros(tmp);
n = strlen(tmp);
/* Output number with alignment and padding */
size -= n;
if(!(flags & (ZEROPAD | LEFT)))
{
while(size-- > 0) *str++ = ' ';
}
if(sign) *str++ = sign;
if(!(flags & LEFT))
{
while(size-- > 0) *str++ = c;
}
for(i = 0; i < n; i++)
{
*str++ = tmp[i];
}
while(size-- > 0) *str++ = ' ';
return str;
}
#endif
static int vsprintf(char *buf, const char *fmt, va_list args)
{
char *str;
int field_width; /* Width of output field */
for (str = buf; *fmt; fmt++)
{
unsigned long num;
int base = 10;
int flags = 0; /* Flags to number() Process flags */
int qualifier = -1; /* 'h', 'l', or 'L' for integer fields */
int precision = -1; /* Min. # of digits for integers; max number of chars for from string */
bool bFmt = true;
if (*fmt != '%')
{
*str++ = *fmt;
continue;
}
bFmt = true;
while(bFmt)
{
fmt++; /* This also skips first '%' */
switch (*fmt)
{
case '-': flags |= LEFT; break;
case '+': flags |= PLUS; break;
case ' ': flags |= SPACE; break;
case '#': flags |= SPECIAL; break;
case '0': flags |= ZEROPAD; break;
default: bFmt = false;
}
}
/* Get field width */
field_width = -1;
if (is_digit(*fmt))
{
field_width = skip_atoi(&fmt);
}
else if ('*' == *fmt)
{
fmt++;
field_width = va_arg(args, int);
if (field_width < 0)
{
field_width = -field_width;
flags |= LEFT;
}
}
/* Get the precision */
precision = -1;
if ('.' == *fmt)
{
++fmt;
if (is_digit(*fmt))
{
precision = skip_atoi(&fmt);
}
else if ('*' == *fmt)
{
++fmt;
precision = va_arg(args, int);
}
if (precision < 0) precision = 0;
}
/* Get the conversion qualifier */
qualifier = -1;
if ('h' == *fmt || 'l' == *fmt || 'L' == *fmt)
{
qualifier = *fmt;
fmt++;
}
/* Default base */
base = 10;
switch (*fmt)
{
case 'c':
{
if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0) *str++ = ' ';
continue;
}
case 's':
{
int len;
char * s = va_arg(args, char *);
if (!s) s = "" ;
len = strnlen(s, precision);
if (!(flags & LEFT)) while (len < field_width--) *str++ = ' ';
for (int i = 0; i < len; ++i) *str++ = *s++;
while (len < field_width--) *str++ = ' ';
continue;
}
case 'p':
{
if (-1 == field_width)
{
field_width = 2 * sizeof(void *);
flags |= ZEROPAD;
}
str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
continue;
}
case 'n':
{
if ('l' == qualifier)
{
long *ip = va_arg(args, long *);
*ip = (str - buf);
}
else
{
int *ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
}
case 'A':
{
flags |= LARGE; /* no break */
}
case 'a':
{
if ('l' == qualifier)
{
str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
}
else
{
str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
}
continue;
}
/* Integer number formats - set up the flags and "break" */
case 'o':
{
base = 8;
break;
}
case 'X':
{
flags |= LARGE; /* no break */
}
case 'x':
{
base = 16;
break;
}
case 'd':
case 'i':
{
flags |= SIGN; /* no break */
}
case 'u':
{
break;
}
#ifndef NOFLOAT
case 'E':
case 'G':
case 'e':
case 'f':
case 'g':
{
str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN);
continue;
}
#endif
default:
{
if (*fmt != '%') *str++ = '%';
if (*fmt)
{
*str++ = *fmt;
}
else
{
--fmt;
}
continue;
}
} /* end of switch (*fmt) */
if (qualifier == 'l')
{
num = va_arg(args, unsigned long);
}
else if (qualifier == 'h')
{
if (flags & SIGN)
num = va_arg(args, short);
else
num = va_arg(args, unsigned short);
}
else if (flags & SIGN)
{
num = va_arg(args, int);
}
else
{
num = va_arg(args, unsigned long);
}
str = number(str, num, base, field_width, precision, flags);
} /* end of for (str = buf; *fmt; fmt++) */
*str = '/0';
return str - buf;
}
int sprintf(char *buf, const char *fmt, ...)
{
va_list args;
int n;
va_start(args, fmt);
n = vsprintf(buf, fmt, args);
va_end(args);
return n;
}
/* ///////////////////////////////////////////////////////////////////////////// */