summaryrefslogtreecommitdiffstats
path: root/newlib/libc/stdio/nano-vfprintf_float.c
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2014-07-04 17:21:45 +0000
committerJeff Johnston <jjohnstn@redhat.com>2014-07-04 17:21:45 +0000
commitd34336767e45ee801ebb107e40abe4b1acbd3d14 (patch)
tree4b39e537048f743fc262f68c917df3592bac84d9 /newlib/libc/stdio/nano-vfprintf_float.c
parentfcef025b94860210c8567e87ca0df0220b2ff237 (diff)
downloadcygnal-d34336767e45ee801ebb107e40abe4b1acbd3d14.tar.gz
cygnal-d34336767e45ee801ebb107e40abe4b1acbd3d14.tar.bz2
cygnal-d34336767e45ee801ebb107e40abe4b1acbd3d14.zip
2014-07-04 Bin Cheng <bin.cheng@arm.com>
* README (--enable-newlib-nano-formatted-io): Describe. * acconfig.h (_NANO_FORMATTED_IO): Undef. * newlib.hin (_NANO_FORMATTED_IO): Undef. * configure.in (--enable-newlib-nano-formatted-io): New option. * configure: Regenerated. * libc/configure.in (--enable-newlib-nano-formatted-io): New option. * libc/configure: Regenerated. * libc/stdio/Makefile.am (NEWLIB_NANO_FORMATTED_IO): Support new configuration option. * libc/stdio/Makefile.in: Regenerated. * libc/stdio/asnprintf.c (_asniprintf_r, asniprintf): Use _NANO_FORMATTED_IO to declare alias prototypes. * libc/stdio/asprintf.c (_asiprintf_r, asiprintf): Ditto. * libc/stdio/dprintf.c (_diprintf_r, diprintf): Ditto. * libc/stdio/fprintf.c (_fiprintf_r, fiprintf): Ditto. * libc/stdio/fscanf.c (fiscanf, _fiscanf_r): Ditto. * libc/stdio/printf.c (_iprintf_r, iprintf): Ditto. * libc/stdio/scanf.c (iscanf, _iscanf_r): Ditto. * libc/stdio/snprintf.c (_sniprintf_r, sniprintf): Ditto. * libc/stdio/sprintf.c (_siprintf_r, siprintf): Ditto. * libc/stdio/sscanf.c (siscanf, _siscanf_r): Ditto. * libc/stdio/vasnprintf.c (_vasniprintf_r, vasniprintf): Ditto. * libc/stdio/vasprintf.c (vasiprintf, _vasiprintf_r): Ditto. * libc/stdio/vdprintf.c (_vdiprintf_r, vdiprintf): Ditto. * libc/stdio/vprintf.c (viprintf, _viprintf_r): Ditto. * libc/stdio/vscanf.c (viscanf, _viscanf_r): Ditto. * libc/stdio/vsnprintf.c (vsniprintf, _vsniprintf_r): Ditto. * libc/stdio/vsprintf.c (vsiprintf, _vsiprintf_r): Ditto. * libc/stdio/vsscanf.c (vsiscanf, _vsiscanf_r): Ditto. * libc/stdio/nano-vfprintf.c: New file. * libc/stdio/nano-vfprintf_float.c: New file. * libc/stdio/nano-vfprintf_i.c: New file. * libc/stdio/nano-vfprintf_local.h: New file. * libc/stdio/nano-vfscanf.c: New file. * libc/stdio/nano-vfscanf_float.c: New file. * libc/stdio/nano-vfscanf_i.c: New file. * libc/stdio/nano-vfscanf_local.h: New file.
Diffstat (limited to 'newlib/libc/stdio/nano-vfprintf_float.c')
-rw-r--r--newlib/libc/stdio/nano-vfprintf_float.c364
1 files changed, 364 insertions, 0 deletions
diff --git a/newlib/libc/stdio/nano-vfprintf_float.c b/newlib/libc/stdio/nano-vfprintf_float.c
new file mode 100644
index 000000000..aca24aec0
--- /dev/null
+++ b/newlib/libc/stdio/nano-vfprintf_float.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <newlib.h>
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <wchar.h>
+#include <sys/lock.h>
+#include <stdarg.h>
+#include "local.h"
+#include "../stdlib/local.h"
+#include "fvwrite.h"
+#include "vfieeefp.h"
+#include "nano-vfprintf_local.h"
+
+char *__cvt (struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits,
+ int flags, char *sign, int *decpt, int ch, int *length,
+ char *buf);
+
+int __exponent (char *p0, int exp, int fmtch);
+
+#ifdef FLOATING_POINT
+
+/* Using reentrant DATA, convert finite VALUE into a string of digits
+ with no decimal point, using NDIGITS precision and FLAGS as guides
+ to whether trailing zeros must be included. Set *SIGN to nonzero
+ if VALUE was negative. Set *DECPT to the exponent plus one. Set
+ *LENGTH to the length of the returned string. CH must be one of
+ [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
+ otherwise the return value shares the mprec reentrant storage. */
+char *
+__cvt (struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
+ char *sign, int *decpt, int ch, int *length, char *buf)
+{
+ int mode, dsgn;
+ char *digits, *bp, *rve;
+ union double_union tmp;
+
+ tmp.d = value;
+ /* This will check for "< 0" and "-0.0". */
+ if (word0 (tmp) & Sign_bit)
+ {
+ value = -value;
+ *sign = '-';
+ }
+ else
+ *sign = '\000';
+
+ if (ch == 'f' || ch == 'F')
+ {
+ /* Ndigits after the decimal point. */
+ mode = 3;
+ }
+ else
+ {
+ /* To obtain ndigits after the decimal point for the 'e'
+ and 'E' formats, round to ndigits + 1 significant figures. */
+ if (ch == 'e' || ch == 'E')
+ {
+ ndigits++;
+ }
+ /* Ndigits significant digits. */
+ mode = 2;
+ }
+
+ digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
+
+ /* Print trailing zeros. */
+ if ((ch != 'g' && ch != 'G') || flags & ALT)
+ {
+ bp = digits + ndigits;
+ if (ch == 'f' || ch == 'F')
+ {
+ if (*digits == '0' && value)
+ *decpt = -ndigits + 1;
+ bp += *decpt;
+ }
+ /* Kludge for __dtoa irregularity. */
+ if (value == 0)
+ rve = bp;
+ while (rve < bp)
+ *rve++ = '0';
+ }
+ *length = rve - digits;
+ return (digits);
+}
+
+/* This function is copied from exponent in vfprintf.c with support for
+ C99 formats removed. We don't use the original function in order to
+ decouple nano implementation of formatted IO from the Newlib one. */
+int
+__exponent (char *p0, int exp, int fmtch)
+{
+ register char *p, *t;
+ char expbuf[MAXEXPLEN];
+#define isa 0
+
+ p = p0;
+ *p++ = isa ? 'p' - 'a' + fmtch : fmtch;
+ if (exp < 0)
+ {
+ exp = -exp;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = expbuf + MAXEXPLEN;
+ if (exp > 9)
+ {
+ do
+ {
+ *--t = to_char (exp % 10);
+ }
+ while ((exp /= 10) > 9);
+ *--t = to_char (exp);
+ for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
+ }
+ else
+ {
+ if (!isa)
+ *p++ = '0';
+ *p++ = to_char (exp);
+ }
+ return (p - p0);
+}
+
+/* Decode and print floating point number specified by "eEfgG". */
+int
+_printf_float (struct _reent *data,
+ struct _prt_data_t *pdata,
+ FILE * fp,
+ int (*pfunc) (struct _reent *, FILE *, _CONST char *,
+ size_t len), va_list * ap)
+{
+#define _fpvalue (pdata->_double_)
+
+ char *decimal_point = _localeconv_r (data)->decimal_point;
+ size_t decp_len = strlen (decimal_point);
+ /* Temporary negative sign for floats. */
+ char softsign;
+ /* Integer value of exponent. */
+ int expt;
+ /* Character count for expstr. */
+ int expsize = 0;
+ /* Actual number of digits returned by cvt. */
+ int ndig = 0;
+ char *cp;
+ int n;
+ /* Field size expanded by dprec(not for _printf_float). */
+ int realsz;
+ char code = pdata->code;
+
+ if (pdata->flags & LONGDBL)
+ {
+ _fpvalue = (double) GET_ARG (N, *ap, _LONG_DOUBLE);
+ }
+ else
+ {
+ _fpvalue = GET_ARG (N, *ap, double);
+ }
+
+ /* Do this before tricky precision changes.
+
+ If the output is infinite or NaN, leading
+ zeros are not permitted. Otherwise, scanf
+ could not read what printf wrote. */
+ if (isinf (_fpvalue))
+ {
+ if (_fpvalue < 0)
+ pdata->l_buf[0] = '-';
+ if (code <= 'G') /* 'A', 'E', 'F', or 'G'. */
+ cp = "INF";
+ else
+ cp = "inf";
+ pdata->size = 3;
+ pdata->flags &= ~ZEROPAD;
+ goto print_float;
+ }
+ if (isnan (_fpvalue))
+ {
+ if (code <= 'G') /* 'A', 'E', 'F', or 'G'. */
+ cp = "NAN";
+ else
+ cp = "nan";
+ pdata->size = 3;
+ pdata->flags &= ~ZEROPAD;
+ goto print_float;
+ }
+
+ if (pdata->prec == -1)
+ {
+ pdata->prec = DEFPREC;
+ }
+ else if ((code == 'g' || code == 'G') && pdata->prec == 0)
+ {
+ pdata->prec = 1;
+ }
+
+ pdata->flags |= FPT;
+
+ cp = __cvt (data, _fpvalue, pdata->prec, pdata->flags, &softsign,
+ &expt, code, &ndig, cp);
+
+ if (code == 'g' || code == 'G')
+ {
+ if (expt <= -4 || expt > pdata->prec)
+ /* 'e' or 'E'. */
+ code -= 2;
+ else
+ code = 'g';
+ }
+ if (code <= 'e')
+ {
+ /* 'a', 'A', 'e', or 'E' fmt. */
+ --expt;
+ expsize = __exponent (pdata->expstr, expt, code);
+ pdata->size = expsize + ndig;
+ if (ndig > 1 || pdata->flags & ALT)
+ ++pdata->size;
+ }
+ else
+ {
+ if (code == 'f')
+ {
+ /* 'f' fmt. */
+ if (expt > 0)
+ {
+ pdata->size = expt;
+ if (pdata->prec || pdata->flags & ALT)
+ pdata->size += pdata->prec + 1;
+ }
+ else
+ /* "0.X". */
+ pdata->size = (pdata->prec || pdata->flags & ALT)
+ ? pdata->prec + 2 : 1;
+ }
+ else if (expt >= ndig)
+ {
+ /* Fixed g fmt. */
+ pdata->size = expt;
+ if (pdata->flags & ALT)
+ ++pdata->size;
+ }
+ else
+ pdata->size = ndig + (expt > 0 ? 1 : 2 - expt);
+ pdata->lead = expt;
+ }
+
+ if (softsign)
+ pdata->l_buf[0] = '-';
+print_float:
+ if (_printf_common (data, pdata, &realsz, fp, pfunc) == -1)
+ goto error;
+
+ if ((pdata->flags & FPT) == 0)
+ {
+ PRINT (cp, pdata->size);
+ }
+ else
+ {
+ /* Glue together f_p fragments. */
+ if (code >= 'f')
+ {
+ /* 'f' or 'g'. */
+ if (_fpvalue == 0)
+ {
+ /* Kludge for __dtoa irregularity. */
+ PRINT ("0", 1);
+ if (expt < ndig || pdata->flags & ALT)
+ {
+ PRINT (decimal_point, decp_len);
+ PAD (ndig - 1, pdata->zero);
+ }
+ }
+ else if (expt <= 0)
+ {
+ PRINT ("0", 1);
+ if (expt || ndig || pdata->flags & ALT)
+ {
+ PRINT (decimal_point, decp_len);
+ PAD (-expt, pdata->zero);
+ PRINT (cp, ndig);
+ }
+ }
+ else
+ {
+ char *convbuf = cp;
+ PRINTANDPAD (cp, convbuf + ndig, pdata->lead, pdata->zero);
+ cp += pdata->lead;
+ if (expt < ndig || pdata->flags & ALT)
+ PRINT (decimal_point, decp_len);
+ PRINTANDPAD (cp, convbuf + ndig, ndig - expt, pdata->zero);
+ }
+ }
+ else
+ {
+ /* 'a', 'A', 'e', or 'E'. */
+ if (ndig > 1 || pdata->flags & ALT)
+ {
+ PRINT (cp, 1);
+ cp++;
+ PRINT (decimal_point, decp_len);
+ if (_fpvalue)
+ {
+ PRINT (cp, ndig - 1);
+ }
+ /* "0.[0..]". */
+ else
+ /* __dtoa irregularity. */
+ PAD (ndig - 1, pdata->zero);
+ }
+ else /* "XeYYY". */
+ PRINT (cp, 1);
+ PRINT (pdata->expstr, expsize);
+ }
+ }
+
+ /* Left-adjusting padding (always blank). */
+ if (pdata->flags & LADJUST)
+ PAD (pdata->width - realsz, pdata->blank);
+
+ return (pdata->width > realsz ? pdata->width : realsz);
+error:
+ return -1;
+
+#undef _fpvalue
+}
+
+#endif