Merge from vendor branch DIFFUTILS:
[dragonfly.git] / contrib / 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 _IO_helper_overflow (fp, c)
88      _IO_FILE *fp;
89      int c;
90 {
91   _IO_FILE *target = ((struct helper_file*)fp)->_put_stream;
92   int used = fp->_IO_write_ptr - fp->_IO_write_base;
93   if (used)
94     {
95       _IO_sputn(target, fp->_IO_write_base, used);
96       fp->_IO_write_ptr -= used;
97     }
98   return _IO_putc (c, fp);
99 }
100
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)
120 };
121
122 static int
123 helper_vfprintf (fp, fmt0, ap)
124      _IO_FILE *fp;
125      char const *fmt0;
126      _IO_va_list ap;
127 {
128   char buf[_IO_BUFSIZ];
129   struct helper_file helper;
130   register _IO_FILE *hp = (_IO_FILE*)&helper;
131   int result, to_flush;
132
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;
140   
141   /* Now print to helper instead. */
142   result = _IO_vfprintf(hp, fmt0, ap);
143
144   /* Now flush anything from the helper to the fp. */
145   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
146     {
147       if (_IO_sputn(fp, hp->_IO_write_base, to_flush) != to_flush)
148         return EOF;
149     }
150   return result;
151 }
152
153 #ifdef FLOATING_POINT
154
155 #include "floatio.h"
156 #define BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
157 #define DEFPREC         6
158 extern double modf __P((double, double*));
159
160 #else /* no FLOATING_POINT */
161
162 #define BUF             40
163
164 #endif /* FLOATING_POINT */
165
166
167 /*
168  * Macros for converting digits to letters and vice versa
169  */
170 #define to_digit(c)     ((c) - '0')
171 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
172 #define to_char(n)      ((n) + '0')
173
174 /*
175  * Flags used during conversion.
176  */
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 */
184
185 int
186 _IO_vfprintf (fp, fmt0, ap)
187      _IO_FILE *fp;
188      char const *fmt0;
189      _IO_va_list ap;
190 {
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 */
219
220         /*
221          * BEWARE, these `goto error' on error, and PAD uses `n'.
222          */
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;
227
228         /*
229          * To extend shorts properly, we need both signed and unsigned
230          * argument extraction methods.
231          */
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))
240
241         /* optimise stderr (and other unbuffered Unix files) */
242         if (fp->_IO_file_flags & _IO_UNBUFFERED)
243             return helper_vfprintf(fp, fmt0, ap);
244
245         fmt = fmt0;
246         ret = 0;
247
248         /*
249          * Scan the format for conversions (`%' character).
250          */
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;
257                 }
258                 if (ch == '\0')
259                         goto done;
260                 fmt++;          /* skip over '%' */
261
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';
270
271 rflag:          ch = *fmt++;
272 reswitch:       switch (ch) {
273                 case ' ':
274                         /*
275                          * ``If the space and + flags both appear, the space
276                          * flag will be ignored.''
277                          *      -- ANSI X3J11
278                          */
279                         if (!sign)
280                                 sign = ' ';
281                         goto rflag;
282                 case '#':
283                         flags |= ALT;
284                         goto rflag;
285                 case '*':
286                         /*
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.
291                          */
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;
308                         }
309                         n = 0;
310                         while (is_digit(ch)) {
311                                 n = 10 * n + to_digit(ch);
312                                 ch = *fmt++;
313                         }
314                         prec = n < 0 ? -1 : n;
315                         goto reswitch;
316                 case '0':
317                         /*
318                          * ``Note that 0 is taken as a flag, not as the
319                          * beginning of a field width.''
320                          *      -- ANSI X3J11
321                          */
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 = '-';
359                         }
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
371                         {
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;
386                         }
387                         /* CHECK ERROR! */
388                         continue;
389 #else
390                         /*
391                          * don't do unrealistic precision; just pad it with
392                          * zeroes later, so buffer size stays rational.
393                          */
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':
433                         /*
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
439                          */
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) {
450                                 /*
451                                  * can't use strlen; can only look for the
452                                  * NUL in the first `prec' characters, and
453                                  * strlen() will go further.
454                                  */
455                                 char *p = (char*)memchr(cp, 0, prec);
456
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;
481
482                         /* unsigned conversions */
483 nosign:                 sign = '\0';
484                         /*
485                          * ``... diouXx conversions ... if a precision is
486                          * specified, the 0 flag will be ignored.''
487                          *      -- ANSI X3J11
488                          */
489 number:                 if ((dprec = prec) >= 0)
490                                 flags &= ~ZEROPAD;
491
492                         /*
493                          * ``The result of converting a zero value with an
494                          * explicit precision of zero is no characters.''
495                          *      -- ANSI X3J11
496                          */
497                         cp = buf + BUF;
498                         if (_ulong != 0 || prec != 0) {
499                                 char *xdigs; /* digits for [xX] conversion */
500                                 /*
501                                  * unsigned mod is hard, and unsigned mod
502                                  * by a constant is easier than that by
503                                  * a variable; hence this switch.
504                                  */
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;
515
516                                 case DEC:
517                                         /* many numbers are 1 digit */
518                                         while (_ulong >= 10) {
519                                                 *--cp = to_char(_ulong % 10);
520                                                 _ulong /= 10;
521                                         }
522                                         *--cp = to_char(_ulong);
523                                         break;
524
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;
535
536                                 default:
537                                         cp = "bug in vform: bad base";
538                                         goto skipsize;
539                                 }
540                         }
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;
553                 }
554
555                 /*
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.
567                  */
568
569                 /*
570                  * compute actual size, so we know how much to pad.
571                  */
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;
580
581                 if (sign)
582                         fieldsz++;
583                 else if (flags & HEXPREFIX)
584                         fieldsz += 2;
585                 fieldsz += dpad;
586
587                 /* right-adjusting blank padding */
588                 if ((flags & (LADJUST|ZEROPAD)) == 0)
589                         PAD_SP(width - fieldsz);
590
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);
598                 }
599
600                 /* right-adjusting zero padding */
601                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
602                         PAD_0(width - fieldsz);
603
604                 /* leading zeroes from decimal precision */
605                 PAD_0(dpad);
606
607                 /* the string or number proper */
608                 PRINT(cp, size);
609
610 #if defined(FLOATING_POINT) && !defined (_IO_USE_DTOA)
611                 /* trailing f.p. zeroes */
612                 PAD_0(fpprec);
613 #endif
614
615                 /* left-adjusting padding (always blank) */
616                 if (flags & LADJUST)
617                         PAD_SP(width - fieldsz);
618
619                 /* finally, adjust ret */
620                 ret += width > fieldsz ? width : fieldsz;
621
622         }
623 done:
624         return ret;
625 error:
626         return EOF;
627         /* NOTREACHED */
628 }
629
630 #if defined(FLOATING_POINT) && !defined(_IO_USE_DTOA)
631
632 static char *exponent(register char *p, register int exp, int fmtch)
633 {
634         register char *t;
635         char expbuf[MAXEXP];
636
637         *p++ = fmtch;
638         if (exp < 0) {
639                 exp = -exp;
640                 *p++ = '-';
641         }
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++);
651         }
652         else {
653                 *p++ = '0';
654                 *p++ = to_char(exp);
655         }
656         return (p);
657 }
658
659 static char * round(double fract, int *exp,
660                     register char *start, register char *end,
661                     char ch, int *signp)
662 {
663         double tmp;
664
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;
680                                 }
681                                 else {          /* f; add extra digit */
682                                 *--end = '1';
683                                 --start;
684                                 }
685                                 break;
686                         }
687                 }
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;
697                 }
698         return (start);
699 }
700
701 int __cvt_double(double number, register int prec, int flags, int *signp,
702                  int fmtch, char *startp, char *endp)
703 {
704         register char *p, *t;
705         register double fract;
706         int dotrim = 0, expcnt, gformat = 0;
707         double integer, tmp;
708
709         expcnt = 0;
710         if (number < 0) {
711                 number = -number;
712                 *signp = '-';
713         } else
714                 *signp = 0;
715
716         fract = modf(number, &integer);
717
718         /* get an extra slot for rounding. */
719         t = ++startp;
720
721         /*
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...
724          */
725         for (p = endp - 1; p >= startp && integer; ++expcnt) {
726                 tmp = modf(integer / 10, &integer);
727                 *p-- = to_char((int)((tmp + .01) * 10));
728         }
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';
737                 /*
738                  * if precision required or alternate flag set, add in a
739                  * decimal point.
740                  */
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);
753                 }
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;
765                         /*
766                          * if done precision and more of the integer component,
767                          * round using it; adjust fract so we don't re-round
768                          * later.
769                          */
770                         if (!prec && ++p < endp) {
771                                 fract = 0;
772                                 startp = round((double)0, &expcnt, startp,
773                                     t - 1, *p, signp);
774                         }
775                         /* adjust expcnt for digit in front of decimal */
776                         --expcnt;
777                 }
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;
785                         }
786                         *t++ = to_char((int)tmp);
787                         if (prec || flags&ALT)
788                                 *t++ = '.';
789                 }
790                 else {
791                         *t++ = '0';
792                         if (prec || flags&ALT)
793                                 *t++ = '.';
794                 }
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);
805                 }
806                 /* if requires more precision */
807                 for (; prec--; *t++ = '0');
808
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;
815                 }
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;
823                 /*
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
828                  */
829                 if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
830                         /*
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.
836                          */
837                         --prec;
838                         fmtch -= 2;             /* G->E, g->e */
839                         gformat = 1;
840                         goto eformat;
841                 }
842                 /*
843                  * reverse integer into beginning of buffer,
844                  * note, decrement precision
845                  */
846                 if (expcnt)
847                         for (; ++p < endp; *t++ = *p, --prec);
848                 else
849                         *t++ = '0';
850                 /*
851                  * if precision required or alternate flag set, add in a
852                  * decimal point.  If no digits yet, add in leading 0.
853                  */
854                 if (prec || flags&ALT) {
855                         dotrim = 1;
856                         *t++ = '.';
857                 }
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);
872                                 }
873                         }
874                         if (fract)
875                                 startp = round(fract, (int *)NULL, startp,
876                                     t - 1, (char)0, signp);
877                 }
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;
885                 }
886         }
887         return (t - startp);
888 }
889
890 #endif /* defined(FLOATING_POINT) && !defined(_IO_USE_DTOA) */