portable xprintf implementation

This commit is contained in:
Yuichi Nishiwaki 2015-01-28 00:28:54 +09:00
parent e4248584b6
commit 32d6760d4f
1 changed files with 63 additions and 12 deletions

View File

@ -561,24 +561,75 @@ xfprintf(xFILE *stream, const char *fmt, ...)
return n;
}
static void
xfile_printint(xFILE *stream, long x, int base)
{
static char digits[] = "0123456789abcdef";
char buf[20];
int i, neg;
neg = 0;
if (x < 0) {
neg = 1;
x = -x;
}
i = 0;
do {
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
if (neg) {
buf[i++] = '-';
}
while (i-- > 0) {
xputc(buf[i], stream);
}
}
PIC_INLINE int
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
{
va_list ap2;
const char *p;
char *sval;
int ival;
double dval;
void *vp;
long seekr = xftell(stream);
va_copy(ap2, ap);
{
char buf[vsnprintf(NULL, 0, fmt, ap2)];
vsnprintf(buf, sizeof buf + 1, fmt, ap);
if (xfwrite(buf, sizeof buf, 1, stream) < 1) {
return -1;
for (p = fmt; *p; p++) {
if (*p != '%') {
xputc(*p, stream);
continue;
}
switch (*++p) {
case 'd':
case 'i':
ival = va_arg(ap, int);
xfile_printint(stream, ival, 10);
break;
case 'f':
dval = va_arg(ap, double);
xfile_printint(stream, dval, 10);
xputc('.', stream);
xfile_printint(stream, fabs((dval - (int)dval) * 1e4), 10);
break;
case 's':
sval = va_arg(ap, char*);
xfputs(sval, stream);
break;
case 'p':
vp = va_arg(ap, void*);
xfputs("0x", stream);
xfile_printint(stream, dval, 16);
break;
default:
xputc(*(p-1), stream);
break;
}
va_end(ap2);
return (int)(sizeof buf);
}
return xftell(stream) - seekr;
}
#if defined(__cplusplus)