/* * pANS stdio -- vfprintf */ #include "iolib.h" #include #include #include #include /* * 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) */ #define VLONG 512 /* 'll' convert a long long integer */ 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; int vfprintf(FILE *f, const char *s, va_list args) { int tfl, flags, width, precision; 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(tfl = tflag[*s&_IO_CHMASK]){ if(tfl == LONG && (flags & LONG)){ flags &= ~LONG; tfl = VLONG; } flags |= tfl; s++; } if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision); else if(*s){ putc(*s++, f); nprint++; } } return ferror(f)? -1: 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= 0) for(i=0; i!=precision && s[i]; i++); else for(i=0; s[i]; i++); for(; i= 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 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(ndig == 0) { ndig = 1; digits = "0"; } 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(eptr0 || flags&ALT) putc('.', f); for(i=0; i!=precision; i++) putc(0<=i+exponent && i+exponent0 || flags&ALT) putc('.', f); for(i=0; i!=precision; i++) putc(iebuf) putc(*--eptr, f); } while(nout < width){ putc(' ', f); nout++; } return nout; }