diff options
Diffstat (limited to 'nuttx/lib/stdio/lib_libdtoa.c')
-rw-r--r-- | nuttx/lib/stdio/lib_libdtoa.c | 368 |
1 files changed, 150 insertions, 218 deletions
diff --git a/nuttx/lib/stdio/lib_libdtoa.c b/nuttx/lib/stdio/lib_libdtoa.c index 3bfe70aea..1e022a8eb 100644 --- a/nuttx/lib/stdio/lib_libdtoa.c +++ b/nuttx/lib/stdio/lib_libdtoa.c @@ -48,7 +48,15 @@ * Pre-processor Definitions ****************************************************************************/ -#define MAXEXP 308 +#define MAX_PREC 16 + +#ifndef MIN +# define MIN(a,b) (a < b ? a : b) +#endif + +#ifndef MAX +# define MAX(a,b) (a > b ? a : b) +#endif /**************************************************************************** * Private Type Declarations @@ -58,10 +66,6 @@ * Private Function Prototypes ****************************************************************************/ -static char* cvt(double value, int ndigits, int flags, char *sign, - int *decpt, int ch, int *length); -static int exponent(char *p0, int exp, int fmtch); - /**************************************************************************** * Global Constant Data ****************************************************************************/ @@ -79,284 +83,212 @@ static int exponent(char *p0, int exp, int fmtch); ****************************************************************************/ /**************************************************************************** + * Name: zeroes + * + * Description: + * Print the specified number of zeres + * + ****************************************************************************/ + +static void zeroes(FAR struct lib_outstream_s *obj, int nzeroes) +{ + int i; + + for (i = nzeroes; i > 0; i--) + { + obj->put(obj, '0'); + } +} + +/**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: cvt + * Name: lib_dtoa + * + * Description: + * This is part of lib_vsprintf(). It handles the floating point formats. + * This version supports only the %f (with precision). If no precision + * was provided in the format, this will use precision == 0 which is + * probably not what you want. + * + * Input Parameters: + * obj - The output stream object + * fmt - The format character. Not used 'f' is always assumed + * prec - The number of digits to the right of the decimal point. If no + * precision is provided in the format, this will be zero. And, + * unfortunately in this case, it will be treated literally as + * a precision of zero. + * flags - Only ALTFORM and SHOWPLUS flags are supported. ALTFORM only + * applies if prec == 0 which is not supported anyway. + * value - The floating point value to convert. + * ****************************************************************************/ -static char* cvt(double value, int ndigits, int flags, char *sign, - int *decpt, int ch, int *length) +static void lib_dtoa(FAR struct lib_outstream_s *obj, int fmt, int prec, + uint8_t flags, double value) { - int mode, dsgn; - char *digits, *bp, *rve; + FAR char *digits; /* String returned by __dtoa */ + FAR char *digalloc; /* Copy of digits to be freed after usage */ + FAR char *rve; /* Points to the end of the return value */ + int expt; /* Integer value of exponent */ + int numlen; /* Actual number of digits returned by cvt */ + int nchars; /* Number of characters to print */ + int dsgn; /* Unused sign indicator */ + int i; - if (ch == 'f') + /* Non-zero... positive or negative */ + + if (value < 0) { - mode = 3; /* ndigits after the decimal point */ + value = -value; + SET_NEGATE(flags); } - 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++; - } - mode = 2; /* ndigits significant digits */ - } + /* Perform the conversion */ - if (value < 0) + digits = __dtoa(value, 3, prec, &expt, &dsgn, &rve); + digalloc = digits; + numlen = rve - digits; + + if (IS_NEGATE(flags)) { - value = -value; - *sign = '-'; + obj->put(obj, '-'); } - else + else if (IS_SHOWPLUS(flags)) { - *sign = '\000'; + obj->put(obj, '+'); } - digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); - if ((ch != 'g' && ch != 'G') || IS_ALTFORM(flags)) + /* Special case exact zero or the case where the number is smaller than + * the print precision. + */ + + if (value == 0 || expt < -prec) { - /* Print trailing zeros */ + /* kludge for __dtoa irregularity */ - bp = digits + ndigits; - if (ch == 'f') - { - if (*digits == '0' && value) - { - *decpt = -ndigits + 1; - } - bp += *decpt; - } + obj->put(obj, '0'); - if (value == 0) + /* A decimal point is printed only in the alternate form or if a + * particular precision is requested. + */ + + if (prec > 0 || IS_ALTFORM(flags)) { - /* kludge for __dtoa irregularity */ + obj->put(obj, '.'); - rve = bp; - } + /* Always print at least one digit to the right of the decimal point. */ - while (rve < bp) - { - *rve++ = '0'; + prec = MAX(1, prec); } } - *length = rve - digits; - return digits; -} - -/**************************************************************************** - * Name: exponent - ****************************************************************************/ - -static int exponent(FAR char *p0, int exp, int fmtch) -{ - FAR char *p; - FAR char *t; - char expbuf[MAXEXP]; + /* A non-zero value will be printed */ - p = p0; - *p++ = fmtch; - if (exp < 0) - { - exp = -exp; - *p++ = '-'; - } else { - *p++ = '+'; - } - t = expbuf + MAXEXP; - if (exp > 9) - { - do + /* Handle the case where the value is less than 1.0 (in magnitude) and + * will need a leading zero. + */ + + if (expt <= 0) { - *--t = (exp % 10) + '0'; - } - while ((exp /= 10) > 9); - *--t = exp + '0'; - for (; t < expbuf + MAXEXP; *p++ = *t++); - } - else - { - *p++ = '0'; - *p++ = exp + '0'; - } - return (p - p0); -} + /* Print a single zero to the left of the decimal point */ -/**************************************************************************** - * Name: lib_dtoa - * - * Description: - * This is part of lib_vsprintf(). It handles the floating point formats. - * - ****************************************************************************/ + obj->put(obj, '0'); -static void lib_dtoa(FAR struct lib_outstream_s *obj, int ch, int prec, - uint8_t flags, double _double) -{ - FAR char *cp; /* Handy char pointer (short term usage) */ - FAR char *cp_free = NULL; /* BIONIC: copy of cp to be freed after usage */ - char expstr[7]; /* Buffer for exponent string */ - char sign; /* Temporary negative sign for floats */ - int expt; /* Integer value of exponent */ - int expsize = 0; /* Character count for expstr */ - int ndig; /* Actual number of digits returned by cvt */ - int size; /* Size of converted field or string */ - int i; + /* Print the decimal point */ - cp = cvt(_double, prec, flags, &sign, &expt, ch, &ndig); - cp_free = cp; + obj->put(obj, '.'); - if (ch == 'g' || ch == 'G') - { - /* 'g' or 'G' fmt */ + /* Print any leading zeros to the right of the decimal point */ - if (expt <= -4 || expt > prec) - { - ch = (ch == 'g') ? 'e' : 'E'; - } - else - { - ch = 'g'; + if (expt < 0) + { + nchars = MIN(-expt, prec); + zeroes(obj, nchars); + prec -= nchars; + } } - } - if (ch <= 'e') - { - /* 'e' or 'E' fmt */ + /* Handle the general case where the value is greater than 1.0 (in + * magnitude). + */ - --expt; - expsize = exponent(expstr, expt, ch); - size = expsize + ndig; - if (ndig > 1 || IS_ALTFORM(flags)) + else { - ++size; - } - } - else if (ch == 'f') - { - /* f fmt */ + /* Print the integer part to the left of the decimal point */ - if (expt > 0) - { - size = expt; - if (prec || IS_ALTFORM(flags)) + for (i = expt; i > 0; i--) { - size += prec + 1; + obj->put(obj, *digits); + digits++; } - } - else /* "0.X" */ - { - size = prec + 2; - } - } - else if (expt >= ndig) - { - /* fixed g fmt */ - size = expt; - if (IS_ALTFORM(flags)) - { - ++size; - } - } - else - { - size = ndig + (expt > 0 ? 1 : 2 - expt); - } + /* Get the length of the fractional part */ - if (sign) - { - obj->put(obj, '-'); - } + numlen -= expt; - if (_double == 0) - { - /* kludge for __dtoa irregularity */ - - obj->put(obj, '0'); - if (expt < ndig || IS_ALTFORM(flags)) - { - obj->put(obj, '.'); + /* If there is no fractional part, then a decimal point is printed + * only in the alternate form or if a particular precision is + * requested. + */ - i = ndig - 1; - while (i > 0) + if (numlen > 0 || prec > 0 || IS_ALTFORM(flags)) { - obj->put(obj, '0'); - i--; + /* Print the decimal point */ + + obj->put(obj, '.'); + + /* Always print at least one digit to the right of the decimal + * point. + */ + + prec = MAX(1, prec); } } - } - else if (expt <= 0) - { - obj->put(obj, '0'); - obj->put(obj, '.'); - i = ndig; - while (i > 0) + /* If a precision was specified, then limit the number digits to the + * right of the decimal point. + */ + + if (prec > 0) { - obj->put(obj, *cp); - i--; - cp++; + nchars = MIN(numlen, prec); } - } - else if (expt >= ndig) - { - i = ndig; - while (i > 0) + else { - obj->put(obj, *cp); - i--; - cp++; + nchars = numlen; } - i = expt - ndig; - while (i > 0) - { - obj->put(obj, '0'); - i--; - } + /* Print the fractional part to the right of the decimal point */ - if (IS_ALTFORM(flags)) + for (i = nchars; i > 0; i--) { - obj->put(obj, '.'); + obj->put(obj, *digits); + digits++; } - } - else - { - /* print the integer */ - i = expt; - while (i > 0) - { - obj->put(obj, *cp); - i--; - cp++; - } + /* Decremnt to get the number of trailing zeroes to print */ + + prec -= nchars; + } - /* print the decimal place */ + /* Finally, print any trailing zeroes */ - obj->put(obj, '.'); + zeroes(obj, prec); - /* print the decimal */ + /* Is this memory supposed to be freed or not? */ - i = ndig - expt; - while (i > 0) - { - obj->put(obj, *cp); - i--; - cp++; - } +#if 0 + if (digalloc) + { + free(digalloc); } +#endif } /**************************************************************************** |