ignored by import
[gcc.git] / libio / iovfprintf.c
1 /*
2 Copyright (C) 1993 Free Software Foundation
3
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.
9
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.
14
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.
18
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. */
24
25 /*
26 * Copyright (c) 1990 Regents of the University of California.
27 * All rights reserved.
28 *
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.
40 */
41
42
43 #if defined(LIBC_SCCS) && !defined(lint)
44 static char sccsid[] = "%W% (Berkeley) %G%";
45 #endif /* LIBC_SCCS and not lint */
46
47 /*
48 * Actual printf innards.
49 *
50 * This code is large and complicated...
51 */
52
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
61
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
65
66 /*
67 * Define FLOATING_POINT to get floating point.
68 */
69 #ifndef NO_FLOATING_POINT
70 #define FLOATING_POINT
71 #endif
72
73 /* end of configuration stuff */
74
75
76 /*
77 * Helper "class" for `fprintf to unbuffered': creates a
78 * temporary buffer. */
79
80 struct helper_file
81 {
82 struct _IO_FILE_plus _f;
83 _IO_FILE *_put_stream;
84 };
85
86 static int
87 DEFUN(_IO_helper_overflow, (fp, c),
88 _IO_FILE *fp AND int c)
89 {
90 _IO_FILE *target = ((struct helper_file*)fp)->_put_stream;
91 int used = fp->_IO_write_ptr - fp->_IO_write_base;
92 if (used)
93 {
94 _IO_sputn(target, fp->_IO_write_base, used);
95 fp->_IO_write_ptr -= used;
96 }
97 return _IO_putc (c, fp);
98 }
99
100 static struct _IO_jump_t _IO_helper_jumps = {
101 JUMP_INIT_DUMMY,
102 JUMP_INIT(finish, _IO_default_finish),
103 JUMP_INIT(overflow, _IO_helper_overflow),
104 JUMP_INIT(underflow, _IO_default_underflow),
105 JUMP_INIT(uflow, _IO_default_uflow),
106 JUMP_INIT(pbackfail, _IO_default_pbackfail),
107 JUMP_INIT(xsputn, _IO_default_xsputn),
108 JUMP_INIT(xsgetn, _IO_default_xsgetn),
109 JUMP_INIT(seekoff, _IO_default_seekoff),
110 JUMP_INIT(seekpos, _IO_default_seekpos),
111 JUMP_INIT(setbuf, _IO_default_setbuf),
112 JUMP_INIT(sync, _IO_default_sync),
113 JUMP_INIT(doallocate, _IO_default_doallocate),
114 JUMP_INIT(read, _IO_default_read),
115 JUMP_INIT(write, _IO_default_write),
116 JUMP_INIT(seek, _IO_default_seek),
117 JUMP_INIT(close, _IO_default_close),
118 JUMP_INIT(stat, _IO_default_stat)
119 };
120
121 static int
122 DEFUN(helper_vfprintf, (fp, fmt0, ap),
123 register _IO_FILE* fp AND char const *fmt0 AND _IO_va_list ap)
124 {
125 char buf[_IO_BUFSIZ];
126 struct helper_file helper;
127 register _IO_FILE *hp = (_IO_FILE*)&helper;
128 int result, to_flush;
129
130 /* initialize helper */
131 helper._put_stream = fp;
132 hp->_IO_write_base = buf;
133 hp->_IO_write_ptr = buf;
134 hp->_IO_write_end = buf+_IO_BUFSIZ;
135 hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
136 _IO_JUMPS(hp) = &_IO_helper_jumps;
137
138 /* Now print to helper instead. */
139 result = _IO_vfprintf(hp, fmt0, ap);
140
141 /* Now flush anything from the helper to the fp. */
142 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
143 {
144 if (_IO_sputn(fp, hp->_IO_write_base, to_flush) != to_flush)
145 return EOF;
146 }
147 return result;
148 }
149
150 #ifdef FLOATING_POINT
151
152 #include "floatio.h"
153 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
154 #define DEFPREC 6
155 extern double modf __P((double, double*));
156
157 #else /* no FLOATING_POINT */
158
159 #define BUF 40
160
161 #endif /* FLOATING_POINT */
162
163
164 /*
165 * Macros for converting digits to letters and vice versa
166 */
167 #define to_digit(c) ((c) - '0')
168 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
169 #define to_char(n) ((n) + '0')
170
171 /*
172 * Flags used during conversion.
173 */
174 #define LONGINT 0x01 /* long integer */
175 #define LONGDBL 0x02 /* long double; unimplemented */
176 #define SHORTINT 0x04 /* short integer */
177 #define ALT 0x08 /* alternate form */
178 #define LADJUST 0x10 /* left adjustment */
179 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
180 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */
181
182 int
183 DEFUN(_IO_vfprintf, (fp, fmt0, ap),
184 register _IO_FILE* fp AND char const *fmt0 AND _IO_va_list ap)
185 {
186 register const char *fmt; /* format string */
187 register int ch; /* character from fmt */
188 register int n; /* handy integer (short term usage) */
189 register char *cp; /* handy char pointer (short term usage) */
190 const char *fmark; /* for remembering a place in fmt */
191 register int flags; /* flags as above */
192 int ret; /* return value accumulator */
193 int width; /* width from format (%8d), or 0 */
194 int prec; /* precision from format (%.3d), or -1 */
195 char sign; /* sign prefix (' ', '+', '-', or \0) */
196 #ifdef FLOATING_POINT
197 int softsign; /* temporary negative sign for floats */
198 double _double; /* double precision arguments %[eEfgG] */
199 #ifndef _IO_USE_DTOA
200 int fpprec; /* `extra' floating precision in [eEfgG] */
201 #endif
202 #endif
203 unsigned long _ulong; /* integer arguments %[diouxX] */
204 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
205 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
206 int dpad; /* extra 0 padding needed for integers */
207 int fieldsz; /* field size expanded by sign, dpad etc */
208 /* The initialization of 'size' is to suppress a warning that
209 'size' might be used unitialized. It seems gcc can't
210 quite grok this spaghetti code ... */
211 int size = 0; /* size of converted field or string */
212 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
213 char ox[2]; /* space for 0x hex-prefix */
214
215 /*
216 * BEWARE, these `goto error' on error, and PAD uses `n'.
217 */
218 #define PRINT(ptr, len) \
219 do { if (_IO_sputn(fp,ptr, len) != len) goto error; } while (0)
220 #define PAD_SP(howmany) if (_IO_padn(fp, ' ', howmany) < (howmany)) goto error;
221 #define PAD_0(howmany) if (_IO_padn(fp, '0', howmany) < (howmany)) goto error;
222
223 /*
224 * To extend shorts properly, we need both signed and unsigned
225 * argument extraction methods.
226 */
227 #define SARG() \
228 (flags&LONGINT ? va_arg(ap, long) : \
229 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
230 (long)va_arg(ap, int))
231 #define UARG() \
232 (flags&LONGINT ? va_arg(ap, unsigned long) : \
233 flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
234 (unsigned long)va_arg(ap, unsigned int))
235
236 /* optimise stderr (and other unbuffered Unix files) */
237 if (fp->_IO_file_flags & _IO_UNBUFFERED)
238 return helper_vfprintf(fp, fmt0, ap);
239
240 fmt = fmt0;
241 ret = 0;
242
243 /*
244 * Scan the format for conversions (`%' character).
245 */
246 for (;;) {
247 for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
248 /* void */;
249 if ((n = fmt - fmark) != 0) {
250 PRINT(fmark, n);
251 ret += n;
252 }
253 if (ch == '\0')
254 goto done;
255 fmt++; /* skip over '%' */
256
257 flags = 0;
258 dprec = 0;
259 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
260 fpprec = 0;
261 #endif
262 width = 0;
263 prec = -1;
264 sign = '\0';
265
266 rflag: ch = *fmt++;
267 reswitch: switch (ch) {
268 case ' ':
269 /*
270 * ``If the space and + flags both appear, the space
271 * flag will be ignored.''
272 * -- ANSI X3J11
273 */
274 if (!sign)
275 sign = ' ';
276 goto rflag;
277 case '#':
278 flags |= ALT;
279 goto rflag;
280 case '*':
281 /*
282 * ``A negative field width argument is taken as a
283 * - flag followed by a positive field width.''
284 * -- ANSI X3J11
285 * They don't exclude field widths read from args.
286 */
287 if ((width = va_arg(ap, int)) >= 0)
288 goto rflag;
289 width = -width;
290 /* FALLTHROUGH */
291 case '-':
292 flags |= LADJUST;
293 flags &= ~ZEROPAD; /* '-' disables '0' */
294 goto rflag;
295 case '+':
296 sign = '+';
297 goto rflag;
298 case '.':
299 if ((ch = *fmt++) == '*') {
300 n = va_arg(ap, int);
301 prec = n < 0 ? -1 : n;
302 goto rflag;
303 }
304 n = 0;
305 while (is_digit(ch)) {
306 n = 10 * n + to_digit(ch);
307 ch = *fmt++;
308 }
309 prec = n < 0 ? -1 : n;
310 goto reswitch;
311 case '0':
312 /*
313 * ``Note that 0 is taken as a flag, not as the
314 * beginning of a field width.''
315 * -- ANSI X3J11
316 */
317 if (!(flags & LADJUST))
318 flags |= ZEROPAD; /* '-' disables '0' */
319 goto rflag;
320 case '1': case '2': case '3': case '4':
321 case '5': case '6': case '7': case '8': case '9':
322 n = 0;
323 do {
324 n = 10 * n + to_digit(ch);
325 ch = *fmt++;
326 } while (is_digit(ch));
327 width = n;
328 goto reswitch;
329 #ifdef FLOATING_POINT
330 case 'L':
331 flags |= LONGDBL;
332 goto rflag;
333 #endif
334 case 'h':
335 flags |= SHORTINT;
336 goto rflag;
337 case 'l':
338 flags |= LONGINT;
339 goto rflag;
340 case 'c':
341 *(cp = buf) = va_arg(ap, int);
342 size = 1;
343 sign = '\0';
344 break;
345 case 'D':
346 flags |= LONGINT;
347 /*FALLTHROUGH*/
348 case 'd':
349 case 'i':
350 _ulong = SARG();
351 if ((long)_ulong < 0) {
352 _ulong = -_ulong;
353 sign = '-';
354 }
355 base = DEC;
356 goto number;
357 #ifdef FLOATING_POINT
358 case 'e':
359 case 'E':
360 case 'f':
361 case 'F':
362 case 'g':
363 case 'G':
364 _double = va_arg(ap, double);
365 #ifdef _IO_USE_DTOA
366 {
367 int fmt_flags = 0;
368 int fill = ' ';
369 if (flags & ALT)
370 fmt_flags |= _IO_SHOWPOINT;
371 if (flags & LADJUST)
372 fmt_flags |= _IO_LEFT;
373 else if (flags & ZEROPAD)
374 fmt_flags |= _IO_INTERNAL, fill = '0';
375 n = _IO_outfloat(_double, fp, ch, width,
376 prec < 0 ? DEFPREC : prec,
377 fmt_flags, sign, fill);
378 if (n < 0)
379 goto error;
380 ret += n;
381 }
382 /* CHECK ERROR! */
383 continue;
384 #else
385 /*
386 * don't do unrealistic precision; just pad it with
387 * zeroes later, so buffer size stays rational.
388 */
389 if (prec > MAXFRACT) {
390 if ((ch != 'g' && ch != 'G') || (flags&ALT))
391 fpprec = prec - MAXFRACT;
392 prec = MAXFRACT;
393 } else if (prec == -1)
394 prec = DEFPREC;
395 /* __cvt_double may have to round up before the
396 "start" of its buffer, i.e.
397 ``intf("%.2f", (double)9.999);'';
398 if the first character is still NUL, it did.
399 softsign avoids negative 0 if _double < 0 but
400 no significant digits will be shown. */
401 cp = buf;
402 *cp = '\0';
403 size = __cvt_double(_double, prec, flags, &softsign,
404 ch, cp, buf + sizeof(buf));
405 if (softsign)
406 sign = '-';
407 if (*cp == '\0')
408 cp++;
409 break;
410 #endif
411 #endif /* FLOATING_POINT */
412 case 'n':
413 if (flags & LONGINT)
414 *va_arg(ap, long *) = ret;
415 else if (flags & SHORTINT)
416 *va_arg(ap, short *) = ret;
417 else
418 *va_arg(ap, int *) = ret;
419 continue; /* no output */
420 case 'O':
421 flags |= LONGINT;
422 /*FALLTHROUGH*/
423 case 'o':
424 _ulong = UARG();
425 base = OCT;
426 goto nosign;
427 case 'p':
428 /*
429 * ``The argument shall be a pointer to void. The
430 * value of the pointer is converted to a sequence
431 * of printable characters, in an implementation-
432 * defined manner.''
433 * -- ANSI X3J11
434 */
435 /* NOSTRICT */
436 _ulong = (unsigned long)va_arg(ap, void *);
437 base = HEX;
438 flags |= HEXPREFIX;
439 ch = 'x';
440 goto nosign;
441 case 's':
442 if ((cp = va_arg(ap, char *)) == NULL)
443 cp = "(null)";
444 if (prec >= 0) {
445 /*
446 * can't use strlen; can only look for the
447 * NUL in the first `prec' characters, and
448 * strlen() will go further.
449 */
450 char *p = (char*)memchr(cp, 0, prec);
451
452 if (p != NULL) {
453 size = p - cp;
454 if (size > prec)
455 size = prec;
456 } else
457 size = prec;
458 } else
459 size = strlen(cp);
460 sign = '\0';
461 break;
462 case 'U':
463 flags |= LONGINT;
464 /*FALLTHROUGH*/
465 case 'u':
466 _ulong = UARG();
467 base = DEC;
468 goto nosign;
469 case 'X':
470 case 'x':
471 _ulong = UARG();
472 base = HEX;
473 /* leading 0x/X only if non-zero */
474 if (flags & ALT && _ulong != 0)
475 flags |= HEXPREFIX;
476
477 /* unsigned conversions */
478 nosign: sign = '\0';
479 /*
480 * ``... diouXx conversions ... if a precision is
481 * specified, the 0 flag will be ignored.''
482 * -- ANSI X3J11
483 */
484 number: if ((dprec = prec) >= 0)
485 flags &= ~ZEROPAD;
486
487 /*
488 * ``The result of converting a zero value with an
489 * explicit precision of zero is no characters.''
490 * -- ANSI X3J11
491 */
492 cp = buf + BUF;
493 if (_ulong != 0 || prec != 0) {
494 char *xdigs; /* digits for [xX] conversion */
495 /*
496 * unsigned mod is hard, and unsigned mod
497 * by a constant is easier than that by
498 * a variable; hence this switch.
499 */
500 switch (base) {
501 case OCT:
502 do {
503 *--cp = to_char(_ulong & 7);
504 _ulong >>= 3;
505 } while (_ulong);
506 /* handle octal leading 0 */
507 if (flags & ALT && *cp != '0')
508 *--cp = '0';
509 break;
510
511 case DEC:
512 /* many numbers are 1 digit */
513 while (_ulong >= 10) {
514 *--cp = to_char(_ulong % 10);
515 _ulong /= 10;
516 }
517 *--cp = to_char(_ulong);
518 break;
519
520 case HEX:
521 if (ch == 'X')
522 xdigs = "0123456789ABCDEF";
523 else /* ch == 'x' || ch == 'p' */
524 xdigs = "0123456789abcdef";
525 do {
526 *--cp = xdigs[_ulong & 15];
527 _ulong >>= 4;
528 } while (_ulong);
529 break;
530
531 default:
532 cp = "bug in vform: bad base";
533 goto skipsize;
534 }
535 }
536 size = buf + BUF - cp;
537 skipsize:
538 break;
539 default: /* "%?" prints ?, unless ? is NUL */
540 if (ch == '\0')
541 goto done;
542 /* pretend it was %c with argument ch */
543 cp = buf;
544 *cp = ch;
545 size = 1;
546 sign = '\0';
547 break;
548 }
549
550 /*
551 * All reasonable formats wind up here. At this point,
552 * `cp' points to a string which (if not flags&LADJUST)
553 * should be padded out to `width' places. If
554 * flags&ZEROPAD, it should first be prefixed by any
555 * sign or other prefix; otherwise, it should be blank
556 * padded before the prefix is emitted. After any
557 * left-hand padding and prefixing, emit zeroes
558 * required by a decimal [diouxX] precision, then print
559 * the string proper, then emit zeroes required by any
560 * leftover floating precision; finally, if LADJUST,
561 * pad with blanks.
562 */
563
564 /*
565 * compute actual size, so we know how much to pad.
566 */
567 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
568 fieldsz = size + fpprec;
569 #else
570 fieldsz = size;
571 #endif
572 dpad = dprec - size;
573 if (dpad < 0)
574 dpad = 0;
575
576 if (sign)
577 fieldsz++;
578 else if (flags & HEXPREFIX)
579 fieldsz += 2;
580 fieldsz += dpad;
581
582 /* right-adjusting blank padding */
583 if ((flags & (LADJUST|ZEROPAD)) == 0)
584 PAD_SP(width - fieldsz);
585
586 /* prefix */
587 if (sign) {
588 PRINT(&sign, 1);
589 } else if (flags & HEXPREFIX) {
590 ox[0] = '0';
591 ox[1] = ch;
592 PRINT(ox, 2);
593 }
594
595 /* right-adjusting zero padding */
596 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
597 PAD_0(width - fieldsz);
598
599 /* leading zeroes from decimal precision */
600 PAD_0(dpad);
601
602 /* the string or number proper */
603 PRINT(cp, size);
604
605 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
606 /* trailing f.p. zeroes */
607 PAD_0(fpprec);
608 #endif
609
610 /* left-adjusting padding (always blank) */
611 if (flags & LADJUST)
612 PAD_SP(width - fieldsz);
613
614 /* finally, adjust ret */
615 ret += width > fieldsz ? width : fieldsz;
616
617 }
618 done:
619 return ret;
620 error:
621 return EOF;
622 /* NOTREACHED */
623 }
624
625 #if defined(FLOATING_POINT) && !defined(_IO_USE_DTOA)
626
627 static char *exponent(register char *p, register int exp, int fmtch)
628 {
629 register char *t;
630 char expbuf[MAXEXP];
631
632 *p++ = fmtch;
633 if (exp < 0) {
634 exp = -exp;
635 *p++ = '-';
636 }
637 else
638 *p++ = '+';
639 t = expbuf + MAXEXP;
640 if (exp > 9) {
641 do {
642 *--t = to_char(exp % 10);
643 } while ((exp /= 10) > 9);
644 *--t = to_char(exp);
645 for (; t < expbuf + MAXEXP; *p++ = *t++);
646 }
647 else {
648 *p++ = '0';
649 *p++ = to_char(exp);
650 }
651 return (p);
652 }
653
654 static char * round(double fract, int *exp,
655 register char *start, register char *end,
656 char ch, int *signp)
657 {
658 double tmp;
659
660 if (fract)
661 (void)modf(fract * 10, &tmp);
662 else
663 tmp = to_digit(ch);
664 if (tmp > 4)
665 for (;; --end) {
666 if (*end == '.')
667 --end;
668 if (++*end <= '9')
669 break;
670 *end = '0';
671 if (end == start) {
672 if (exp) { /* e/E; increment exponent */
673 *end = '1';
674 ++*exp;
675 }
676 else { /* f; add extra digit */
677 *--end = '1';
678 --start;
679 }
680 break;
681 }
682 }
683 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
684 else if (*signp == '-')
685 for (;; --end) {
686 if (*end == '.')
687 --end;
688 if (*end != '0')
689 break;
690 if (end == start)
691 *signp = 0;
692 }
693 return (start);
694 }
695
696 int __cvt_double(double number, register int prec, int flags, int *signp,
697 int fmtch, char *startp, char *endp)
698 {
699 register char *p, *t;
700 register double fract;
701 int dotrim = 0, expcnt, gformat = 0;
702 double integer, tmp;
703
704 expcnt = 0;
705 if (number < 0) {
706 number = -number;
707 *signp = '-';
708 } else
709 *signp = 0;
710
711 fract = modf(number, &integer);
712
713 /* get an extra slot for rounding. */
714 t = ++startp;
715
716 /*
717 * get integer portion of number; put into the end of the buffer; the
718 * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
719 */
720 for (p = endp - 1; p >= startp && integer; ++expcnt) {
721 tmp = modf(integer / 10, &integer);
722 *p-- = to_char((int)((tmp + .01) * 10));
723 }
724 switch (fmtch) {
725 case 'f':
726 case 'F':
727 /* reverse integer into beginning of buffer */
728 if (expcnt)
729 for (; ++p < endp; *t++ = *p);
730 else
731 *t++ = '0';
732 /*
733 * if precision required or alternate flag set, add in a
734 * decimal point.
735 */
736 if (prec || flags&ALT)
737 *t++ = '.';
738 /* if requires more precision and some fraction left */
739 if (fract) {
740 if (prec)
741 do {
742 fract = modf(fract * 10, &tmp);
743 *t++ = to_char((int)tmp);
744 } while (--prec && fract);
745 if (fract)
746 startp = round(fract, (int *)NULL, startp,
747 t - 1, (char)0, signp);
748 }
749 for (; prec--; *t++ = '0');
750 break;
751 case 'e':
752 case 'E':
753 eformat: if (expcnt) {
754 *t++ = *++p;
755 if (prec || flags&ALT)
756 *t++ = '.';
757 /* if requires more precision and some integer left */
758 for (; prec && ++p < endp; --prec)
759 *t++ = *p;
760 /*
761 * if done precision and more of the integer component,
762 * round using it; adjust fract so we don't re-round
763 * later.
764 */
765 if (!prec && ++p < endp) {
766 fract = 0;
767 startp = round((double)0, &expcnt, startp,
768 t - 1, *p, signp);
769 }
770 /* adjust expcnt for digit in front of decimal */
771 --expcnt;
772 }
773 /* until first fractional digit, decrement exponent */
774 else if (fract) {
775 /* adjust expcnt for digit in front of decimal */
776 for (expcnt = -1;; --expcnt) {
777 fract = modf(fract * 10, &tmp);
778 if (tmp)
779 break;
780 }
781 *t++ = to_char((int)tmp);
782 if (prec || flags&ALT)
783 *t++ = '.';
784 }
785 else {
786 *t++ = '0';
787 if (prec || flags&ALT)
788 *t++ = '.';
789 }
790 /* if requires more precision and some fraction left */
791 if (fract) {
792 if (prec)
793 do {
794 fract = modf(fract * 10, &tmp);
795 *t++ = to_char((int)tmp);
796 } while (--prec && fract);
797 if (fract)
798 startp = round(fract, &expcnt, startp,
799 t - 1, (char)0, signp);
800 }
801 /* if requires more precision */
802 for (; prec--; *t++ = '0');
803
804 /* unless alternate flag, trim any g/G format trailing 0's */
805 if (gformat && !(flags&ALT)) {
806 while (t > startp && *--t == '0');
807 if (*t == '.')
808 --t;
809 ++t;
810 }
811 t = exponent(t, expcnt, fmtch);
812 break;
813 case 'g':
814 case 'G':
815 /* a precision of 0 is treated as a precision of 1. */
816 if (!prec)
817 ++prec;
818 /*
819 * ``The style used depends on the value converted; style e
820 * will be used only if the exponent resulting from the
821 * conversion is less than -4 or greater than the precision.''
822 * -- ANSI X3J11
823 */
824 if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
825 /*
826 * g/G format counts "significant digits, not digits of
827 * precision; for the e/E format, this just causes an
828 * off-by-one problem, i.e. g/G considers the digit
829 * before the decimal point significant and e/E doesn't
830 * count it as precision.
831 */
832 --prec;
833 fmtch -= 2; /* G->E, g->e */
834 gformat = 1;
835 goto eformat;
836 }
837 /*
838 * reverse integer into beginning of buffer,
839 * note, decrement precision
840 */
841 if (expcnt)
842 for (; ++p < endp; *t++ = *p, --prec);
843 else
844 *t++ = '0';
845 /*
846 * if precision required or alternate flag set, add in a
847 * decimal point. If no digits yet, add in leading 0.
848 */
849 if (prec || flags&ALT) {
850 dotrim = 1;
851 *t++ = '.';
852 }
853 else
854 dotrim = 0;
855 /* if requires more precision and some fraction left */
856 if (fract) {
857 if (prec) {
858 /* If no integer part, don't count initial
859 * zeros as significant digits. */
860 do {
861 fract = modf(fract * 10, &tmp);
862 *t++ = to_char((int)tmp);
863 } while(!tmp && !expcnt);
864 while (--prec && fract) {
865 fract = modf(fract * 10, &tmp);
866 *t++ = to_char((int)tmp);
867 }
868 }
869 if (fract)
870 startp = round(fract, (int *)NULL, startp,
871 t - 1, (char)0, signp);
872 }
873 /* alternate format, adds 0's for precision, else trim 0's */
874 if (flags&ALT)
875 for (; prec--; *t++ = '0');
876 else if (dotrim) {
877 while (t > startp && *--t == '0');
878 if (*t != '.')
879 ++t;
880 }
881 }
882 return (t - startp);
883 }
884
885 #endif /* defined(FLOATING_POINT) && !defined(_IO_USE_DTOA) */