| #include <math.h>
enum {
fmt_flg_ralign =0x01,
fmt_flg_showsign=0x02,
fmt_flg_leading0=0x04,
fmt_flg_short =0x08,
fmt_flg_long =0x10,
fmt_flg_upper =0x20
};
#define BITS(x) (8*sizeof(x))
//#define BITS(x) (16*sizeof(x)) // for 16bit TI DSP C2406A
#define TYPE_MAX_DEC_DIGIT(bits) (((bits)*77+255)>>8)
enum { UINT_MAX_DEC_DIGIT=TYPE_MAX_DEC_DIGIT(BITS(unsigned)) };
void istrfmt_cnt(void* ctx,char c) { ++*((int*)ctx); }
int istrfmt_i(int x,int w1, char flg,void (*wc)(void* ctx,char c),void* ctx) {
int i,len,len0; unsigned w; char c;
if (x<0) { x=-x; c='-'; flg|=fmt_flg_showsign; } else { c='+'; }
w=1; len=UINT_MAX_DEC_DIGIT; for(i=1;i<len;++i) { w*=10; if ((unsigned long)x<w) len=i; }
len0=len; if (flg&fmt_flg_showsign) len++;
if ( flg&fmt_flg_ralign ) {
if (flg&fmt_flg_leading0) {
if (flg&fmt_flg_showsign) wc(ctx,c);
for(i=w1-len;i>0;--i) wc(ctx,'0');
} else {
for(i=w1-len;i>0;--i) wc(ctx,' ');
if (flg&fmt_flg_showsign) wc(ctx,c);
}
} else {
if (flg&fmt_flg_showsign) wc(ctx,c);
}
for(i=len0;i>0;--i) {
if (i!=UINT_MAX_DEC_DIGIT) w/=10;
c=(unsigned)x/w; x-=c*w; wc(ctx,'0'+c);
}
if (!(flg&fmt_flg_ralign)) { for(i=w1-len;i>0;--i) wc(ctx,' '); }
return len>w1?len:w1;
}
static int istrfmt_check_nan(double x,int w1,char flg,void (*wc)(void* ctx,char c),void* ctx) {
char c='+'; int len=0;
if (x!=x) {
if (w1>0 && flg&fmt_flg_ralign) { for(int i=3;i<w1;i++) wc(ctx,' '); }
if (flg&fmt_flg_upper) { wc(ctx,'N'); wc(ctx,'A'); wc(ctx,'N'); }
else { wc(ctx,'n'); wc(ctx,'a'); wc(ctx,'n'); }
if (w1>0 && !(flg&fmt_flg_ralign)) { for(int i=3;i<w1;i++) wc(ctx,' '); }
len=3; if (w1>len) len=w1;
return len;
}
if (x<0) { x=-x; c='-'; }
if (x>1 && x*x==x) {
if (w1>0 && flg&fmt_flg_ralign) { for(int i=4;i<w1;i++) wc(ctx,' '); }
wc(ctx,c);
if (flg&fmt_flg_upper) { wc(ctx,'I'); wc(ctx,'N'); wc(ctx,'F'); }
else { wc(ctx,'i'); wc(ctx,'n'); wc(ctx,'f'); }
if (w1>0 && !(flg&fmt_flg_ralign)) { for(int i=4;i<w1;i++) wc(ctx,' '); }
len=4; if (w1>len) len=w1;
}
return len;
}
int istrfmt_f(double x,int w1,int w2,char flg,void (*wc)(void* ctx,char c),void* ctx) {
int i,len,exp; char c;
if (w2==0) w2=6; // if not specified
len=istrfmt_check_nan(x,w1,flg,wc,ctx); if (len) return len;
if (x<0 || 1/x<0) { c='-'; x=-x; flg|=fmt_flg_showsign; } else c='+';
exp=0; len=flg&fmt_flg_showsign?1:0;
if (x!=0) {
if (w2>0) { double w;
w=0.50001;
for(i=w2;i>0;--i) w/=10;
x+=w;
}
while(x>=10.0) { x/=10; exp++; }
}
if (w2>0) len+=1+w2;
len+=exp+1;
if ( flg&fmt_flg_ralign ) for(i=w1-len;i>0;--i) wc(ctx,' ');
if (flg&fmt_flg_showsign) wc(ctx,c);
c=(char)floor(x);wc(ctx,'0'+c);
for(;exp>0;--exp) {
x-=c; x*=10;
c=(char)floor(x);wc(ctx,'0'+c);
}
if (w2>0) {
wc(ctx,'.');
for(i=0;i<w2;++i) {
x-=c; x*=10;
c=(char)floor(x);wc(ctx,'0'+c);
}
}
if (!(flg&fmt_flg_ralign)) for(i=w1-len;i>0;--i) wc(ctx,' ');
return len>w1?len:w1;
}
int istrfmt_e(double x,int w1,int w2,char flg,void (*wc)(void* ctx,char c),void* ctx) {
int i,len,exp; char c;
enum { exp_len=3,exp_flg=fmt_flg_showsign|fmt_flg_leading0|fmt_flg_ralign };
if (w2==0) w2=6; // if not specified
len=istrfmt_check_nan(x,w1,flg,wc,ctx); if (len) return len;
if (x<0 || 1/x<0) { c='-'; x=-x; flg|=fmt_flg_showsign; } else c='+';
exp=0; len=flg&fmt_flg_showsign?1:0;
if (x!=0) {
while(x>1.0) { x/=10; exp++; }
while(x>0 && x<1.0) { x*=10; exp--; }
{ double w;
w=0.50001; i=-w2;
for(;i<0;++i) w/=10;
for(;i>0;--i) w*=10;
x+=w;
}
}
len+=3+w2;
istrfmt_i(exp,exp_len,exp_flg,istrfmt_cnt,&len);
if ( flg&fmt_flg_ralign ) for(i=w1-len;i>0;--i) wc(ctx,' ');
if (flg&fmt_flg_showsign) wc(ctx,c);
c=(char)floor(x);wc(ctx,'0'+c);
if (w2>0) {
wc(ctx,'.');
for(i=0;i<w2;++i) {
x-=c; x*=10;
c=(char)floor(x);wc(ctx,'0'+c);
}
}
wc(ctx,flg&fmt_flg_upper?'E':'e');
istrfmt_i(exp,exp_len,exp_flg,wc,ctx);
if (!(flg&fmt_flg_ralign)) for(i=w1-len;i>0;--i) wc(ctx,' ');
return len>w1?len:w1;
}
int istrfmt_g(double x,int w1,int w2,char flg,void (*wc)(void* ctx,char c),void* ctx) {
int i,len,zd,exp; char c,q; double w;
enum { exp_len=3,exp_ll=-4,exp_flg=fmt_flg_showsign|fmt_flg_leading0|fmt_flg_ralign };
if (w2==0) w2=6; // if not specified
len=istrfmt_check_nan(x,w1,flg,wc,ctx); if (len) return len;
if (x<0 || 1/x<0) { c='-'; x=-x; flg|=fmt_flg_showsign; } else c='+';
zd=1;exp=0;len=flg&fmt_flg_showsign?1:0;
if (x!=0.0) {
while(x>1.0) { x/=10; exp++; }
while(x>0 && x<1.0) { x*=10; exp--; }
w=5.001; i=-w2;
for(;i<0;++i) w/=10;
for(;i>0;--i) w*=10;
x+=w;
w=x; q=(char)floor(w); for(i=1;i<w2;++i) { w-=q; w*=10; q=(char)floor(w); if (q!=0) zd=1+i; }
}
if (exp<exp_ll || exp+1>w2) {
len+=zd+2; // d.e
istrfmt_i(exp,exp_len,exp_flg,istrfmt_cnt,&len);
} // exp form
else {
if (exp+1==zd) len+=zd; // 123
else if (exp>=0) len+=(zd<exp+1?exp:zd)+1; // 1.23
else len+=zd+1-exp; // 0.0123
} // normal form
if ( flg&fmt_flg_ralign ) for(i=w1-len;i>0;--i) wc(ctx,' ');
if (flg&fmt_flg_showsign) wc(ctx,c);
if (exp<exp_ll || exp+1>w2) { // exp
for(i=0;i<zd;++i) { // 1.23e+45
c=(char)floor(x); x-=c; x*=10;
if (i==1) wc(ctx,'.');
wc(ctx,'0'+c);
}
wc(ctx,flg&fmt_flg_upper?'E':'e');
istrfmt_i(exp,exp_len,exp_flg,wc,ctx);
} else { // norm
if (exp+1==zd) { // 123
for(i=0;i<zd;++i) {
c=(char)floor(x); x-=c; x*=10;
wc(ctx,'0'+c);
}
} else if (exp>=0) { // 1.23
for(i=0;i<zd || i<=exp;++i) {
c=(char)floor(x); x-=c; x*=10;
if (i-1==exp) wc(ctx,'.');
wc(ctx,'0'+c);
}
} else { // 0.0123
wc(ctx,'0');wc(ctx,'.');
for(i=-1;i>exp;--i) wc(ctx,'0');
for(i=0;i<zd;++i) {
c=(char)floor(x); x-=c; x*=10;
wc(ctx,'0'+c);
}
}
}
if (!(flg&fmt_flg_ralign)) for(i=w1-len;i>0;--i) wc(ctx,' ');
return len>w1?len:w1;
}
|