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