13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier * pANS stdio -- vfprintf
33e12c5d1SDavid du Colombier */
43e12c5d1SDavid du Colombier #include "iolib.h"
53e12c5d1SDavid du Colombier #include <stdarg.h>
63e12c5d1SDavid du Colombier #include <math.h>
73e12c5d1SDavid du Colombier #include <stdlib.h>
83e12c5d1SDavid du Colombier #include <string.h>
93e12c5d1SDavid du Colombier /*
103e12c5d1SDavid du Colombier * Leading flags
113e12c5d1SDavid du Colombier */
123e12c5d1SDavid du Colombier #define SPACE 1 /* ' ' prepend space if no sign printed */
133e12c5d1SDavid du Colombier #define ALT 2 /* '#' use alternate conversion */
143e12c5d1SDavid du Colombier #define SIGN 4 /* '+' prepend sign, even if positive */
153e12c5d1SDavid du Colombier #define LEFT 8 /* '-' left-justify */
163e12c5d1SDavid du Colombier #define ZPAD 16 /* '0' zero-pad */
173e12c5d1SDavid du Colombier /*
183e12c5d1SDavid du Colombier * Trailing flags
193e12c5d1SDavid du Colombier */
203e12c5d1SDavid du Colombier #define SHORT 32 /* 'h' convert a short integer */
213e12c5d1SDavid du Colombier #define LONG 64 /* 'l' convert a long integer */
223e12c5d1SDavid du Colombier #define LDBL 128 /* 'L' convert a long double */
233e12c5d1SDavid du Colombier #define PTR 256 /* convert a void * (%p) */
24d9306527SDavid du Colombier #define VLONG 512 /* 'll' convert a long long integer */
253e12c5d1SDavid du Colombier
263e12c5d1SDavid du Colombier static int lflag[] = { /* leading flags */
273e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
283e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
293e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
303e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
313e12c5d1SDavid du Colombier SPACE, 0, 0, ALT, 0, 0, 0, 0, /* sp ! " # $ % & ' */
323e12c5d1SDavid du Colombier 0, 0, 0, SIGN, 0, LEFT, 0, 0, /* ( ) * + , - . / */
333e12c5d1SDavid du Colombier ZPAD, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
343e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
353e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
363e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
373e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
383e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
393e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
403e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
413e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
423e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
433e12c5d1SDavid du Colombier
443e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
453e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
463e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
473e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
483e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
493e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
503e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
513e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
523e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
533e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
543e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
553e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
563e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
573e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
583e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
593e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
603e12c5d1SDavid du Colombier };
613e12c5d1SDavid du Colombier
623e12c5d1SDavid du Colombier static int tflag[] = { /* trailing flags */
633e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
643e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
653e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
663e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
673e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
683e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
693e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
703e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
713e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
723e12c5d1SDavid du Colombier 0, 0, 0, 0, LDBL, 0, 0, 0, /* H I J K L M N O */
733e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
743e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
753e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
763e12c5d1SDavid du Colombier SHORT, 0, 0, 0, LONG, 0, 0, 0, /* h i j k l m n o */
773e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
783e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
793e12c5d1SDavid du Colombier
803e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
813e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
823e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
833e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
843e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
853e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
863e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
873e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
883e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
893e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
903e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
913e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
923e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
933e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
943e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
953e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
963e12c5d1SDavid du Colombier };
973e12c5d1SDavid du Colombier
983e12c5d1SDavid du Colombier static int ocvt_E(FILE *, va_list *, int, int, int);
993e12c5d1SDavid du Colombier static int ocvt_G(FILE *, va_list *, int, int, int);
1003e12c5d1SDavid du Colombier static int ocvt_X(FILE *, va_list *, int, int, int);
1013e12c5d1SDavid du Colombier static int ocvt_c(FILE *, va_list *, int, int, int);
1023e12c5d1SDavid du Colombier static int ocvt_d(FILE *, va_list *, int, int, int);
1033e12c5d1SDavid du Colombier static int ocvt_e(FILE *, va_list *, int, int, int);
1043e12c5d1SDavid du Colombier static int ocvt_f(FILE *, va_list *, int, int, int);
1053e12c5d1SDavid du Colombier static int ocvt_g(FILE *, va_list *, int, int, int);
1063e12c5d1SDavid du Colombier static int ocvt_n(FILE *, va_list *, int, int, int);
1073e12c5d1SDavid du Colombier static int ocvt_o(FILE *, va_list *, int, int, int);
1083e12c5d1SDavid du Colombier static int ocvt_p(FILE *, va_list *, int, int, int);
1093e12c5d1SDavid du Colombier static int ocvt_s(FILE *, va_list *, int, int, int);
1103e12c5d1SDavid du Colombier static int ocvt_u(FILE *, va_list *, int, int, int);
1113e12c5d1SDavid du Colombier static int ocvt_x(FILE *, va_list *, int, int, int);
1123e12c5d1SDavid du Colombier
1133e12c5d1SDavid du Colombier static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
1143e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
1153e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
1163e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
1173e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
1183e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
1193e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
1203e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
1213e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
1223e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, ocvt_E, 0, ocvt_G, /* @ A B C D E F G */
1233e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
1243e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
1253e12c5d1SDavid du Colombier ocvt_X, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
1263e12c5d1SDavid du Colombier 0, 0, 0, ocvt_c, ocvt_d, ocvt_e, ocvt_f, ocvt_g, /* ` a b c d e f g */
1273e12c5d1SDavid du Colombier 0, ocvt_d, 0, 0, 0, 0, ocvt_n, ocvt_o, /* h i j k l m n o */
1283e12c5d1SDavid du Colombier ocvt_p, 0, 0, ocvt_s, 0, ocvt_u, 0, 0, /* p q r s t u v w */
1293e12c5d1SDavid du Colombier ocvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
1303e12c5d1SDavid du Colombier
1313e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1323e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1333e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1343e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1353e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1363e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1373e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1383e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1393e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1403e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1413e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1423e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1433e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1443e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1453e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1463e12c5d1SDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0,
1473e12c5d1SDavid du Colombier };
1483e12c5d1SDavid du Colombier
1493e12c5d1SDavid du Colombier static int nprint;
1503e12c5d1SDavid du Colombier
1513e12c5d1SDavid du Colombier int
vfprintf(FILE * f,const char * s,va_list args)1523e12c5d1SDavid du Colombier vfprintf(FILE *f, const char *s, va_list args)
1533e12c5d1SDavid du Colombier {
154d9306527SDavid du Colombier int tfl, flags, width, precision;
1553e12c5d1SDavid du Colombier
1563e12c5d1SDavid du Colombier nprint = 0;
1573e12c5d1SDavid du Colombier while(*s){
1583e12c5d1SDavid du Colombier if(*s != '%'){
1593e12c5d1SDavid du Colombier putc(*s++, f);
1603e12c5d1SDavid du Colombier nprint++;
1613e12c5d1SDavid du Colombier continue;
1623e12c5d1SDavid du Colombier }
1633e12c5d1SDavid du Colombier s++;
1643e12c5d1SDavid du Colombier flags = 0;
1653e12c5d1SDavid du Colombier while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
1663e12c5d1SDavid du Colombier if(*s == '*'){
1673e12c5d1SDavid du Colombier width = va_arg(args, int);
1683e12c5d1SDavid du Colombier s++;
1693e12c5d1SDavid du Colombier if(width<0){
1703e12c5d1SDavid du Colombier flags |= LEFT;
1713e12c5d1SDavid du Colombier width = -width;
1723e12c5d1SDavid du Colombier }
1733e12c5d1SDavid du Colombier }
1743e12c5d1SDavid du Colombier else{
1753e12c5d1SDavid du Colombier width = 0;
1763e12c5d1SDavid du Colombier while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier if(*s == '.'){
1793e12c5d1SDavid du Colombier s++;
1803e12c5d1SDavid du Colombier if(*s == '*'){
1813e12c5d1SDavid du Colombier precision = va_arg(args, int);
1823e12c5d1SDavid du Colombier s++;
1833e12c5d1SDavid du Colombier }
1843e12c5d1SDavid du Colombier else{
1853e12c5d1SDavid du Colombier precision = 0;
1863e12c5d1SDavid du Colombier while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
1873e12c5d1SDavid du Colombier }
1883e12c5d1SDavid du Colombier }
1893e12c5d1SDavid du Colombier else
1903e12c5d1SDavid du Colombier precision = -1;
191d9306527SDavid du Colombier while(tfl = tflag[*s&_IO_CHMASK]){
192d9306527SDavid du Colombier if(tfl == LONG && (flags & LONG)){
193d9306527SDavid du Colombier flags &= ~LONG;
194d9306527SDavid du Colombier tfl = VLONG;
195d9306527SDavid du Colombier }
196d9306527SDavid du Colombier flags |= tfl;
197d9306527SDavid du Colombier s++;
198d9306527SDavid du Colombier }
1993e12c5d1SDavid du Colombier if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
2003e12c5d1SDavid du Colombier else if(*s){
2013e12c5d1SDavid du Colombier putc(*s++, f);
2023e12c5d1SDavid du Colombier nprint++;
2033e12c5d1SDavid du Colombier }
2043e12c5d1SDavid du Colombier }
205219b2ee8SDavid du Colombier return ferror(f)? -1: nprint;;
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier
2083e12c5d1SDavid du Colombier static int
ocvt_c(FILE * f,va_list * args,int flags,int width,int precision)2093e12c5d1SDavid du Colombier ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
2103e12c5d1SDavid du Colombier {
2113e12c5d1SDavid du Colombier #pragma ref precision
2123e12c5d1SDavid du Colombier int i;
2133e12c5d1SDavid du Colombier
2143e12c5d1SDavid du Colombier if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
2153e12c5d1SDavid du Colombier putc((unsigned char)va_arg(*args, int), f);
2163e12c5d1SDavid du Colombier if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
2173e12c5d1SDavid du Colombier return width<1 ? 1 : width;
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier
2203e12c5d1SDavid du Colombier static int
ocvt_s(FILE * f,va_list * args,int flags,int width,int precision)2213e12c5d1SDavid du Colombier ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
2223e12c5d1SDavid du Colombier {
2233e12c5d1SDavid du Colombier int i, n = 0;
2243e12c5d1SDavid du Colombier char *s;
2253e12c5d1SDavid du Colombier
2263e12c5d1SDavid du Colombier s = va_arg(*args, char *);
227219b2ee8SDavid du Colombier if(!s)
228219b2ee8SDavid du Colombier s = "";
2293e12c5d1SDavid du Colombier if(!(flags&LEFT)){
2303e12c5d1SDavid du Colombier if(precision >= 0)
2313e12c5d1SDavid du Colombier for(i=0; i!=precision && s[i]; i++);
2323e12c5d1SDavid du Colombier else
2333e12c5d1SDavid du Colombier for(i=0; s[i]; i++);
2343e12c5d1SDavid du Colombier for(; i<width; i++){
2353e12c5d1SDavid du Colombier putc(' ', f);
2363e12c5d1SDavid du Colombier n++;
2373e12c5d1SDavid du Colombier }
2383e12c5d1SDavid du Colombier }
2393e12c5d1SDavid du Colombier if(precision >= 0){
2403e12c5d1SDavid du Colombier for(i=0; i!=precision && *s; i++){
2413e12c5d1SDavid du Colombier putc(*s++, f);
2423e12c5d1SDavid du Colombier n++;
2433e12c5d1SDavid du Colombier }
2443e12c5d1SDavid du Colombier } else{
2453e12c5d1SDavid du Colombier for(i=0;*s;i++){
2463e12c5d1SDavid du Colombier putc(*s++, f);
2473e12c5d1SDavid du Colombier n++;
2483e12c5d1SDavid du Colombier }
2493e12c5d1SDavid du Colombier }
2503e12c5d1SDavid du Colombier if(flags&LEFT){
2513e12c5d1SDavid du Colombier for(; i<width; i++){
2523e12c5d1SDavid du Colombier putc(' ', f);
2533e12c5d1SDavid du Colombier n++;
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier }
2563e12c5d1SDavid du Colombier return n;
2573e12c5d1SDavid du Colombier }
2583e12c5d1SDavid du Colombier
2593e12c5d1SDavid du Colombier static int
ocvt_n(FILE * f,va_list * args,int flags,int width,int precision)2603e12c5d1SDavid du Colombier ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
2613e12c5d1SDavid du Colombier {
2623e12c5d1SDavid du Colombier #pragma ref f
2633e12c5d1SDavid du Colombier #pragma ref width
2643e12c5d1SDavid du Colombier #pragma ref precision
2653e12c5d1SDavid du Colombier if(flags&SHORT)
2663e12c5d1SDavid du Colombier *va_arg(*args, short *) = nprint;
2673e12c5d1SDavid du Colombier else if(flags&LONG)
2683e12c5d1SDavid du Colombier *va_arg(*args, long *) = nprint;
269d9306527SDavid du Colombier else if(flags&VLONG)
270d9306527SDavid du Colombier *va_arg(*args, long long*) = nprint;
2713e12c5d1SDavid du Colombier else
2723e12c5d1SDavid du Colombier *va_arg(*args, int *) = nprint;
2733e12c5d1SDavid du Colombier return 0;
2743e12c5d1SDavid du Colombier }
2753e12c5d1SDavid du Colombier
2763e12c5d1SDavid du Colombier /*
2773e12c5d1SDavid du Colombier * Generic fixed-point conversion
2783e12c5d1SDavid du Colombier * f is the output FILE *;
2793e12c5d1SDavid du Colombier * args is the va_list * from which to get the number;
2803e12c5d1SDavid du Colombier * flags, width and precision are the results of printf-cracking;
2813e12c5d1SDavid du Colombier * radix is the number base to print in;
2823e12c5d1SDavid du Colombier * alphabet is the set of digits to use;
2833e12c5d1SDavid du Colombier * prefix is the prefix to print before non-zero numbers when
2843e12c5d1SDavid du Colombier * using ``alternate form.''
2853e12c5d1SDavid du Colombier */
2863e12c5d1SDavid du Colombier static int
ocvt_fixed(FILE * f,va_list * args,int flags,int width,int precision,int radix,int sgned,char alphabet[],char * prefix)2873e12c5d1SDavid du Colombier ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
2883e12c5d1SDavid du Colombier int radix, int sgned, char alphabet[], char *prefix)
2893e12c5d1SDavid du Colombier {
2903e12c5d1SDavid du Colombier char digits[128]; /* no reasonable machine will ever overflow this */
2913e12c5d1SDavid du Colombier char *sign;
2923e12c5d1SDavid du Colombier char *dp;
293d9306527SDavid du Colombier long long snum;
294d9306527SDavid du Colombier unsigned long long num;
2953e12c5d1SDavid du Colombier int nout, npad, nlzero;
2963e12c5d1SDavid du Colombier
2973e12c5d1SDavid du Colombier if(sgned){
2983e12c5d1SDavid du Colombier if(flags&PTR) snum = (long)va_arg(*args, void *);
2993e12c5d1SDavid du Colombier else if(flags&SHORT) snum = va_arg(*args, short);
3003e12c5d1SDavid du Colombier else if(flags&LONG) snum = va_arg(*args, long);
301d9306527SDavid du Colombier else if(flags&VLONG) snum = va_arg(*args, long long);
3023e12c5d1SDavid du Colombier else snum = va_arg(*args, int);
3033e12c5d1SDavid du Colombier if(snum < 0){
3043e12c5d1SDavid du Colombier sign = "-";
3053e12c5d1SDavid du Colombier num = -snum;
3063e12c5d1SDavid du Colombier } else{
3073e12c5d1SDavid du Colombier if(flags&SIGN) sign = "+";
3083e12c5d1SDavid du Colombier else if(flags&SPACE) sign = " ";
3093e12c5d1SDavid du Colombier else sign = "";
3103e12c5d1SDavid du Colombier num = snum;
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier } else {
3133e12c5d1SDavid du Colombier sign = "";
3143e12c5d1SDavid du Colombier if(flags&PTR) num = (long)va_arg(*args, void *);
3153e12c5d1SDavid du Colombier else if(flags&SHORT) num = va_arg(*args, unsigned short);
3163e12c5d1SDavid du Colombier else if(flags&LONG) num = va_arg(*args, unsigned long);
317d9306527SDavid du Colombier else if(flags&VLONG) num = va_arg(*args, unsigned long long);
3183e12c5d1SDavid du Colombier else num = va_arg(*args, unsigned int);
3193e12c5d1SDavid du Colombier }
3203e12c5d1SDavid du Colombier if(num == 0) prefix = "";
3213e12c5d1SDavid du Colombier dp = digits;
3223e12c5d1SDavid du Colombier do{
3233e12c5d1SDavid du Colombier *dp++ = alphabet[num%radix];
3243e12c5d1SDavid du Colombier num /= radix;
3253e12c5d1SDavid du Colombier }while(num);
3263e12c5d1SDavid du Colombier if(precision==0 && dp-digits==1 && dp[-1]=='0')
3273e12c5d1SDavid du Colombier dp--;
3283e12c5d1SDavid du Colombier nlzero = precision-(dp-digits);
3293e12c5d1SDavid du Colombier if(nlzero < 0) nlzero = 0;
3303e12c5d1SDavid du Colombier if(flags&ALT){
3313e12c5d1SDavid du Colombier if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
3323e12c5d1SDavid du Colombier }
3333e12c5d1SDavid du Colombier else prefix = "";
3343e12c5d1SDavid du Colombier nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
3353e12c5d1SDavid du Colombier npad = width-nout;
3363e12c5d1SDavid du Colombier if(npad < 0) npad = 0;
3373e12c5d1SDavid du Colombier nout += npad;
3383e12c5d1SDavid du Colombier if(!(flags&LEFT)){
339219b2ee8SDavid du Colombier if(flags&ZPAD && precision <= 0){
3403e12c5d1SDavid du Colombier fputs(sign, f);
3413e12c5d1SDavid du Colombier fputs(prefix, f);
3423e12c5d1SDavid du Colombier while(npad){
3433e12c5d1SDavid du Colombier putc('0', f);
3443e12c5d1SDavid du Colombier --npad;
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier } else{
3473e12c5d1SDavid du Colombier while(npad){
3483e12c5d1SDavid du Colombier putc(' ', f);
3493e12c5d1SDavid du Colombier --npad;
3503e12c5d1SDavid du Colombier }
3513e12c5d1SDavid du Colombier fputs(sign, f);
3523e12c5d1SDavid du Colombier fputs(prefix, f);
3533e12c5d1SDavid du Colombier }
3543e12c5d1SDavid du Colombier while(nlzero){
3553e12c5d1SDavid du Colombier putc('0', f);
3563e12c5d1SDavid du Colombier --nlzero;
3573e12c5d1SDavid du Colombier }
3583e12c5d1SDavid du Colombier while(dp!=digits) putc(*--dp, f);
3593e12c5d1SDavid du Colombier }
3603e12c5d1SDavid du Colombier else{
3613e12c5d1SDavid du Colombier fputs(sign, f);
3623e12c5d1SDavid du Colombier fputs(prefix, f);
3633e12c5d1SDavid du Colombier while(nlzero){
3643e12c5d1SDavid du Colombier putc('0', f);
3653e12c5d1SDavid du Colombier --nlzero;
3663e12c5d1SDavid du Colombier }
3673e12c5d1SDavid du Colombier while(dp != digits) putc(*--dp, f);
3683e12c5d1SDavid du Colombier while(npad){
3693e12c5d1SDavid du Colombier putc(' ', f);
3703e12c5d1SDavid du Colombier --npad;
3713e12c5d1SDavid du Colombier }
3723e12c5d1SDavid du Colombier }
3733e12c5d1SDavid du Colombier return nout;
3743e12c5d1SDavid du Colombier }
3753e12c5d1SDavid du Colombier
3763e12c5d1SDavid du Colombier static int
ocvt_X(FILE * f,va_list * args,int flags,int width,int precision)3773e12c5d1SDavid du Colombier ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
3783e12c5d1SDavid du Colombier {
3793e12c5d1SDavid du Colombier return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
3803e12c5d1SDavid du Colombier }
3813e12c5d1SDavid du Colombier
3823e12c5d1SDavid du Colombier static int
ocvt_d(FILE * f,va_list * args,int flags,int width,int precision)3833e12c5d1SDavid du Colombier ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
3843e12c5d1SDavid du Colombier {
3853e12c5d1SDavid du Colombier return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
3863e12c5d1SDavid du Colombier }
3873e12c5d1SDavid du Colombier
3883e12c5d1SDavid du Colombier static int
ocvt_o(FILE * f,va_list * args,int flags,int width,int precision)3893e12c5d1SDavid du Colombier ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
3903e12c5d1SDavid du Colombier {
3913e12c5d1SDavid du Colombier return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
3923e12c5d1SDavid du Colombier }
3933e12c5d1SDavid du Colombier
3943e12c5d1SDavid du Colombier static int
ocvt_p(FILE * f,va_list * args,int flags,int width,int precision)3953e12c5d1SDavid du Colombier ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
3963e12c5d1SDavid du Colombier {
3973e12c5d1SDavid du Colombier return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
3989a747e4fSDavid du Colombier "0123456789ABCDEF", "0x");
3993e12c5d1SDavid du Colombier }
4003e12c5d1SDavid du Colombier
4013e12c5d1SDavid du Colombier static int
ocvt_u(FILE * f,va_list * args,int flags,int width,int precision)4023e12c5d1SDavid du Colombier ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
4033e12c5d1SDavid du Colombier {
4043e12c5d1SDavid du Colombier return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
4053e12c5d1SDavid du Colombier }
4063e12c5d1SDavid du Colombier
4073e12c5d1SDavid du Colombier static int
ocvt_x(FILE * f,va_list * args,int flags,int width,int precision)4083e12c5d1SDavid du Colombier ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
4093e12c5d1SDavid du Colombier {
4103e12c5d1SDavid du Colombier return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
4113e12c5d1SDavid du Colombier }
4123e12c5d1SDavid du Colombier
4133e12c5d1SDavid du Colombier static int ocvt_flt(FILE *, va_list *, int, int, int, char);
4143e12c5d1SDavid du Colombier
4153e12c5d1SDavid du Colombier static int
ocvt_E(FILE * f,va_list * args,int flags,int width,int precision)4163e12c5d1SDavid du Colombier ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
4173e12c5d1SDavid du Colombier {
4183e12c5d1SDavid du Colombier return ocvt_flt(f, args, flags, width, precision, 'E');
4193e12c5d1SDavid du Colombier }
4203e12c5d1SDavid du Colombier
4213e12c5d1SDavid du Colombier static int
ocvt_G(FILE * f,va_list * args,int flags,int width,int precision)4223e12c5d1SDavid du Colombier ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
4233e12c5d1SDavid du Colombier {
4243e12c5d1SDavid du Colombier return ocvt_flt(f, args, flags, width, precision, 'G');
4253e12c5d1SDavid du Colombier }
4263e12c5d1SDavid du Colombier
4273e12c5d1SDavid du Colombier static int
ocvt_e(FILE * f,va_list * args,int flags,int width,int precision)4283e12c5d1SDavid du Colombier ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
4293e12c5d1SDavid du Colombier {
4303e12c5d1SDavid du Colombier return ocvt_flt(f, args, flags, width, precision, 'e');
4313e12c5d1SDavid du Colombier }
4323e12c5d1SDavid du Colombier
4333e12c5d1SDavid du Colombier static int
ocvt_f(FILE * f,va_list * args,int flags,int width,int precision)4343e12c5d1SDavid du Colombier ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
4353e12c5d1SDavid du Colombier {
4363e12c5d1SDavid du Colombier return ocvt_flt(f, args, flags, width, precision, 'f');
4373e12c5d1SDavid du Colombier }
4383e12c5d1SDavid du Colombier
4393e12c5d1SDavid du Colombier static int
ocvt_g(FILE * f,va_list * args,int flags,int width,int precision)4403e12c5d1SDavid du Colombier ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
4413e12c5d1SDavid du Colombier {
4423e12c5d1SDavid du Colombier return ocvt_flt(f, args, flags, width, precision, 'g');
4433e12c5d1SDavid du Colombier }
4443e12c5d1SDavid du Colombier
4453e12c5d1SDavid du Colombier static int
ocvt_flt(FILE * f,va_list * args,int flags,int width,int precision,char afmt)4463e12c5d1SDavid du Colombier ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
4473e12c5d1SDavid du Colombier {
4483e12c5d1SDavid du Colombier extern char *_dtoa(double, int, int, int*, int*, char **);
4493e12c5d1SDavid du Colombier int echr;
4503e12c5d1SDavid du Colombier char *digits, *edigits;
4513e12c5d1SDavid du Colombier int exponent;
4523e12c5d1SDavid du Colombier char fmt;
4533e12c5d1SDavid du Colombier int sign;
4543e12c5d1SDavid du Colombier int ndig;
4553e12c5d1SDavid du Colombier int nout, i;
4563e12c5d1SDavid du Colombier char ebuf[20]; /* no sensible machine will overflow this */
4573e12c5d1SDavid du Colombier char *eptr;
4583e12c5d1SDavid du Colombier double d;
4593e12c5d1SDavid du Colombier
4603e12c5d1SDavid du Colombier echr = 'e';
4613e12c5d1SDavid du Colombier fmt = afmt;
4623e12c5d1SDavid du Colombier d = va_arg(*args, double);
4633e12c5d1SDavid du Colombier if(precision < 0) precision = 6;
4643e12c5d1SDavid du Colombier switch(fmt){
4653e12c5d1SDavid du Colombier case 'f':
4663e12c5d1SDavid du Colombier digits = _dtoa(d, 3, precision, &exponent, &sign, &edigits);
4673e12c5d1SDavid du Colombier break;
4683e12c5d1SDavid du Colombier case 'E':
4693e12c5d1SDavid du Colombier echr = 'E';
4703e12c5d1SDavid du Colombier fmt = 'e';
4713e12c5d1SDavid du Colombier /* fall through */
4723e12c5d1SDavid du Colombier case 'e':
4733e12c5d1SDavid du Colombier digits = _dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
4743e12c5d1SDavid du Colombier break;
4753e12c5d1SDavid du Colombier case 'G':
4763e12c5d1SDavid du Colombier echr = 'E';
4773e12c5d1SDavid du Colombier /* fall through */
4783e12c5d1SDavid du Colombier case 'g':
4793e12c5d1SDavid du Colombier if (precision > 0)
4803e12c5d1SDavid du Colombier digits = _dtoa(d, 2, precision, &exponent, &sign, &edigits);
4813e12c5d1SDavid du Colombier else {
4823e12c5d1SDavid du Colombier digits = _dtoa(d, 0, precision, &exponent, &sign, &edigits);
4833e12c5d1SDavid du Colombier precision = edigits - digits;
4843e12c5d1SDavid du Colombier if (exponent > precision && exponent <= precision + 4)
4853e12c5d1SDavid du Colombier precision = exponent;
4863e12c5d1SDavid du Colombier }
4873e12c5d1SDavid du Colombier if(exponent >= -3 && exponent <= precision){
4883e12c5d1SDavid du Colombier fmt = 'f';
4893e12c5d1SDavid du Colombier precision -= exponent;
4903e12c5d1SDavid du Colombier }else{
4913e12c5d1SDavid du Colombier fmt = 'e';
4923e12c5d1SDavid du Colombier --precision;
4933e12c5d1SDavid du Colombier }
4943e12c5d1SDavid du Colombier break;
4953e12c5d1SDavid du Colombier }
4963e12c5d1SDavid du Colombier if (exponent == 9999) {
4973e12c5d1SDavid du Colombier /* Infinity or Nan */
4983e12c5d1SDavid du Colombier precision = 0;
4993e12c5d1SDavid du Colombier exponent = edigits - digits;
5003e12c5d1SDavid du Colombier fmt = 'f';
5013e12c5d1SDavid du Colombier }
5023e12c5d1SDavid du Colombier ndig = edigits-digits;
5033e12c5d1SDavid du Colombier if(ndig == 0) {
5043e12c5d1SDavid du Colombier ndig = 1;
5053e12c5d1SDavid du Colombier digits = "0";
5063e12c5d1SDavid du Colombier }
5073e12c5d1SDavid du Colombier if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */
5083e12c5d1SDavid du Colombier if(fmt == 'f'){
5093e12c5d1SDavid du Colombier if(precision+exponent > ndig) {
5103e12c5d1SDavid du Colombier precision = ndig - exponent;
5113e12c5d1SDavid du Colombier if(precision < 0)
5123e12c5d1SDavid du Colombier precision = 0;
5133e12c5d1SDavid du Colombier }
5143e12c5d1SDavid du Colombier }
5153e12c5d1SDavid du Colombier else{
5163e12c5d1SDavid du Colombier if(precision > ndig-1) precision = ndig-1;
5173e12c5d1SDavid du Colombier }
5183e12c5d1SDavid du Colombier }
5193e12c5d1SDavid du Colombier nout = precision; /* digits after decimal point */
5203e12c5d1SDavid du Colombier if(precision!=0 || flags&ALT) nout++; /* decimal point */
5213e12c5d1SDavid du Colombier if(fmt=='f' && exponent>0) nout += exponent; /* digits before decimal point */
5223e12c5d1SDavid du Colombier else nout++; /* there's always at least one */
5233e12c5d1SDavid du Colombier if(sign || flags&(SPACE|SIGN)) nout++; /* sign */
5243e12c5d1SDavid du Colombier if(fmt != 'f'){ /* exponent */
5253e12c5d1SDavid du Colombier eptr = ebuf;
5263e12c5d1SDavid du Colombier for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
5273e12c5d1SDavid du Colombier *eptr++ = '0' + i%10;
5283e12c5d1SDavid du Colombier while(eptr<ebuf+2) *eptr++ = '0';
5293e12c5d1SDavid du Colombier nout += eptr-ebuf+2; /* e+99 */
5303e12c5d1SDavid du Colombier }
531219b2ee8SDavid du Colombier if(!(flags&ZPAD) && !(flags&LEFT))
5323e12c5d1SDavid du Colombier while(nout < width){
5333e12c5d1SDavid du Colombier putc(' ', f);
5343e12c5d1SDavid du Colombier nout++;
5353e12c5d1SDavid du Colombier }
5363e12c5d1SDavid du Colombier if(sign) putc('-', f);
5373e12c5d1SDavid du Colombier else if(flags&SIGN) putc('+', f);
5383e12c5d1SDavid du Colombier else if(flags&SPACE) putc(' ', f);
539*7def40e1SDavid du Colombier if((flags&ZPAD) && !(flags&LEFT))
540219b2ee8SDavid du Colombier while(nout < width){
541219b2ee8SDavid du Colombier putc('0', f);
542219b2ee8SDavid du Colombier nout++;
543219b2ee8SDavid du Colombier }
5443e12c5d1SDavid du Colombier if(fmt == 'f'){
5453e12c5d1SDavid du Colombier for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
5463e12c5d1SDavid du Colombier if(i == 0) putc('0', f);
5473e12c5d1SDavid du Colombier if(precision>0 || flags&ALT) putc('.', f);
5483e12c5d1SDavid du Colombier for(i=0; i!=precision; i++)
5493e12c5d1SDavid du Colombier putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
5503e12c5d1SDavid du Colombier }
5513e12c5d1SDavid du Colombier else{
5523e12c5d1SDavid du Colombier putc(digits[0], f);
5533e12c5d1SDavid du Colombier if(precision>0 || flags&ALT) putc('.', f);
5543e12c5d1SDavid du Colombier for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
5553e12c5d1SDavid du Colombier }
5563e12c5d1SDavid du Colombier if(fmt != 'f'){
5573e12c5d1SDavid du Colombier putc(echr, f);
5583e12c5d1SDavid du Colombier putc(exponent<=0?'-':'+', f);
5593e12c5d1SDavid du Colombier while(eptr>ebuf) putc(*--eptr, f);
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier while(nout < width){
5623e12c5d1SDavid du Colombier putc(' ', f);
5633e12c5d1SDavid du Colombier nout++;
5643e12c5d1SDavid du Colombier }
5653e12c5d1SDavid du Colombier return nout;
5663e12c5d1SDavid du Colombier }
567