Changeset 34b9299 in mainline


Ignore:
Timestamp:
2012-10-31T19:47:53Z (11 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
82d062d8
Parents:
f0da6855
git-author:
Adam Hraska <adam.hraska@…> (2012-10-31 19:47:53)
git-committer:
Jakub Jermar <jakub@…> (2012-10-31 19:47:53)
Message:

printf() full floating point support.
(Thanks to Adam Hraska.)

Location:
uspace
Files:
8 added
7 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/tester/Makefile

    rf0da6855 r34b9299  
    4242        print/print4.c \
    4343        print/print5.c \
     44        print/print6.c \
    4445        console/console1.c \
    4546        stdio/stdio1.c \
  • uspace/app/tester/print/print5.def

    rf0da6855 r34b9299  
    11{
    2         "print1",
    3         "String printf test",
    4         &test_print1,
     2        "print5",
     3        "Char printf test",
     4        &test_print5,
    55        true
    66},
  • uspace/app/tester/tester.c

    rf0da6855 r34b9299  
    5353#include "print/print4.def"
    5454#include "print/print5.def"
     55#include "print/print6.def"
    5556#include "console/console1.def"
    5657#include "stdio/stdio1.def"
  • uspace/app/tester/tester.h

    rf0da6855 r34b9299  
    8585extern const char *test_print4(void);
    8686extern const char *test_print5(void);
     87extern const char *test_print6(void);
    8788extern const char *test_console1(void);
    8889extern const char *test_stdio1(void);
  • uspace/lib/c/Makefile

    rf0da6855 r34b9299  
    116116        generic/iplink.c \
    117117        generic/iplink_srv.c \
     118        generic/ieee_double.c \
     119        generic/power_of_ten.c \
     120        generic/double_to_str.c \
    118121        generic/malloc.c \
    119122        generic/sysinfo.c \
  • uspace/lib/c/generic/io/printf_core.c

    rf0da6855 r34b9299  
    4242#include <ctype.h>
    4343#include <str.h>
     44#include <double_to_str.h>
     45#include <ieee_double.h>
     46#include <assert.h>
     47#include <macros.h>
     48
    4449
    4550/** show prefixes 0x or 0 */
    4651#define __PRINTF_FLAG_PREFIX       0x00000001
    4752
     53/** show the decimal point even if no fractional digits present */
     54#define __PRINTF_FLAG_DECIMALPT    0x00000001
     55
    4856/** signed / unsigned number */
    4957#define __PRINTF_FLAG_SIGNED       0x00000002
     
    6674/** number has - sign */
    6775#define __PRINTF_FLAG_NEGATIVE     0x00000100
     76
     77/** don't print trailing zeros in the fractional part */
     78#define __PRINTF_FLAG_NOFRACZEROS  0x00000200
     79
    6880
    6981/**
     
    110122static const char invalch = U_SPECIAL;
    111123
     124
     125
     126/** Unformatted double number string representation. */
     127typedef struct {
     128        /** Buffer with len digits, no sign or leading zeros. */
     129        char *str;
     130        /** Number of digits in str. */
     131        int len;
     132        /** Decimal exponent, ie number = str * 10^dec_exp */
     133        int dec_exp;
     134        /** True if negative. */
     135        bool neg;
     136} double_str_t;
     137
     138
     139
     140/** Returns the sign character or 0 if no sign should be printed. */
     141static int get_sign_char(bool negative, uint32_t flags)
     142{
     143        if (negative) {
     144                return '-';
     145        } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
     146                return '+';
     147        } else if (flags & __PRINTF_FLAG_SPACESIGN) {
     148                return ' ';
     149        } else {
     150                return 0;
     151        }
     152}
     153
     154/** Prints count times character ch. */
     155static int print_padding(char ch, int count, printf_spec_t *ps)
     156{
     157        for (int i = 0; i < count; ++i) {
     158                if (ps->str_write(&ch, 1, ps->data) < 0) {
     159                        return -1;
     160                }
     161        }
     162
     163        return count;
     164}
     165
     166
    112167/** Print one or more characters without adding newline.
    113168 *
     
    281336                return printf_putstr(nullstr, ps);
    282337       
    283         /* Print leading spaces. */
    284338        size_t strw = str_length(str);
     339
     340        /* Precision unspecified - print everything. */
    285341        if ((precision == 0) || (precision > strw))
    286342                precision = strw;
     
    329385                return printf_putstr(nullstr, ps);
    330386       
    331         /* Print leading spaces. */
    332387        size_t strw = wstr_length(str);
     388
     389        /* Precision not specified - print everything. */
    333390        if ((precision == 0) || (precision > strw))
    334391                precision = strw;
     
    377434    uint32_t flags, printf_spec_t *ps)
    378435{
     436        /* Precision not specified. */
     437        if (precision < 0) {
     438                precision = 0;
     439        }
     440       
    379441        const char *digits;
    380442        if (flags & __PRINTF_FLAG_BIGCHARS)
     
    525587       
    526588        return ((int) counter);
     589}
     590
     591/** Prints a special double (ie NaN, infinity) padded to width characters. */
     592static int print_special(ieee_double_t val, int width, uint32_t flags,
     593        printf_spec_t *ps)
     594{
     595        assert(val.is_special);
     596
     597        char sign = get_sign_char(val.is_negative, flags);
     598
     599        const int str_len = 3;
     600        const char *str;
     601       
     602        if (flags & __PRINTF_FLAG_BIGCHARS) {
     603                str = val.is_infinity ? "INF" : "NAN";
     604        } else {
     605                str = val.is_infinity ? "inf" : "nan";
     606        }
     607
     608        int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
     609
     610        int counter = 0;
     611        int ret;
     612
     613        /* Leading padding. */
     614        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
     615                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     616                        return -1;
     617
     618                counter += ret;
     619        }
     620
     621        if (sign) {
     622                if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
     623                        return -1;
     624               
     625                counter += ret;
     626        }
     627
     628        if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
     629                return -1;
     630       
     631        counter += ret;
     632
     633
     634        /* Trailing padding. */
     635        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     636                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     637                        return -1;
     638
     639                counter += ret;
     640        }
     641
     642        return counter;
     643}
     644
     645/** Trims trailing zeros but leaves a single "0" intact. */
     646static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
     647{
     648        /* Cut the zero off by adjusting the exponent. */
     649        while (2 <= *len && '0' == buf[*len - 1]) {
     650                --*len;
     651                ++*dec_exp;
     652        }
     653}
     654
     655/** Textually round up the last digit thereby eliminating it. */
     656static void fp_round_up(char *buf, int *len, int *dec_exp)
     657{
     658        assert(1 <= *len);
     659
     660        char *last_digit = &buf[*len - 1];
     661
     662        int carry = ('5' <= *last_digit);
     663
     664        /* Cut the digit off by adjusting the exponent. */
     665        --*len;
     666        ++*dec_exp;
     667        --last_digit;
     668
     669        if (carry) {
     670                /* Skip all the digits to cut off/round to zero. */
     671                while (buf <= last_digit && '9' == *last_digit) {
     672                        --last_digit;
     673                }
     674
     675                /* last_digit points to the last digit to round but not '9' */
     676                if (buf <= last_digit) {
     677                        *last_digit += 1;
     678                        int new_len = last_digit - buf + 1;
     679                        *dec_exp += *len - new_len;
     680                        *len = new_len;
     681                } else {
     682                        /* All len digits rounded to 0. */
     683                        buf[0] = '1';
     684                        *dec_exp += *len;
     685                        *len = 1;
     686                }
     687        } else {
     688                /* The only digit was rounded to 0. */
     689                if (last_digit < buf) {
     690                        buf[0] = '0';
     691                        *dec_exp = 0;
     692                        *len = 1;
     693                }
     694        }
     695}
     696
     697
     698/** Format and print the double string repressentation according
     699 *  to the %f specifier.
     700 */
     701static int print_double_str_fixed(double_str_t *val_str, int precision, int width,
     702        uint32_t flags, printf_spec_t *ps)
     703{
     704        int len = val_str->len;
     705        char *buf = val_str->str;
     706        int dec_exp = val_str->dec_exp;
     707
     708        assert(0 < len);
     709        assert(0 <= precision);
     710        assert(0 <= dec_exp || -dec_exp <= precision);
     711
     712        /* Number of integral digits to print (at least leading zero). */
     713        int int_len = max(1, len + dec_exp);
     714
     715        char sign = get_sign_char(val_str->neg, flags);
     716
     717        /* Fractional portion lengths. */
     718        int last_frac_signif_pos = max(0, -dec_exp);
     719        int leading_frac_zeros = max(0, last_frac_signif_pos - len);
     720        int signif_frac_figs = min(last_frac_signif_pos, len);
     721        int trailing_frac_zeros = precision - last_frac_signif_pos;
     722        char *buf_frac = buf + len - signif_frac_figs;
     723
     724        if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     725                trailing_frac_zeros = 0;
     726        }
     727
     728        int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
     729
     730        bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT);
     731
     732        /* Number of non-padding chars to print. */
     733        int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len;
     734
     735        int padding_len = max(0, width - num_len);
     736        int ret = 0;
     737        int counter = 0;
     738
     739        /* Leading padding and sign. */
     740
     741        if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
     742                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     743                        return -1;
     744
     745                counter += ret;
     746        }
     747
     748        if (sign) {
     749                if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
     750                        return -1;
     751               
     752                counter += ret;
     753        }
     754
     755        if (flags & __PRINTF_FLAG_ZEROPADDED) {
     756                if ((ret = print_padding('0', padding_len, ps)) < 0)
     757                        return -1;
     758
     759                counter += ret;
     760        }
     761
     762        /* Print the intergral part of the buffer. */
     763
     764        int buf_int_len = min(len, len + dec_exp);
     765
     766        if (0 < buf_int_len) {
     767                if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0)
     768                        return -1;
     769
     770                counter += ret;
     771
     772                /* Print trailing zeros of the integral part of the number. */
     773                if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0)
     774                        return -1;
     775        } else {
     776                /* Single leading integer 0. */
     777                char ch = '0';
     778                if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
     779                        return -1;
     780        }
     781
     782        counter += ret;
     783       
     784        /* Print the decimal point and the fractional part. */
     785        if (has_decimal_pt) {
     786                char ch = '.';
     787
     788                if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
     789                        return -1;
     790               
     791                counter += ret;
     792
     793                /* Print leading zeros of the fractional part of the number. */
     794                if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0)
     795                        return -1;
     796
     797                counter += ret;
     798
     799                /* Print significant digits of the fractional part of the number. */
     800                if (0 < signif_frac_figs) {
     801                        if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0)
     802                                return -1;
     803
     804                        counter += ret;
     805                }
     806
     807                /* Print trailing zeros of the fractional part of the number. */
     808                if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
     809                        return -1;
     810
     811                counter += ret;
     812        }
     813
     814        /* Trailing padding. */
     815        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     816                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     817                        return -1;
     818
     819                counter += ret;
     820        }
     821
     822        return counter;
     823}
     824
     825
     826/** Convert, format and print a double according to the %f specifier.
     827 *
     828 * @param g     Double to print.
     829 * @param precision Number of fractional digits to print. If 0 no
     830 *              decimal point will be printed unless the flag
     831 *              __PRINTF_FLAG_DECIMALPT is specified.
     832 * @param width Minimum number of characters to display. Pads
     833 *              with '0' or ' ' depending on the set flags;
     834 * @param flags Printf flags.
     835 * @param ps    Printing functions.
     836 *
     837 * @return The number of characters printed; negative on failure.
     838 */
     839static int print_double_fixed(double g, int precision, int width, uint32_t flags,
     840        printf_spec_t *ps)
     841{
     842        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     843                flags &= ~__PRINTF_FLAG_ZEROPADDED;
     844        }
     845
     846        if (flags & __PRINTF_FLAG_DECIMALPT) {
     847                flags &= ~__PRINTF_FLAG_NOFRACZEROS;
     848        }
     849
     850        ieee_double_t val = extract_ieee_double(g);
     851
     852        if (val.is_special) {
     853                return print_special(val, width, flags, ps);
     854        }
     855
     856        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     857        const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
     858        double_str_t val_str;
     859
     860        val_str.str = buf;
     861        val_str.neg = val.is_negative;
     862
     863        if (0 <= precision) {
     864                /*
     865                 * Request one more digit so we can round the result. The last
     866                 * digit it returns may have an error of at most +/- 1.
     867                 */
     868                val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size,
     869                        &val_str.dec_exp);
     870
     871                /*
     872                 * Round using the last digit to produce precision fractional digits.
     873                 * If less than precision+1 fractional digits were output the last
     874                 * digit is definitely inaccurate so also round to get rid of it.
     875                 */
     876                fp_round_up(buf, &val_str.len, &val_str.dec_exp);
     877
     878                /* Rounding could have introduced trailing zeros. */
     879                if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     880                        fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
     881                }
     882        } else {
     883                /* Let the implementation figure out the proper precision. */
     884                val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
     885               
     886                /* Precision needed for the last significant digit. */
     887                precision = max(0, -val_str.dec_exp);
     888        }
     889
     890        return print_double_str_fixed(&val_str, precision, width, flags, ps);
     891}
     892
     893/** Prints the decimal exponent part of a %e specifier formatted number. */
     894static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
     895{
     896        int counter = 0;
     897        int ret;
     898
     899        char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
     900
     901        if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0)
     902                return -1;
     903       
     904        counter += ret;
     905
     906        char exp_sign = (exp_val < 0) ? '-' : '+';
     907
     908        if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
     909                return -1;
     910
     911        counter += ret;
     912
     913        /* Print the exponent. */
     914        exp_val = abs(exp_val);
     915       
     916        char exp_str[4] = { 0 };
     917
     918        exp_str[0] = '0' + exp_val / 100;
     919        exp_str[1] = '0' + (exp_val % 100) / 10 ;
     920        exp_str[2] = '0' + (exp_val % 10);
     921       
     922        int exp_len = (exp_str[0] == '0') ? 2 : 3;
     923        const char *exp_str_start = &exp_str[3] - exp_len;
     924
     925        if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0)
     926                return -1;
     927
     928        counter += ret;
     929
     930        return counter;
     931}
     932
     933
     934/** Format and print the double string repressentation according
     935 *  to the %e specifier.
     936 */
     937static int print_double_str_scient(double_str_t *val_str, int precision,
     938        int width, uint32_t flags, printf_spec_t *ps)
     939{
     940        int len = val_str->len;
     941        int dec_exp = val_str->dec_exp;
     942        char *buf  = val_str->str;
     943
     944        assert(0 < len);
     945
     946        char sign = get_sign_char(val_str->neg, flags);
     947        bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
     948        int dec_pt_len = has_decimal_pt ? 1 : 0;
     949
     950        /* Fractional part lengths. */
     951        int signif_frac_figs = len - 1;
     952        int trailing_frac_zeros = precision - signif_frac_figs;
     953
     954        if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     955                trailing_frac_zeros = 0;
     956        }
     957
     958        int frac_len = signif_frac_figs + trailing_frac_zeros;
     959
     960        int exp_val = dec_exp + len - 1;
     961        /* Account for exponent sign and 'e'; minimum 2 digits. */
     962        int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2);
     963
     964        /* Number of non-padding chars to print. */
     965        int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len;
     966
     967        int padding_len = max(0, width - num_len);
     968        int ret = 0;
     969        int counter = 0;
     970
     971        if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
     972                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     973                        return -1;
     974
     975                counter += ret;
     976        }
     977
     978        if (sign) {
     979                if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
     980                        return -1;
     981               
     982                counter += ret;
     983        }
     984
     985        if (flags & __PRINTF_FLAG_ZEROPADDED) {
     986                if ((ret = print_padding('0', padding_len, ps)) < 0)
     987                        return -1;
     988
     989                counter += ret;
     990        }
     991
     992        /* Single leading integer. */
     993        if ((ret = ps->str_write(buf, 1, ps->data)) < 0)
     994                return -1;
     995
     996        counter += ret;
     997
     998        /* Print the decimal point and the fractional part. */
     999        if (has_decimal_pt) {
     1000                char ch = '.';
     1001
     1002                if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
     1003                        return -1;
     1004               
     1005                counter += ret;
     1006
     1007                /* Print significant digits of the fractional part of the number. */
     1008                if (0 < signif_frac_figs) {
     1009                        if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0)
     1010                                return -1;
     1011
     1012                        counter += ret;
     1013                }
     1014
     1015                /* Print trailing zeros of the fractional part of the number. */
     1016                if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
     1017                        return -1;
     1018
     1019                counter += ret;
     1020        }
     1021
     1022        /* Print the exponent. */
     1023        if ((ret = print_exponent(exp_val, flags, ps)) < 0)
     1024                return -1;
     1025
     1026        counter += ret;
     1027
     1028        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     1029                if ((ret = print_padding(' ', padding_len, ps)) < 0)
     1030                        return -1;
     1031
     1032                counter += ret;
     1033        }
     1034
     1035        return counter;
     1036}
     1037
     1038
     1039/** Convert, format and print a double according to the %e specifier.
     1040 *
     1041 * Note that if g is large, the output may be huge (3e100 prints
     1042 * with at least 100 digits).
     1043 *
     1044 * %e style: [-]d.dddde+dd
     1045 *  left-justified:  [-]d.dddde+dd[space_pad]
     1046 *  right-justified: [space_pad][-][zero_pad]d.dddde+dd
     1047 *
     1048 * @param g     Double to print.
     1049 * @param precision Number of fractional digits to print, ie
     1050 *              precision + 1 significant digits to display. If 0 no
     1051 *              decimal point will be printed unless the flag
     1052 *              __PRINTF_FLAG_DECIMALPT is specified. If negative
     1053 *              the shortest accurate number will be printed.
     1054 * @param width Minimum number of characters to display. Pads
     1055 *              with '0' or ' ' depending on the set flags;
     1056 * @param flags Printf flags.
     1057 * @param ps    Printing functions.
     1058 *
     1059 * @return The number of characters printed; negative on failure.
     1060 */
     1061static int print_double_scientific(double g, int precision, int width,
     1062        uint32_t flags, printf_spec_t *ps)
     1063{
     1064        if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     1065                flags &= ~__PRINTF_FLAG_ZEROPADDED;
     1066        }
     1067
     1068        ieee_double_t val = extract_ieee_double(g);
     1069
     1070        if (val.is_special) {
     1071                return print_special(val, width, flags, ps);
     1072        }
     1073
     1074        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     1075        const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
     1076        double_str_t val_str;
     1077
     1078        val_str.str = buf;
     1079        val_str.neg = val.is_negative;
     1080
     1081        if (0 <= precision) {
     1082                /*
     1083                 * Request one more digit (in addition to the leading integer)
     1084                 * so we can round the result. The last digit it returns may
     1085                 * have an error of at most +/- 1.
     1086                 */
     1087                val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size,
     1088                        &val_str.dec_exp);
     1089
     1090                /*
     1091                 * Round the extra digit to produce precision+1 significant digits.
     1092                 * If less than precision+2 significant digits were returned the last
     1093                 * digit is definitely inaccurate so also round to get rid of it.
     1094                 */
     1095                fp_round_up(buf, &val_str.len, &val_str.dec_exp);
     1096
     1097                /* Rounding could have introduced trailing zeros. */
     1098                if (flags & __PRINTF_FLAG_NOFRACZEROS) {
     1099                        fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
     1100                }
     1101        } else {
     1102                /* Let the implementation figure out the proper precision. */
     1103                val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
     1104               
     1105                /* Use all produced digits. */
     1106                precision = val_str.len - 1;
     1107        }
     1108
     1109        return print_double_str_scient(&val_str, precision, width, flags, ps);
     1110}
     1111
     1112
     1113/** Convert, format and print a double according to the %g specifier.
     1114 *
     1115 * %g style chooses between %f and %e.
     1116 *
     1117 * @param g     Double to print.
     1118 * @param precision Number of significant digits to display; excluding
     1119 *              any leading zeros from this count. If negative
     1120 *              the shortest accurate number will be printed.
     1121 * @param width Minimum number of characters to display. Pads
     1122 *              with '0' or ' ' depending on the set flags;
     1123 * @param flags Printf flags.
     1124 * @param ps    Printing functions.
     1125 *
     1126 * @return The number of characters printed; negative on failure.
     1127 */
     1128static int print_double_generic(double g, int precision, int width,
     1129        uint32_t flags, printf_spec_t *ps)
     1130{
     1131        ieee_double_t val = extract_ieee_double(g);
     1132
     1133        if (val.is_special) {
     1134                return print_special(val, width, flags, ps);
     1135        }
     1136
     1137        char buf[MAX_DOUBLE_STR_BUF_SIZE];
     1138        const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
     1139        int dec_exp;
     1140        int len;
     1141
     1142        /* Honor the user requested number of significant digits. */
     1143        if (0 <= precision) {
     1144                /*
     1145                 * Do a quick and dirty conversion of a single digit to determine
     1146                 * the decimal exponent.
     1147                 */
     1148                len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp);
     1149                assert(0 < len);
     1150
     1151                precision = max(1, precision);
     1152
     1153                if (-4 <= dec_exp && dec_exp < precision) {
     1154                        precision = precision - (dec_exp + 1);
     1155                        return print_double_fixed(g, precision, width,
     1156                                flags | __PRINTF_FLAG_NOFRACZEROS, ps);
     1157                } else {
     1158                        --precision;
     1159                        return print_double_scientific(g, precision, width,
     1160                                flags | __PRINTF_FLAG_NOFRACZEROS, ps);
     1161                }
     1162        } else {
     1163                /* Convert to get the decimal exponent and digit count.*/
     1164                len = double_to_short_str(val, buf, buf_size, &dec_exp);
     1165                assert(0 < len);
     1166
     1167                if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     1168                        flags &= ~__PRINTF_FLAG_ZEROPADDED;
     1169                }
     1170
     1171                double_str_t val_str;
     1172                val_str.str = buf;
     1173                val_str.len = len;
     1174                val_str.neg = val.is_negative;
     1175                val_str.dec_exp = dec_exp;
     1176
     1177                int first_digit_pos = len + dec_exp;
     1178                int last_digit_pos = dec_exp;
     1179
     1180                /* The whole number (15 digits max) fits between dec places 15 .. -6 */
     1181                if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) {
     1182                        /* Precision needed for the last significant digit. */
     1183                        precision = max(0, -val_str.dec_exp);
     1184                        return print_double_str_fixed(&val_str, precision, width, flags, ps);
     1185                } else {
     1186                        /* Use all produced digits. */
     1187                        precision = val_str.len - 1;
     1188                        return print_double_str_scient(&val_str, precision, width, flags, ps);
     1189                }
     1190        }
     1191}
     1192
     1193
     1194/** Convert, format and print a double according to the specifier.
     1195 *
     1196 * Depending on the specifier it prints the double using the styles
     1197 * %g, %f or %e by means of print_double_generic(), print_double_fixed(),
     1198 * print_double_scientific().
     1199 *
     1200 * @param g     Double to print.
     1201 * @param spec  Specifier of the style to print in; one of: 'g','G','f','F',
     1202 *              'e','E'.
     1203 * @param precision Number of fractional digits to display. If negative
     1204 *              the shortest accurate number will be printed for style %g;
     1205 *              negative precision defaults to 6 for styles %f, %e.
     1206 * @param width Minimum number of characters to display. Pads
     1207 *              with '0' or ' ' depending on the set flags;
     1208 * @param flags Printf flags.
     1209 * @param ps    Printing functions.
     1210 *
     1211 * @return The number of characters printed; negative on failure.
     1212 */
     1213static int print_double(double g, char spec, int precision, int width,
     1214        uint32_t flags, printf_spec_t *ps)
     1215{
     1216        switch (spec) {
     1217        case 'F':
     1218                flags |= __PRINTF_FLAG_BIGCHARS;
     1219                /* Fall through.*/
     1220        case 'f':
     1221                precision = (precision < 0) ? 6 : precision;
     1222                return print_double_fixed(g, precision, width, flags, ps);
     1223
     1224        case 'E':
     1225                flags |= __PRINTF_FLAG_BIGCHARS;
     1226                /* Fall through.*/
     1227        case 'e':
     1228                precision = (precision < 0) ? 6 : precision;
     1229                return print_double_scientific(g, precision, width, flags, ps);
     1230
     1231        case 'G':
     1232                flags |= __PRINTF_FLAG_BIGCHARS;
     1233                /* Fall through.*/
     1234        case 'g':
     1235                return print_double_generic(g, precision, width, flags, ps);
     1236
     1237        default:
     1238                assert(false);
     1239                return -1;
     1240        }
    5271241}
    5281242
     
    6561370                                case '#':
    6571371                                        flags |= __PRINTF_FLAG_PREFIX;
     1372                                        flags |= __PRINTF_FLAG_DECIMALPT;
    6581373                                        break;
    6591374                                case '-':
     
    7011416                       
    7021417                        /* Precision and '*' operator */
    703                         int precision = 0;
     1418                        int precision = -1;
    7041419                        if (uc == '.') {
    7051420                                i = nxt;
    7061421                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    7071422                                if (isdigit(uc)) {
     1423                                        precision = 0;
    7081424                                        while (true) {
    7091425                                                precision *= 10;
     
    7231439                                        precision = (int) va_arg(ap, int);
    7241440                                        if (precision < 0) {
    725                                                 /* Ignore negative precision */
    726                                                 precision = 0;
     1441                                                /* Ignore negative precision - use default instead */
     1442                                                precision = -1;
    7271443                                        }
    7281444                                }
     
    7741490                         */
    7751491                        case 's':
     1492                                precision = max(0,  precision);
     1493                               
    7761494                                if (qualifier == PrintfQualifierLong)
    7771495                                        retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
     
    7971515                                        goto out;
    7981516                                };
     1517                               
     1518                                counter += retval;
     1519                                j = nxt;
     1520                                goto next_char;
     1521                               
     1522                        /*
     1523                         * Floating point values
     1524                         */
     1525                        case 'G':
     1526                        case 'g':
     1527                        case 'F':
     1528                        case 'f':
     1529                        case 'E':
     1530                        case 'e':
     1531                                retval = print_double(va_arg(ap, double), uc, precision,
     1532                                        width, flags, ps);
     1533                               
     1534                                if (retval < 0) {
     1535                                        counter = -counter;
     1536                                        goto out;
     1537                                }
    7991538                               
    8001539                                counter += retval;
  • uspace/lib/c/include/macros.h

    rf0da6855 r34b9299  
    3838#define min(a, b)  ((a) < (b) ? (a) : (b))
    3939#define max(a, b)  ((a) > (b) ? (a) : (b))
     40#define abs(a)     ((a) >= 0 ? (a) : (-a))
     41
    4042
    4143#define KiB2SIZE(kb)  ((kb) << 10)
Note: See TracChangeset for help on using the changeset viewer.