OSDN Git Service

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