diff options
Diffstat (limited to 'crypto/bio/b_print.c')
-rw-r--r-- | crypto/bio/b_print.c | 149 |
1 files changed, 139 insertions, 10 deletions
diff --git a/crypto/bio/b_print.c b/crypto/bio/b_print.c index 0ae4f25..36400cd 100644 --- a/crypto/bio/b_print.c +++ b/crypto/bio/b_print.c @@ -52,7 +52,7 @@ static int fmtstr(char **, char **, size_t *, size_t *, 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, @@ -90,6 +90,11 @@ static int _dopr(char **sbuffer, char **buffer, #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) @@ -268,7 +273,7 @@ _dopr(char **sbuffer, else fvalue = va_arg(args, double); if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, - flags)) + flags, F_FORMAT)) return 0; break; case 'E': @@ -279,7 +284,7 @@ _dopr(char **sbuffer, else fvalue = va_arg(args, double); if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, - flags)) + flags, E_FORMAT)) return 0; break; case 'G': @@ -290,7 +295,7 @@ _dopr(char **sbuffer, else fvalue = va_arg(args, double); if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, - flags)) + flags, G_FORMAT)) return 0; break; case 'c': @@ -542,23 +547,28 @@ static int 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) @@ -566,6 +576,68 @@ fmtfp(char **sbuffer, 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; /* @@ -597,16 +669,51 @@ fmtfp(char **sbuffer, 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; @@ -660,6 +767,28 @@ fmtfp(char **sbuffer, 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, ' ')) |