1220 lines
35 KiB
C
1220 lines
35 KiB
C
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <float.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include "LoggerInterface.h"
|
|
|
|
#define FETCH_BYTE(p) (*(unsigned char*)(p))
|
|
/* Max number conversion buffer length: a long in base 2, plus NUL byte. */
|
|
#define MAXNBUF (sizeof(long) * 8 + 1)
|
|
|
|
static unsigned char *ksprintn(unsigned char *buf, unsigned long v, unsigned char base,
|
|
int width, unsigned char *lp);
|
|
|
|
static unsigned char mkhex(unsigned char ch);
|
|
|
|
#define ARCH_HAVE_FPU 1
|
|
|
|
#if ARCH_HAVE_FPU
|
|
|
|
static int cvt_f(double number, int prec, int sharpflag, unsigned char *negp,
|
|
unsigned char fmtch, unsigned char *startp, unsigned char *endp);
|
|
|
|
#endif
|
|
|
|
int stream_logger_vprintf(tLoggerInterface *logger, char const *fmt, va_list ap) {
|
|
//#define PUTC(c) { putchar(stream,(unsigned char)(c)); ++retval; }
|
|
#define PUTC(c) { char p = c; (logger)->logging((logger)->env, NULL, 0, 0, &p, 1, false); ++retval; }
|
|
|
|
|
|
unsigned char nbuf[MAXNBUF], padding, *q;
|
|
const unsigned char *s;
|
|
unsigned char c, base, lflag, ladjust, sharpflag, neg, dot, size;
|
|
int16_t n, width, dwidth, retval, uppercase, extrazeros, sign;
|
|
unsigned long ul;
|
|
|
|
if (!logger)
|
|
return 0;
|
|
if (!fmt)
|
|
fmt = "(null)\n";
|
|
|
|
retval = 0;
|
|
for (;;) {
|
|
while ((c = FETCH_BYTE (fmt++)) != '%') {
|
|
if (!c)
|
|
return retval;
|
|
PUTC (c);
|
|
}
|
|
padding = ' ';
|
|
width = 0;
|
|
extrazeros = 0;
|
|
lflag = 0;
|
|
ladjust = 0;
|
|
sharpflag = 0;
|
|
neg = 0;
|
|
sign = 0;
|
|
dot = 0;
|
|
uppercase = 0;
|
|
dwidth = -1;
|
|
reswitch:
|
|
switch (c = FETCH_BYTE (fmt++)) {
|
|
case '.':
|
|
dot = 1;
|
|
padding = ' ';
|
|
dwidth = 0;
|
|
goto reswitch;
|
|
|
|
case '#':
|
|
sharpflag = 1;
|
|
goto reswitch;
|
|
|
|
case '+':
|
|
sign = -1;
|
|
goto reswitch;
|
|
|
|
case '-':
|
|
ladjust = 1;
|
|
goto reswitch;
|
|
|
|
case '%': PUTC (c);
|
|
break;
|
|
|
|
case '*':
|
|
if (!dot) {
|
|
width = va_arg (ap, int);
|
|
if (width < 0) {
|
|
ladjust = !ladjust;
|
|
width = -width;
|
|
}
|
|
} else {
|
|
dwidth = va_arg (ap, int);
|
|
}
|
|
goto reswitch;
|
|
|
|
case '0':
|
|
if (!dot) {
|
|
padding = '0';
|
|
goto reswitch;
|
|
}
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
for (n = 0;; ++fmt) {
|
|
n = n * 10 + c - '0';
|
|
c = FETCH_BYTE (fmt);
|
|
if (c < '0' || c > '9')
|
|
break;
|
|
}
|
|
if (dot)
|
|
dwidth = n;
|
|
else
|
|
width = n;
|
|
goto reswitch;
|
|
|
|
case 'b':
|
|
ul = va_arg (ap, int);
|
|
s = va_arg (ap, const unsigned char*);
|
|
q = ksprintn(nbuf, ul, *s++, -1, 0);
|
|
while (*q) PUTC (*q--);
|
|
|
|
if (!ul)
|
|
break;
|
|
size = 0;
|
|
while (*s) {
|
|
n = *s++;
|
|
if ((char) (ul >> (n - 1)) & 1) {
|
|
PUTC (size ? ',' : '<');
|
|
for (; (n = *s) > ' '; ++s) PUTC (n);
|
|
size = 1;
|
|
} else
|
|
while (*s > ' ')
|
|
++s;
|
|
}
|
|
if (size) PUTC ('>');
|
|
break;
|
|
|
|
case 'c':
|
|
if (!ladjust && width > 0)
|
|
while (width--) PUTC (' ');
|
|
|
|
PUTC (va_arg(ap, int));
|
|
|
|
if (ladjust && width > 0)
|
|
while (width--) PUTC (' ');
|
|
break;
|
|
|
|
case 'D':
|
|
s = va_arg (ap, const unsigned char*);
|
|
if (!width)
|
|
width = 16;
|
|
if (sharpflag)
|
|
padding = ':';
|
|
while (width--) {
|
|
c = *s++;
|
|
PUTC (mkhex(c >> 4));
|
|
PUTC (mkhex(c));
|
|
if (width) PUTC (padding);
|
|
}
|
|
break;
|
|
|
|
case 'd':
|
|
ul = lflag ? va_arg (ap, long) : va_arg (ap, int);
|
|
if (!sign) sign = 1;
|
|
base = 10;
|
|
goto number;
|
|
|
|
case 'l':
|
|
lflag = 1;
|
|
goto reswitch;
|
|
|
|
case 'o':
|
|
ul = lflag ? va_arg (ap, unsigned long) :
|
|
va_arg (ap, unsigned int);
|
|
base = 8;
|
|
goto nosign;
|
|
|
|
case 'p':
|
|
ul = (size_t) va_arg (ap, void*);
|
|
if (!ul) {
|
|
s = (const unsigned char *) "(nil)";
|
|
goto const_string;
|
|
}
|
|
base = 16;
|
|
sharpflag = (width == 0);
|
|
goto nosign;
|
|
|
|
case 'n':
|
|
ul = lflag ? va_arg (ap, unsigned long) :
|
|
sign ? (unsigned long) va_arg (ap, int) :
|
|
va_arg (ap, unsigned int);
|
|
base = 10;
|
|
goto number;
|
|
|
|
case 'S':
|
|
#if __AVR__
|
|
s = va_arg (ap, const unsigned char*);
|
|
if (! s)
|
|
s = (const unsigned char*) "(null)";
|
|
const_string:
|
|
n = 0;
|
|
if (! dot)
|
|
while (FETCH_BYTE (s+n))
|
|
++n;
|
|
else
|
|
while (n<dwidth && FETCH_BYTE (s+n))
|
|
++n;
|
|
|
|
width -= n;
|
|
|
|
if (! ladjust && width > 0)
|
|
while (width--)
|
|
PUTC (' ');
|
|
while (n--)
|
|
PUTC (FETCH_BYTE (s++));
|
|
if (ladjust && width > 0)
|
|
while (width--)
|
|
PUTC (' ');
|
|
break;
|
|
#endif /* LY: AVR, and no break here! */
|
|
|
|
case 's':
|
|
s = va_arg (ap, unsigned char*);
|
|
#ifdef __AVR__
|
|
if (! s) {
|
|
s = (const unsigned char*) "(null)";
|
|
goto const_string;
|
|
}
|
|
#else
|
|
if (!s)
|
|
s = (const unsigned char *) "(null)";
|
|
const_string:
|
|
#endif
|
|
if (!dot)
|
|
n = strlen(s);
|
|
else
|
|
for (n = 0; n < dwidth && s[n]; n++)
|
|
continue;
|
|
|
|
width -= n;
|
|
|
|
if (!ladjust && width > 0)
|
|
while (width--) PUTC (' ');
|
|
while (n--) PUTC (*s++);
|
|
if (ladjust && width > 0)
|
|
while (width--) PUTC (' ');
|
|
break;
|
|
|
|
case 'r':
|
|
/* Saturated counters. */
|
|
base = 10;
|
|
if (lflag) {
|
|
ul = va_arg (ap, unsigned long);
|
|
if (ul == -1) {
|
|
cnt_unknown:
|
|
if (ladjust) PUTC ('-');
|
|
while (--width > 0) PUTC (' ');
|
|
if (!ladjust) PUTC ('-');
|
|
break;
|
|
}
|
|
if (ul >= -2) {
|
|
ul = -3;
|
|
neg = '>';
|
|
goto nosign;
|
|
}
|
|
} else {
|
|
ul = va_arg (ap, unsigned int);
|
|
if (ul == (unsigned short) -1)
|
|
goto cnt_unknown;
|
|
if (ul >= (unsigned short) -2) {
|
|
ul = (unsigned short) -3;
|
|
neg = '>';
|
|
goto nosign;
|
|
}
|
|
}
|
|
goto nosign;
|
|
|
|
case 'u':
|
|
ul = lflag ? va_arg (ap, unsigned long) :
|
|
va_arg (ap, unsigned int);
|
|
base = 10;
|
|
goto nosign;
|
|
|
|
case 'x':
|
|
case 'X':
|
|
ul = lflag ? va_arg (ap, unsigned long) :
|
|
va_arg (ap, unsigned int);
|
|
base = 16;
|
|
uppercase = (c == 'X');
|
|
goto nosign;
|
|
case 'z':
|
|
case 'Z':
|
|
ul = lflag ? va_arg (ap, unsigned long) :
|
|
sign ? (unsigned long) va_arg (ap, int) :
|
|
va_arg (ap, unsigned int);
|
|
base = 16;
|
|
uppercase = (c == 'Z');
|
|
goto number;
|
|
|
|
nosign:
|
|
sign = 0;
|
|
number:
|
|
if (sign && ((long) ul != 0L)) {
|
|
if ((long) ul < 0L) {
|
|
neg = '-';
|
|
ul = -(long) ul;
|
|
} else if (sign < 0)
|
|
neg = '+';
|
|
}
|
|
if (dwidth >= (int) sizeof(nbuf)) {
|
|
extrazeros = dwidth - sizeof(nbuf) + 1;
|
|
dwidth = sizeof(nbuf) - 1;
|
|
}
|
|
s = ksprintn(nbuf, ul, base, dwidth, &size);
|
|
if (sharpflag && ul != 0) {
|
|
if (base == 8)
|
|
size++;
|
|
else if (base == 16)
|
|
size += 2;
|
|
}
|
|
if (neg)
|
|
size++;
|
|
|
|
if (!ladjust && width && padding == ' ' &&
|
|
(width -= size) > 0)
|
|
do {
|
|
PUTC (' ');
|
|
} while (--width > 0);
|
|
|
|
if (neg) PUTC (neg);
|
|
|
|
if (sharpflag && ul != 0) {
|
|
if (base == 8) {
|
|
PUTC ('0');
|
|
} else if (base == 16) {
|
|
PUTC ('0');
|
|
PUTC (uppercase ? 'X' : 'x');
|
|
}
|
|
}
|
|
|
|
if (extrazeros)
|
|
do {
|
|
PUTC ('0');
|
|
} while (--extrazeros > 0);
|
|
|
|
if (!ladjust && width && (width -= size) > 0)
|
|
do {
|
|
PUTC (padding);
|
|
} while (--width > 0);
|
|
|
|
for (; *s; --s) {
|
|
if (uppercase && *s >= 'a' && *s <= 'z') {
|
|
PUTC (*s + 'A' - 'a');
|
|
} else {
|
|
PUTC (*s);
|
|
}
|
|
}
|
|
|
|
if (ladjust && width && (width -= size) > 0)
|
|
do {
|
|
PUTC (' ');
|
|
} while (--width > 0);
|
|
break;
|
|
#if ARCH_HAVE_FPU
|
|
case 'e':
|
|
case 'E':
|
|
case 'f':
|
|
case 'F':
|
|
case 'g':
|
|
case 'G': {
|
|
double d = va_arg (ap, double);
|
|
/*
|
|
* don't do unrealistic precision; just pad it with
|
|
* zeroes later, so buffer size stays rational.
|
|
*/
|
|
if (dwidth > DBL_DIG) {
|
|
if ((c != 'g' && c != 'G') || sharpflag)
|
|
extrazeros = dwidth - DBL_DIG;
|
|
dwidth = DBL_DIG;
|
|
} else if (dwidth == -1) {
|
|
dwidth = (lflag ? DBL_DIG : FLT_DIG);
|
|
}
|
|
/*
|
|
* softsign avoids negative 0 if d is < 0 and
|
|
* no significant digits will be shown
|
|
*/
|
|
if (d < 0) {
|
|
neg = 1;
|
|
d = -d;
|
|
}
|
|
/*
|
|
* cvt may have to round up past the "start" of the
|
|
* buffer, i.e. ``intf("%.2f", (double)9.999);'';
|
|
* if the first char isn't NULL, it did.
|
|
*/
|
|
if (isnan (d) || isinf (d)) {
|
|
strcpy(nbuf, isnan (d) ? "NaN" : "Inf");
|
|
size = 3;
|
|
extrazeros = 0;
|
|
s = nbuf;
|
|
} else {
|
|
*nbuf = 0;
|
|
size = cvt_f(d, dwidth, sharpflag, &neg, c,
|
|
nbuf, nbuf + sizeof(nbuf) - 1);
|
|
if (*nbuf) {
|
|
s = nbuf;
|
|
nbuf[size] = 0;
|
|
} else {
|
|
s = nbuf + 1;
|
|
nbuf[size + 1] = 0;
|
|
}
|
|
}
|
|
if (neg)
|
|
size++;
|
|
if (!ladjust && width && padding == ' ' &&
|
|
(width -= size) > 0)
|
|
do {
|
|
PUTC (' ');
|
|
} while (--width > 0);
|
|
|
|
if (neg) PUTC ('-');
|
|
|
|
if (!ladjust && width && (width -= size) > 0)
|
|
do {
|
|
PUTC (padding);
|
|
} while (--width > 0);
|
|
|
|
for (; *s; ++s) {
|
|
if (extrazeros && (*s == 'e' || *s == 'E'))
|
|
do {
|
|
PUTC ('0');
|
|
} while (--extrazeros > 0);
|
|
|
|
PUTC (*s);
|
|
}
|
|
if (extrazeros)
|
|
do {
|
|
PUTC ('0');
|
|
} while (--extrazeros > 0);
|
|
|
|
if (ladjust && width && (width -= size) > 0)
|
|
do {
|
|
PUTC (' ');
|
|
} while (--width > 0);
|
|
break;
|
|
}
|
|
#endif
|
|
default: PUTC ('%');
|
|
if (lflag) PUTC ('l');
|
|
PUTC (c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse
|
|
* order; return an optional length and a pointer to the last character
|
|
* written in the buffer (i.e., the first character of the string).
|
|
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
|
|
*/
|
|
static unsigned char *
|
|
ksprintn(unsigned char *nbuf, unsigned long ul, unsigned char base, int width,
|
|
unsigned char *lenp) {
|
|
unsigned char *p;
|
|
|
|
p = nbuf;
|
|
*p = 0;
|
|
for (;;) {
|
|
*++p = mkhex(ul % base);
|
|
ul /= base;
|
|
if (--width > 0)
|
|
continue;
|
|
if (!ul)
|
|
break;
|
|
}
|
|
if (lenp)
|
|
*lenp = p - nbuf;
|
|
return (p);
|
|
}
|
|
|
|
static unsigned char
|
|
mkhex(unsigned char ch) {
|
|
ch &= 15;
|
|
if (ch > 9)
|
|
return ch + 'a' - 10;
|
|
return ch + '0';
|
|
}
|
|
|
|
#if ARCH_HAVE_FPU
|
|
|
|
static unsigned char *
|
|
cvtround_f(double fract, int *exp, unsigned char *start, unsigned char *end, unsigned char ch,
|
|
unsigned char *negp) {
|
|
double tmp;
|
|
|
|
if (fract) {
|
|
modf(fract * 10, &tmp);
|
|
} else {
|
|
tmp = ch - '0';
|
|
}
|
|
if (tmp > 4) {
|
|
for (;; --end) {
|
|
if (*end == '.') {
|
|
--end;
|
|
}
|
|
if (++*end <= '9') {
|
|
break;
|
|
}
|
|
*end = '0';
|
|
if (end == start) {
|
|
if (exp) { /* e/E; increment exponent */
|
|
*end = '1';
|
|
++*exp;
|
|
} else { /* f; add extra digit */
|
|
*--end = '1';
|
|
--start;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else if (*negp) {
|
|
/*
|
|
* ``"%.3f", (double)-0.0004'' gives you a negative 0.
|
|
*/
|
|
for (;; --end) {
|
|
if (*end == '.') {
|
|
--end;
|
|
}
|
|
if (*end != '0') {
|
|
break;
|
|
}
|
|
if (end == start) {
|
|
*negp = 0;
|
|
}
|
|
}
|
|
}
|
|
return start;
|
|
}
|
|
|
|
static unsigned char *
|
|
exponent(unsigned char *p, int exp, unsigned char fmtch) {
|
|
unsigned char expbuf[8], *t;
|
|
|
|
*p++ = fmtch;
|
|
if (exp < 0) {
|
|
exp = -exp;
|
|
*p++ = '-';
|
|
} else {
|
|
*p++ = '+';
|
|
}
|
|
t = expbuf + sizeof(expbuf);
|
|
if (exp > 9) {
|
|
do {
|
|
*--t = exp % 10 + '0';
|
|
} while ((exp /= 10) > 9);
|
|
*--t = exp + '0';
|
|
for (; t < expbuf + sizeof(expbuf); *p++ = *t++)
|
|
continue;
|
|
} else {
|
|
*p++ = '0';
|
|
*p++ = exp + '0';
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static int
|
|
cvt_f(double number, int prec, int sharpflag, unsigned char *negp, unsigned char fmtch,
|
|
unsigned char *startp, unsigned char *endp) {
|
|
unsigned char *p, *t;
|
|
double fract;
|
|
int dotrim, expcnt, gformat;
|
|
double integer, tmp;
|
|
|
|
expcnt = 0;
|
|
dotrim = expcnt = gformat = 0;
|
|
fract = modf(number, &integer);
|
|
|
|
/*
|
|
* get an extra slot for rounding
|
|
*/
|
|
t = ++startp;
|
|
|
|
/*
|
|
* get integer portion of number; put into the end of the buffer; the
|
|
* .01 is added for modf (356.0 / 10, &integer) returning .59999999...
|
|
*/
|
|
for (p = endp - 1; integer; ++expcnt) {
|
|
tmp = modf(integer / 10, &integer);
|
|
*p-- = (int) ((tmp + .01) * 10) + '0';
|
|
}
|
|
switch (fmtch) {
|
|
case 'f':
|
|
/* reverse integer into beginning of buffer */
|
|
if (expcnt) {
|
|
for (; ++p < endp; *t++ = *p);
|
|
} else {
|
|
*t++ = '0';
|
|
}
|
|
|
|
/*
|
|
* if precision required or alternate flag set, add in a
|
|
* decimal point.
|
|
*/
|
|
if (prec || sharpflag) {
|
|
*t++ = '.';
|
|
}
|
|
|
|
/*
|
|
* if requires more precision and some fraction left
|
|
*/
|
|
if (fract) {
|
|
if (prec) {
|
|
do {
|
|
fract = modf(fract * 10, &tmp);
|
|
*t++ = (int) tmp + '0';
|
|
} while (--prec && fract);
|
|
}
|
|
if (fract) {
|
|
startp = cvtround_f(fract, 0, startp,
|
|
t - 1, '0', negp);
|
|
}
|
|
}
|
|
for (; prec--; *t++ = '0');
|
|
break;
|
|
case 'e':
|
|
case 'E':
|
|
eformat:
|
|
if (expcnt) {
|
|
*t++ = *++p;
|
|
if (prec || sharpflag) {
|
|
*t++ = '.';
|
|
}
|
|
|
|
/*
|
|
* if requires more precision and some integer left
|
|
*/
|
|
for (; prec && ++p < endp; --prec) {
|
|
*t++ = *p;
|
|
}
|
|
|
|
/*
|
|
* if done precision and more of the integer component,
|
|
* round using it; adjust fract so we don't re-round
|
|
* later.
|
|
*/
|
|
if (!prec && ++p < endp) {
|
|
fract = 0;
|
|
startp = cvtround_f(0, &expcnt, startp,
|
|
t - 1, *p, negp);
|
|
}
|
|
/*
|
|
* adjust expcnt for digit in front of decimal
|
|
*/
|
|
--expcnt;
|
|
}
|
|
/*
|
|
* until first fractional digit, decrement exponent
|
|
*/
|
|
else if (fract) {
|
|
/*
|
|
* adjust expcnt for digit in front of decimal
|
|
*/
|
|
for (expcnt = -1;; --expcnt) {
|
|
fract = modf(fract * 10, &tmp);
|
|
if (tmp) {
|
|
break;
|
|
}
|
|
}
|
|
*t++ = (int) tmp + '0';
|
|
if (prec || sharpflag) {
|
|
*t++ = '.';
|
|
}
|
|
} else {
|
|
*t++ = '0';
|
|
if (prec || sharpflag) {
|
|
*t++ = '.';
|
|
}
|
|
}
|
|
/*
|
|
* if requires more precision and some fraction left
|
|
*/
|
|
if (fract) {
|
|
if (prec) {
|
|
do {
|
|
fract = modf(fract * 10, &tmp);
|
|
*t++ = (int) tmp + '0';
|
|
} while (--prec && fract);
|
|
}
|
|
if (fract) {
|
|
startp = cvtround_f(fract, &expcnt, startp,
|
|
t - 1, '0', negp);
|
|
}
|
|
}
|
|
/*
|
|
* if requires more precision
|
|
*/
|
|
for (; prec--; *t++ = '0');
|
|
|
|
/*
|
|
* unless alternate flag, trim any g/G format trailing 0's
|
|
*/
|
|
if (gformat && !sharpflag) {
|
|
while (t > startp && *--t == '0');
|
|
if (*t == '.') {
|
|
--t;
|
|
}
|
|
++t;
|
|
}
|
|
t = exponent(t, expcnt, fmtch);
|
|
break;
|
|
case 'g':
|
|
case 'G':
|
|
/*
|
|
* a precision of 0 is treated as a precision of 1
|
|
*/
|
|
if (!prec) {
|
|
++prec;
|
|
}
|
|
|
|
/*
|
|
* ``The style used depends on the value converted; style e
|
|
* will be used only if the exponent resulting from the
|
|
* conversion is less than -4 or greater than the precision.''
|
|
* -- ANSI X3J11
|
|
*/
|
|
if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
|
|
/*
|
|
* g/G format counts "significant digits, not digits of
|
|
* precision; for the e/E format, this just causes an
|
|
* off-by-one problem, i.e. g/G considers the digit
|
|
* before the decimal point significant and e/E doesn't
|
|
* count it as precision.
|
|
*/
|
|
--prec;
|
|
fmtch -= 2; /* G->E, g->e */
|
|
gformat = 1;
|
|
goto eformat;
|
|
}
|
|
/*
|
|
* reverse integer into beginning of buffer,
|
|
* note, decrement precision
|
|
*/
|
|
if (expcnt) {
|
|
for (; ++p < endp; *t++ = *p, --prec);
|
|
} else {
|
|
*t++ = '0';
|
|
}
|
|
/*
|
|
* if precision required or alternate flag set, add in a
|
|
* decimal point. If no digits yet, add in leading 0.
|
|
*/
|
|
if (prec || sharpflag) {
|
|
dotrim = 1;
|
|
*t++ = '.';
|
|
} else {
|
|
dotrim = 0;
|
|
}
|
|
/*
|
|
* if requires more precision and some fraction left
|
|
*/
|
|
while (prec && fract) {
|
|
fract = modf(fract * 10, &tmp);
|
|
*t++ = (int) tmp + '0';
|
|
prec--;
|
|
}
|
|
if (fract) {
|
|
startp = cvtround_f(fract, 0, startp, t - 1, '0', negp);
|
|
}
|
|
/*
|
|
* alternate format, adds 0's for precision, else trim 0's
|
|
*/
|
|
if (sharpflag) {
|
|
for (; prec--; *t++ = '0');
|
|
} else if (dotrim) {
|
|
while (t > startp && *--t == '0');
|
|
if (*t != '.') {
|
|
++t;
|
|
}
|
|
}
|
|
}
|
|
return (t - startp);
|
|
}
|
|
|
|
#endif /* ARCH_HAVE_FPU */
|
|
|
|
|
|
void LoggerPrintf(
|
|
tLoggerInterface *logger,
|
|
const char *authorStatic,
|
|
const uint8_t authorLen,
|
|
eLoggerLevel loglevel,
|
|
bool complete,
|
|
const char *fmt,
|
|
...
|
|
) {
|
|
|
|
// va_list args;
|
|
// int err;
|
|
//
|
|
// LoggerCnInfo(logger, "ss", "", 0);
|
|
//
|
|
// va_start (args, fmt);
|
|
// err = stream_logger_vprintf(logger, fmt, args);
|
|
// va_end (args);
|
|
//
|
|
// LoggerInfo(logger, "ss", "", 0);
|
|
|
|
char str[512];
|
|
|
|
int result;
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
result = vsprintf(str, fmt, args);
|
|
va_end(args);
|
|
|
|
logger->logging(logger->env, authorStatic, authorLen, loglevel, str, result, complete);
|
|
}
|
|
|
|
#ifdef TEST
|
|
/*
|
|
* Testing vprintf(3).
|
|
*/
|
|
#undef printf
|
|
#undef fclose
|
|
#undef fflush
|
|
#undef vprintf
|
|
#undef getchar
|
|
#undef putchar
|
|
#undef gets
|
|
#undef puts
|
|
#undef feof
|
|
#define snprintf snprintf_tmp
|
|
#define vsnprintf vsnprintf_tmp
|
|
#include <stdio.h>
|
|
#undef snprintf
|
|
#undef vsnprintf
|
|
|
|
#ifndef UCHAR_MAX
|
|
#define UCHAR_MAX ((unsigned char) -1)
|
|
#endif
|
|
#ifndef USHRT_MAX
|
|
#define USHRT_MAX ((unsigned short) -1)
|
|
#endif
|
|
|
|
#define fputs(s,f) printstring (s)
|
|
#define puts(s) { printstring (s); write (1, "\n", 1); }
|
|
|
|
unsigned write (int fd, const void *buf, unsigned count);
|
|
|
|
static void
|
|
printchar (stream_t *stream, short ch)
|
|
{
|
|
write (1, &ch, 1);
|
|
}
|
|
|
|
static void
|
|
printstring (const char *str)
|
|
{
|
|
write (1, str, strlen (str));
|
|
}
|
|
|
|
int
|
|
printf (const char *fmt, ...)
|
|
{
|
|
static stream_interface_t output_interface = {
|
|
(void (*) (stream_t*, short)) printchar,
|
|
0, 0,
|
|
};
|
|
stream_t output = { &output_interface };
|
|
va_list args;
|
|
int err;
|
|
|
|
va_start (args, fmt);
|
|
err = stream_vprintf (&output, fmt, args);
|
|
va_end (args);
|
|
return err;
|
|
}
|
|
|
|
static void rfg1 (void);
|
|
static void rfg2 (void);
|
|
static void rfg3 (void);
|
|
|
|
static void fmtchk (const char *fmt)
|
|
{
|
|
(void)fputs (fmt, stdout);
|
|
(void)printf (":\t`");
|
|
(void)printf (fmt, 0x12);
|
|
(void)printf ("'\n");
|
|
}
|
|
|
|
static void fmtst1chk (const char *fmt)
|
|
{
|
|
(void)fputs (fmt, stdout);
|
|
(void)printf (":\t`");
|
|
(void)printf (fmt, 4, 0x12);
|
|
(void)printf ("'\n");
|
|
}
|
|
|
|
static void fmtst2chk (const char *fmt)
|
|
{
|
|
(void)fputs (fmt, stdout);
|
|
(void)printf (":\t`");
|
|
(void)printf (fmt, 4, 4, 0x12);
|
|
(void)printf ("'\n");
|
|
}
|
|
|
|
/* This page is covered by the following copyright: */
|
|
|
|
/* (C) Copyright C E Chew
|
|
*
|
|
* Feel free to copy, use and distribute this software provided:
|
|
*
|
|
* 1. you do not pretend that you wrote it
|
|
* 2. you leave this copyright notice intact.
|
|
*/
|
|
|
|
/*
|
|
* Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans.
|
|
*/
|
|
|
|
#define DEC -123
|
|
#define INT 255
|
|
#define UNS (~0)
|
|
|
|
/* Formatted Output Test
|
|
*
|
|
* This exercises the output formatting code.
|
|
*/
|
|
|
|
static void fp_test (void)
|
|
{
|
|
int i, j, k, l;
|
|
char buf[7];
|
|
char *prefix = buf;
|
|
char tp[20];
|
|
|
|
puts ("\nFormatted output test");
|
|
printf ("prefix 6d 6o 6x 6X 6u\n");
|
|
strcpy (prefix, "%");
|
|
for (i = 0; i < 2; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
for (k = 0; k < 2; k++) {
|
|
for (l = 0; l < 2; l++) {
|
|
strcpy (prefix, "%");
|
|
if (i == 0)
|
|
strcat (prefix, "-");
|
|
if (j == 0)
|
|
strcat (prefix, "+");
|
|
if (k == 0)
|
|
strcat (prefix, "#");
|
|
if (l == 0)
|
|
strcat (prefix, "0");
|
|
printf ("%5s |", prefix);
|
|
strcpy (tp, prefix);
|
|
strcat (tp, "6d |");
|
|
printf (tp, DEC);
|
|
strcpy (tp, prefix);
|
|
strcat (tp, "6o |");
|
|
printf (tp, INT);
|
|
strcpy (tp, prefix);
|
|
strcat (tp, "6x |");
|
|
printf (tp, INT);
|
|
strcpy (tp, prefix);
|
|
strcat (tp, "6X |");
|
|
printf (tp, INT);
|
|
strcpy (tp, prefix);
|
|
strcat (tp, "6u |");
|
|
printf (tp, UNS);
|
|
printf ("\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
printf ("%10s\n", (char *)0);
|
|
printf ("%-10s\n", (char *)0);
|
|
}
|
|
|
|
int main ()
|
|
{
|
|
static char shortstr[] = "Hi, Z.";
|
|
static char longstr[] = "Good morning, Doctor Chandra. This is Hal. \
|
|
I am ready for my first lesson today.";
|
|
int result = 0;
|
|
|
|
fmtchk ("%.4x");
|
|
fmtchk ("%04x");
|
|
fmtchk ("%4.4x");
|
|
fmtchk ("%04.4x");
|
|
fmtchk ("%4.3x");
|
|
fmtchk ("%04.3x");
|
|
|
|
fmtst1chk ("%.*x");
|
|
fmtst1chk ("%0*x");
|
|
fmtst2chk ("%*.*x");
|
|
fmtst2chk ("%0*.*x");
|
|
|
|
printf ("binary format:\t\"%b\"\n", 55, "\20\7b7\6b6\5b5\4b4\3b3\2b2\1b1");
|
|
printf ("nil pointer (padded):\t\"%10p\"\n", (void *)0);
|
|
|
|
printf ("decimal negative:\t\"%d\"\n", -2345);
|
|
printf ("octal negative:\t\"%o\"\n", -2345);
|
|
printf ("hex negative:\t\"%x\"\n", -2345);
|
|
printf ("long decimal number:\t\"%ld\"\n", -123456L);
|
|
printf ("long octal negative:\t\"%lo\"\n", -2345L);
|
|
printf ("long unsigned decimal number:\t\"%lu\"\n", -123456L);
|
|
printf ("zero-padded LDN:\t\"%010ld\"\n", -123456L);
|
|
printf ("left-adjusted ZLDN:\t\"%-010ld\"\n", -123456L);
|
|
printf ("space-padded LDN:\t\"%10ld\"\n", -123456L);
|
|
printf ("left-adjusted SLDN:\t\"%-10ld\"\n", -123456L);
|
|
|
|
printf ("zero-padded string:\t\"%010s\"\n", shortstr);
|
|
printf ("left-adjusted Z string:\t\"%-010s\"\n", shortstr);
|
|
printf ("space-padded string:\t\"%10s\"\n", shortstr);
|
|
printf ("left-adjusted S string:\t\"%-10s\"\n", shortstr);
|
|
printf ("null string:\t\"%s\"\n", (char *)0);
|
|
printf ("limited string:\t\"%.22s\"\n", longstr);
|
|
|
|
printf ("e-style >= 1:\t\"%e\"\n", 12.34);
|
|
printf ("e-style >= .1:\t\"%e\"\n", 0.1234);
|
|
printf ("e-style < .1:\t\"%e\"\n", 0.001234);
|
|
printf ("e-style big:\t\"%.60e\"\n", 1e20);
|
|
printf ("e-style == .1:\t\"%e\"\n", 0.1);
|
|
printf ("f-style >= 1:\t\"%f\"\n", 12.34);
|
|
printf ("f-style >= .1:\t\"%f\"\n", 0.1234);
|
|
printf ("f-style < .1:\t\"%f\"\n", 0.001234);
|
|
printf ("g-style >= 1:\t\"%g\"\n", 12.34);
|
|
printf ("g-style >= .1:\t\"%g\"\n", 0.1234);
|
|
printf ("g-style < .1:\t\"%g\"\n", 0.001234);
|
|
printf ("g-style big:\t\"%.60g\"\n", 1e20);
|
|
|
|
printf (" %6.5f\n", .099999999860301614);
|
|
printf (" %6.5f\n", .1);
|
|
printf ("x%5.4fx\n", .5);
|
|
|
|
printf ("%#03x\n", 1);
|
|
|
|
printf ("something really insane: %.10000f\n", 1.0);
|
|
|
|
{
|
|
double d = FLT_MIN;
|
|
int niter = 17;
|
|
|
|
while (niter-- != 0)
|
|
printf ("%.17e\n", d / 2);
|
|
fflush (stdout);
|
|
}
|
|
|
|
printf ("%15.5e\n", 4.9406564584124654e-324);
|
|
|
|
#define FORMAT "|%12.4f|%12.4e|%12.4g|\n"
|
|
printf (FORMAT, 0.0, 0.0, 0.0);
|
|
printf (FORMAT, 1.0, 1.0, 1.0);
|
|
printf (FORMAT, -1.0, -1.0, -1.0);
|
|
printf (FORMAT, 100.0, 100.0, 100.0);
|
|
printf (FORMAT, 1000.0, 1000.0, 1000.0);
|
|
printf (FORMAT, 10000.0, 10000.0, 10000.0);
|
|
printf (FORMAT, 12345.0, 12345.0, 12345.0);
|
|
printf (FORMAT, 100000.0, 100000.0, 100000.0);
|
|
printf (FORMAT, 123456.0, 123456.0, 123456.0);
|
|
#undef FORMAT
|
|
|
|
{
|
|
char buf[20];
|
|
char buf2[512];
|
|
|
|
printf ("snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n",
|
|
snprintf (buf, sizeof (buf), "%30s", "foo"), (int)sizeof (buf),
|
|
buf);
|
|
printf ("snprintf (\"%%.999999u\", 10) == %d\n",
|
|
snprintf (buf2, sizeof (buf2), "%.999999u", 10));
|
|
}
|
|
|
|
fp_test ();
|
|
|
|
printf ("%e should be 1.234568e+06\n", 1234567.8);
|
|
printf ("%f should be 1234567.800000\n", 1234567.8);
|
|
printf ("%g should be 1.23457e+06\n", 1234567.8);
|
|
printf ("%g should be 123.456\n", 123.456);
|
|
printf ("%g should be 1e+06\n", 1000000.0);
|
|
printf ("%g should be 10\n", 10.0);
|
|
printf ("%g should be 0.02\n", 0.02);
|
|
|
|
{
|
|
char buf[200];
|
|
|
|
snprintf (buf, sizeof(buf), "%*s%*s%*s", -1, "one", -20, "two", -30, "three");
|
|
|
|
result |= strcmp (buf,
|
|
"onetwo three ");
|
|
|
|
puts (result != 0 ? "Test failed!" : "Test ok.");
|
|
}
|
|
#if 0
|
|
{
|
|
char buf[200];
|
|
|
|
snprintf (buf, sizeof(buf), "%07Lo", 040000000000ll);
|
|
printf ("sprintf (buf, \"%%07Lo\", 040000000000ll) = %s", buf);
|
|
|
|
if (strcmp (buf, "40000000000") != 0) {
|
|
result = 1;
|
|
fputs ("\tFAILED", stdout);
|
|
}
|
|
puts ("");
|
|
}
|
|
|
|
printf ("printf (\"%%hhu\", %u) = %hhu\n", UCHAR_MAX + 2, UCHAR_MAX + 2);
|
|
printf ("printf (\"%%hu\", %u) = %hu\n", USHRT_MAX + 2, USHRT_MAX + 2);
|
|
#endif
|
|
puts ("--- Should be no further output. ---");
|
|
rfg1 ();
|
|
rfg2 ();
|
|
#if 0
|
|
rfg3 ();
|
|
{
|
|
char bytes[7];
|
|
char buf[20];
|
|
|
|
memset (bytes, '\xff', sizeof bytes);
|
|
snprintf (buf, sizeof(buf), "foo%hhn\n", &bytes[3]);
|
|
if (bytes[0] != '\xff' || bytes[1] != '\xff' || bytes[2] != '\xff'
|
|
|| bytes[4] != '\xff' || bytes[5] != '\xff' || bytes[6] != '\xff') {
|
|
puts ("%hhn overwrite more bytes");
|
|
result = 1;
|
|
}
|
|
if (bytes[3] != 3) {
|
|
puts ("%hhn wrote incorrect value");
|
|
result = 1;
|
|
}
|
|
}
|
|
#endif
|
|
return result != 0;
|
|
}
|
|
|
|
static void rfg1 (void)
|
|
{
|
|
char buf[100];
|
|
|
|
snprintf (buf, sizeof(buf), "%5.s", "xyz");
|
|
if (strcmp (buf, " ") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " ");
|
|
snprintf (buf, sizeof(buf), "%5.f", 33.3);
|
|
if (strcmp (buf, " 33") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 33");
|
|
snprintf (buf, sizeof(buf), "%8.e", 33.3e7);
|
|
if (strcmp (buf, " 3e+08") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 3e+08");
|
|
snprintf (buf, sizeof(buf), "%8.E", 33.3e7);
|
|
if (strcmp (buf, " 3E+08") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 3E+08");
|
|
snprintf (buf, sizeof(buf), "%.g", 33.3);
|
|
if (strcmp (buf, "3e+01") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, "3e+01");
|
|
snprintf (buf, sizeof(buf), "%.G", 33.3);
|
|
if (strcmp (buf, "3E+01") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, "3E+01");
|
|
}
|
|
|
|
static void rfg2 (void)
|
|
{
|
|
int prec;
|
|
char buf[100];
|
|
|
|
prec = 0;
|
|
snprintf (buf, sizeof(buf), "%.*g", prec, 3.3);
|
|
if (strcmp (buf, "3") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, "3");
|
|
prec = 0;
|
|
snprintf (buf, sizeof(buf), "%.*G", prec, 3.3);
|
|
if (strcmp (buf, "3") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, "3");
|
|
prec = 0;
|
|
snprintf (buf, sizeof(buf), "%7.*G", prec, 3.33);
|
|
if (strcmp (buf, " 3") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 3");
|
|
prec = 3;
|
|
snprintf (buf, sizeof(buf), "%04.*o", prec, 33);
|
|
if (strcmp (buf, " 041") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 041");
|
|
prec = 7;
|
|
snprintf (buf, sizeof(buf), "%09.*u", prec, 33);
|
|
if (strcmp (buf, " 0000033") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 0000033");
|
|
prec = 3;
|
|
snprintf (buf, sizeof(buf), "%04.*x", prec, 33);
|
|
if (strcmp (buf, " 021") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 021");
|
|
prec = 3;
|
|
snprintf (buf, sizeof(buf), "%04.*X", prec, 33);
|
|
if (strcmp (buf, " 021") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf, " 021");
|
|
}
|
|
|
|
static void rfg3 (void)
|
|
{
|
|
char buf[100];
|
|
double g = 5.0000001;
|
|
unsigned long l = 1234567890;
|
|
double d = 321.7654321;
|
|
const char s[] = "test-string";
|
|
int i = 12345;
|
|
int h = 1234;
|
|
|
|
snprintf (buf, sizeof(buf),
|
|
"%1$*5$d %2$*6$hi %3$*7$lo %4$*8$f %9$*12$e %10$*13$g %11$*14$s",
|
|
i, h, l, d, 8, 5, 14, 14, d, g, s, 14, 3, 14);
|
|
if (strcmp (buf,
|
|
" 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string") != 0)
|
|
printf ("got: '%s', expected: '%s'\n", buf,
|
|
" 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string");
|
|
}
|
|
#endif
|