OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.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) */