* c-common.c (warn_format_security): New variable.
[official-gcc.git] / libio / iovfprintf.c
blob229215ad0e089c4f04f5c4ee4227302ed394c7f9
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, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. [rescinded 22 July 1999]
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "%W% (Berkeley) %G%";
58 #endif /* LIBC_SCCS and not lint */
61 * Actual printf innards.
63 * This code is large and complicated...
66 #include <sys/types.h>
67 #include "libioP.h"
68 #include <string.h>
69 #ifdef __STDC__
70 #include <stdarg.h>
71 #else
72 #include <varargs.h>
73 #endif
75 #ifndef _IO_USE_DTOA
76 int __cvt_double __P((double number, register int prec, int flags, int *signp, int fmtch, char *startp, char *endp));
77 #endif
80 * Define FLOATING_POINT to get floating point.
82 #ifndef NO_FLOATING_POINT
83 #define FLOATING_POINT
84 #endif
86 /* end of configuration stuff */
90 * Helper "class" for `fprintf to unbuffered': creates a
91 * temporary buffer. */
93 struct helper_file
95 struct _IO_FILE_plus _f;
96 _IO_FILE *_put_stream;
99 static int
100 _IO_helper_overflow (fp, c)
101 _IO_FILE *fp;
102 int c;
104 _IO_FILE *target = ((struct helper_file*)fp)->_put_stream;
105 int used = fp->_IO_write_ptr - fp->_IO_write_base;
106 if (used)
108 _IO_sputn(target, fp->_IO_write_base, used);
109 fp->_IO_write_ptr -= used;
111 return _IO_putc (c, fp);
114 static struct _IO_jump_t _IO_helper_jumps = {
115 JUMP_INIT_DUMMY,
116 JUMP_INIT(finish, _IO_default_finish),
117 JUMP_INIT(overflow, _IO_helper_overflow),
118 JUMP_INIT(underflow, _IO_default_underflow),
119 JUMP_INIT(uflow, _IO_default_uflow),
120 JUMP_INIT(pbackfail, _IO_default_pbackfail),
121 JUMP_INIT(xsputn, _IO_default_xsputn),
122 JUMP_INIT(xsgetn, _IO_default_xsgetn),
123 JUMP_INIT(seekoff, _IO_default_seekoff),
124 JUMP_INIT(seekpos, _IO_default_seekpos),
125 JUMP_INIT(setbuf, _IO_default_setbuf),
126 JUMP_INIT(sync, _IO_default_sync),
127 JUMP_INIT(doallocate, _IO_default_doallocate),
128 JUMP_INIT(read, _IO_default_read),
129 JUMP_INIT(write, _IO_default_write),
130 JUMP_INIT(seek, _IO_default_seek),
131 JUMP_INIT(close, _IO_default_close),
132 JUMP_INIT(stat, _IO_default_stat)
135 static int
136 helper_vfprintf (fp, fmt0, ap)
137 _IO_FILE *fp;
138 char const *fmt0;
139 _IO_va_list ap;
141 char buf[_IO_BUFSIZ];
142 struct helper_file helper;
143 register _IO_FILE *hp = (_IO_FILE*)&helper;
144 int result, to_flush;
146 /* initialize helper */
147 helper._put_stream = fp;
148 hp->_IO_write_base = buf;
149 hp->_IO_write_ptr = buf;
150 hp->_IO_write_end = buf+_IO_BUFSIZ;
151 hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
152 _IO_JUMPS(hp) = &_IO_helper_jumps;
154 /* Now print to helper instead. */
155 result = _IO_vfprintf(hp, fmt0, ap);
157 /* Now flush anything from the helper to the fp. */
158 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
160 if (_IO_sputn(fp, hp->_IO_write_base, to_flush) != to_flush)
161 return EOF;
163 return result;
166 #ifdef FLOATING_POINT
168 #include "floatio.h"
169 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
170 #define DEFPREC 6
171 extern double modf __P((double, double*));
173 #else /* no FLOATING_POINT */
175 #define BUF 40
177 #endif /* FLOATING_POINT */
181 * Macros for converting digits to letters and vice versa
183 #define to_digit(c) ((c) - '0')
184 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
185 #define to_char(n) ((n) + '0')
188 * Flags used during conversion.
190 #define LONGINT 0x01 /* long integer */
191 #define LONGDBL 0x02 /* long double; unimplemented */
192 #define SHORTINT 0x04 /* short integer */
193 #define ALT 0x08 /* alternate form */
194 #define LADJUST 0x10 /* left adjustment */
195 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
196 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */
199 _IO_vfprintf (fp, fmt0, ap)
200 _IO_FILE *fp;
201 char const *fmt0;
202 _IO_va_list ap;
204 register const char *fmt; /* format string */
205 register int ch; /* character from fmt */
206 register int n; /* handy integer (short term usage) */
207 register char *cp; /* handy char pointer (short term usage) */
208 const char *fmark; /* for remembering a place in fmt */
209 register int flags; /* flags as above */
210 int ret; /* return value accumulator */
211 int width; /* width from format (%8d), or 0 */
212 int prec; /* precision from format (%.3d), or -1 */
213 char sign; /* sign prefix (' ', '+', '-', or \0) */
214 #ifdef FLOATING_POINT
215 int softsign; /* temporary negative sign for floats */
216 double _double; /* double precision arguments %[eEfgG] */
217 #ifndef _IO_USE_DTOA
218 int fpprec; /* `extra' floating precision in [eEfgG] */
219 #endif
220 #endif
221 unsigned long _ulong; /* integer arguments %[diouxX] */
222 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
223 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
224 int dpad; /* extra 0 padding needed for integers */
225 int fieldsz; /* field size expanded by sign, dpad etc */
226 /* The initialization of 'size' is to suppress a warning that
227 'size' might be used unitialized. It seems gcc can't
228 quite grok this spaghetti code ... */
229 int size = 0; /* size of converted field or string */
230 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
231 char ox[2]; /* space for 0x hex-prefix */
234 * BEWARE, these `goto error' on error, and PAD uses `n'.
236 #define PRINT(ptr, len) \
237 do { if (_IO_sputn(fp,ptr, len) != len) goto error; } while (0)
238 #define PAD_SP(howmany) if (_IO_padn(fp, ' ', howmany) < (howmany)) goto error;
239 #define PAD_0(howmany) if (_IO_padn(fp, '0', howmany) < (howmany)) goto error;
242 * To extend shorts properly, we need both signed and unsigned
243 * argument extraction methods.
245 #define SARG() \
246 (flags&LONGINT ? va_arg(ap, long) : \
247 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
248 (long)va_arg(ap, int))
249 #define UARG() \
250 (flags&LONGINT ? va_arg(ap, unsigned long) : \
251 flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
252 (unsigned long)va_arg(ap, unsigned int))
254 /* optimise stderr (and other unbuffered Unix files) */
255 if (fp->_IO_file_flags & _IO_UNBUFFERED)
256 return helper_vfprintf(fp, fmt0, ap);
258 fmt = fmt0;
259 ret = 0;
262 * Scan the format for conversions (`%' character).
264 for (;;) {
265 for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
266 /* void */;
267 if ((n = fmt - fmark) != 0) {
268 PRINT(fmark, n);
269 ret += n;
271 if (ch == '\0')
272 goto done;
273 fmt++; /* skip over '%' */
275 flags = 0;
276 dprec = 0;
277 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
278 fpprec = 0;
279 #endif
280 width = 0;
281 prec = -1;
282 sign = '\0';
284 rflag: ch = *fmt++;
285 reswitch: switch (ch) {
286 case ' ':
288 * ``If the space and + flags both appear, the space
289 * flag will be ignored.''
290 * -- ANSI X3J11
292 if (!sign)
293 sign = ' ';
294 goto rflag;
295 case '#':
296 flags |= ALT;
297 goto rflag;
298 case '*':
300 * ``A negative field width argument is taken as a
301 * - flag followed by a positive field width.''
302 * -- ANSI X3J11
303 * They don't exclude field widths read from args.
305 if ((width = va_arg(ap, int)) >= 0)
306 goto rflag;
307 width = -width;
308 /* FALLTHROUGH */
309 case '-':
310 flags |= LADJUST;
311 flags &= ~ZEROPAD; /* '-' disables '0' */
312 goto rflag;
313 case '+':
314 sign = '+';
315 goto rflag;
316 case '.':
317 if ((ch = *fmt++) == '*') {
318 n = va_arg(ap, int);
319 prec = n < 0 ? -1 : n;
320 goto rflag;
322 n = 0;
323 while (is_digit(ch)) {
324 n = 10 * n + to_digit(ch);
325 ch = *fmt++;
327 prec = n < 0 ? -1 : n;
328 goto reswitch;
329 case '0':
331 * ``Note that 0 is taken as a flag, not as the
332 * beginning of a field width.''
333 * -- ANSI X3J11
335 if (!(flags & LADJUST))
336 flags |= ZEROPAD; /* '-' disables '0' */
337 goto rflag;
338 case '1': case '2': case '3': case '4':
339 case '5': case '6': case '7': case '8': case '9':
340 n = 0;
341 do {
342 n = 10 * n + to_digit(ch);
343 ch = *fmt++;
344 } while (is_digit(ch));
345 width = n;
346 goto reswitch;
347 #ifdef FLOATING_POINT
348 case 'L':
349 flags |= LONGDBL;
350 goto rflag;
351 #endif
352 case 'h':
353 flags |= SHORTINT;
354 goto rflag;
355 case 'l':
356 flags |= LONGINT;
357 goto rflag;
358 case 'c':
359 *(cp = buf) = va_arg(ap, int);
360 size = 1;
361 sign = '\0';
362 break;
363 case 'D':
364 flags |= LONGINT;
365 /*FALLTHROUGH*/
366 case 'd':
367 case 'i':
368 _ulong = SARG();
369 if ((long)_ulong < 0) {
370 _ulong = -_ulong;
371 sign = '-';
373 base = DEC;
374 goto number;
375 #ifdef FLOATING_POINT
376 case 'e':
377 case 'E':
378 case 'f':
379 case 'F':
380 case 'g':
381 case 'G':
382 _double = va_arg(ap, double);
383 #ifdef _IO_USE_DTOA
385 int fmt_flags = 0;
386 int fill = ' ';
387 if (flags & ALT)
388 fmt_flags |= _IO_SHOWPOINT;
389 if (flags & LADJUST)
390 fmt_flags |= _IO_LEFT;
391 else if (flags & ZEROPAD)
392 fmt_flags |= _IO_INTERNAL, fill = '0';
393 n = _IO_outfloat(_double, fp, ch, width,
394 prec < 0 ? DEFPREC : prec,
395 fmt_flags, sign, fill);
396 if (n < 0)
397 goto error;
398 ret += n;
400 /* CHECK ERROR! */
401 continue;
402 #else
404 * don't do unrealistic precision; just pad it with
405 * zeroes later, so buffer size stays rational.
407 if (prec > MAXFRACT) {
408 if ((ch != 'g' && ch != 'G') || (flags&ALT))
409 fpprec = prec - MAXFRACT;
410 prec = MAXFRACT;
411 } else if (prec == -1)
412 prec = DEFPREC;
413 /* __cvt_double may have to round up before the
414 "start" of its buffer, i.e.
415 ``intf("%.2f", (double)9.999);'';
416 if the first character is still NUL, it did.
417 softsign avoids negative 0 if _double < 0 but
418 no significant digits will be shown. */
419 cp = buf;
420 *cp = '\0';
421 size = __cvt_double(_double, prec, flags, &softsign,
422 ch, cp, buf + sizeof(buf));
423 if (softsign)
424 sign = '-';
425 if (*cp == '\0')
426 cp++;
427 break;
428 #endif
429 #endif /* FLOATING_POINT */
430 case 'n':
431 if (flags & LONGINT)
432 *va_arg(ap, long *) = ret;
433 else if (flags & SHORTINT)
434 *va_arg(ap, short *) = ret;
435 else
436 *va_arg(ap, int *) = ret;
437 continue; /* no output */
438 case 'O':
439 flags |= LONGINT;
440 /*FALLTHROUGH*/
441 case 'o':
442 _ulong = UARG();
443 base = OCT;
444 goto nosign;
445 case 'p':
447 * ``The argument shall be a pointer to void. The
448 * value of the pointer is converted to a sequence
449 * of printable characters, in an implementation-
450 * defined manner.''
451 * -- ANSI X3J11
453 /* NOSTRICT */
454 _ulong = (unsigned long)va_arg(ap, void *);
455 base = HEX;
456 flags |= HEXPREFIX;
457 ch = 'x';
458 goto nosign;
459 case 's':
460 if ((cp = va_arg(ap, char *)) == NULL)
461 cp = "(null)";
462 if (prec >= 0) {
464 * can't use strlen; can only look for the
465 * NUL in the first `prec' characters, and
466 * strlen() will go further.
468 char *p = (char*)memchr(cp, 0, prec);
470 if (p != NULL) {
471 size = p - cp;
472 if (size > prec)
473 size = prec;
474 } else
475 size = prec;
476 } else
477 size = strlen(cp);
478 sign = '\0';
479 break;
480 case 'U':
481 flags |= LONGINT;
482 /*FALLTHROUGH*/
483 case 'u':
484 _ulong = UARG();
485 base = DEC;
486 goto nosign;
487 case 'X':
488 case 'x':
489 _ulong = UARG();
490 base = HEX;
491 /* leading 0x/X only if non-zero */
492 if (flags & ALT && _ulong != 0)
493 flags |= HEXPREFIX;
495 /* unsigned conversions */
496 nosign: sign = '\0';
498 * ``... diouXx conversions ... if a precision is
499 * specified, the 0 flag will be ignored.''
500 * -- ANSI X3J11
502 number: if ((dprec = prec) >= 0)
503 flags &= ~ZEROPAD;
506 * ``The result of converting a zero value with an
507 * explicit precision of zero is no characters.''
508 * -- ANSI X3J11
510 cp = buf + BUF;
511 if (_ulong != 0 || prec != 0) {
512 char *xdigs; /* digits for [xX] conversion */
514 * unsigned mod is hard, and unsigned mod
515 * by a constant is easier than that by
516 * a variable; hence this switch.
518 switch (base) {
519 case OCT:
520 do {
521 *--cp = to_char(_ulong & 7);
522 _ulong >>= 3;
523 } while (_ulong);
524 /* handle octal leading 0 */
525 if (flags & ALT && *cp != '0')
526 *--cp = '0';
527 break;
529 case DEC:
530 /* many numbers are 1 digit */
531 while (_ulong >= 10) {
532 *--cp = to_char(_ulong % 10);
533 _ulong /= 10;
535 *--cp = to_char(_ulong);
536 break;
538 case HEX:
539 if (ch == 'X')
540 xdigs = "0123456789ABCDEF";
541 else /* ch == 'x' || ch == 'p' */
542 xdigs = "0123456789abcdef";
543 do {
544 *--cp = xdigs[_ulong & 15];
545 _ulong >>= 4;
546 } while (_ulong);
547 break;
549 default:
550 cp = "bug in vform: bad base";
551 goto skipsize;
554 size = buf + BUF - cp;
555 skipsize:
556 break;
557 default: /* "%?" prints ?, unless ? is NUL */
558 if (ch == '\0')
559 goto done;
560 /* pretend it was %c with argument ch */
561 cp = buf;
562 *cp = ch;
563 size = 1;
564 sign = '\0';
565 break;
569 * All reasonable formats wind up here. At this point,
570 * `cp' points to a string which (if not flags&LADJUST)
571 * should be padded out to `width' places. If
572 * flags&ZEROPAD, it should first be prefixed by any
573 * sign or other prefix; otherwise, it should be blank
574 * padded before the prefix is emitted. After any
575 * left-hand padding and prefixing, emit zeroes
576 * required by a decimal [diouxX] precision, then print
577 * the string proper, then emit zeroes required by any
578 * leftover floating precision; finally, if LADJUST,
579 * pad with blanks.
583 * compute actual size, so we know how much to pad.
585 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
586 fieldsz = size + fpprec;
587 #else
588 fieldsz = size;
589 #endif
590 dpad = dprec - size;
591 if (dpad < 0)
592 dpad = 0;
594 if (sign)
595 fieldsz++;
596 else if (flags & HEXPREFIX)
597 fieldsz += 2;
598 fieldsz += dpad;
600 /* right-adjusting blank padding */
601 if ((flags & (LADJUST|ZEROPAD)) == 0)
602 PAD_SP(width - fieldsz);
604 /* prefix */
605 if (sign) {
606 PRINT(&sign, 1);
607 } else if (flags & HEXPREFIX) {
608 ox[0] = '0';
609 ox[1] = ch;
610 PRINT(ox, 2);
613 /* right-adjusting zero padding */
614 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
615 PAD_0(width - fieldsz);
617 /* leading zeroes from decimal precision */
618 PAD_0(dpad);
620 /* the string or number proper */
621 PRINT(cp, size);
623 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
624 /* trailing f.p. zeroes */
625 PAD_0(fpprec);
626 #endif
628 /* left-adjusting padding (always blank) */
629 if (flags & LADJUST)
630 PAD_SP(width - fieldsz);
632 /* finally, adjust ret */
633 ret += width > fieldsz ? width : fieldsz;
636 done:
637 return ret;
638 error:
639 return EOF;
640 /* NOTREACHED */
643 #if defined(FLOATING_POINT) && !defined(_IO_USE_DTOA)
645 static char *exponent(register char *p, register int exp, int fmtch)
647 register char *t;
648 char expbuf[MAXEXP];
650 *p++ = fmtch;
651 if (exp < 0) {
652 exp = -exp;
653 *p++ = '-';
655 else
656 *p++ = '+';
657 t = expbuf + MAXEXP;
658 if (exp > 9) {
659 do {
660 *--t = to_char(exp % 10);
661 } while ((exp /= 10) > 9);
662 *--t = to_char(exp);
663 for (; t < expbuf + MAXEXP; *p++ = *t++);
665 else {
666 *p++ = '0';
667 *p++ = to_char(exp);
669 return (p);
672 static char * round(double fract, int *exp,
673 register char *start, register char *end,
674 char ch, int *signp)
676 double tmp;
678 if (fract)
679 (void)modf(fract * 10, &tmp);
680 else
681 tmp = to_digit(ch);
682 if (tmp > 4)
683 for (;; --end) {
684 if (*end == '.')
685 --end;
686 if (++*end <= '9')
687 break;
688 *end = '0';
689 if (end == start) {
690 if (exp) { /* e/E; increment exponent */
691 *end = '1';
692 ++*exp;
694 else { /* f; add extra digit */
695 *--end = '1';
696 --start;
698 break;
701 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
702 else if (*signp == '-')
703 for (;; --end) {
704 if (*end == '.')
705 --end;
706 if (*end != '0')
707 break;
708 if (end == start)
709 *signp = 0;
711 return (start);
714 int __cvt_double(double number, register int prec, int flags, int *signp,
715 int fmtch, char *startp, char *endp)
717 register char *p, *t;
718 register double fract;
719 int dotrim = 0, expcnt, gformat = 0;
720 double integer, tmp;
722 expcnt = 0;
723 if (number < 0) {
724 number = -number;
725 *signp = '-';
726 } else
727 *signp = 0;
729 fract = modf(number, &integer);
731 /* get an extra slot for rounding. */
732 t = ++startp;
735 * get integer portion of number; put into the end of the buffer; the
736 * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
738 for (p = endp - 1; p >= startp && integer; ++expcnt) {
739 tmp = modf(integer / 10, &integer);
740 *p-- = to_char((int)((tmp + .01) * 10));
742 switch (fmtch) {
743 case 'f':
744 case 'F':
745 /* reverse integer into beginning of buffer */
746 if (expcnt)
747 for (; ++p < endp; *t++ = *p);
748 else
749 *t++ = '0';
751 * if precision required or alternate flag set, add in a
752 * decimal point.
754 if (prec || flags&ALT)
755 *t++ = '.';
756 /* if requires more precision and some fraction left */
757 if (fract) {
758 if (prec)
759 do {
760 fract = modf(fract * 10, &tmp);
761 *t++ = to_char((int)tmp);
762 } while (--prec && fract);
763 if (fract)
764 startp = round(fract, (int *)NULL, startp,
765 t - 1, (char)0, signp);
767 for (; prec--; *t++ = '0');
768 break;
769 case 'e':
770 case 'E':
771 eformat: if (expcnt) {
772 *t++ = *++p;
773 if (prec || flags&ALT)
774 *t++ = '.';
775 /* if requires more precision and some integer left */
776 for (; prec && ++p < endp; --prec)
777 *t++ = *p;
779 * if done precision and more of the integer component,
780 * round using it; adjust fract so we don't re-round
781 * later.
783 if (!prec && ++p < endp) {
784 fract = 0;
785 startp = round((double)0, &expcnt, startp,
786 t - 1, *p, signp);
788 /* adjust expcnt for digit in front of decimal */
789 --expcnt;
791 /* until first fractional digit, decrement exponent */
792 else if (fract) {
793 /* adjust expcnt for digit in front of decimal */
794 for (expcnt = -1;; --expcnt) {
795 fract = modf(fract * 10, &tmp);
796 if (tmp)
797 break;
799 *t++ = to_char((int)tmp);
800 if (prec || flags&ALT)
801 *t++ = '.';
803 else {
804 *t++ = '0';
805 if (prec || flags&ALT)
806 *t++ = '.';
808 /* if requires more precision and some fraction left */
809 if (fract) {
810 if (prec)
811 do {
812 fract = modf(fract * 10, &tmp);
813 *t++ = to_char((int)tmp);
814 } while (--prec && fract);
815 if (fract)
816 startp = round(fract, &expcnt, startp,
817 t - 1, (char)0, signp);
819 /* if requires more precision */
820 for (; prec--; *t++ = '0');
822 /* unless alternate flag, trim any g/G format trailing 0's */
823 if (gformat && !(flags&ALT)) {
824 while (t > startp && *--t == '0');
825 if (*t == '.')
826 --t;
827 ++t;
829 t = exponent(t, expcnt, fmtch);
830 break;
831 case 'g':
832 case 'G':
833 /* a precision of 0 is treated as a precision of 1. */
834 if (!prec)
835 ++prec;
837 * ``The style used depends on the value converted; style e
838 * will be used only if the exponent resulting from the
839 * conversion is less than -4 or greater than the precision.''
840 * -- ANSI X3J11
842 if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
844 * g/G format counts "significant digits, not digits of
845 * precision; for the e/E format, this just causes an
846 * off-by-one problem, i.e. g/G considers the digit
847 * before the decimal point significant and e/E doesn't
848 * count it as precision.
850 --prec;
851 fmtch -= 2; /* G->E, g->e */
852 gformat = 1;
853 goto eformat;
856 * reverse integer into beginning of buffer,
857 * note, decrement precision
859 if (expcnt)
860 for (; ++p < endp; *t++ = *p, --prec);
861 else
862 *t++ = '0';
864 * if precision required or alternate flag set, add in a
865 * decimal point. If no digits yet, add in leading 0.
867 if (prec || flags&ALT) {
868 dotrim = 1;
869 *t++ = '.';
871 else
872 dotrim = 0;
873 /* if requires more precision and some fraction left */
874 if (fract) {
875 if (prec) {
876 /* If no integer part, don't count initial
877 * zeros as significant digits. */
878 do {
879 fract = modf(fract * 10, &tmp);
880 *t++ = to_char((int)tmp);
881 } while(!tmp && !expcnt);
882 while (--prec && fract) {
883 fract = modf(fract * 10, &tmp);
884 *t++ = to_char((int)tmp);
887 if (fract)
888 startp = round(fract, (int *)NULL, startp,
889 t - 1, (char)0, signp);
891 /* alternate format, adds 0's for precision, else trim 0's */
892 if (flags&ALT)
893 for (; prec--; *t++ = '0');
894 else if (dotrim) {
895 while (t > startp && *--t == '0');
896 if (*t != '.')
897 ++t;
900 return (t - startp);
903 #endif /* defined(FLOATING_POINT) && !defined(_IO_USE_DTOA) */