static int fmtint(char **, char **, size_t *, size_t *,
LLONG, int, int, int, int);
static int fmtfp(char **, char **, size_t *, size_t *,
- LDOUBLE, int, int, int);
+ LDOUBLE, int, int, int, int);
static int doapr_outch(char **, char **, size_t *, size_t *, int);
static int _dopr(char **sbuffer, char **buffer,
size_t *maxlen, size_t *retlen, int *truncated,
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
+/* Floating point formats */
+#define F_FORMAT 0
+#define E_FORMAT 1
+#define G_FORMAT 2
+
/* some handy macros */
#define char_to_int(p) (p - '0')
#define OSSL_MAX(p,q) ((p >= q) ? p : q)
else
fvalue = va_arg(args, double);
if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
- flags))
+ flags, F_FORMAT))
return 0;
break;
case 'E':
else
fvalue = va_arg(args, double);
if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
- flags))
+ flags, E_FORMAT))
return 0;
break;
case 'G':
else
fvalue = va_arg(args, double);
if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
- flags))
+ flags, G_FORMAT))
return 0;
break;
case 'c':
fmtfp(char **sbuffer,
char **buffer,
size_t *currlen,
- size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags)
+ size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style)
{
int signvalue = 0;
LDOUBLE ufvalue;
+ LDOUBLE tmpvalue;
char iconvert[20];
char fconvert[20];
+ char econvert[20];
int iplace = 0;
int fplace = 0;
+ int eplace = 0;
int padlen = 0;
int zpadlen = 0;
+ long exp = 0;
long intpart;
long fracpart;
long max10;
+ int realstyle;
if (max < 0)
max = 6;
- ufvalue = abs_val(fvalue);
+
if (fvalue < 0)
signvalue = '-';
else if (flags & DP_F_PLUS)
else if (flags & DP_F_SPACE)
signvalue = ' ';
+ /*
+ * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT
+ * depending on the number to be printed. Work out which one it is and use
+ * that from here on.
+ */
+ if (style == G_FORMAT) {
+ if (fvalue == 0.0) {
+ realstyle = F_FORMAT;
+ } else if (fvalue < 0.0001) {
+ realstyle = E_FORMAT;
+ } else if ((max == 0 && fvalue >= 10)
+ || (max > 0 && fvalue >= pow_10(max))) {
+ realstyle = E_FORMAT;
+ } else {
+ realstyle = F_FORMAT;
+ }
+ } else {
+ realstyle = style;
+ }
+
+ if (style != F_FORMAT) {
+ tmpvalue = fvalue;
+ /* Calculate the exponent */
+ if (fvalue != 0.0) {
+ while (tmpvalue < 1) {
+ tmpvalue *= 10;
+ exp--;
+ }
+ while (tmpvalue > 10) {
+ tmpvalue /= 10;
+ exp++;
+ }
+ }
+ if (style == G_FORMAT) {
+ /*
+ * In G_FORMAT the "precision" represents significant digits. We
+ * always have at least 1 significant digit.
+ */
+ if (max == 0)
+ max = 1;
+ /* Now convert significant digits to decimal places */
+ if (realstyle == F_FORMAT) {
+ max -= (exp + 1);
+ if (max < 0) {
+ /*
+ * Should not happen. If we're in F_FORMAT then exp < max?
+ */
+ return 0;
+ }
+ } else {
+ /*
+ * In E_FORMAT there is always one significant digit in front
+ * of the decimal point, so:
+ * significant digits == 1 + decimal places
+ */
+ max--;
+ }
+ }
+ if (realstyle == E_FORMAT)
+ fvalue = tmpvalue;
+ }
+ ufvalue = abs_val(fvalue);
intpart = (long)ufvalue;
/*
iconvert[iplace] = 0;
/* convert fractional part */
- do {
+ while (fplace < max) {
+ if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) {
+ /* We strip trailing zeros in G_FORMAT */
+ max--;
+ fracpart = fracpart / 10;
+ if (fplace < max)
+ continue;
+ break;
+ }
fconvert[fplace++] = "0123456789"[fracpart % 10];
fracpart = (fracpart / 10);
- } while (fplace < max);
+ }
+
if (fplace == sizeof fconvert)
fplace--;
fconvert[fplace] = 0;
- /* -1 for decimal point, another -1 if we are printing a sign */
- padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ /* convert exponent part */
+ if (realstyle == E_FORMAT) {
+ int tmpexp;
+ if (exp < 0)
+ tmpexp = -exp;
+ else
+ tmpexp = exp;
+
+ do {
+ econvert[eplace++] = "0123456789"[tmpexp % 10];
+ tmpexp = (tmpexp / 10);
+ } while (tmpexp > 0 && eplace < (int)sizeof(econvert));
+ /* Exponent is huge!! Too big to print */
+ if (tmpexp > 0)
+ return 0;
+ /* Add a leading 0 for single digit exponents */
+ if (eplace == 1)
+ econvert[eplace++] = '0';
+ }
+
+ /*
+ * -1 for decimal point (if we have one, i.e. max > 0),
+ * another -1 if we are printing a sign
+ */
+ padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0);
+ /* Take some off for exponent prefix "+e" and exponent */
+ if (realstyle == E_FORMAT)
+ padlen -= 2 + eplace;
zpadlen = max - fplace;
if (zpadlen < 0)
zpadlen = 0;
return 0;
--zpadlen;
}
+ if (realstyle == E_FORMAT) {
+ char ech;
+
+ if ((flags & DP_F_UP) == 0)
+ ech = 'e';
+ else
+ ech = 'E';
+ if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech))
+ return 0;
+ if (exp < 0) {
+ if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-'))
+ return 0;
+ } else {
+ if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+'))
+ return 0;
+ }
+ while (eplace > 0) {
+ if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
+ econvert[--eplace]))
+ return 0;
+ }
+ }
while (padlen < 0) {
if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))