xref: /plan9/sys/src/ape/lib/ap/stdio/vfprintf.c (revision 7def40e1c78937471995a3444a833ed191304442)
1 /*
2  * pANS stdio -- vfprintf
3  */
4 #include "iolib.h"
5 #include <stdarg.h>
6 #include <math.h>
7 #include <stdlib.h>
8 #include <string.h>
9 /*
10  * Leading flags
11  */
12 #define	SPACE	1		/* ' ' prepend space if no sign printed */
13 #define	ALT	2		/* '#' use alternate conversion */
14 #define	SIGN	4		/* '+' prepend sign, even if positive */
15 #define	LEFT	8		/* '-' left-justify */
16 #define	ZPAD	16		/* '0' zero-pad */
17 /*
18  * Trailing flags
19  */
20 #define	SHORT	32		/* 'h' convert a short integer */
21 #define	LONG	64		/* 'l' convert a long integer */
22 #define	LDBL	128		/* 'L' convert a long double */
23 #define	PTR	256		/*     convert a void * (%p) */
24 #define	VLONG	512		/* 'll' convert a long long integer */
25 
26 static int lflag[] = {	/* leading flags */
27 0,	0,	0,	0,	0,	0,	0,	0,	/* ^@ ^A ^B ^C ^D ^E ^F ^G */
28 0,	0,	0,	0,	0,	0,	0,	0,	/* ^H ^I ^J ^K ^L ^M ^N ^O */
29 0,	0,	0,	0,	0,	0,	0,	0,	/* ^P ^Q ^R ^S ^T ^U ^V ^W */
30 0,	0,	0,	0,	0,	0,	0,	0,	/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
31 SPACE,	0,	0,	ALT,	0,	0,	0,	0,	/* sp  !  "  #  $  %  &  ' */
32 0,	0,	0,	SIGN,	0,	LEFT,	0,	0,	/*  (  )  *  +  ,  -  .  / */
33 ZPAD,	0,	0,	0,	0,	0,	0,	0,	/*  0  1  2  3  4  5  6  7 */
34 0,	0,	0,	0,	0,	0,	0,	0,	/*  8  9  :  ;  <  =  >  ? */
35 0,	0,	0,	0,	0,	0,	0,	0,	/*  @  A  B  C  D  E  F  G */
36 0,	0,	0,	0,	0,	0,	0,	0,	/*  H  I  J  K  L  M  N  O */
37 0,	0,	0,	0,	0,	0,	0,	0,	/*  P  Q  R  S  T  U  V  W */
38 0,	0,	0,	0,	0,	0,	0,	0,	/*  X  Y  Z  [  \  ]  ^  _ */
39 0,	0,	0,	0,	0,	0,	0,	0,	/*  `  a  b  c  d  e  f  g */
40 0,	0,	0,	0,	0,	0,	0,	0,	/*  h  i  j  k  l  m  n  o */
41 0,	0,	0,	0,	0,	0,	0,	0,	/*  p  q  r  s  t  u  v  w */
42 0,	0,	0,	0,	0,	0,	0,	0,	/*  x  y  z  {  |  }  ~ ^? */
43 
44 0,	0,	0,	0,	0,	0,	0,	0,
45 0,	0,	0,	0,	0,	0,	0,	0,
46 0,	0,	0,	0,	0,	0,	0,	0,
47 0,	0,	0,	0,	0,	0,	0,	0,
48 0,	0,	0,	0,	0,	0,	0,	0,
49 0,	0,	0,	0,	0,	0,	0,	0,
50 0,	0,	0,	0,	0,	0,	0,	0,
51 0,	0,	0,	0,	0,	0,	0,	0,
52 0,	0,	0,	0,	0,	0,	0,	0,
53 0,	0,	0,	0,	0,	0,	0,	0,
54 0,	0,	0,	0,	0,	0,	0,	0,
55 0,	0,	0,	0,	0,	0,	0,	0,
56 0,	0,	0,	0,	0,	0,	0,	0,
57 0,	0,	0,	0,	0,	0,	0,	0,
58 0,	0,	0,	0,	0,	0,	0,	0,
59 0,	0,	0,	0,	0,	0,	0,	0,
60 };
61 
62 static int tflag[] = {	/* trailing flags */
63 0,	0,	0,	0,	0,	0,	0,	0,	/* ^@ ^A ^B ^C ^D ^E ^F ^G */
64 0,	0,	0,	0,	0,	0,	0,	0,	/* ^H ^I ^J ^K ^L ^M ^N ^O */
65 0,	0,	0,	0,	0,	0,	0,	0,	/* ^P ^Q ^R ^S ^T ^U ^V ^W */
66 0,	0,	0,	0,	0,	0,	0,	0,	/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
67 0,	0,	0,	0,	0,	0,	0,	0,	/* sp  !  "  #  $  %  &  ' */
68 0,	0,	0,	0,	0,	0,	0,	0,	/*  (  )  *  +  ,  -  .  / */
69 0,	0,	0,	0,	0,	0,	0,	0,	/*  0  1  2  3  4  5  6  7 */
70 0,	0,	0,	0,	0,	0,	0,	0,	/*  8  9  :  ;  <  =  >  ? */
71 0,	0,	0,	0,	0,	0,	0,	0,	/*  @  A  B  C  D  E  F  G */
72 0,	0,	0,	0,	LDBL,	0,	0,	0,	/*  H  I  J  K  L  M  N  O */
73 0,	0,	0,	0,	0,	0,	0,	0,	/*  P  Q  R  S  T  U  V  W */
74 0,	0,	0,	0,	0,	0,	0,	0,	/*  X  Y  Z  [  \  ]  ^  _ */
75 0,	0,	0,	0,	0,	0,	0,	0,	/*  `  a  b  c  d  e  f  g */
76 SHORT,	0,	0,	0,	LONG,	0,	0,	0,	/*  h  i  j  k  l  m  n  o */
77 0,	0,	0,	0,	0,	0,	0,	0,	/*  p  q  r  s  t  u  v  w */
78 0,	0,	0,	0,	0,	0,	0,	0,	/*  x  y  z  {  |  }  ~ ^? */
79 
80 0,	0,	0,	0,	0,	0,	0,	0,
81 0,	0,	0,	0,	0,	0,	0,	0,
82 0,	0,	0,	0,	0,	0,	0,	0,
83 0,	0,	0,	0,	0,	0,	0,	0,
84 0,	0,	0,	0,	0,	0,	0,	0,
85 0,	0,	0,	0,	0,	0,	0,	0,
86 0,	0,	0,	0,	0,	0,	0,	0,
87 0,	0,	0,	0,	0,	0,	0,	0,
88 0,	0,	0,	0,	0,	0,	0,	0,
89 0,	0,	0,	0,	0,	0,	0,	0,
90 0,	0,	0,	0,	0,	0,	0,	0,
91 0,	0,	0,	0,	0,	0,	0,	0,
92 0,	0,	0,	0,	0,	0,	0,	0,
93 0,	0,	0,	0,	0,	0,	0,	0,
94 0,	0,	0,	0,	0,	0,	0,	0,
95 0,	0,	0,	0,	0,	0,	0,	0,
96 };
97 
98 static int ocvt_E(FILE *, va_list *, int, int, int);
99 static int ocvt_G(FILE *, va_list *, int, int, int);
100 static int ocvt_X(FILE *, va_list *, int, int, int);
101 static int ocvt_c(FILE *, va_list *, int, int, int);
102 static int ocvt_d(FILE *, va_list *, int, int, int);
103 static int ocvt_e(FILE *, va_list *, int, int, int);
104 static int ocvt_f(FILE *, va_list *, int, int, int);
105 static int ocvt_g(FILE *, va_list *, int, int, int);
106 static int ocvt_n(FILE *, va_list *, int, int, int);
107 static int ocvt_o(FILE *, va_list *, int, int, int);
108 static int ocvt_p(FILE *, va_list *, int, int, int);
109 static int ocvt_s(FILE *, va_list *, int, int, int);
110 static int ocvt_u(FILE *, va_list *, int, int, int);
111 static int ocvt_x(FILE *, va_list *, int, int, int);
112 
113 static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
114 0,	0,	0,	0,	0,	0,	0,	0,	/* ^@ ^A ^B ^C ^D ^E ^F ^G */
115 0,	0,	0,	0,	0,	0,	0,	0,	/* ^H ^I ^J ^K ^L ^M ^N ^O */
116 0,	0,	0,	0,	0,	0,	0,	0,	/* ^P ^Q ^R ^S ^T ^U ^V ^W */
117 0,	0,	0,	0,	0,	0,	0,	0,	/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
118 0,	0,	0,	0,	0,	0,	0,	0,	/* sp  !  "  #  $  %  &  ' */
119 0,	0,	0,	0,	0,	0,	0,	0,	/*  (  )  *  +  ,  -  .  / */
120 0,	0,	0,	0,	0,	0,	0,	0,	/*  0  1  2  3  4  5  6  7 */
121 0,	0,	0,	0,	0,	0,	0,	0,	/*  8  9  :  ;  <  =  >  ? */
122 0,	0,	0,	0,	0,	ocvt_E,	0,	ocvt_G,	/*  @  A  B  C  D  E  F  G */
123 0,	0,	0,	0,	0,	0,	0,	0,	/*  H  I  J  K  L  M  N  O */
124 0,	0,	0,	0,	0,	0,	0,	0,	/*  P  Q  R  S  T  U  V  W */
125 ocvt_X,	0,	0,	0,	0,	0,	0,	0,	/*  X  Y  Z  [  \  ]  ^  _ */
126 0,	0,	0,	ocvt_c,	ocvt_d,	ocvt_e,	ocvt_f,	ocvt_g,	/*  `  a  b  c  d  e  f  g */
127 0,	ocvt_d,	0,	0,	0,	0,	ocvt_n,	ocvt_o,	/*  h  i  j  k  l  m  n  o */
128 ocvt_p,	0,	0,	ocvt_s,	0,	ocvt_u,	0,	0,	/*  p  q  r  s  t  u  v  w */
129 ocvt_x,	0,	0,	0,	0,	0,	0,	0,	/*  x  y  z  {  |  }  ~ ^? */
130 
131 0,	0,	0,	0,	0,	0,	0,	0,
132 0,	0,	0,	0,	0,	0,	0,	0,
133 0,	0,	0,	0,	0,	0,	0,	0,
134 0,	0,	0,	0,	0,	0,	0,	0,
135 0,	0,	0,	0,	0,	0,	0,	0,
136 0,	0,	0,	0,	0,	0,	0,	0,
137 0,	0,	0,	0,	0,	0,	0,	0,
138 0,	0,	0,	0,	0,	0,	0,	0,
139 0,	0,	0,	0,	0,	0,	0,	0,
140 0,	0,	0,	0,	0,	0,	0,	0,
141 0,	0,	0,	0,	0,	0,	0,	0,
142 0,	0,	0,	0,	0,	0,	0,	0,
143 0,	0,	0,	0,	0,	0,	0,	0,
144 0,	0,	0,	0,	0,	0,	0,	0,
145 0,	0,	0,	0,	0,	0,	0,	0,
146 0,	0,	0,	0,	0,	0,	0,	0,
147 };
148 
149 static int nprint;
150 
151 int
vfprintf(FILE * f,const char * s,va_list args)152 vfprintf(FILE *f, const char *s, va_list args)
153 {
154 	int tfl, flags, width, precision;
155 
156 	nprint = 0;
157 	while(*s){
158 		if(*s != '%'){
159 			putc(*s++, f);
160 			nprint++;
161 			continue;
162 		}
163 		s++;
164 		flags = 0;
165 		while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
166 		if(*s == '*'){
167 			width = va_arg(args, int);
168 			s++;
169 			if(width<0){
170 				flags |= LEFT;
171 				width = -width;
172 			}
173 		}
174 		else{
175 			width = 0;
176 			while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
177 		}
178 		if(*s == '.'){
179 			s++;
180 			if(*s == '*'){
181 				precision = va_arg(args, int);
182 				s++;
183 			}
184 			else{
185 				precision = 0;
186 				while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
187 			}
188 		}
189 		else
190 			precision = -1;
191 		while(tfl = tflag[*s&_IO_CHMASK]){
192 			if(tfl == LONG && (flags & LONG)){
193 				flags &= ~LONG;
194 				tfl = VLONG;
195 			}
196 			flags |= tfl;
197 			s++;
198 		}
199 		if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
200 		else if(*s){
201 			putc(*s++, f);
202 			nprint++;
203 		}
204 	}
205 	return ferror(f)? -1: nprint;;
206 }
207 
208 static int
ocvt_c(FILE * f,va_list * args,int flags,int width,int precision)209 ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
210 {
211 #pragma ref precision
212 	int i;
213 
214 	if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
215 	putc((unsigned char)va_arg(*args, int), f);
216 	if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
217 	return width<1 ? 1 : width;
218 }
219 
220 static int
ocvt_s(FILE * f,va_list * args,int flags,int width,int precision)221 ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
222 {
223 	int i, n = 0;
224 	char *s;
225 
226 	s = va_arg(*args, char *);
227 	if(!s)
228 		s = "";
229 	if(!(flags&LEFT)){
230 		if(precision >= 0)
231 			for(i=0; i!=precision && s[i]; i++);
232 		else
233 			for(i=0; s[i]; i++);
234 		for(; i<width; i++){
235 			putc(' ', f);
236 			n++;
237 		}
238 	}
239 	if(precision >= 0){
240 		for(i=0; i!=precision && *s; i++){
241 			putc(*s++, f);
242 			n++;
243 		}
244 	} else{
245 		for(i=0;*s;i++){
246 			putc(*s++, f);
247 			n++;
248 		}
249 	}
250 	if(flags&LEFT){
251 		for(; i<width; i++){
252 			putc(' ', f);
253 			n++;
254 		}
255 	}
256 	return n;
257 }
258 
259 static int
ocvt_n(FILE * f,va_list * args,int flags,int width,int precision)260 ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
261 {
262 #pragma ref f
263 #pragma ref width
264 #pragma ref precision
265 	if(flags&SHORT)
266 		*va_arg(*args, short *) = nprint;
267 	else if(flags&LONG)
268 		*va_arg(*args, long *) = nprint;
269 	else if(flags&VLONG)
270 		*va_arg(*args, long long*) = nprint;
271 	else
272 		*va_arg(*args, int *) = nprint;
273 	return 0;
274 }
275 
276 /*
277  * Generic fixed-point conversion
278  *	f is the output FILE *;
279  *	args is the va_list * from which to get the number;
280  *	flags, width and precision are the results of printf-cracking;
281  *	radix is the number base to print in;
282  *	alphabet is the set of digits to use;
283  *	prefix is the prefix to print before non-zero numbers when
284  *	using ``alternate form.''
285  */
286 static int
ocvt_fixed(FILE * f,va_list * args,int flags,int width,int precision,int radix,int sgned,char alphabet[],char * prefix)287 ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
288 	int radix, int sgned, char alphabet[], char *prefix)
289 {
290 	char digits[128];	/* no reasonable machine will ever overflow this */
291 	char *sign;
292 	char *dp;
293 	long long snum;
294 	unsigned long long num;
295 	int nout, npad, nlzero;
296 
297 	if(sgned){
298 		if(flags&PTR) snum = (long)va_arg(*args, void *);
299 		else if(flags&SHORT) snum = va_arg(*args, short);
300 		else if(flags&LONG) snum = va_arg(*args, long);
301 		else if(flags&VLONG) snum = va_arg(*args, long long);
302 		else snum = va_arg(*args, int);
303 		if(snum < 0){
304 			sign = "-";
305 			num = -snum;
306 		} else{
307 			if(flags&SIGN) sign = "+";
308 			else if(flags&SPACE) sign = " ";
309 			else sign = "";
310 			num = snum;
311 		}
312 	} else {
313 		sign = "";
314 		if(flags&PTR) num = (long)va_arg(*args, void *);
315 		else if(flags&SHORT) num = va_arg(*args, unsigned short);
316 		else if(flags&LONG) num = va_arg(*args, unsigned long);
317 		else if(flags&VLONG) num = va_arg(*args, unsigned long long);
318 		else num = va_arg(*args, unsigned int);
319 	}
320 	if(num == 0) prefix = "";
321 	dp = digits;
322 	do{
323 		*dp++ = alphabet[num%radix];
324 		num /= radix;
325 	}while(num);
326 	if(precision==0 && dp-digits==1 && dp[-1]=='0')
327 		dp--;
328 	nlzero = precision-(dp-digits);
329 	if(nlzero < 0) nlzero = 0;
330 	if(flags&ALT){
331 		if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
332 	}
333 	else prefix = "";
334 	nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
335 	npad = width-nout;
336 	if(npad < 0) npad = 0;
337 	nout += npad;
338 	if(!(flags&LEFT)){
339 		if(flags&ZPAD && precision <= 0){
340 			fputs(sign, f);
341 			fputs(prefix, f);
342 			while(npad){
343 				putc('0', f);
344 				--npad;
345 			}
346 		} else{
347 			while(npad){
348 				putc(' ', f);
349 				--npad;
350 			}
351 			fputs(sign, f);
352 			fputs(prefix, f);
353 		}
354 		while(nlzero){
355 			putc('0', f);
356 			--nlzero;
357 		}
358 		while(dp!=digits) putc(*--dp, f);
359 	}
360 	else{
361 		fputs(sign, f);
362 		fputs(prefix, f);
363 		while(nlzero){
364 			putc('0', f);
365 			--nlzero;
366 		}
367 		while(dp != digits) putc(*--dp, f);
368 		while(npad){
369 			putc(' ', f);
370 			--npad;
371 		}
372 	}
373 	return nout;
374 }
375 
376 static int
ocvt_X(FILE * f,va_list * args,int flags,int width,int precision)377 ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
378 {
379 	return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
380 }
381 
382 static int
ocvt_d(FILE * f,va_list * args,int flags,int width,int precision)383 ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
384 {
385 	return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
386 }
387 
388 static int
ocvt_o(FILE * f,va_list * args,int flags,int width,int precision)389 ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
390 {
391 	return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
392 }
393 
394 static int
ocvt_p(FILE * f,va_list * args,int flags,int width,int precision)395 ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
396 {
397 	return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
398 		"0123456789ABCDEF", "0x");
399 }
400 
401 static int
ocvt_u(FILE * f,va_list * args,int flags,int width,int precision)402 ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
403 {
404 	return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
405 }
406 
407 static int
ocvt_x(FILE * f,va_list * args,int flags,int width,int precision)408 ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
409 {
410 	return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
411 }
412 
413 static int ocvt_flt(FILE *, va_list *, int, int, int, char);
414 
415 static int
ocvt_E(FILE * f,va_list * args,int flags,int width,int precision)416 ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
417 {
418 	return ocvt_flt(f, args, flags, width, precision, 'E');
419 }
420 
421 static int
ocvt_G(FILE * f,va_list * args,int flags,int width,int precision)422 ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
423 {
424 	return ocvt_flt(f, args, flags, width, precision, 'G');
425 }
426 
427 static int
ocvt_e(FILE * f,va_list * args,int flags,int width,int precision)428 ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
429 {
430 	return ocvt_flt(f, args, flags, width, precision, 'e');
431 }
432 
433 static int
ocvt_f(FILE * f,va_list * args,int flags,int width,int precision)434 ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
435 {
436 	return ocvt_flt(f, args, flags, width, precision, 'f');
437 }
438 
439 static int
ocvt_g(FILE * f,va_list * args,int flags,int width,int precision)440 ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
441 {
442 	return ocvt_flt(f, args, flags, width, precision, 'g');
443 }
444 
445 static int
ocvt_flt(FILE * f,va_list * args,int flags,int width,int precision,char afmt)446 ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
447 {
448 	extern char *_dtoa(double, int, int, int*, int*, char **);
449 	int echr;
450 	char *digits, *edigits;
451 	int exponent;
452 	char fmt;
453 	int sign;
454 	int ndig;
455 	int nout, i;
456 	char ebuf[20];	/* no sensible machine will overflow this */
457 	char *eptr;
458 	double d;
459 
460 	echr = 'e';
461 	fmt = afmt;
462 	d = va_arg(*args, double);
463 	if(precision < 0) precision = 6;
464 	switch(fmt){
465 	case 'f':
466 		digits = _dtoa(d, 3, precision, &exponent, &sign, &edigits);
467 		break;
468 	case 'E':
469 		echr = 'E';
470 		fmt = 'e';
471 		/* fall through */
472 	case 'e':
473 		digits = _dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
474 		break;
475 	case 'G':
476 		echr = 'E';
477 		/* fall through */
478 	case 'g':
479 		if (precision > 0)
480 			digits = _dtoa(d, 2, precision, &exponent, &sign, &edigits);
481 		else {
482 			digits = _dtoa(d, 0, precision, &exponent, &sign, &edigits);
483 			precision = edigits - digits;
484 			if (exponent > precision && exponent <= precision + 4)
485 				precision = exponent;
486 			}
487 		if(exponent >= -3 && exponent <= precision){
488 			fmt = 'f';
489 			precision -= exponent;
490 		}else{
491 			fmt = 'e';
492 			--precision;
493 		}
494 		break;
495 	}
496 	if (exponent == 9999) {
497 		/* Infinity or Nan */
498 		precision = 0;
499 		exponent = edigits - digits;
500 		fmt = 'f';
501 	}
502 	ndig = edigits-digits;
503 	if(ndig == 0) {
504 		ndig = 1;
505 		digits = "0";
506 	}
507 	if((afmt=='g' || afmt=='G') && !(flags&ALT)){	/* knock off trailing zeros */
508 		if(fmt == 'f'){
509 			if(precision+exponent > ndig) {
510 				precision = ndig - exponent;
511 				if(precision < 0)
512 					precision = 0;
513 			}
514 		}
515 		else{
516 			if(precision > ndig-1) precision = ndig-1;
517 		}
518 	}
519 	nout = precision;				/* digits after decimal point */
520 	if(precision!=0 || flags&ALT) nout++;		/* decimal point */
521 	if(fmt=='f' && exponent>0) nout += exponent;	/* digits before decimal point */
522 	else nout++;					/* there's always at least one */
523 	if(sign || flags&(SPACE|SIGN)) nout++;		/* sign */
524 	if(fmt != 'f'){					/* exponent */
525 		eptr = ebuf;
526 		for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
527 			*eptr++ = '0' + i%10;
528 		while(eptr<ebuf+2) *eptr++ = '0';
529 		nout += eptr-ebuf+2;			/* e+99 */
530 	}
531 	if(!(flags&ZPAD) && !(flags&LEFT))
532 		while(nout < width){
533 			putc(' ', f);
534 			nout++;
535 		}
536 	if(sign) putc('-', f);
537 	else if(flags&SIGN) putc('+', f);
538 	else if(flags&SPACE) putc(' ', f);
539 	if((flags&ZPAD) && !(flags&LEFT))
540 		while(nout < width){
541 			putc('0', f);
542 			nout++;
543 		}
544 	if(fmt == 'f'){
545 		for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
546 		if(i == 0) putc('0', f);
547 		if(precision>0 || flags&ALT) putc('.', f);
548 		for(i=0; i!=precision; i++)
549 			putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
550 	}
551 	else{
552 		putc(digits[0], f);
553 		if(precision>0 || flags&ALT) putc('.', f);
554 		for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
555 	}
556 	if(fmt != 'f'){
557 		putc(echr, f);
558 		putc(exponent<=0?'-':'+', f);
559 		while(eptr>ebuf) putc(*--eptr, f);
560 	}
561 	while(nout < width){
562 		putc(' ', f);
563 		nout++;
564 	}
565 	return nout;
566 }
567