This patch fixes vsnprintf and snprintf's return codes to be the number of characters that would have been printed had there been enough room, as is apparently required by C99. Notes: Wed Jan 20 15:47:39 EST 2010 geoff C99 is wrong: functions should return the count of characters they actually produced, not the number that they wish they could have produced, had the stars been aligned just so. Dunno what to do with this patch. Blessing ANSI's increasingly- stupid decisions doesn't seem like the right answer. Reference: /n/sources/patch/maybe/ape-vsnprintf Date: Thu Feb 12 01:32:53 CET 2009 Signed-off-by: nwf@cs.jhu.edu Reviewed-by: geoff --- /sys/src/ape/lib/ap/stdio/iolib.h Thu Feb 12 01:32:32 2009 +++ /sys/src/ape/lib/ap/stdio/iolib.h Thu Feb 12 01:32:31 2009 @@ -42,3 +42,5 @@ FILE *_IO_sopenr(const char*); FILE *_IO_sopenw(void); char *_IO_sclose(FILE *); + +int _vfprintf(FILE *f, const char *s, va_list args); --- /sys/src/ape/lib/ap/stdio/mkfile Thu Feb 12 01:32:32 2009 +++ /sys/src/ape/lib/ap/stdio/mkfile Thu Feb 12 01:32:32 2009 @@ -6,6 +6,7 @@ _IO_putc.$O\ _dtoa.$O\ _fconv.$O\ + _vfprintf.$O \ clearerr.$O\ atexit.$O\ exit.$O\ --- /sys/src/ape/lib/ap/stdio/snprintf.c Thu Feb 12 01:32:33 2009 +++ /sys/src/ape/lib/ap/stdio/snprintf.c Thu Feb 12 01:32:33 2009 @@ -10,7 +10,7 @@ return 0; setvbuf(f, buf, _IOFBF, nbuf); va_start(args, fmt); - n=vfprintf(f, fmt, args); + n=_vfprintf(f, fmt, args); va_end(args); _IO_sclose(f); return n; --- /sys/src/ape/lib/ap/stdio/vfprintf.c Thu Feb 12 01:32:34 2009 +++ /sys/src/ape/lib/ap/stdio/vfprintf.c Thu Feb 12 01:32:33 2009 @@ -2,565 +2,9 @@ * 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; + int ret = _vfprintf(f,s,args); + return ferror(f) ? -1 : ret; } --- /sys/src/ape/lib/ap/stdio/vprintf.c Thu Feb 12 01:32:34 2009 +++ /sys/src/ape/lib/ap/stdio/vprintf.c Thu Feb 12 01:32:34 2009 @@ -3,5 +3,6 @@ */ #include "iolib.h" int vprintf(const char *fmt, va_list args){ - return vfprintf(stdout, fmt, args); + int ret = _vfprintf(stdout, fmt, args); + return ferror(stdout) ? -1 : ret; } --- /sys/src/ape/lib/ap/stdio/vsnprintf.c Thu Feb 12 01:32:35 2009 +++ /sys/src/ape/lib/ap/stdio/vsnprintf.c Thu Feb 12 01:32:34 2009 @@ -8,7 +8,7 @@ if(f==NULL) return 0; setvbuf(f, buf, _IOFBF, nbuf); - n=vfprintf(f, fmt, args); + n=_vfprintf(f, fmt, args); _IO_sclose(f); - return n; + return n; // no ferror() check. } --- /sys/src/ape/lib/ap/stdio/vsprintf.c Thu Feb 12 01:32:35 2009 +++ /sys/src/ape/lib/ap/stdio/vsprintf.c Thu Feb 12 01:32:35 2009 @@ -8,7 +8,8 @@ if(f==NULL) return 0; setvbuf(f, buf, _IOFBF, 100000); - n=vfprintf(f, fmt, args); + n=_vfprintf(f, fmt, args); + int err = ferror(f); _IO_sclose(f); - return n; + return err ? -1 : n; } --- /sys/src/ape/lib/ap/stdio/_vfprintf.c Thu Jan 1 00:00:00 1970 +++ /sys/src/ape/lib/ap/stdio/_vfprintf.c Thu Feb 12 01:32:35 2009 @@ -0,0 +1,567 @@ +/* + * 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 nprint; + // ferror(f)? -1: +} + +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; +}