* decl.c (initialize_local_var): Handle static variables here.
[official-gcc.git] / libio / iovfprintf.c
blob755334c2bf2333e917b34fb2b5f2762bb92fb100
1 /*
2 Copyright (C) 1993 Free Software Foundation
4 This file is part of the GNU IO Library. This library is free
5 software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this library; see the file COPYING. If not, write to the Free
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does not cause
21 the resulting executable to be covered by the GNU General Public License.
22 This exception does not however invalidate any other reasons why
23 the executable file might be covered by the GNU General Public License. */
26 * Copyright (c) 1990 Regents of the University of California.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms are permitted
30 * provided that the above copyright notice and this paragraph are
31 * duplicated in all such forms and that any documentation,
32 * advertising materials, and other materials related to such
33 * distribution and use acknowledge that the software was developed
34 * by the University of California, Berkeley. The name of the
35 * University may not be used to endorse or promote products derived
36 * from this software without specific prior written permission.
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
38 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
39 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 #if defined(LIBC_SCCS) && !defined(lint)
44 static char sccsid[] = "%W% (Berkeley) %G%";
45 #endif /* LIBC_SCCS and not lint */
48 * Actual printf innards.
50 * This code is large and complicated...
53 #include <sys/types.h>
54 #include "libioP.h"
55 #include <string.h>
56 #ifdef __STDC__
57 #include <stdarg.h>
58 #else
59 #include <varargs.h>
60 #endif
62 #ifndef _IO_USE_DTOA
63 int __cvt_double __P((double number, register int prec, int flags, int *signp, int fmtch, char *startp, char *endp));
64 #endif
67 * Define FLOATING_POINT to get floating point.
69 #ifndef NO_FLOATING_POINT
70 #define FLOATING_POINT
71 #endif
73 /* end of configuration stuff */
77 * Helper "class" for `fprintf to unbuffered': creates a
78 * temporary buffer. */
80 struct helper_file
82 struct _IO_FILE_plus _f;
83 _IO_FILE *_put_stream;
86 static int
87 _IO_helper_overflow (fp, c)
88 _IO_FILE *fp;
89 int c;
91 _IO_FILE *target = ((struct helper_file*)fp)->_put_stream;
92 int used = fp->_IO_write_ptr - fp->_IO_write_base;
93 if (used)
95 _IO_sputn(target, fp->_IO_write_base, used);
96 fp->_IO_write_ptr -= used;
98 return _IO_putc (c, fp);
101 static struct _IO_jump_t _IO_helper_jumps = {
102 JUMP_INIT_DUMMY,
103 JUMP_INIT(finish, _IO_default_finish),
104 JUMP_INIT(overflow, _IO_helper_overflow),
105 JUMP_INIT(underflow, _IO_default_underflow),
106 JUMP_INIT(uflow, _IO_default_uflow),
107 JUMP_INIT(pbackfail, _IO_default_pbackfail),
108 JUMP_INIT(xsputn, _IO_default_xsputn),
109 JUMP_INIT(xsgetn, _IO_default_xsgetn),
110 JUMP_INIT(seekoff, _IO_default_seekoff),
111 JUMP_INIT(seekpos, _IO_default_seekpos),
112 JUMP_INIT(setbuf, _IO_default_setbuf),
113 JUMP_INIT(sync, _IO_default_sync),
114 JUMP_INIT(doallocate, _IO_default_doallocate),
115 JUMP_INIT(read, _IO_default_read),
116 JUMP_INIT(write, _IO_default_write),
117 JUMP_INIT(seek, _IO_default_seek),
118 JUMP_INIT(close, _IO_default_close),
119 JUMP_INIT(stat, _IO_default_stat)
122 static int
123 helper_vfprintf (fp, fmt0, ap)
124 _IO_FILE *fp;
125 char const *fmt0;
126 _IO_va_list ap;
128 char buf[_IO_BUFSIZ];
129 struct helper_file helper;
130 register _IO_FILE *hp = (_IO_FILE*)&helper;
131 int result, to_flush;
133 /* initialize helper */
134 helper._put_stream = fp;
135 hp->_IO_write_base = buf;
136 hp->_IO_write_ptr = buf;
137 hp->_IO_write_end = buf+_IO_BUFSIZ;
138 hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
139 _IO_JUMPS(hp) = &_IO_helper_jumps;
141 /* Now print to helper instead. */
142 result = _IO_vfprintf(hp, fmt0, ap);
144 /* Now flush anything from the helper to the fp. */
145 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
147 if (_IO_sputn(fp, hp->_IO_write_base, to_flush) != to_flush)
148 return EOF;
150 return result;
153 #ifdef FLOATING_POINT
155 #include "floatio.h"
156 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
157 #define DEFPREC 6
158 extern double modf __P((double, double*));
160 #else /* no FLOATING_POINT */
162 #define BUF 40
164 #endif /* FLOATING_POINT */
168 * Macros for converting digits to letters and vice versa
170 #define to_digit(c) ((c) - '0')
171 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
172 #define to_char(n) ((n) + '0')
175 * Flags used during conversion.
177 #define LONGINT 0x01 /* long integer */
178 #define LONGDBL 0x02 /* long double; unimplemented */
179 #define SHORTINT 0x04 /* short integer */
180 #define ALT 0x08 /* alternate form */
181 #define LADJUST 0x10 /* left adjustment */
182 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
183 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */
186 _IO_vfprintf (fp, fmt0, ap)
187 _IO_FILE *fp;
188 char const *fmt0;
189 _IO_va_list ap;
191 register const char *fmt; /* format string */
192 register int ch; /* character from fmt */
193 register int n; /* handy integer (short term usage) */
194 register char *cp; /* handy char pointer (short term usage) */
195 const char *fmark; /* for remembering a place in fmt */
196 register int flags; /* flags as above */
197 int ret; /* return value accumulator */
198 int width; /* width from format (%8d), or 0 */
199 int prec; /* precision from format (%.3d), or -1 */
200 char sign; /* sign prefix (' ', '+', '-', or \0) */
201 #ifdef FLOATING_POINT
202 int softsign; /* temporary negative sign for floats */
203 double _double; /* double precision arguments %[eEfgG] */
204 #ifndef _IO_USE_DTOA
205 int fpprec; /* `extra' floating precision in [eEfgG] */
206 #endif
207 #endif
208 unsigned long _ulong; /* integer arguments %[diouxX] */
209 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
210 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
211 int dpad; /* extra 0 padding needed for integers */
212 int fieldsz; /* field size expanded by sign, dpad etc */
213 /* The initialization of 'size' is to suppress a warning that
214 'size' might be used unitialized. It seems gcc can't
215 quite grok this spaghetti code ... */
216 int size = 0; /* size of converted field or string */
217 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
218 char ox[2]; /* space for 0x hex-prefix */
221 * BEWARE, these `goto error' on error, and PAD uses `n'.
223 #define PRINT(ptr, len) \
224 do { if (_IO_sputn(fp,ptr, len) != len) goto error; } while (0)
225 #define PAD_SP(howmany) if (_IO_padn(fp, ' ', howmany) < (howmany)) goto error;
226 #define PAD_0(howmany) if (_IO_padn(fp, '0', howmany) < (howmany)) goto error;
229 * To extend shorts properly, we need both signed and unsigned
230 * argument extraction methods.
232 #define SARG() \
233 (flags&LONGINT ? va_arg(ap, long) : \
234 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
235 (long)va_arg(ap, int))
236 #define UARG() \
237 (flags&LONGINT ? va_arg(ap, unsigned long) : \
238 flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
239 (unsigned long)va_arg(ap, unsigned int))
241 /* optimise stderr (and other unbuffered Unix files) */
242 if (fp->_IO_file_flags & _IO_UNBUFFERED)
243 return helper_vfprintf(fp, fmt0, ap);
245 fmt = fmt0;
246 ret = 0;
249 * Scan the format for conversions (`%' character).
251 for (;;) {
252 for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
253 /* void */;
254 if ((n = fmt - fmark) != 0) {
255 PRINT(fmark, n);
256 ret += n;
258 if (ch == '\0')
259 goto done;
260 fmt++; /* skip over '%' */
262 flags = 0;
263 dprec = 0;
264 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
265 fpprec = 0;
266 #endif
267 width = 0;
268 prec = -1;
269 sign = '\0';
271 rflag: ch = *fmt++;
272 reswitch: switch (ch) {
273 case ' ':
275 * ``If the space and + flags both appear, the space
276 * flag will be ignored.''
277 * -- ANSI X3J11
279 if (!sign)
280 sign = ' ';
281 goto rflag;
282 case '#':
283 flags |= ALT;
284 goto rflag;
285 case '*':
287 * ``A negative field width argument is taken as a
288 * - flag followed by a positive field width.''
289 * -- ANSI X3J11
290 * They don't exclude field widths read from args.
292 if ((width = va_arg(ap, int)) >= 0)
293 goto rflag;
294 width = -width;
295 /* FALLTHROUGH */
296 case '-':
297 flags |= LADJUST;
298 flags &= ~ZEROPAD; /* '-' disables '0' */
299 goto rflag;
300 case '+':
301 sign = '+';
302 goto rflag;
303 case '.':
304 if ((ch = *fmt++) == '*') {
305 n = va_arg(ap, int);
306 prec = n < 0 ? -1 : n;
307 goto rflag;
309 n = 0;
310 while (is_digit(ch)) {
311 n = 10 * n + to_digit(ch);
312 ch = *fmt++;
314 prec = n < 0 ? -1 : n;
315 goto reswitch;
316 case '0':
318 * ``Note that 0 is taken as a flag, not as the
319 * beginning of a field width.''
320 * -- ANSI X3J11
322 if (!(flags & LADJUST))
323 flags |= ZEROPAD; /* '-' disables '0' */
324 goto rflag;
325 case '1': case '2': case '3': case '4':
326 case '5': case '6': case '7': case '8': case '9':
327 n = 0;
328 do {
329 n = 10 * n + to_digit(ch);
330 ch = *fmt++;
331 } while (is_digit(ch));
332 width = n;
333 goto reswitch;
334 #ifdef FLOATING_POINT
335 case 'L':
336 flags |= LONGDBL;
337 goto rflag;
338 #endif
339 case 'h':
340 flags |= SHORTINT;
341 goto rflag;
342 case 'l':
343 flags |= LONGINT;
344 goto rflag;
345 case 'c':
346 *(cp = buf) = va_arg(ap, int);
347 size = 1;
348 sign = '\0';
349 break;
350 case 'D':
351 flags |= LONGINT;
352 /*FALLTHROUGH*/
353 case 'd':
354 case 'i':
355 _ulong = SARG();
356 if ((long)_ulong < 0) {
357 _ulong = -_ulong;
358 sign = '-';
360 base = DEC;
361 goto number;
362 #ifdef FLOATING_POINT
363 case 'e':
364 case 'E':
365 case 'f':
366 case 'F':
367 case 'g':
368 case 'G':
369 _double = va_arg(ap, double);
370 #ifdef _IO_USE_DTOA
372 int fmt_flags = 0;
373 int fill = ' ';
374 if (flags & ALT)
375 fmt_flags |= _IO_SHOWPOINT;
376 if (flags & LADJUST)
377 fmt_flags |= _IO_LEFT;
378 else if (flags & ZEROPAD)
379 fmt_flags |= _IO_INTERNAL, fill = '0';
380 n = _IO_outfloat(_double, fp, ch, width,
381 prec < 0 ? DEFPREC : prec,
382 fmt_flags, sign, fill);
383 if (n < 0)
384 goto error;
385 ret += n;
387 /* CHECK ERROR! */
388 continue;
389 #else
391 * don't do unrealistic precision; just pad it with
392 * zeroes later, so buffer size stays rational.
394 if (prec > MAXFRACT) {
395 if ((ch != 'g' && ch != 'G') || (flags&ALT))
396 fpprec = prec - MAXFRACT;
397 prec = MAXFRACT;
398 } else if (prec == -1)
399 prec = DEFPREC;
400 /* __cvt_double may have to round up before the
401 "start" of its buffer, i.e.
402 ``intf("%.2f", (double)9.999);'';
403 if the first character is still NUL, it did.
404 softsign avoids negative 0 if _double < 0 but
405 no significant digits will be shown. */
406 cp = buf;
407 *cp = '\0';
408 size = __cvt_double(_double, prec, flags, &softsign,
409 ch, cp, buf + sizeof(buf));
410 if (softsign)
411 sign = '-';
412 if (*cp == '\0')
413 cp++;
414 break;
415 #endif
416 #endif /* FLOATING_POINT */
417 case 'n':
418 if (flags & LONGINT)
419 *va_arg(ap, long *) = ret;
420 else if (flags & SHORTINT)
421 *va_arg(ap, short *) = ret;
422 else
423 *va_arg(ap, int *) = ret;
424 continue; /* no output */
425 case 'O':
426 flags |= LONGINT;
427 /*FALLTHROUGH*/
428 case 'o':
429 _ulong = UARG();
430 base = OCT;
431 goto nosign;
432 case 'p':
434 * ``The argument shall be a pointer to void. The
435 * value of the pointer is converted to a sequence
436 * of printable characters, in an implementation-
437 * defined manner.''
438 * -- ANSI X3J11
440 /* NOSTRICT */
441 _ulong = (unsigned long)va_arg(ap, void *);
442 base = HEX;
443 flags |= HEXPREFIX;
444 ch = 'x';
445 goto nosign;
446 case 's':
447 if ((cp = va_arg(ap, char *)) == NULL)
448 cp = "(null)";
449 if (prec >= 0) {
451 * can't use strlen; can only look for the
452 * NUL in the first `prec' characters, and
453 * strlen() will go further.
455 char *p = (char*)memchr(cp, 0, prec);
457 if (p != NULL) {
458 size = p - cp;
459 if (size > prec)
460 size = prec;
461 } else
462 size = prec;
463 } else
464 size = strlen(cp);
465 sign = '\0';
466 break;
467 case 'U':
468 flags |= LONGINT;
469 /*FALLTHROUGH*/
470 case 'u':
471 _ulong = UARG();
472 base = DEC;
473 goto nosign;
474 case 'X':
475 case 'x':
476 _ulong = UARG();
477 base = HEX;
478 /* leading 0x/X only if non-zero */
479 if (flags & ALT && _ulong != 0)
480 flags |= HEXPREFIX;
482 /* unsigned conversions */
483 nosign: sign = '\0';
485 * ``... diouXx conversions ... if a precision is
486 * specified, the 0 flag will be ignored.''
487 * -- ANSI X3J11
489 number: if ((dprec = prec) >= 0)
490 flags &= ~ZEROPAD;
493 * ``The result of converting a zero value with an
494 * explicit precision of zero is no characters.''
495 * -- ANSI X3J11
497 cp = buf + BUF;
498 if (_ulong != 0 || prec != 0) {
499 char *xdigs; /* digits for [xX] conversion */
501 * unsigned mod is hard, and unsigned mod
502 * by a constant is easier than that by
503 * a variable; hence this switch.
505 switch (base) {
506 case OCT:
507 do {
508 *--cp = to_char(_ulong & 7);
509 _ulong >>= 3;
510 } while (_ulong);
511 /* handle octal leading 0 */
512 if (flags & ALT && *cp != '0')
513 *--cp = '0';
514 break;
516 case DEC:
517 /* many numbers are 1 digit */
518 while (_ulong >= 10) {
519 *--cp = to_char(_ulong % 10);
520 _ulong /= 10;
522 *--cp = to_char(_ulong);
523 break;
525 case HEX:
526 if (ch == 'X')
527 xdigs = "0123456789ABCDEF";
528 else /* ch == 'x' || ch == 'p' */
529 xdigs = "0123456789abcdef";
530 do {
531 *--cp = xdigs[_ulong & 15];
532 _ulong >>= 4;
533 } while (_ulong);
534 break;
536 default:
537 cp = "bug in vform: bad base";
538 goto skipsize;
541 size = buf + BUF - cp;
542 skipsize:
543 break;
544 default: /* "%?" prints ?, unless ? is NUL */
545 if (ch == '\0')
546 goto done;
547 /* pretend it was %c with argument ch */
548 cp = buf;
549 *cp = ch;
550 size = 1;
551 sign = '\0';
552 break;
556 * All reasonable formats wind up here. At this point,
557 * `cp' points to a string which (if not flags&LADJUST)
558 * should be padded out to `width' places. If
559 * flags&ZEROPAD, it should first be prefixed by any
560 * sign or other prefix; otherwise, it should be blank
561 * padded before the prefix is emitted. After any
562 * left-hand padding and prefixing, emit zeroes
563 * required by a decimal [diouxX] precision, then print
564 * the string proper, then emit zeroes required by any
565 * leftover floating precision; finally, if LADJUST,
566 * pad with blanks.
570 * compute actual size, so we know how much to pad.
572 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
573 fieldsz = size + fpprec;
574 #else
575 fieldsz = size;
576 #endif
577 dpad = dprec - size;
578 if (dpad < 0)
579 dpad = 0;
581 if (sign)
582 fieldsz++;
583 else if (flags & HEXPREFIX)
584 fieldsz += 2;
585 fieldsz += dpad;
587 /* right-adjusting blank padding */
588 if ((flags & (LADJUST|ZEROPAD)) == 0)
589 PAD_SP(width - fieldsz);
591 /* prefix */
592 if (sign) {
593 PRINT(&sign, 1);
594 } else if (flags & HEXPREFIX) {
595 ox[0] = '0';
596 ox[1] = ch;
597 PRINT(ox, 2);
600 /* right-adjusting zero padding */
601 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
602 PAD_0(width - fieldsz);
604 /* leading zeroes from decimal precision */
605 PAD_0(dpad);
607 /* the string or number proper */
608 PRINT(cp, size);
610 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
611 /* trailing f.p. zeroes */
612 PAD_0(fpprec);
613 #endif
615 /* left-adjusting padding (always blank) */
616 if (flags & LADJUST)
617 PAD_SP(width - fieldsz);
619 /* finally, adjust ret */
620 ret += width > fieldsz ? width : fieldsz;
623 done:
624 return ret;
625 error:
626 return EOF;
627 /* NOTREACHED */
630 #if defined(FLOATING_POINT) && !defined(_IO_USE_DTOA)
632 static char *exponent(register char *p, register int exp, int fmtch)
634 register char *t;
635 char expbuf[MAXEXP];
637 *p++ = fmtch;
638 if (exp < 0) {
639 exp = -exp;
640 *p++ = '-';
642 else
643 *p++ = '+';
644 t = expbuf + MAXEXP;
645 if (exp > 9) {
646 do {
647 *--t = to_char(exp % 10);
648 } while ((exp /= 10) > 9);
649 *--t = to_char(exp);
650 for (; t < expbuf + MAXEXP; *p++ = *t++);
652 else {
653 *p++ = '0';
654 *p++ = to_char(exp);
656 return (p);
659 static char * round(double fract, int *exp,
660 register char *start, register char *end,
661 char ch, int *signp)
663 double tmp;
665 if (fract)
666 (void)modf(fract * 10, &tmp);
667 else
668 tmp = to_digit(ch);
669 if (tmp > 4)
670 for (;; --end) {
671 if (*end == '.')
672 --end;
673 if (++*end <= '9')
674 break;
675 *end = '0';
676 if (end == start) {
677 if (exp) { /* e/E; increment exponent */
678 *end = '1';
679 ++*exp;
681 else { /* f; add extra digit */
682 *--end = '1';
683 --start;
685 break;
688 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
689 else if (*signp == '-')
690 for (;; --end) {
691 if (*end == '.')
692 --end;
693 if (*end != '0')
694 break;
695 if (end == start)
696 *signp = 0;
698 return (start);
701 int __cvt_double(double number, register int prec, int flags, int *signp,
702 int fmtch, char *startp, char *endp)
704 register char *p, *t;
705 register double fract;
706 int dotrim = 0, expcnt, gformat = 0;
707 double integer, tmp;
709 expcnt = 0;
710 if (number < 0) {
711 number = -number;
712 *signp = '-';
713 } else
714 *signp = 0;
716 fract = modf(number, &integer);
718 /* get an extra slot for rounding. */
719 t = ++startp;
722 * get integer portion of number; put into the end of the buffer; the
723 * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
725 for (p = endp - 1; p >= startp && integer; ++expcnt) {
726 tmp = modf(integer / 10, &integer);
727 *p-- = to_char((int)((tmp + .01) * 10));
729 switch (fmtch) {
730 case 'f':
731 case 'F':
732 /* reverse integer into beginning of buffer */
733 if (expcnt)
734 for (; ++p < endp; *t++ = *p);
735 else
736 *t++ = '0';
738 * if precision required or alternate flag set, add in a
739 * decimal point.
741 if (prec || flags&ALT)
742 *t++ = '.';
743 /* if requires more precision and some fraction left */
744 if (fract) {
745 if (prec)
746 do {
747 fract = modf(fract * 10, &tmp);
748 *t++ = to_char((int)tmp);
749 } while (--prec && fract);
750 if (fract)
751 startp = round(fract, (int *)NULL, startp,
752 t - 1, (char)0, signp);
754 for (; prec--; *t++ = '0');
755 break;
756 case 'e':
757 case 'E':
758 eformat: if (expcnt) {
759 *t++ = *++p;
760 if (prec || flags&ALT)
761 *t++ = '.';
762 /* if requires more precision and some integer left */
763 for (; prec && ++p < endp; --prec)
764 *t++ = *p;
766 * if done precision and more of the integer component,
767 * round using it; adjust fract so we don't re-round
768 * later.
770 if (!prec && ++p < endp) {
771 fract = 0;
772 startp = round((double)0, &expcnt, startp,
773 t - 1, *p, signp);
775 /* adjust expcnt for digit in front of decimal */
776 --expcnt;
778 /* until first fractional digit, decrement exponent */
779 else if (fract) {
780 /* adjust expcnt for digit in front of decimal */
781 for (expcnt = -1;; --expcnt) {
782 fract = modf(fract * 10, &tmp);
783 if (tmp)
784 break;
786 *t++ = to_char((int)tmp);
787 if (prec || flags&ALT)
788 *t++ = '.';
790 else {
791 *t++ = '0';
792 if (prec || flags&ALT)
793 *t++ = '.';
795 /* if requires more precision and some fraction left */
796 if (fract) {
797 if (prec)
798 do {
799 fract = modf(fract * 10, &tmp);
800 *t++ = to_char((int)tmp);
801 } while (--prec && fract);
802 if (fract)
803 startp = round(fract, &expcnt, startp,
804 t - 1, (char)0, signp);
806 /* if requires more precision */
807 for (; prec--; *t++ = '0');
809 /* unless alternate flag, trim any g/G format trailing 0's */
810 if (gformat && !(flags&ALT)) {
811 while (t > startp && *--t == '0');
812 if (*t == '.')
813 --t;
814 ++t;
816 t = exponent(t, expcnt, fmtch);
817 break;
818 case 'g':
819 case 'G':
820 /* a precision of 0 is treated as a precision of 1. */
821 if (!prec)
822 ++prec;
824 * ``The style used depends on the value converted; style e
825 * will be used only if the exponent resulting from the
826 * conversion is less than -4 or greater than the precision.''
827 * -- ANSI X3J11
829 if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
831 * g/G format counts "significant digits, not digits of
832 * precision; for the e/E format, this just causes an
833 * off-by-one problem, i.e. g/G considers the digit
834 * before the decimal point significant and e/E doesn't
835 * count it as precision.
837 --prec;
838 fmtch -= 2; /* G->E, g->e */
839 gformat = 1;
840 goto eformat;
843 * reverse integer into beginning of buffer,
844 * note, decrement precision
846 if (expcnt)
847 for (; ++p < endp; *t++ = *p, --prec);
848 else
849 *t++ = '0';
851 * if precision required or alternate flag set, add in a
852 * decimal point. If no digits yet, add in leading 0.
854 if (prec || flags&ALT) {
855 dotrim = 1;
856 *t++ = '.';
858 else
859 dotrim = 0;
860 /* if requires more precision and some fraction left */
861 if (fract) {
862 if (prec) {
863 /* If no integer part, don't count initial
864 * zeros as significant digits. */
865 do {
866 fract = modf(fract * 10, &tmp);
867 *t++ = to_char((int)tmp);
868 } while(!tmp && !expcnt);
869 while (--prec && fract) {
870 fract = modf(fract * 10, &tmp);
871 *t++ = to_char((int)tmp);
874 if (fract)
875 startp = round(fract, (int *)NULL, startp,
876 t - 1, (char)0, signp);
878 /* alternate format, adds 0's for precision, else trim 0's */
879 if (flags&ALT)
880 for (; prec--; *t++ = '0');
881 else if (dotrim) {
882 while (t > startp && *--t == '0');
883 if (*t != '.')
884 ++t;
887 return (t - startp);
890 #endif /* defined(FLOATING_POINT) && !defined(_IO_USE_DTOA) */