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