You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
9.4 KiB
365 lines
9.4 KiB
/**************************************************************************** |
|
* lib/unistd/lib_libdtoa.c |
|
* |
|
* This file was ported to NuttX by Yolande Cates. |
|
* |
|
* Copyright (c) 1990, 1993 |
|
* 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. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by the University of |
|
* California, Berkeley and its contributors. |
|
* 4. 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. |
|
* |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Included Files |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Pre-processor Definitions |
|
****************************************************************************/ |
|
|
|
#define MAXEXP 308 |
|
|
|
/**************************************************************************** |
|
* Private Type Declarations |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* 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 |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Global Variables |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Private Constant Data |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Private Variables |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Private Functions |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Name: cvt |
|
****************************************************************************/ |
|
|
|
static char* cvt(double value, int ndigits, int flags, char *sign, |
|
int *decpt, int ch, int *length) |
|
{ |
|
int mode, dsgn; |
|
char *digits, *bp, *rve; |
|
|
|
if (ch == 'f') |
|
{ |
|
mode = 3; /* ndigits after the decimal point */ |
|
} |
|
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 */ |
|
} |
|
|
|
if (value < 0) |
|
{ |
|
value = -value; |
|
*sign = '-'; |
|
} |
|
else |
|
{ |
|
*sign = '\000'; |
|
} |
|
|
|
digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); |
|
if ((ch != 'g' && ch != 'G') || IS_ALTFORM(flags)) |
|
{ |
|
/* Print trailing zeros */ |
|
|
|
bp = digits + ndigits; |
|
if (ch == 'f') |
|
{ |
|
if (*digits == '0' && value) |
|
{ |
|
*decpt = -ndigits + 1; |
|
} |
|
bp += *decpt; |
|
} |
|
|
|
if (value == 0) |
|
{ |
|
/* kludge for __dtoa irregularity */ |
|
|
|
rve = bp; |
|
} |
|
|
|
while (rve < bp) |
|
{ |
|
*rve++ = '0'; |
|
} |
|
} |
|
|
|
*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]; |
|
|
|
p = p0; |
|
*p++ = fmtch; |
|
if (exp < 0) |
|
{ |
|
exp = -exp; |
|
*p++ = '-'; |
|
} |
|
else |
|
{ |
|
*p++ = '+'; |
|
} |
|
|
|
t = expbuf + MAXEXP; |
|
if (exp > 9) |
|
{ |
|
do |
|
{ |
|
*--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); |
|
} |
|
|
|
/**************************************************************************** |
|
* Name: lib_dtoa |
|
* |
|
* Description: |
|
* This is part of lib_vsprintf(). It handles the floating point formats. |
|
* |
|
****************************************************************************/ |
|
|
|
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; |
|
|
|
cp = cvt(_double, prec, flags, &sign, &expt, ch, &ndig); |
|
cp_free = cp; |
|
|
|
if (ch == 'g' || ch == 'G') |
|
{ |
|
/* 'g' or 'G' fmt */ |
|
|
|
if (expt <= -4 || expt > prec) |
|
{ |
|
ch = (ch == 'g') ? 'e' : 'E'; |
|
} |
|
else |
|
{ |
|
ch = 'g'; |
|
} |
|
} |
|
|
|
if (ch <= 'e') |
|
{ |
|
/* 'e' or 'E' fmt */ |
|
|
|
--expt; |
|
expsize = exponent(expstr, expt, ch); |
|
size = expsize + ndig; |
|
if (ndig > 1 || IS_ALTFORM(flags)) |
|
{ |
|
++size; |
|
} |
|
} |
|
else if (ch == 'f') |
|
{ |
|
/* f fmt */ |
|
|
|
if (expt > 0) |
|
{ |
|
size = expt; |
|
if (prec || IS_ALTFORM(flags)) |
|
{ |
|
size += prec + 1; |
|
} |
|
} |
|
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); |
|
} |
|
|
|
if (sign) |
|
{ |
|
obj->put(obj, '-'); |
|
} |
|
|
|
if (_double == 0) |
|
{ |
|
/* kludge for __dtoa irregularity */ |
|
|
|
obj->put(obj, '0'); |
|
if (expt < ndig || IS_ALTFORM(flags)) |
|
{ |
|
obj->put(obj, '.'); |
|
|
|
i = ndig - 1; |
|
while (i > 0) |
|
{ |
|
obj->put(obj, '0'); |
|
i--; |
|
} |
|
} |
|
} |
|
else if (expt <= 0) |
|
{ |
|
obj->put(obj, '0'); |
|
obj->put(obj, '.'); |
|
|
|
i = ndig; |
|
while (i > 0) |
|
{ |
|
obj->put(obj, *cp); |
|
i--; |
|
cp++; |
|
} |
|
} |
|
else if (expt >= ndig) |
|
{ |
|
i = ndig; |
|
while (i > 0) |
|
{ |
|
obj->put(obj, *cp); |
|
i--; |
|
cp++; |
|
} |
|
|
|
i = expt - ndig; |
|
while (i > 0) |
|
{ |
|
obj->put(obj, '0'); |
|
i--; |
|
} |
|
|
|
if (IS_ALTFORM(flags)) |
|
{ |
|
obj->put(obj, '.'); |
|
} |
|
} |
|
else |
|
{ |
|
/* print the integer */ |
|
|
|
i = expt; |
|
while (i > 0) |
|
{ |
|
obj->put(obj, *cp); |
|
i--; |
|
cp++; |
|
} |
|
|
|
/* print the decimal place */ |
|
|
|
obj->put(obj, '.'); |
|
|
|
/* print the decimal */ |
|
|
|
i = ndig - expt; |
|
while (i > 0) |
|
{ |
|
obj->put(obj, *cp); |
|
i--; |
|
cp++; |
|
} |
|
} |
|
} |
|
|
|
/**************************************************************************** |
|
* Public Functions |
|
****************************************************************************/ |
|
|
|
|