123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- /*
- * pANS stdio -- vfprintf
- */
- #include "iolib.h"
- /*
- * Leading flags
- */
- #define SPACE 1 /* ' ' prepend space if no sign printed */
- #define ALT 2 /* '#' use alternate conversion */
- #define SIGN 4 /* '+' prepend sign, even if positive */
- #define LEFT 8 /* '-' left-justify */
- #define ZPAD 16 /* '0' zero-pad */
- /*
- * Trailing flags
- */
- #define SHORT 32 /* 'h' convert a short integer */
- #define LONG 64 /* 'l' convert a long integer */
- #define LDBL 128 /* 'L' convert a long double */
- #define PTR 256 /* convert a void * (%p) */
- static int lflag[] = { /* leading flags */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
- SPACE, 0, 0, ALT, 0, 0, 0, 0, /* sp ! " # $ % & ' */
- 0, 0, 0, SIGN, 0, LEFT, 0, 0, /* ( ) * + , - . / */
- ZPAD, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
- 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
- 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
- 0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
- 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
- 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
- 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- };
- static int tflag[] = { /* trailing flags */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
- 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
- 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
- 0, 0, 0, 0, LDBL, 0, 0, 0, /* H I J K L M N O */
- 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
- 0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
- SHORT, 0, 0, 0, LONG, 0, 0, 0, /* h i j k l m n o */
- 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
- 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- };
- static int ocvt_E(FILE *, va_list *, int, int, int);
- static int ocvt_G(FILE *, va_list *, int, int, int);
- static int ocvt_X(FILE *, va_list *, int, int, int);
- static int ocvt_c(FILE *, va_list *, int, int, int);
- static int ocvt_d(FILE *, va_list *, int, int, int);
- static int ocvt_e(FILE *, va_list *, int, int, int);
- static int ocvt_f(FILE *, va_list *, int, int, int);
- static int ocvt_g(FILE *, va_list *, int, int, int);
- static int ocvt_n(FILE *, va_list *, int, int, int);
- static int ocvt_o(FILE *, va_list *, int, int, int);
- static int ocvt_p(FILE *, va_list *, int, int, int);
- static int ocvt_s(FILE *, va_list *, int, int, int);
- static int ocvt_u(FILE *, va_list *, int, int, int);
- static int ocvt_x(FILE *, va_list *, int, int, int);
- static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
- 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
- 0, 0, 0, 0, 0, ocvt_E, 0, ocvt_G, /* @ A B C D E F G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
- 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
- ocvt_X, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
- 0, 0, 0, ocvt_c, ocvt_d, ocvt_e, ocvt_f, ocvt_g, /* ` a b c d e f g */
- 0, ocvt_d, 0, 0, 0, 0, ocvt_n, ocvt_o, /* h i j k l m n o */
- ocvt_p, 0, 0, ocvt_s, 0, ocvt_u, 0, 0, /* p q r s t u v w */
- ocvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- };
- static int nprint;
- QLock _stdiolk;
- int
- vfprintf(FILE *f, const char *s, va_list args)
- {
- int flags, width, precision;
- qlock(&_stdiolk);
- nprint = 0;
- while(*s){
- if(*s != '%'){
- putc(*s++, f);
- nprint++;
- continue;
- }
- s++;
- flags = 0;
- while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
- if(*s == '*'){
- width = va_arg(args, int);
- s++;
- if(width<0){
- flags |= LEFT;
- width = -width;
- }
- }
- else{
- width = 0;
- while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
- }
- if(*s == '.'){
- s++;
- if(*s == '*'){
- precision = va_arg(args, int);
- s++;
- }
- else{
- precision = 0;
- while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
- }
- }
- else
- precision = -1;
- while(tflag[*s&_IO_CHMASK]) flags |= tflag[*s++&_IO_CHMASK];
- if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
- else if(*s){
- putc(*s++, f);
- nprint++;
- }
- }
- qunlock(&_stdiolk);
- if(ferror(f)){
- if((f->flags&STRING) && f->wp==f->rp && f->wp>f->buf){
- *(f->wp-1) = '\0';
- return nprint;
- }
- return -1;
- }
- return nprint;
- }
- static int
- ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
- {
- #pragma ref precision
- int i;
- if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
- putc((unsigned char)va_arg(*args, int), f);
- if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
- return width<1 ? 1 : width;
- }
- static int
- ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
- {
- int i, n = 0;
- char *s;
- s = va_arg(*args, char *);
- if(!(flags&LEFT)){
- if(precision >= 0)
- for(i=0; i!=precision && s[i]; i++);
- else
- for(i=0; s[i]; i++);
- for(; i<width; i++){
- putc(' ', f);
- n++;
- }
- }
- if(precision >= 0){
- for(i=0; i!=precision && *s; i++){
- putc(*s++, f);
- n++;
- }
- } else{
- for(i=0;*s;i++){
- putc(*s++, f);
- n++;
- }
- }
- if(flags&LEFT){
- for(; i<width; i++){
- putc(' ', f);
- n++;
- }
- }
- return n;
- }
- static int
- ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
- {
- #pragma ref f
- #pragma ref width
- #pragma ref precision
- if(flags&SHORT)
- *va_arg(*args, short *) = nprint;
- else if(flags&LONG)
- *va_arg(*args, long *) = nprint;
- else
- *va_arg(*args, int *) = nprint;
- return 0;
- }
- /*
- * Generic fixed-point conversion
- * f is the output FILE *;
- * args is the va_list * from which to get the number;
- * flags, width and precision are the results of printf-cracking;
- * radix is the number base to print in;
- * alphabet is the set of digits to use;
- * prefix is the prefix to print before non-zero numbers when
- * using ``alternate form.''
- */
- static int
- ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
- int radix, int sgned, char alphabet[], char *prefix)
- {
- char digits[128]; /* no reasonable machine will ever overflow this */
- char *sign;
- char *dp;
- long snum;
- unsigned long num;
- int nout, npad, nlzero;
- if(sgned){
- if(flags&PTR) snum = (long)va_arg(*args, void *);
- else if(flags&SHORT) snum = va_arg(*args, short);
- else if(flags&LONG) snum = va_arg(*args, long);
- else snum = va_arg(*args, int);
- if(snum < 0){
- sign = "-";
- num = -snum;
- } else{
- if(flags&SIGN) sign = "+";
- else if(flags&SPACE) sign = " ";
- else sign = "";
- num = snum;
- }
- } else {
- sign = "";
- if(flags&PTR) num = (long)va_arg(*args, void *);
- else if(flags&SHORT) num = va_arg(*args, unsigned short);
- else if(flags&LONG) num = va_arg(*args, unsigned long);
- else num = va_arg(*args, unsigned int);
- }
- if(num == 0) prefix = "";
- dp = digits;
- do{
- *dp++ = alphabet[num%radix];
- num /= radix;
- }while(num);
- if(precision==0 && dp-digits==1 && dp[-1]=='0')
- dp--;
- nlzero = precision-(dp-digits);
- if(nlzero < 0) nlzero = 0;
- if(flags&ALT){
- if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
- }
- else prefix = "";
- nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
- npad = width-nout;
- if(npad < 0) npad = 0;
- nout += npad;
- if(!(flags&LEFT)){
- if(flags&ZPAD && precision <= 0){
- fputs(sign, f);
- fputs(prefix, f);
- while(npad){
- putc('0', f);
- --npad;
- }
- } else{
- while(npad){
- putc(' ', f);
- --npad;
- }
- fputs(sign, f);
- fputs(prefix, f);
- }
- while(nlzero){
- putc('0', f);
- --nlzero;
- }
- while(dp!=digits) putc(*--dp, f);
- }
- else{
- fputs(sign, f);
- fputs(prefix, f);
- while(nlzero){
- putc('0', f);
- --nlzero;
- }
- while(dp != digits) putc(*--dp, f);
- while(npad){
- putc(' ', f);
- --npad;
- }
- }
- return nout;
- }
- static int
- ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
- }
- static int
- ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
- }
- static int
- ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
- }
- static int
- ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
- "0123456789ABCDEF", "0X");
- }
- static int
- ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
- }
- static int
- ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
- }
- static int ocvt_flt(FILE *, va_list *, int, int, int, char);
- static int
- ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_flt(f, args, flags, width, precision, 'E');
- }
- static int
- ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_flt(f, args, flags, width, precision, 'G');
- }
- static int
- ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_flt(f, args, flags, width, precision, 'e');
- }
- static int
- ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_flt(f, args, flags, width, precision, 'f');
- }
- static int
- ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
- {
- return ocvt_flt(f, args, flags, width, precision, 'g');
- }
- static int
- ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
- {
- int echr;
- char *digits, *edigits;
- int exponent;
- char fmt;
- int sign;
- int ndig;
- int nout, i;
- char ebuf[20]; /* no sensible machine will overflow this */
- char *eptr;
- double d;
- echr = 'e';
- fmt = afmt;
- d = va_arg(*args, double);
- if(precision < 0) precision = 6;
- switch(fmt){
- case 'f':
- digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
- break;
- case 'E':
- echr = 'E';
- fmt = 'e';
- /* fall through */
- case 'e':
- digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
- break;
- case 'G':
- echr = 'E';
- /* fall through */
- case 'g':
- if (precision > 0)
- digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
- else {
- digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
- precision = edigits - digits;
- if (exponent > precision && exponent <= precision + 4)
- precision = exponent;
- }
- if(exponent >= -3 && exponent <= precision){
- fmt = 'f';
- precision -= exponent;
- }else{
- fmt = 'e';
- --precision;
- }
- break;
- }
- if (exponent == 9999) {
- /* Infinity or Nan */
- precision = 0;
- exponent = edigits - digits;
- fmt = 'f';
- }
- ndig = edigits-digits;
- if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */
- if(fmt == 'f'){
- if(precision+exponent > ndig) {
- precision = ndig - exponent;
- if(precision < 0)
- precision = 0;
- }
- }
- else{
- if(precision > ndig-1) precision = ndig-1;
- }
- }
- nout = precision; /* digits after decimal point */
- if(precision!=0 || flags&ALT) nout++; /* decimal point */
- if(fmt=='f' && exponent>0) nout += exponent; /* digits before decimal point */
- else nout++; /* there's always at least one */
- if(sign || flags&(SPACE|SIGN)) nout++; /* sign */
- if(fmt != 'f'){ /* exponent */
- eptr = ebuf;
- for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
- *eptr++ = '0' + i%10;
- while(eptr<ebuf+2) *eptr++ = '0';
- nout += eptr-ebuf+2; /* e+99 */
- }
- if(!(flags&ZPAD) && !(flags&LEFT))
- while(nout < width){
- putc(' ', f);
- nout++;
- }
- if(sign) putc('-', f);
- else if(flags&SIGN) putc('+', f);
- else if(flags&SPACE) putc(' ', f);
- if(flags&ZPAD)
- while(nout < width){
- putc('0', f);
- nout++;
- }
- if(fmt == 'f'){
- for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
- if(i == 0) putc('0', f);
- if(precision>0 || flags&ALT) putc('.', f);
- for(i=0; i!=precision; i++)
- putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
- }
- else{
- putc(digits[0], f);
- if(precision>0 || flags&ALT) putc('.', f);
- for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
- }
- if(fmt != 'f'){
- putc(echr, f);
- putc(exponent<=0?'-':'+', f);
- while(eptr>ebuf) putc(*--eptr, f);
- }
- while(nout < width){
- putc(' ', f);
- nout++;
- }
- freedtoa(digits);
- return nout;
- }
|