TwlToolsRED/build/tools/sctools/common/src/logprintf.c

796 lines
20 KiB
C

/**************************************************************************
* Copyright (C) 1997, Nintendo Co.,Ltd. *
*************************************************************************/
#include <twl.h>
#include "text.h"
#include "mprintf.h"
#include "logprintf.h"
#define __std(ref) ref
// #define __std(ref) ::std::ref
#include <twl.h>
#include "text.h"
#include "mprintf.h"
#include "logprintf.h"
#define __fourbytealign(n) ((((unsigned long) (n)) + 3U) & ~3U)
#define __va_start(parm) ((__std(va_list)) ((char*) ((unsigned long)(&parm) & ~3U) + __fourbytealign(sizeof(parm))))
#define va_start(ap, parm) ((ap) = __va_start(parm))
#define va_arg(ap, type) (*(type *) ((ap += __fourbytealign(sizeof(type))) - __fourbytealign(sizeof(type))))
#define va_end(ap) ((void) 0)
static void *my_memcpy(void *dest, const void *src, size_t n)
{
unsigned char *s = (unsigned char *)dest;
unsigned char *ss = (unsigned char *)src;
while(n--) {
*s++ = *ss++ ;
}
return dest;
}
static const char *strchr(const char *s,int c)
{
int a;
while( (a = (int)*s) != NULL ) {
if(a == c)
return s;
s++;
}
return (const char *)NULL;
}
static size_t strlen(const char *s)
{
size_t n=0;
while( *s != NULL) {
n++;
s++;
}
return n;
}
static void *proutPrintf(void *fd, const char *buf, size_t n)
{
/* write to file */
/* return (fwrite(buf, 1, n, str) == n ? str : NULL);*/
int i;
for (i = 0; i < n; i++) {
OS_PutChar( buf[i] );
// m_putchar( (void *)tc[0], buf[i] );
}
if( fd != NULL ) {
(void)FS_WriteFile(fd, (void *)buf, (long)n );
}
/* return a fake pointer so that it's not NULL */
return ((void *)fd);
}
static int _Printf(void *(*pfn)(void *, const char *, size_t),
void *arg, int len, const char *fmt, va_list ap);
void miya_log_fprintf(FSFile *fd, const char *fmt, ...)
{
int ans;
va_list ap;
va_start(ap, fmt);
ans = _Printf(&proutPrintf, (void *)fd, 0x200, fmt, ap);
va_end(ap);
}
/**************************************************************/
/*******************************************************/
/* _Printf function */
#define _YVALS
/* float properties */
#define _D0 3
#define _DBIAS (0x400-1)
#define _DLONG 0
#define _DOFF 4
#define _LBIAS (0x400-1)
#define _LONG_DOUBLE 0
/* pointer properties */
#define _NULL (void *) 0
typedef unsigned int _Sizet;
/***********************************************************/
#define _FSP 0x01
#define _FPL 0x02
#define _FMI 0x04
#define _FNO 0x08
#define _FZE 0x10
#define _WMAX 999
#define _WANT (EOF-1)
#if _LONG_DOUBLE
typedef long double ldouble;
#else
typedef double ldouble;
#endif
typedef struct {
union {
long long ll;
ldouble ld;
} v;
char *s;
int n0, nz0, n1, nz1, n2, nz2, prec, width;
size_t nchar;
unsigned int flags;
char qual;
} _Pft;
/* declarations */
static void miya_Ldtob(_Pft *, char);
static void miya_Litob(_Pft *, char);
/* macros */
#if _DLONG
#define LDSIGN(x) (((unsigned short *) &(x))[_D0 ? 4 : 0] & 0x8000)
#else
#define LDSIGN(x) (((unsigned short *) &(x))[_D0] & 0x8000)
#endif
#define ISDIGIT(c) ((c >= '0') && (c <= '9'))
#define MAX_PAD (sizeof(spaces) - 1)
#define PAD(s, n) \
if (0 < (n)) { \
int i, j = (n); \
for (; 0 < j; j -= i) { \
i = MAX_PAD < j ? MAX_PAD : j; \
PUT(s, i); \
} \
}
#if 0 // miyamoto
#define PUT(s, n) \
if( len > n ) {\
if (0 < (n)) { \
len -= n; \
if ((arg = (*pfn)(arg, s, n)) != NULL) \
x.nchar += (n); \
else \
return (x.nchar); \
} \
} \
else { \
return (x.nchar); \
}
#else
#define PUT(s, n) \
if( len > n ) {\
if (0 < (n)) { \
len -= n; \
arg = (*pfn)(arg, s, n); \
x.nchar += (n); \
} \
} \
else { \
return (x.nchar); \
}
#endif
static char spaces[] = " ";
static char zeroes[] = "00000000000000000000000000000000";
static void _Putfld(_Pft *, va_list *, char, char *);
typedef struct {
long quot;
long rem;
} miya_ldiv_t;
typedef struct {
long long quot;
long long rem;
} miya_lldiv_t;
static miya_lldiv_t miya_lldiv(long long a, long long b)
{
miya_lldiv_t t;
t.quot = a / b;
t.rem = a % b;
return t;
}
static miya_ldiv_t miya_ldiv(long a, long b)
{
miya_ldiv_t t;
t.quot = a / b;
t.rem = a % b;
return t;
}
static int _Printf(void *(*pfn)(void *, const char *, size_t),
void *arg, int len, const char *fmt, va_list ap)
{ /* print formatted */
_Pft x;
x.nchar = 0;
while (1) { /* scan format string */
const char *s = fmt;
int c;
const char *t;
static const char fchar[] = {" +-#0"};
static const unsigned int fbit[] = {
_FSP, _FPL, _FMI, _FNO, _FZE, 0};
char ac[32];
/* copy any literal text */
while ( (0 < (c = (int)(*s++)) ) && (c != '%')) {
}
--s;
#if 1
PUT(fmt, s - fmt);
#else
if (0 < (s-fmt)) {
if ((arg = (*pfn)(arg, fmt, s-fmt)) != NULL)
x.nchar += (s-fmt);
else
return (x.nchar);
}
}
else {
return (x.nchar);
}
#endif
if (c == '\0')
return (x.nchar);
fmt = ++s;
/* parse a conversion specifier */
for (x.flags = 0; (t = strchr(fchar, *s)) != NULL; ++s)
x.flags |= fbit[t - fchar];
if (*s == '*') { /* get width argument */
x.width = va_arg(ap, int);
if (x.width < 0) { /* same as '-' flag */
x.width = -x.width;
x.flags |= _FMI;
}
++s;
} else /* accumulate width digits */
for (x.width = 0; ISDIGIT((int)*s); ++s)
if (x.width < _WMAX)
x.width = x.width * 10 + *s - '0';
if (*s != '.')
x.prec = -1;
else if ( *++s == '*') { /* get precision argument */
x.prec = va_arg(ap, int);
++s;
} else /* accumulate precision digits */
for (x.prec = 0; ISDIGIT(*s); ++s)
if (x.prec < _WMAX)
x.prec = x.prec * 10 + *s - '0';
x.qual = (char)(strchr("hlL", *s) ? *s++ : '\0');
if (( x.qual == 'l') && ( *s == 'l')) {
x.qual= 'L'; /* the %ll qualifier */
s++;
}
/* do the conversion */
_Putfld(&x, &ap, *s, ac);
x.width -= x.n0 + x.nz0 + x.n1 + x.nz1 + x.n2 + x.nz2;
if (!(x.flags & _FMI))
PAD(spaces, x.width);
PUT(ac, x.n0);
PAD(zeroes, x.nz0);
PUT(x.s, x.n1);
PAD(zeroes, x.nz1);
PUT(x.s + x.n1, x.n2);
PAD(zeroes, x.nz2);
if (x.flags & _FMI)
PAD(spaces, x.width);
fmt = s + 1;
}
/* shouldn't reach here, only used to eliminate the compiler warning */
// return 0;
}
static void _Putfld(_Pft *px, va_list *pap, char code, char *ac)
{ /* convert a field for _Printf */
px->n0 = px->nz0 = px->n1 = px->nz1 = px->n2 = px->nz2 = 0;
switch (code) { /* switch on conversion specifier */
case 'c':
ac[px->n0++] = (char)va_arg(*pap, int);
break;
case 'd':
case 'i': /* convert a signed decimal integer */
if (px->qual == 'l')
px->v.ll = va_arg(*pap, long);
else if (px->qual == 'L')
px->v.ll = va_arg(*pap, long long);
else
px->v.ll = va_arg(*pap, int);
if ( px->qual == 'h')
px->v.ll = (short) px->v.ll;
if (px->v.ll < 0) /* negate safely in miya_Litob */
ac[px->n0++] = '-';
else if (px->flags & _FPL)
ac[px->n0++] = '+';
else if (px->flags & _FSP)
ac[px->n0++] = ' ';
px->s = &ac[px->n0];
miya_Litob(px, code);
break;
case 'o':
case 'u':
case 'x':
case 'X': /* convert unsigned */
if (px->qual == 'l')
px->v.ll = va_arg(*pap, long);
else if (px->qual == 'L')
px->v.ll = va_arg(*pap, long long);
else
px->v.ll = va_arg(*pap, int);
if (px->qual == 'h')
px->v.ll = (unsigned short) px->v.ll;
else if (px->qual == '\0')
px->v.ll = (unsigned int) px->v.ll;
if (px->flags & _FNO) { /* indicate base with prefix */
ac[px->n0++] = '0';
if (code == 'x' || code == 'X')
ac[px->n0++] = code;
}
px->s = &ac[px->n0];
miya_Litob(px, code);
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G': /* convert floating */
px->v.ld = px->qual == 'L' ?
va_arg(*pap, ldouble) : va_arg(*pap, double);
if (LDSIGN(px->v.ld))
ac[px->n0++] = '-';
else if (px->flags & _FPL)
ac[px->n0++] = '+';
else if (px->flags & _FSP)
ac[px->n0++] = ' ';
px->s = &ac[px->n0];
miya_Ldtob(px, code);
break;
case 'n': /* return output count */
if (px->qual == 'h')
*va_arg(*pap, short *) = (short)(px->nchar);
else if (px->qual == 'l')
*va_arg(*pap, long *) = px->nchar;
else if (px->qual == 'L')
*va_arg(*pap, long long *) = px->nchar;
else
*va_arg(*pap, int *) = px->nchar;
break;
case 'p': /* convert a pointer, hex long version */
px->v.ll = (long) va_arg(*pap, void *);
px->s = &ac[px->n0];
miya_Litob(px, 'x');
break;
case 's': /* convert a string */
px->s = va_arg(*pap, char *);
px->n1 = strlen(px->s);
if (0 <= px->prec && px->prec < px->n1)
px->n1 = px->prec;
break;
case '%': /* put a '%' */
ac[px->n0++] = '%';
break;
default: /* undefined specifier, print it out */
ac[px->n0++] = code;
break;
}
}
/*****************************************************************/
/* miya_Litob function */
/* IEEE 754 properties */
#define _DFRAC ((1<<_DOFF)-1)
#define _DMASK (0x7fff&~_DFRAC)
#define _DMAX ((1<<(15-_DOFF))-1)
#define _DNAN (0x8000|_DMAX<<_DOFF|1<<(_DOFF-1))
#define _DSIGN 0x8000
#define DSIGN(x) (((unsigned short *)&(x))[_D0] & _DSIGN)
#define HUGE_EXP (int)(_DMAX * 900L / 1000)
#define HUGE_RAD 3.14e30
#define SAFE_EXP (_DMAX>>1)
/* word offsets within double */
#if _D0==3
#define _D1 2 /* little-endian order */
#define _D2 1
#define _D3 0
#else
#define _D1 1 /* big-endian order */
#define _D2 2
#define _D3 3
#endif
/* return values for _D functions */
#define FINITE -1
#define INF 1
#define _NAN 2
static char ldigs[] = "0123456789abcdef";
static char udigs[] = "0123456789ABCDEF";
static void miya_Litob(_Pft *px, char code)
{ /* convert unsigned long to text */
char ac[24]; /* safe for 64-bit integers */
char *digs = code == 'X' ? udigs : ldigs;
int base = code == 'o' ? 8 : code != 'x' && code != 'X' ? 10 : 16;
int i = sizeof(ac);
unsigned long long ullval = px->v.ll;
if ((code == 'd' || code == 'i') && px->v.ll < 0)
ullval = -ullval; /* safe against overflow */
if (ullval || px->prec)
ac[--i] = digs[ullval % base];
px->v.ll = ullval / base;
while (0 < px->v.ll && 0 < i) { /* convert digits */
miya_lldiv_t qr = miya_lldiv(px->v.ll, (long long) base);
px->v.ll = qr.quot;
ac[--i] = digs[qr.rem];
}
px->n1 = sizeof(ac) - i;
(void)my_memcpy(px->s, &ac[i], px->n1);
if (px->n1 < px->prec)
px->nz0 = px->prec - px->n1;
if (px->prec < 0 && (px->flags & (_FMI | _FZE)) == _FZE
&& 0 < (i = px->width - px->n0 - px->nz0 - px->n1))
px->nz0 += i;
}
/*************************************************/
/* miya_Ldtob function */
#include "float.h"
/* macros */
#define NDIG 8
/* static data */
static const ldouble pows[] = {
1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L,
#if 0x100 < _LBIAS /* assume IEEE 754 8- or 10-byte */
1e64L, 1e128L, 1e256L,
#if _DLONG /* assume IEEE 754 10-byte */
1e512L, 1e1024L, 1e2048L, 1e4096L,
#endif
#endif
};
static short _Ldunscale(short *, ldouble *);
static void _Genld(_Pft *, char, char *, short, short);
static void miya_Ldtob(_Pft *px, char code)
{ /* convert long double to text */
char ac[32];
char *p = ac;
ldouble ldval = px->v.ld;
short errx, nsig, xexp;
if (px->prec < 0)
px->prec = 6;
else if (px->prec == 0 && (code == 'g' || code == 'G'))
px->prec = 1;
if (0 < (errx = _Ldunscale(&xexp, &px->v.ld))) {
/* x == Nan, x == INF */
(void)my_memcpy(px->s, errx == _NAN ? "NaN" : "Inf", px->n1 = 3);
return;
} else if (0 == errx) /*x == 0 */
nsig = 0, xexp = 0;
else { /* 0 < |x|, convert it */
{ /* scale ldval to ~~10^(NDIG/2) */
int i, n;
if (ldval < 0.0)
ldval = -ldval;
if ((xexp = (short)(xexp * 30103L / 100000L - NDIG/2)) < 0) {
/* scale up */
n = (-xexp + (NDIG/2-1)) & ~(NDIG/2-1), xexp = (short)(-n);
for (i = 0; 0 < n; n >>= 1, ++i)
if (n & 1)
ldval *= pows[i];
} else if (0 < xexp) { /* scale down */
ldouble factor = 1.0;
xexp &= ~(NDIG/2-1);
for (n = xexp, i = 0; 0 < n; n >>= 1, ++i)
if (n & 1)
factor *= pows[i];
ldval /= factor;
}
}
{ /* convert significant digits */
int gen = px->prec +
(code == 'f' ? xexp + 2 + NDIG : 2 + NDIG / 2);
if (LDBL_DIG + NDIG / 2 < gen)
gen = LDBL_DIG + NDIG / 2;
for ( *p++ = '0' ; 0 < gen && 0.0 < ldval; p += NDIG) {
/* convert NDIG at a time */
int j;
long lo = (long) ldval;
if (0 < (gen -= NDIG))
ldval = (ldval - (ldouble) lo) * 1e8L;
for (p += NDIG, j = NDIG; 0 < lo && 0 <= --j; ) {
/* convert NDIG digits */
miya_ldiv_t qr;
qr = miya_ldiv(lo, 10);
*--p = (char)(qr.rem + '0'), lo = qr.quot;
}
while (0 <= --j)
*--p = '0';
}
gen = p - &ac[1];
for (p = &ac[1], xexp += NDIG - 1; *p == '0'; ++p)
--gen, --xexp; /* correct xexp */
/* miya
char code
int prec
short nsig, xexp;
*/
nsig = (short)(px->prec + (code == 'f' ? xexp + 1 :
code == 'e' || code == 'E' ? 1 : 0));
if (gen < nsig)
nsig = (short)gen;
if (0 < nsig) { /* round and strip trailing zeros */
/* const char drop; */
char drop;
int n;
drop = (char)(nsig < gen && '5' <= p[nsig] ? '9' : '0');
for (n = nsig; p[--n] == drop; )
--nsig;
if ( drop == '9') {
p[n] = *(&(p[n])+1);
// ++p[n];
}
if (n < 0)
--p, ++nsig, ++xexp;
}
}
}
_Genld(px, code, p, nsig, xexp);
}
#if _DLONG /* 10-byte IEEE format */
#define _LMASK 0x7fff
#define _LMAX 0x7fff
#define _LSIGN 0x8000
#if _D0==3 /* little-endian order */
#define _L0 4
#define _L1 3
#define _L2 2
#define _L3 1
#define _L4 0
#else
#define _L0 0
#define _L1 1
#define _L2 2
#define _L3 3
#define _L4 4
#endif
static short dnorm(unsigned short *ps)
{ /* normalize long double fraction */
short xchar;
for (xchar = 0; ps[_L1] == 0; xchar -= 16) { /* shift left by 16 */
ps[_L1] = ps[_L2], ps[_L2] = ps[_L3];
ps[_L3] = ps[_L4], ps[_L4] = 0;
}
for (; ps[_L1] < 1U<<_LOFF; --xchar) { /* shift left by 1 */
ps[_L1] = ps[_L1] << 1 | ps[_L2] >> 15;
ps[_L2] = ps[_L2] << 1 | ps[_L3] >> 15;
ps[_L3] = ps[_L3] << 1 | ps[_L4] >> 15;
ps[_L4] <<= 1;
}
return (xchar);
}
static short _Ldunscale(short *pex, ldouble *px)
{ /* separate *px to |frac| < 1/2 and 2^*pex */
unsigned short *ps = (unsigned short *) px;
short xchar = ps[_L0] & _LMAX;
if (xchar == _LMAX) { /* NaN or INF */
*pex = 0;
return (ps[_L1] & 0x7fff || ps[_L2] || ps[_L3] || ps[_L4] ?
_NAN : INF);
} else if (ps[_L1] == 0 && ps[_L2] == 0 && ps[_L3] == 0 && ps[_L4] == 0) {
/* zero */
*pex = 0;
return (0);
} else { /* finite, reduce to [1/2, 1) */
xchar += dnorm(ps);
ps[_L0] = ps[_L0] & _LSIGN | _LBIAS;
*pex = xchar - _LBIAS;
return (FINITE);
}
}
#else /* long double same as double */
/*
static short _Dnorm(unsigned short *ps)
{
short xchar;
unsigned short sign = ps[_D0] & _DSIGN;
xchar = 0;
if ((ps[_D0] &= _DFRAC) != 0 || ps[_D1] || ps[_D2] || ps[_D3]) {
for (; ps[_D0] == 0; xchar -= 16) {
ps[_D0] = ps[_D1], ps[_D1] = ps[_D2];
ps[_D2] = ps[_D3], ps[_D3] = 0;
}
for (; ps[_D0] < 1<<_DOFF; --xchar) {
ps[_D0] = ps[_D0] << 1 | ps[_D1] >> 15;
ps[_D1] = ps[_D1] << 1 | ps[_D2] >> 15;
ps[_D2] = ps[_D2] << 1 | ps[_D3] >> 15;
ps[_D3] <<= 1;
}
for (; 1<<_DOFF+1 <= ps[_D0]; ++xchar) {
ps[_D3] = ps[_D3] >> 1 | ps[_D2] << 15;
ps[_D2] = ps[_D2] >> 1 | ps[_D1] << 15;
ps[_D1] = ps[_D1] >> 1 | ps[_D0] << 15;
ps[_D0] >>= 1;
}
ps[_D0] &= _DFRAC;
}
ps[_D0] |= sign;
return (xchar);
}
*/
static short _Ldunscale(short *pex, ldouble *px)
{ /* separate *px to |frac| < 1/2 and 2^*pex */
unsigned short *ps = (unsigned short *) px;
short xchar = (short)((ps[_D0] & _DMASK) >> _DOFF);
if (xchar == _DMAX) { /* NaN or INF */
*pex = 0;
return (short)(ps[_D0] & _DFRAC || ps[_D1] || ps[_D2] || ps[_D3] ?
_NAN : INF);
} else if (0 < xchar /* || (xchar = _Dnorm(ps)) != 0 */) {
/* finite, reduce to [1/2, 1) */
ps[_D0] = (short)(ps[_D0] & ~_DMASK | _DBIAS << _DOFF);
#if _LONG_DOUBLE
*pex = (short)(xchar - _DBIAS);
#else
*pex = (short)(xchar - _DBIAS + 1); /* for SGI */
#endif
return (FINITE);
} else if (xchar < 0) { /* error! */
return (_NAN);
} else { /* zero */
*pex = 0;
return (0);
}
}
#endif
static void _Genld(_Pft *px, char code, char *p, short nsig, short xexp)
{ /* generate long double text */
const char point = '.';
if (nsig <= 0)
nsig = 1, p = "0";
if (code == 'f' || (code == 'g' || code == 'G') &&
-4 <= xexp && xexp < px->prec) { /* 'f' format */
++xexp; /* change to leading digit count */
if (code != 'f') { /* fixup for 'g' */
if (!(px->flags & _FNO) && nsig < px->prec)
px->prec = nsig;
if ((px->prec -= xexp) < 0)
px->prec = 0;
}
if (xexp <= 0) { /* digits only to right of point */
px->s[px->n1++] = '0';
if (0 < px->prec || px->flags & _FNO)
px->s[px->n1++] = point;
if (px->prec < -xexp)
xexp = (short)(-px->prec);
px->nz1 = -xexp;
px->prec += xexp;
if (px->prec < nsig)
nsig = (short)(px->prec);
(void)my_memcpy(&px->s[px->n1], p, px->n2 = nsig);
px->nz2 = px->prec - nsig;
} else if (nsig < xexp) { /* zeros before point */
(void)my_memcpy(&px->s[px->n1], p, nsig);
px->n1 += nsig;
px->nz1 = xexp - nsig;
if (0 < px->prec || px->flags & _FNO)
px->s[px->n1] = point, ++px->n2;
px->nz2 = px->prec;
} else { /* enough digits before point */
(void)my_memcpy(&px->s[px->n1], p, xexp);
px->n1 += xexp;
nsig -= xexp;
if (0 < px->prec || px->flags & _FNO)
px->s[px->n1++] = point;
if (px->prec < nsig)
nsig = (short)(px->prec);
(void)my_memcpy(&px->s[px->n1], p + xexp, nsig);
px->n1 += nsig;
px->nz1 = px->prec - nsig;
}
} else { /* 'e' format */
if (code == 'g' || code == 'G') { /* fixup for 'g' */
if (nsig < px->prec)
px->prec = nsig;
if (--px->prec < 0)
px->prec = 0;
code = (char)(code == 'g' ? 'e' : 'E');
}
px->s[px->n1++] = *p++;
if (0 < px->prec || px->flags & _FNO)
px->s[px->n1++] = point;
if (0 < px->prec) { /* put fraction digits */
if (px->prec < --nsig)
nsig = (short)(px->prec);
(void)my_memcpy(&px->s[px->n1], p, nsig);
px->n1 += nsig;
px->nz1 = px->prec - nsig;
}
p = &px->s[px->n1]; /* put exponent */
*p++ = code;
if (0 <= xexp)
*p++ = '+';
else { /* negative exponent */
*p++ = '-';
xexp = (short)(-xexp);
}
if (100 <= xexp) { /* put oversize exponent */
if (1000 <= xexp)
*p = (char)(xexp / 1000 + '0'), p++, xexp %= 1000;
*p = (char)(xexp / 100 + '0'), p++, xexp %= 100;
}
*p = (char)(xexp / 10 + '0'),p++, xexp %= 10;
*p = (char)(xexp + '0'); p++;
px->n2 = p - &px->s[px->n1];
}
if ((px->flags & (_FMI | _FZE)) == _FZE) { /* pad with leading zeros */
int n = px->n0 + px->n1 + px->nz1 + px->n2 + px->nz2;
if (n < px->width)
px->nz0 = px->width - n;
}
}