Yes that should be fine.
I wonder if there is any info on "C-standard-non-compliance bugs; the test suite was quite lacking in coverage". I've been using Marco's printf for years and never saw anything weird.
There are many old printf sources floating (no pun intended) around. Here is one from 1993, which came with the Hitech C compiler. The company was taken over by Microchip and those tools have since been abandoned. This code doesn't use itoa, ltoa, etc.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <conio.h>
#include <sys.h>
#include <math.h>
#include <float.h>
/*
* doprnt - long, non-float version depends on conditional compilation.
* Copyright (C) 1993 HI-TECH Software
*
* This version only supports 32 bit floating point
*/
#if (sizeof(long) == sizeof(int) || defined(__FLOAT)) && !defined(__LONG)
#define __LONG 1
#endif
#if sizeof(double) == sizeof(long) && DBL_MAX_EXP == 128
#define frexp(val, ptr) (void)(*(ptr) = ((*(unsigned long *)&val >> 23) & 255) - 126)
#endif
#ifdef __LONG
#define value long
#define NDIG 12 /* max number of digits to be printed */
#else
#define value int
#define NDIG 6 /* max number of digits to be printed */
#endif
const static unsigned value dpowers[] = {1, 10, 100, 1000, 10000,
#ifdef __LONG
100000, 1000000, 10000000, 100000000,
1000000000
#endif
};
const static unsigned value hexpowers[] = {1, 0x10, 0x100, 0x1000,
#if __LONG
0x10000, 0x100000, 0x1000000, 0x10000000
#endif
};
const static unsigned value octpowers[] = {1, 010, 0100, 01000, 010000, 0100000,
#ifdef __LONG
01000000,
010000000, 0100000000, 01000000000, 010000000000,
0100000000000
#endif
};
#ifdef __FLOAT
#if sizeof(long) != sizeof(double)
#error This fnum is only for 32 bit doubles
#endif
#if DBL_MAX_10_EXP > 120
#define expon int
#else
#define expon signed char
#endif
extern const double _powers_[], _npowers_[];
extern unsigned long _div_to_l_(float, float);
/* this routine returns a value to round to the number of decimal
places specified */
double
fround(unsigned char prec)
{
/* prec is guaranteed to be less than NDIG */
if(prec > 10)
return 0.5 * _npowers_[prec/10+9] * _npowers_[prec%10];
return 0.5 * _npowers_[prec];
}
/* this routine returns a scaling factor equal to 1 to the decimal
power supplied */
static double
scale(expon scl)
{
if(scl < 0) {
scl = -scl;
if(scl > 10)
return _npowers_[scl/10+9] * _npowers_[scl%10];
return _npowers_[scl];
}
if(scl > 10)
return _powers_[scl/10+9] * _powers_[scl%10];
return _powers_[scl];
}
#endif /* __FLOAT */
#define OPTSIGN 0x00
#define SPCSIGN 0x01
#define MANSIGN 0x02
#define NEGSIGN 0x03
#define FILL 0x04
#define LEFT 0x08
#define LONG 0x10
#define UPCASE 0x20
#define TEN 0x00
#define EIGHT 0x40
#define SIXTEEN 0x80
#define UNSIGN 0xC0
#define BASEM 0xC0
#define EFMT 0x100
#define GFMT 0x200
#define FFMT 0x400
#define ALTERN 0x800
#define DEFPREC 0x1000
#ifdef _HOSTED
#define pputc(c) (putc(c, fp) != EOF && ++ccnt)
int
vfprintf(FILE * fp, register const char * f, register va_list ap)
{
char cbuf[2];
#else /* _HOSTED */
#define pputc(c) if(pb->ptr) (*pb->ptr++ = c),++ccnt; else ((pb->func(c)),++ccnt)
int
_doprnt(struct __prbuf * pb, register const char * f, register va_list ap)
{
#endif /* _HOSTED */
int prec;
char c;
int width;
unsigned flag;
int ccnt = 0;
#ifdef __FLOAT
double fval;
int exp;
union {
unsigned value _val;
struct {
#if i8086 && SMALL_DATA
far char * _cp;
#else
char * _cp;
#endif
unsigned _len;
} _str;
double _integ;
} _val;
#else
union {
unsigned value _val;
struct {
#if i8086 && SMALL_DATA
far char * _cp;
#else
char * _cp;
#endif
unsigned _len;
} _str;
} _val;
#endif
#define val _val._val
#define cp _val._str._cp
#define len _val._str._len
#define integ _val._integ
flag = 0;
while(c = *f++) {
if(c != '%') {
pputc(c);
continue;
}
width = 0;
flag = 0;
for(;;) {
switch(*f) {
case '-':
flag |= LEFT;
f++;
continue;
case ' ':
flag |= SPCSIGN;
f++;
continue;
case '+':
flag |= MANSIGN;
f++;
continue;
case '#':
flag |= ALTERN;
f++;
continue;
case '0':
flag |= FILL;
f++;
continue;
}
break;
}
if(flag & MANSIGN)
flag &= ~SPCSIGN;
if(flag & LEFT)
flag &= ~FILL;
if(isdigit((unsigned)*f)) {
width = 0;
do
width = width*10 + *f++ - '0';
while(isdigit((unsigned)*f));
} else if(*f == '*') {
width = va_arg(ap, int);
f++;
}
if(*f == '.')
if(*++f == '*') {
prec = va_arg(ap, int);
f++;
} else {
prec = 0;
while(isdigit((unsigned)*f))
prec = prec*10 + *f++ - '0';
}
else {
prec = 0;
#ifdef __FLOAT
flag |= DEFPREC;
#endif
}
#ifdef __LONG
loop:
#endif
switch(c = *f++) {
case 0:
return ccnt;
case 'l':
#ifdef __LONG
flag |= LONG;
goto loop;
#else
cp = "(non-long printf)";
goto strings;
#endif
#ifndef __FLOAT
case 'E':
case 'f':
case 'e':
case 'g':
cp = "(non-float printf)";
goto strings;
#else
case 'f':
flag |= FFMT;
break;
case 'E':
flag |= UPCASE;
case 'e':
flag |= EFMT;
break;
case 'g':
flag |= GFMT;
break;
#endif
case 'o':
flag |= EIGHT;
break;
case 'd':
case 'i':
break;
case 'X':
case 'p':
flag |= UPCASE;
case 'x':
flag |= SIXTEEN;
break;
case 's':
#if i8086 && SMALL_DATA
if(flag & LONG)
cp = va_arg(ap, far char *);
else
#endif
cp = va_arg(ap, char *);
#if !defined(__FLOAT)
strings:
#endif
if(!cp)
cp = "(null)";
len = 0;
while(cp[len])
len++;
dostring:
if(prec && prec < len)
len = prec;
if(width > len)
width -= len;
else
width = 0;
if(!(flag & LEFT))
while(width--)
pputc(' ');
while(len--)
pputc(*cp++);
if(flag & LEFT)
while(width--)
pputc(' ');
continue;
case 'c':
#if _HOSTED
val = va_arg(ap, int);
c = val >> 8;
if(flag & LONG && c && (unsigned char)c != 0xFF) {
cbuf[0] = c;
cbuf[1] = val;
len = 2;
} else {
cbuf[0] = val;
len = 1;
}
cp = cbuf;
goto dostring;
#else
c = va_arg(ap, int);
#endif
default:
cp = &c;
len = 1;
goto dostring;
case 'u':
flag |= UNSIGN;
break;
}
#ifdef __FLOAT
if(flag & (EFMT|GFMT|FFMT)) {
if(flag & DEFPREC)
prec = 6;
fval = va_arg(ap, double);
if(fval < 0.0) {
fval = -fval;
flag |= NEGSIGN;
}
exp = 0;
frexp(fval, &exp); /* get binary exponent */
exp--; /* adjust 0.5 -> 1.0 */
exp *= 3;
exp /= 10; /* estimate decimal exponent */
if(exp < 0)
exp--;
integ = fval * scale(-exp);
if(integ < 1.0)
exp--;
else if(integ >= 10.0)
exp++;
if(exp <= 0)
c = 1;
else
c = exp;
#if 0
if(!(flag & ALTERN) && flag & FFMT && prec == 0) {
val = (long)(fval + 0.5);
flag |= LONG;
goto integer;
}
if(!(flag & ALTERN) && flag & GFMT && exp >= 0 && c <= prec) {
integ = fval + fround(prec - c);
if((unsigned)exp > sizeof dpowers/sizeof dpowers[0] || integ - (float)(unsigned long)integ < fround(prec-c-1)) {
val = (long)integ;
flag |= LONG;
prec = 0;
goto integer;
}
}
#endif
if(flag & EFMT || flag & GFMT && (exp < -4 || exp >= (int)prec)) { /* use e format */
if(prec && flag & GFMT)
prec--; /* g format precision includes integer digit */
if(prec > sizeof dpowers/sizeof dpowers[0] - 1)
c = sizeof dpowers/sizeof dpowers[0] - 1;
else
c = prec;
fval *= scale(c-exp);
if((unsigned long)fval >= dpowers[c+1]) {
fval *= 1e-1;
exp++;
} else if((unsigned long)fval < dpowers[c]) {
fval *= 10.0;
exp--;
}
#if 0
if(fval != 0.0) {
while(fval >= 10.0) {
fval *= 1e-1;
exp++;
if(flag & GFMT)
prec++;
}
while(fval < 1.0) {
fval *= 10.0;
exp--;
if(flag & GFMT)
prec--;
}
}
#endif
fval += 0.5;
if(flag & GFMT && !(flag & ALTERN)) { /* g format, precision means something different */
if(prec > (int)(sizeof dpowers/sizeof dpowers[0]))
prec = sizeof dpowers/sizeof dpowers[0];
val = (unsigned long)fval;
while(val && val % 10 == 0) {
prec--;
val /= 10;
}
if(prec < c) {
fval *= scale(prec-c);
c = prec;
}
}
width -= prec + 5;
if(prec || flag & ALTERN)
width--;
if(flag & (MANSIGN|SPCSIGN))
width--;
if(exp >= 100 || exp <= -100) /* 3 digit exponent */
width--;
if(flag & FILL) {
if(flag & MANSIGN)
pputc(flag & SPCSIGN ? '-' : '+');
else if(flag & SPCSIGN)
pputc(' ');
while(width > 0) {
pputc('0');
width--;
}
} else {
if(!(flag & LEFT))
while(width > 0) {
pputc(' ');
width--;
}
if(flag & MANSIGN)
pputc(flag & SPCSIGN ? '-' : '+');
else if(flag & SPCSIGN)
pputc(' ');
}
val = (unsigned long)fval;
pputc(val/dpowers[c] + '0');
if(prec || flag & ALTERN) {
pputc('.');
prec -= c;
while(c) {
pputc('0' + (val/dpowers[--c]) % 10);
}
while(prec) {
pputc('0');
prec--;
}
}
if(flag & UPCASE)
pputc('E');
else
pputc('e');
if(exp < 0) {
exp = -exp;
pputc('-');
} else
pputc('+');
if(exp >= 100) {
pputc(exp / 100 + '0');
exp %= 100;
}
pputc(exp / 10 + '0');
pputc(exp % 10 + '0');
if((flag & LEFT) && width)
do
pputc(' ');
while(--width);
continue;
}
/* here for f format */
if(flag & GFMT) {
if(exp < 0)
prec -= exp-1;
val = (unsigned long)fval;
for(c = 1 ; c != sizeof dpowers/sizeof dpowers[0] ; c++)
if(val < dpowers[c])
break;
prec -= c;
val = (unsigned long)((fval-(double)val) * scale(prec)+0.5);
while(prec && val % 10 == 0) {
val /= 10;
prec--;
}
}
if(prec <= NDIG)
fval += fround(prec);
if(exp > (int)(sizeof dpowers/sizeof dpowers[0])-1) {
exp -= sizeof dpowers/sizeof dpowers[0]-1;
val = _div_to_l_(fval, scale(exp));
fval = 0.0;
} else {
val = (unsigned long)fval;
fval -= (float)val;
exp = 0;
}
for(c = 1 ; c != sizeof dpowers/sizeof dpowers[0] ; c++)
if(val < dpowers[c])
break;
width -= prec + c + exp;
if(flag & ALTERN || prec)
width--;
if(flag & (MANSIGN|SPCSIGN))
width--;
if(flag & FILL) {
if(flag & MANSIGN)
pputc(flag & SPCSIGN ? '-' : '+');
else if(flag & SPCSIGN)
pputc(' ');
while(width > 0) {
pputc('0');
width--;
}
} else {
if(!(flag & LEFT))
while(width > 0) {
pputc(' ');
width--;
}
if(flag & MANSIGN)
pputc(flag & SPCSIGN ? '-' : '+');
else if(flag & SPCSIGN)
pputc(' ');
}
while(c--)
pputc('0' + (val/dpowers[c]) % 10);
while(exp > 0) {
pputc('0');
exp--;
}
if(prec > (int)(sizeof dpowers/sizeof dpowers[0]))
c = sizeof dpowers/sizeof dpowers[0];
else
c = prec;
prec -= c;
if(c || flag & ALTERN)
pputc('.');
val = (long)(fval * scale(c));
while(c) {
pputc('0' + (val/dpowers[--c]) % 10);
}
while(prec) {
pputc('0');
prec--;
}
if((flag & LEFT) && width)
do
pputc(' ');
while(--width);
continue;
}
#endif /* __FLOAT */
if((flag & BASEM) == TEN) {
#ifdef __LONG
if(flag & LONG)
val = va_arg(ap, long);
else
#endif
val = (value)va_arg(ap, int);
if((value)val < 0) {
flag |= NEGSIGN;
val = -val;
}
} else {
#ifdef __LONG
if(flag & LONG)
val = va_arg(ap, unsigned long);
else
#endif
val = va_arg(ap, unsigned);
}
#ifdef __FLOAT
integer:
#endif
if(prec == 0 && val == 0)
prec++;
switch((unsigned char)(flag & BASEM)) {
case TEN:
case UNSIGN:
for(c = 1 ; c != sizeof dpowers/sizeof dpowers[0] ; c++)
if(val < dpowers[c])
break;
break;
case SIXTEEN:
for(c = 1 ; c != sizeof hexpowers/sizeof hexpowers[0] ; c++)
if(val < hexpowers[c])
break;
break;
case EIGHT:
for(c = 1 ; c != sizeof octpowers/sizeof octpowers[0] ; c++)
if(val < octpowers[c])
break;
break;
}
if(c < prec)
c = prec;
else if(prec < c)
prec = c;
if(width && flag & NEGSIGN)
width--;
if(width > prec)
width -= prec;
else
width = 0;
if((flag & (FILL|BASEM|ALTERN)) == (EIGHT|ALTERN)) {
if(width)
width--;
} else if((flag & (BASEM|ALTERN)) == (SIXTEEN|ALTERN)) {
if(width > 2)
width -= 2;
else
width = 0;
}
if(flag & FILL) {
if(flag & MANSIGN)
pputc(flag & SPCSIGN ? '-' : '+');
else if(flag & SPCSIGN)
pputc(' ');
else if((flag & (BASEM|ALTERN)) == (SIXTEEN|ALTERN)) {
pputc('0');
pputc(flag & UPCASE ? 'X' : 'x');
}
if(width)
do
pputc('0');
while(--width);
} else {
if(width && !(flag & LEFT))
do
pputc(' ');
while(--width);
if(flag & MANSIGN)
pputc(flag & SPCSIGN ? '-' : '+');
else if(flag & SPCSIGN)
pputc(' ');
if((flag & (BASEM|ALTERN)) == (EIGHT|ALTERN))
pputc('0');
else if((flag & (BASEM|ALTERN)) == (SIXTEEN|ALTERN)) {
pputc('0');
pputc(flag & UPCASE ? 'X' : 'x');
}
}
while(prec > c)
pputc('0');
while(prec--) {
switch((unsigned char)(flag & BASEM)) {
case TEN:
case UNSIGN:
c = (val / dpowers[prec]) % 10 + '0';
break;
case SIXTEEN:
c = (flag & UPCASE ? "0123456789ABCDEF" : "0123456789abcdef")[(val / hexpowers[prec]) & 0xF];
break;
case EIGHT:
c = ((val / octpowers[prec]) & 07) + '0';
break;
}
pputc(c);
}
if((flag & LEFT) && width)
do
pputc(' ');
while(--width);
}
return ccnt;
}