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