2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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_pointer)
|
|
|
|
{
|
|
|
|
int flags, width, precision;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
qlock(&_stdiolk);
|
|
|
|
|
|
|
|
va_copy(args, args_pointer);
|
|
|
|
|
|
|
|
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[(uint8_t)(*s)])
|
|
|
|
nprint += (*ocvt[(uint8_t)(*s++)])(f, &args, flags, width, precision);
|
|
|
|
else if(*s){
|
|
|
|
putc(*s++, f);
|
|
|
|
nprint++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
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, int16_t *) = nprint;
|
|
|
|
else if(flags&LONG)
|
|
|
|
*va_arg(*args, int32_t *) = 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;
|
|
|
|
uint64_t snum;
|
|
|
|
unsigned long num;
|
|
|
|
int nout, npad, nlzero;
|
|
|
|
|
|
|
|
if(sgned){
|
|
|
|
if(flags&PTR) snum = (uintptr_t)va_arg(*args, void *);
|
|
|
|
else if(flags&SHORT) snum = va_arg(*args, int);
|
|
|
|
else if(flags&LONG) snum = va_arg(*args, int32_t);
|
|
|
|
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 = (uintptr_t)va_arg(*args, void *);
|
|
|
|
else if(flags&SHORT) num = va_arg(*args, int);
|
|
|
|
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;
|
|
|
|
|
2017-05-19 01:33:09 +02:00
|
|
|
digits = nil;
|
|
|
|
eptr = nil;
|
2016-11-25 17:18:40 +01:00
|
|
|
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;
|
|
|
|
}
|