| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270 |
- /*
- * Copyright (c) 2021, Meco Jianting Man <jiantingman@foxmail.com>
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-27 Meco Man porting for rt_vsnprintf as the fully functional
- * version
- */
- /**
- * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
- * 2021, Haifa, Palestine/Israel
- * @author (c) Marco Paland (info@paland.com)
- * 2014-2019, PALANDesign Hannover, Germany
- *
- * @note Others have made smaller contributions to this file: see the
- * contributors page at https://github.com/eyalroz/printf/graphs/contributors
- * or ask one of the authors.
- *
- * @brief Small stand-alone implementation of the printf family of functions
- * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems
- * with a very limited resources.
- *
- * @note the implementations are thread-safe; re-entrant; use no functions from
- * the standard library; and do not dynamically allocate any memory.
- *
- * @license The MIT License (MIT)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdint.h>
- #include "PikaObj.h"
- #include "pika_adapter_rtt.h"
- #if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 12, 0)
- #error "pika_vsnprintf.c requires at least PikaScript 1.12.0"
- #endif
- // 'ntoa' conversion buffer size, this must be big enough to hold one converted
- // numeric number including padded zeros (dynamically created on stack)
- #ifndef PRINTF_INTEGER_BUFFER_SIZE
- #define PRINTF_INTEGER_BUFFER_SIZE 32
- #endif
- // 'ftoa' conversion buffer size, this must be big enough to hold one converted
- // float number including padded zeros (dynamically created on stack)
- #ifndef PRINTF_FTOA_BUFFER_SIZE
- #define PRINTF_FTOA_BUFFER_SIZE 32
- #endif
- // Support for the decimal notation floating point conversion specifiers (%f,
- // %F)
- #ifndef PRINTF_SUPPORT_DECIMAL_SPECIFIERS
- #define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 1
- #endif
- // Support for the exponential notatin floating point conversion specifiers (%e,
- // %g, %E, %G)
- #ifndef PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- #define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 1
- #endif
- // Default precision for the floating point conversion specifiers (the C
- // standard sets this at 6)
- #ifndef PRINTF_DEFAULT_FLOAT_PRECISION
- #define PRINTF_DEFAULT_FLOAT_PRECISION 6
- #endif
- // According to the C languages standard, printf() and related functions must be
- // able to print any integral number in floating-point notation, regardless of
- // length, when using the %f specifier - possibly hundreds of characters,
- // potentially overflowing your buffers. In this implementation, all values
- // beyond this threshold are switched to exponential notation.
- #ifndef PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL
- #define PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9
- #endif
- // Support for the long long integral types (with the ll, z and t length
- // modifiers for specifiers %d,%i,%o,%x,%X,%u, and with the %p specifier). Note:
- // 'L' (long double) is not supported.
- #ifndef PRINTF_SUPPORT_LONG_LONG
- #define PRINTF_SUPPORT_LONG_LONG 1
- #endif
- #if PRINTF_SUPPORT_LONG_LONG
- typedef unsigned long long printf_unsigned_value_t;
- typedef long long printf_signed_value_t;
- #else
- typedef unsigned long printf_unsigned_value_t;
- typedef long printf_signed_value_t;
- #endif
- #define PRINTF_PREFER_DECIMAL false
- #define PRINTF_PREFER_EXPONENTIAL true
- ///////////////////////////////////////////////////////////////////////////////
- // The following will convert the number-of-digits into an exponential-notation
- // literal
- #define PRINTF_CONCATENATE(s1, s2) s1##s2
- #define PRINTF_EXPAND_THEN_CONCATENATE(s1, s2) PRINTF_CONCATENATE(s1, s2)
- #define PRINTF_FLOAT_NOTATION_THRESHOLD \
- PRINTF_EXPAND_THEN_CONCATENATE(1e, PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL)
- // internal flag definitions
- #define FLAGS_ZEROPAD (1U << 0U)
- #define FLAGS_LEFT (1U << 1U)
- #define FLAGS_PLUS (1U << 2U)
- #define FLAGS_SPACE (1U << 3U)
- #define FLAGS_HASH (1U << 4U)
- #define FLAGS_UPPERCASE (1U << 5U)
- #define FLAGS_CHAR (1U << 6U)
- #define FLAGS_SHORT (1U << 7U)
- #define FLAGS_LONG (1U << 8U)
- #define FLAGS_LONG_LONG (1U << 9U)
- #define FLAGS_PRECISION (1U << 10U)
- #define FLAGS_ADAPT_EXP (1U << 11U)
- #define FLAGS_POINTER (1U << 12U)
- // Note: Similar, but not identical, effect as FLAGS_HASH
- #define BASE_BINARY 2
- #define BASE_OCTAL 8
- #define BASE_DECIMAL 10
- #define BASE_HEX 16
- typedef uint8_t numeric_base_t;
- #if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
- #include <float.h>
- #if FLT_RADIX != 2
- #error "Non-binary-radix floating-point types are unsupported."
- #endif
- #if DBL_MANT_DIG == 24
- #define DOUBLE_SIZE_IN_BITS 32
- typedef uint32_t double_uint_t;
- #define DOUBLE_EXPONENT_MASK 0xFFU
- #define DOUBLE_BASE_EXPONENT 127
- #elif DBL_MANT_DIG == 53
- #define DOUBLE_SIZE_IN_BITS 64
- typedef uint64_t double_uint_t;
- #define DOUBLE_EXPONENT_MASK 0x7FFU
- #define DOUBLE_BASE_EXPONENT 1023
- #else
- #error "Unsupported double type configuration"
- #endif
- #define DOUBLE_STORED_MANTISSA_BITS (DBL_MANT_DIG - 1)
- typedef union {
- double_uint_t U;
- double F;
- } double_with_bit_access;
- // This is unnecessary in C99, since compound initializers can be used,
- // but: 1. Some compilers are finicky about this; 2. Some people may want to
- // convert this to C89;
- // 3. If you try to use it as C++, only C++20 supports compound literals
- static inline double_with_bit_access get_bit_access(double x) {
- double_with_bit_access dwba;
- dwba.F = x;
- return dwba;
- }
- static inline int get_sign(double x) {
- // The sign is stored in the highest bit
- return get_bit_access(x).U >> (DOUBLE_SIZE_IN_BITS - 1);
- }
- static inline int get_exp2(double_with_bit_access x) {
- // The exponent in an IEEE-754 floating-point number occupies a contiguous
- // sequence of bits (e.g. 52..62 for 64-bit doubles), but with a non-trivial
- // representation: An unsigned offset from some negative value (with the
- // extremal offset values reserved for special use).
- return (int)((x.U >> DOUBLE_STORED_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK) -
- DOUBLE_BASE_EXPONENT;
- }
- #define PRINTF_ABS(_x) ((_x) > 0 ? (_x) : -(_x))
- #endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS ||
- // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
- // Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid
- // and well-defined, but if you're not careful you can easily trigger undefined
- // behavior with -LONG_MIN or -LLONG_MIN
- #define ABS_FOR_PRINTING(_x) \
- ((printf_unsigned_value_t)((_x) > 0 ? (_x) : -((printf_signed_value_t)_x)))
- // output function type
- typedef void (*out_fct_type)(char character,
- void* buffer,
- size_t idx,
- size_t maxlen);
- // wrapper (used as buffer) for output function type
- typedef struct {
- void (*fct)(char character, void* arg);
- void* arg;
- } out_function_wrapper_type;
- // internal buffer output
- static inline void out_buffer(char character,
- void* buffer,
- size_t idx,
- size_t maxlen) {
- if (idx < maxlen) {
- ((char*)buffer)[idx] = character;
- }
- }
- // internal null output
- static inline void out_discard(char character,
- void* buffer,
- size_t idx,
- size_t maxlen) {
- (void)character;
- (void)buffer;
- (void)idx;
- (void)maxlen;
- }
- // internal secure strlen
- // @return The length of the string (excluding the terminating 0) limited by
- // 'maxsize'
- static inline unsigned int strnlen_s_(const char* str, size_t maxsize) {
- const char* s;
- for (s = str; *s && maxsize--; ++s)
- ;
- return (unsigned int)(s - str);
- }
- // internal test if char is a digit (0-9)
- // @return true if char is a digit
- static inline bool is_digit_(char ch) {
- return (ch >= '0') && (ch <= '9');
- }
- // internal ASCII string to unsigned int conversion
- static unsigned int atoi_(const char** str) {
- unsigned int i = 0U;
- while (is_digit_(**str)) {
- i = i * 10U + (unsigned int)(*((*str)++) - '0');
- }
- return i;
- }
- // output the specified string in reverse, taking care of any zero-padding
- static size_t out_rev_(out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- const char* buf,
- size_t len,
- unsigned int width,
- unsigned int flags) {
- const size_t start_idx = idx;
- // pad spaces up to given width
- if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
- for (size_t i = len; i < width; i++) {
- out(' ', buffer, idx++, maxlen);
- }
- }
- // reverse string
- while (len) {
- out(buf[--len], buffer, idx++, maxlen);
- }
- // append pad spaces up to given width
- if (flags & FLAGS_LEFT) {
- while (idx - start_idx < width) {
- out(' ', buffer, idx++, maxlen);
- }
- }
- return idx;
- }
- // Invoked by print_integer after the actual number has been printed, performing
- // necessary work on the number's prefix (as the number is initially printed in
- // reverse order)
- static size_t print_integer_finalization(out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- char* buf,
- size_t len,
- bool negative,
- numeric_base_t base,
- unsigned int precision,
- unsigned int width,
- unsigned int flags) {
- size_t unpadded_len = len;
- // pad with leading zeros
- {
- if (!(flags & FLAGS_LEFT)) {
- if (width && (flags & FLAGS_ZEROPAD) &&
- (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
- width--;
- }
- while ((flags & FLAGS_ZEROPAD) && (len < width) &&
- (len < PRINTF_INTEGER_BUFFER_SIZE)) {
- buf[len++] = '0';
- }
- }
- while ((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
- buf[len++] = '0';
- }
- if (base == BASE_OCTAL && (len > unpadded_len)) {
- // Since we've written some zeros, we've satisfied the alternative
- // format leading space requirement
- flags &= ~FLAGS_HASH;
- }
- }
- // handle hash
- if (flags & (FLAGS_HASH | FLAGS_POINTER)) {
- if (!(flags & FLAGS_PRECISION) && len &&
- ((len == precision) || (len == width))) {
- // Let's take back some padding digits to fit in what will
- // eventually be the format-specific prefix
- if (unpadded_len < len) {
- len--;
- }
- if (len && (base == BASE_HEX)) {
- if (unpadded_len < len) {
- len--;
- }
- }
- }
- if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) &&
- (len < PRINTF_INTEGER_BUFFER_SIZE)) {
- buf[len++] = 'x';
- } else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) &&
- (len < PRINTF_INTEGER_BUFFER_SIZE)) {
- buf[len++] = 'X';
- } else if ((base == BASE_BINARY) &&
- (len < PRINTF_INTEGER_BUFFER_SIZE)) {
- buf[len++] = 'b';
- }
- if (len < PRINTF_INTEGER_BUFFER_SIZE) {
- buf[len++] = '0';
- }
- }
- if (len < PRINTF_INTEGER_BUFFER_SIZE) {
- if (negative) {
- buf[len++] = '-';
- } else if (flags & FLAGS_PLUS) {
- buf[len++] = '+'; // ignore the space if the '+' exists
- } else if (flags & FLAGS_SPACE) {
- buf[len++] = ' ';
- }
- }
- return out_rev_(out, buffer, idx, maxlen, buf, len, width, flags);
- }
- // An internal itoa-like function
- static size_t print_integer(out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- printf_unsigned_value_t value,
- bool negative,
- numeric_base_t base,
- unsigned int precision,
- unsigned int width,
- unsigned int flags) {
- char buf[PRINTF_INTEGER_BUFFER_SIZE];
- size_t len = 0U;
- if (!value) {
- if (!(flags & FLAGS_PRECISION)) {
- buf[len++] = '0';
- flags &= ~FLAGS_HASH;
- // We drop this flag this since either the alternative and regular
- // modes of the specifier don't differ on 0 values, or (in the case
- // of octal) we've already provided the special handling for this
- // mode.
- } else if (base == BASE_HEX) {
- flags &= ~FLAGS_HASH;
- // We drop this flag this since either the alternative and regular
- // modes of the specifier don't differ on 0 values
- }
- } else {
- do {
- const char digit = (char)(value % base);
- buf[len++] =
- (char)(digit < 10 ? '0' + digit
- : (flags & FLAGS_UPPERCASE ? 'A' : 'a') +
- digit - 10);
- value /= base;
- } while (value && (len < PRINTF_INTEGER_BUFFER_SIZE));
- }
- return print_integer_finalization(out, buffer, idx, maxlen, buf, len,
- negative, base, precision, width, flags);
- }
- #if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
- struct double_components {
- int_fast64_t integral;
- int_fast64_t fractional;
- bool is_negative;
- };
- #define NUM_DECIMAL_DIGITS_IN_INT64_T 18
- #define PRINTF_MAX_PRECOMPUTED_POWER_OF_10 NUM_DECIMAL_DIGITS_IN_INT64_T
- static const double powers_of_10[NUM_DECIMAL_DIGITS_IN_INT64_T] = {
- 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08,
- 1e09, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17};
- #define PRINTF_MAX_SUPPORTED_PRECISION NUM_DECIMAL_DIGITS_IN_INT64_T - 1
- // Break up a double number - which is known to be a finite non-negative number
- // - into its base-10 parts: integral - before the decimal point, and fractional
- // - after it. Taken the precision into account, but does not change it even
- // internally.
- static struct double_components get_components(double number,
- unsigned int precision) {
- struct double_components number_;
- number_.is_negative = get_sign(number);
- double abs_number = (number_.is_negative) ? -number : number;
- number_.integral = (int_fast64_t)abs_number;
- double remainder =
- (abs_number - number_.integral) * powers_of_10[precision];
- number_.fractional = (int_fast64_t)remainder;
- remainder -= (double)number_.fractional;
- if (remainder > 0.5) {
- ++number_.fractional;
- // handle rollover, e.g. case 0.99 with precision 1 is 1.0
- if ((double)number_.fractional >= powers_of_10[precision]) {
- number_.fractional = 0;
- ++number_.integral;
- }
- } else if (remainder == 0.5) {
- if ((number_.fractional == 0U) || (number_.fractional & 1U)) {
- // if halfway, round up if odd OR if last digit is 0
- ++number_.fractional;
- }
- }
- if (precision == 0U) {
- remainder = abs_number - (double)number_.integral;
- if ((!(remainder < 0.5) || (remainder > 0.5)) &&
- (number_.integral & 1)) {
- // exactly 0.5 and ODD, then round up
- // 1.5 -> 2, but 2.5 -> 2
- ++number_.integral;
- }
- }
- return number_;
- }
- struct scaling_factor {
- double raw_factor;
- bool multiply; // if true, need to multiply by raw_factor; otherwise need
- // to divide by it
- };
- double apply_scaling(double num, struct scaling_factor normalization) {
- return normalization.multiply ? num * normalization.raw_factor
- : num / normalization.raw_factor;
- }
- double unapply_scaling(double normalized, struct scaling_factor normalization) {
- return normalization.multiply ? normalized / normalization.raw_factor
- : normalized * normalization.raw_factor;
- }
- struct scaling_factor update_normalization(struct scaling_factor sf,
- double extra_multiplicative_factor) {
- struct scaling_factor result;
- if (sf.multiply) {
- result.multiply = true;
- result.raw_factor = sf.raw_factor * extra_multiplicative_factor;
- } else {
- int factor_exp2 = get_exp2(get_bit_access(sf.raw_factor));
- int extra_factor_exp2 =
- get_exp2(get_bit_access(extra_multiplicative_factor));
- // Divide the larger-exponent raw raw_factor by the smaller
- if (PRINTF_ABS(factor_exp2) > PRINTF_ABS(extra_factor_exp2)) {
- result.multiply = false;
- result.raw_factor = sf.raw_factor / extra_multiplicative_factor;
- } else {
- result.multiply = true;
- result.raw_factor = extra_multiplicative_factor / sf.raw_factor;
- }
- }
- return result;
- }
- #if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- static struct double_components get_normalized_components(
- bool negative,
- unsigned int precision,
- double non_normalized,
- struct scaling_factor normalization) {
- struct double_components components;
- components.is_negative = negative;
- components.integral =
- (int_fast64_t)apply_scaling(non_normalized, normalization);
- double remainder =
- non_normalized -
- unapply_scaling((double)components.integral, normalization);
- double prec_power_of_10 = powers_of_10[precision];
- struct scaling_factor account_for_precision =
- update_normalization(normalization, prec_power_of_10);
- double scaled_remainder = apply_scaling(remainder, account_for_precision);
- double rounding_threshold = 0.5;
- if (precision == 0U) {
- components.fractional = 0;
- components.integral += (scaled_remainder >= rounding_threshold);
- if (scaled_remainder == rounding_threshold) {
- // banker's rounding: Round towards the even number (making the mean
- // error 0)
- components.integral &= ~((int_fast64_t)0x1);
- }
- } else {
- components.fractional = (int_fast64_t)scaled_remainder;
- scaled_remainder -= components.fractional;
- components.fractional += (scaled_remainder >= rounding_threshold);
- if (scaled_remainder == rounding_threshold) {
- // banker's rounding: Round towards the even number (making the mean
- // error 0)
- components.fractional &= ~((int_fast64_t)0x1);
- }
- // handle rollover, e.g. the case of 0.99 with precision 1 becoming
- // (0,100), and must then be corrected into (1, 0).
- if ((double)components.fractional >= prec_power_of_10) {
- components.fractional = 0;
- ++components.integral;
- }
- }
- return components;
- }
- #endif
- static size_t print_broken_up_decimal(struct double_components number_,
- out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- unsigned int precision,
- unsigned int width,
- unsigned int flags,
- char* buf,
- size_t len) {
- if (precision != 0U) {
- // do fractional part, as an unsigned number
- unsigned int count = precision;
- if (flags & FLAGS_ADAPT_EXP && !(flags & FLAGS_HASH)) {
- // %g/%G mandates we skip the trailing 0 digits...
- if (number_.fractional > 0) {
- while (true) {
- int_fast64_t digit = number_.fractional % 10U;
- if (digit != 0) {
- break;
- }
- --count;
- number_.fractional /= 10U;
- }
- }
- // ... and even the decimal point if there are no
- // non-zero fractional part digits (see below)
- }
- if (number_.fractional > 0 || !(flags & FLAGS_ADAPT_EXP) ||
- (flags & FLAGS_HASH)) {
- while (len < PRINTF_FTOA_BUFFER_SIZE) {
- --count;
- buf[len++] = (char)('0' + number_.fractional % 10U);
- if (!(number_.fractional /= 10U)) {
- break;
- }
- }
- // add extra 0s
- while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
- buf[len++] = '0';
- }
- if (len < PRINTF_FTOA_BUFFER_SIZE) {
- buf[len++] = '.';
- }
- }
- } else {
- if (flags & FLAGS_HASH) {
- if (len < PRINTF_FTOA_BUFFER_SIZE) {
- buf[len++] = '.';
- }
- }
- }
- // Write the integer part of the number (it comes after the fractional
- // since the character order is reversed)
- while (len < PRINTF_FTOA_BUFFER_SIZE) {
- buf[len++] = (char)('0' + (number_.integral % 10));
- if (!(number_.integral /= 10)) {
- break;
- }
- }
- // pad leading zeros
- if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
- if (width &&
- (number_.is_negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
- width--;
- }
- while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
- buf[len++] = '0';
- }
- }
- if (len < PRINTF_FTOA_BUFFER_SIZE) {
- if (number_.is_negative) {
- buf[len++] = '-';
- } else if (flags & FLAGS_PLUS) {
- buf[len++] = '+'; // ignore the space if the '+' exists
- } else if (flags & FLAGS_SPACE) {
- buf[len++] = ' ';
- }
- }
- return out_rev_(out, buffer, idx, maxlen, buf, len, width, flags);
- }
- // internal ftoa for fixed decimal floating point
- static size_t print_decimal_number(out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- double number,
- unsigned int precision,
- unsigned int width,
- unsigned int flags,
- char* buf,
- size_t len) {
- struct double_components value_ = get_components(number, precision);
- return print_broken_up_decimal(value_, out, buffer, idx, maxlen, precision,
- width, flags, buf, len);
- }
- #if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- // internal ftoa variant for exponential floating-point type, contributed by
- // Martijn Jasperse <m.jasperse@gmail.com>
- static size_t print_exponential_number(out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- double number,
- unsigned int precision,
- unsigned int width,
- unsigned int flags,
- char* buf,
- size_t len) {
- const bool negative = get_sign(number);
- // This number will decrease gradually (by factors of 10) as we "extract"
- // the exponent out of it
- double abs_number = negative ? -number : number;
- int exp10;
- bool abs_exp10_covered_by_powers_table;
- struct scaling_factor normalization;
- // Determine the decimal exponent
- if (abs_number == 0.0) {
- // TODO: This is a special-case for 0.0 (and -0.0); but proper handling
- // is required for denormals more generally.
- exp10 = 0; // ... and no need to set a normalization factor or check
- // the powers table
- } else {
- double_with_bit_access conv = get_bit_access(abs_number);
- {
- // based on the algorithm by David Gay
- // (https://www.ampl.com/netlib/fp/dtoa.c)
- int exp2 = get_exp2(conv);
- // drop the exponent, so conv.F comes into the range [1,2)
- conv.U =
- (conv.U &
- (((double_uint_t)(1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) |
- ((double_uint_t)DOUBLE_BASE_EXPONENT
- << DOUBLE_STORED_MANTISSA_BITS);
- // now approximate log10 from the log2 integer part and an expansion
- // of ln around 1.5
- exp10 = (int)(0.1760912590558 + exp2 * 0.301029995663981 +
- (conv.F - 1.5) * 0.289529654602168);
- // now we want to compute 10^exp10 but we want to be sure it won't
- // overflow
- exp2 = (int)(exp10 * 3.321928094887362 + 0.5);
- const double z =
- exp10 * 2.302585092994046 - exp2 * 0.6931471805599453;
- const double z2 = z * z;
- conv.U = ((double_uint_t)(exp2) + DOUBLE_BASE_EXPONENT)
- << DOUBLE_STORED_MANTISSA_BITS;
- // compute exp(z) using continued fractions, see
- // https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
- conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
- // correct for rounding errors
- if (abs_number < conv.F) {
- exp10--;
- conv.F /= 10;
- }
- }
- abs_exp10_covered_by_powers_table =
- PRINTF_ABS(exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10;
- normalization.raw_factor = abs_exp10_covered_by_powers_table
- ? powers_of_10[PRINTF_ABS(exp10)]
- : conv.F;
- }
- // We now begin accounting for the widths of the two parts of our printed
- // field: the decimal part after decimal exponent extraction, and the
- // base-10 exponent part. For both of these, the value of 0 has a special
- // meaning, but not the same one: a 0 exponent-part width means "don't print
- // the exponent"; a 0 decimal-part width means "use as many characters as
- // necessary".
- bool fall_back_to_decimal_only_mode = false;
- if (flags & FLAGS_ADAPT_EXP) {
- int required_significant_digits = (precision == 0) ? 1 : (int)precision;
- // Should we want to fall-back to "%f" mode, and only print the decimal
- // part?
- fall_back_to_decimal_only_mode =
- (exp10 >= -4 && exp10 < required_significant_digits);
- // Now, let's adjust the precision
- // This also decided how we adjust the precision value - as in "%g"
- // mode, "precision" is the number of _significant digits_, and this is
- // when we "translate" the precision value to an actual number of
- // decimal digits.
- int precision_ =
- (fall_back_to_decimal_only_mode)
- ? (int)precision - 1 - exp10
- : (int)precision -
- 1; // the presence of the exponent ensures only one
- // significant digit comes before the decimal point
- precision = (precision_ > 0 ? (unsigned)precision_ : 0U);
- flags |= FLAGS_PRECISION; // make sure print_broken_up_decimal respects
- // our choice above
- }
- normalization.multiply = (exp10 < 0 && abs_exp10_covered_by_powers_table);
- bool should_skip_normalization =
- (fall_back_to_decimal_only_mode || exp10 == 0);
- struct double_components decimal_part_components =
- should_skip_normalization
- ? get_components(negative ? -abs_number : abs_number, precision)
- : get_normalized_components(negative, precision, abs_number,
- normalization);
- // Account for roll-over, e.g. rounding from 9.99 to 100.0 - which effects
- // the exponent and may require additional tweaking of the parts
- if (fall_back_to_decimal_only_mode) {
- if ((flags & FLAGS_ADAPT_EXP) && exp10 >= -1 &&
- decimal_part_components.integral == powers_of_10[exp10 + 1]) {
- exp10++; // Not strictly necessary, since exp10 is no longer really
- // used
- precision--;
- // ... and it should already be the case that
- // decimal_part_components.fractional == 0
- }
- // TODO: What about rollover strictly within the fractional part?
- } else {
- if (decimal_part_components.integral >= 10) {
- exp10++;
- decimal_part_components.integral = 1;
- decimal_part_components.fractional = 0;
- }
- }
- // the exp10 format is "E%+03d" and largest possible exp10 value for a
- // 64-bit double is "307" (for 2^1023), so we set aside 4-5 characters
- // overall
- unsigned int exp10_part_width = fall_back_to_decimal_only_mode ? 0U
- : (PRINTF_ABS(exp10) < 100) ? 4U
- : 5U;
- unsigned int decimal_part_width =
- ((flags & FLAGS_LEFT) && exp10_part_width)
- ?
- // We're padding on the right, so the width constraint is the
- // exponent part's problem, not the decimal part's, so we'll use as
- // many characters as we need:
- 0U
- :
- // We're padding on the left; so the width constraint is the decimal
- // part's problem. Well, can both the decimal part and the exponent
- // part fit within our overall width?
- ((width > exp10_part_width)
- ?
- // Yes, so we limit our decimal part's width.
- // (Note this is trivially valid even if we've fallen back to
- // "%f" mode)
- width - exp10_part_width
- :
- // No; we just give up on any restriction on the decimal part
- // and use as many characters as we need
- 0U);
- const size_t start_idx = idx;
- idx = print_broken_up_decimal(decimal_part_components, out, buffer, idx,
- maxlen, precision, decimal_part_width, flags,
- buf, len);
- if (!fall_back_to_decimal_only_mode) {
- out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
- idx = print_integer(out, buffer, idx, maxlen, ABS_FOR_PRINTING(exp10),
- exp10 < 0, 10, 0, exp10_part_width - 1,
- FLAGS_ZEROPAD | FLAGS_PLUS);
- if (flags & FLAGS_LEFT) {
- // We need to right-pad with spaces to meet the width requirement
- while (idx - start_idx < width)
- out(' ', buffer, idx++, maxlen);
- }
- }
- return idx;
- }
- #endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- static size_t print_floating_point(out_fct_type out,
- char* buffer,
- size_t idx,
- size_t maxlen,
- double value,
- unsigned int precision,
- unsigned int width,
- unsigned int flags,
- bool prefer_exponential) {
- char buf[PRINTF_FTOA_BUFFER_SIZE];
- size_t len = 0U;
- // test for special values
- if (value != value)
- return out_rev_(out, buffer, idx, maxlen, "nan", 3, width, flags);
- if (value < -DBL_MAX)
- return out_rev_(out, buffer, idx, maxlen, "fni-", 4, width, flags);
- if (value > DBL_MAX)
- return out_rev_(out, buffer, idx, maxlen,
- (flags & FLAGS_PLUS) ? "fni+" : "fni",
- (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
- if (!prefer_exponential && ((value > PRINTF_FLOAT_NOTATION_THRESHOLD) ||
- (value < -PRINTF_FLOAT_NOTATION_THRESHOLD))) {
- // The required behavior of standard printf is to print _every_
- // integral-part digit -- which could mean printing hundreds of
- // characters, overflowing any fixed internal buffer and necessitating a
- // more complicated implementation.
- #if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- return print_exponential_number(out, buffer, idx, maxlen, value,
- precision, width, flags, buf, len);
- #else
- return 0U;
- #endif
- }
- // set default precision, if not set explicitly
- if (!(flags & FLAGS_PRECISION)) {
- precision = PRINTF_DEFAULT_FLOAT_PRECISION;
- }
- // limit precision so that our integer holding the fractional part does not
- // overflow
- while ((len < PRINTF_FTOA_BUFFER_SIZE) &&
- (precision > PRINTF_MAX_SUPPORTED_PRECISION)) {
- buf[len++] =
- '0'; // This respects the precision in terms of result length only
- precision--;
- }
- return
- #if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- prefer_exponential
- ? print_exponential_number(out, buffer, idx, maxlen, value,
- precision, width, flags, buf, len)
- :
- #endif
- print_decimal_number(out, buffer, idx, maxlen, value, precision,
- width, flags, buf, len);
- }
- #endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS ||
- // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS)
- // internal vsnprintf
- static int __vsnprintf(out_fct_type out,
- char* buffer,
- const size_t maxlen,
- const char* format,
- va_list va) {
- unsigned int flags, width, precision, n;
- size_t idx = 0U;
- if (!buffer) {
- // use null output function
- out = out_discard;
- }
- while (*format) {
- // format specifier? %[flags][width][.precision][length]
- if (*format != '%') {
- // no
- out(*format, buffer, idx++, maxlen);
- format++;
- continue;
- } else {
- // yes, evaluate it
- format++;
- }
- // evaluate flags
- flags = 0U;
- do {
- switch (*format) {
- case '0':
- flags |= FLAGS_ZEROPAD;
- format++;
- n = 1U;
- break;
- case '-':
- flags |= FLAGS_LEFT;
- format++;
- n = 1U;
- break;
- case '+':
- flags |= FLAGS_PLUS;
- format++;
- n = 1U;
- break;
- case ' ':
- flags |= FLAGS_SPACE;
- format++;
- n = 1U;
- break;
- case '#':
- flags |= FLAGS_HASH;
- format++;
- n = 1U;
- break;
- default:
- n = 0U;
- break;
- }
- } while (n);
- // evaluate width field
- width = 0U;
- if (is_digit_(*format)) {
- width = atoi_(&format);
- } else if (*format == '*') {
- const int w = va_arg(va, int);
- if (w < 0) {
- flags |= FLAGS_LEFT; // reverse padding
- width = (unsigned int)-w;
- } else {
- width = (unsigned int)w;
- }
- format++;
- }
- // evaluate precision field
- precision = 0U;
- if (*format == '.') {
- flags |= FLAGS_PRECISION;
- format++;
- if (is_digit_(*format)) {
- precision = atoi_(&format);
- } else if (*format == '*') {
- const int precision_ = (int)va_arg(va, int);
- precision = precision_ > 0 ? (unsigned int)precision_ : 0U;
- format++;
- }
- }
- // evaluate length field
- switch (*format) {
- case 'l':
- flags |= FLAGS_LONG;
- format++;
- if (*format == 'l') {
- flags |= FLAGS_LONG_LONG;
- format++;
- }
- break;
- case 'h':
- flags |= FLAGS_SHORT;
- format++;
- if (*format == 'h') {
- flags |= FLAGS_CHAR;
- format++;
- }
- break;
- case 't':
- flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG
- : FLAGS_LONG_LONG);
- format++;
- break;
- case 'j':
- flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG
- : FLAGS_LONG_LONG);
- format++;
- break;
- case 'z':
- flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG
- : FLAGS_LONG_LONG);
- format++;
- break;
- default:
- break;
- }
- // evaluate specifier
- switch (*format) {
- case 'd':
- case 'i':
- case 'u':
- case 'x':
- case 'X':
- case 'o':
- case 'b': {
- // set the base
- numeric_base_t base;
- if (*format == 'x' || *format == 'X') {
- base = BASE_HEX;
- } else if (*format == 'o') {
- base = BASE_OCTAL;
- } else if (*format == 'b') {
- base = BASE_BINARY;
- } else {
- base = BASE_DECIMAL;
- flags &= ~FLAGS_HASH; // no hash for dec format
- }
- // uppercase
- if (*format == 'X') {
- flags |= FLAGS_UPPERCASE;
- }
- // no plus or space flag for u, x, X, o, b
- if ((*format != 'i') && (*format != 'd')) {
- flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
- }
- // ignore '0' flag when precision is given
- if (flags & FLAGS_PRECISION) {
- flags &= ~FLAGS_ZEROPAD;
- }
- // convert the integer
- if ((*format == 'i') || (*format == 'd')) {
- // signed
- if (flags & FLAGS_LONG_LONG) {
- #if PRINTF_SUPPORT_LONG_LONG
- const long long value = va_arg(va, long long);
- idx = print_integer(out, buffer, idx, maxlen,
- ABS_FOR_PRINTING(value), value < 0,
- base, precision, width, flags);
- #endif
- } else if (flags & FLAGS_LONG) {
- const long value = va_arg(va, long);
- idx = print_integer(out, buffer, idx, maxlen,
- ABS_FOR_PRINTING(value), value < 0,
- base, precision, width, flags);
- } else {
- const int value =
- (flags & FLAGS_CHAR) ? (signed char)va_arg(va, int)
- : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int)
- : va_arg(va, int);
- idx = print_integer(out, buffer, idx, maxlen,
- ABS_FOR_PRINTING(value), value < 0,
- base, precision, width, flags);
- }
- } else {
- // unsigned
- if (flags & FLAGS_LONG_LONG) {
- #if PRINTF_SUPPORT_LONG_LONG
- idx =
- print_integer(out, buffer, idx, maxlen,
- (printf_unsigned_value_t)va_arg(
- va, unsigned long long),
- false, base, precision, width, flags);
- #endif
- } else if (flags & FLAGS_LONG) {
- idx = print_integer(
- out, buffer, idx, maxlen,
- (printf_unsigned_value_t)va_arg(va, unsigned long),
- false, base, precision, width, flags);
- } else {
- const unsigned int value =
- (flags & FLAGS_CHAR)
- ? (unsigned char)va_arg(va, unsigned int)
- : (flags & FLAGS_SHORT)
- ? (unsigned short int)va_arg(va, unsigned int)
- : va_arg(va, unsigned int);
- idx =
- print_integer(out, buffer, idx, maxlen,
- (printf_unsigned_value_t)value, false,
- base, precision, width, flags);
- }
- }
- format++;
- break;
- }
- #if PRINTF_SUPPORT_DECIMAL_SPECIFIERS
- case 'f':
- case 'F':
- if (*format == 'F')
- flags |= FLAGS_UPPERCASE;
- idx = print_floating_point(out, buffer, idx, maxlen,
- va_arg(va, double), precision, width,
- flags, PRINTF_PREFER_DECIMAL);
- format++;
- break;
- #endif
- #if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- if ((*format == 'g') || (*format == 'G'))
- flags |= FLAGS_ADAPT_EXP;
- if ((*format == 'E') || (*format == 'G'))
- flags |= FLAGS_UPPERCASE;
- idx = print_floating_point(out, buffer, idx, maxlen,
- va_arg(va, double), precision, width,
- flags, PRINTF_PREFER_EXPONENTIAL);
- format++;
- break;
- #endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
- case 'c': {
- unsigned int l = 1U;
- // pre padding
- if (!(flags & FLAGS_LEFT)) {
- while (l++ < width) {
- out(' ', buffer, idx++, maxlen);
- }
- }
- // char output
- out((char)va_arg(va, int), buffer, idx++, maxlen);
- // post padding
- if (flags & FLAGS_LEFT) {
- while (l++ < width) {
- out(' ', buffer, idx++, maxlen);
- }
- }
- format++;
- break;
- }
- case 's': {
- const char* p = va_arg(va, char*);
- if (p == NULL) {
- idx = out_rev_(out, buffer, idx, maxlen, ")llun(", 6, width,
- flags);
- } else {
- unsigned int l =
- strnlen_s_(p, precision ? precision : (size_t)-1);
- // pre padding
- if (flags & FLAGS_PRECISION) {
- l = (l < precision ? l : precision);
- }
- if (!(flags & FLAGS_LEFT)) {
- while (l++ < width) {
- out(' ', buffer, idx++, maxlen);
- }
- }
- // string output
- while ((*p != 0) &&
- (!(flags & FLAGS_PRECISION) || precision--)) {
- out(*(p++), buffer, idx++, maxlen);
- }
- // post padding
- if (flags & FLAGS_LEFT) {
- while (l++ < width) {
- out(' ', buffer, idx++, maxlen);
- }
- }
- }
- format++;
- break;
- }
- case 'p': {
- width = sizeof(void*) * 2U +
- 2; // 2 hex chars per byte + the "0x" prefix
- flags |= FLAGS_ZEROPAD | FLAGS_POINTER;
- uintptr_t value = (uintptr_t)va_arg(va, void*);
- idx = (value == (uintptr_t)NULL)
- ? out_rev_(out, buffer, idx, maxlen, ")lin(", 5,
- width, flags)
- : print_integer(out, buffer, idx, maxlen,
- (printf_unsigned_value_t)value, false,
- BASE_HEX, precision, width, flags);
- format++;
- break;
- }
- case '%':
- out('%', buffer, idx++, maxlen);
- format++;
- break;
- default:
- out(*format, buffer, idx++, maxlen);
- format++;
- break;
- }
- }
- // termination
- out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
- // return written chars without terminating \0
- return (int)idx;
- }
- /**
- * This function will fill a formatted string to buffer.
- *
- * @param buf is the buffer to save formatted string.
- *
- * @param size is the size of buffer.
- *
- * @param fmt is the format parameters.
- *
- * @param args is a list of variable parameters.
- *
- * @return The number of characters actually written to buffer.
- */
- int pika_platform_vsnprintf(char* buff,
- size_t size,
- const char* fmt,
- va_list args) {
- return __vsnprintf(out_buffer, buff, size, fmt, args);
- }
|