From 54d8b0a95defc95a159a2bc4388f1be163019378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 2 Sep 2025 14:12:58 +0800 Subject: [PATCH] Global: adds configurable trailing zeros for double formatting --- src/common/format.c | 4 +- src/common/frequency.c | 2 +- src/common/size.c | 2 +- src/options/display.c | 19 +++++ src/options/display.h | 8 ++ src/util/FFstrbuf.c | 31 +++++--- src/util/FFstrbuf.h | 2 +- tests/strbuf.c | 171 ++++++++++++++++++++++++++++++++++------- 8 files changed, 196 insertions(+), 43 deletions(-) diff --git a/src/common/format.c b/src/common/format.c index f6cbcab8b..5cc27ed77 100644 --- a/src/common/format.c +++ b/src/common/format.c @@ -32,10 +32,10 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg) ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value); break; case FF_FORMAT_ARG_TYPE_FLOAT: - ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits); + ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_HIDE); break; case FF_FORMAT_ARG_TYPE_DOUBLE: - ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits); + ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_HIDE); break; case FF_FORMAT_ARG_TYPE_BOOL: ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false"); diff --git a/src/common/frequency.c b/src/common/frequency.c index ccb3b707f..ae1318969 100644 --- a/src/common/frequency.c +++ b/src/common/frequency.c @@ -11,7 +11,7 @@ bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result) if (ndigits >= 0) { - ffStrbufAppendDouble(result, mhz / 1000., ndigits); + ffStrbufAppendDouble(result, mhz / 1000., ndigits, true); if (spaceBeforeUnit) ffStrbufAppendC(result, ' '); ffStrbufAppendS(result, "GHz"); } diff --git a/src/common/size.c b/src/common/size.c index eafe46a53..07ce86da5 100644 --- a/src/common/size.c +++ b/src/common/size.c @@ -17,7 +17,7 @@ static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const cha if (counter == 0) ffStrbufAppendUInt(result, bytes); else - ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits); + ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits, true); if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER) ffStrbufAppendC(result, ' '); ffStrbufAppendS(result, prefixes[counter]); diff --git a/src/options/display.c b/src/options/display.c index 5bb2a888e..44c9b51c3 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -380,6 +380,24 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va return "display.fraction.ndigits must be an integer"; options->fractionNdigits = (int8_t) yyjson_get_int(ndigits); } + yyjson_val* trailingZeros = yyjson_obj_get(val, "trailingZeros"); + if (trailingZeros) + { + if (yyjson_is_null(trailingZeros)) + options->fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT; + else + { + int value; + const char* error = ffJsonConfigParseEnum(trailingZeros, &value, (FFKeyValuePair[]) { + { "default", FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT }, + { "show", FF_FRACTION_TRAILING_ZEROS_TYPE_SHOW }, + { "hide", FF_FRACTION_TRAILING_ZEROS_TYPE_HIDE }, + {}, + }); + if (error) return error; + options->fractionTrailingZeros = (FFFractionTrailingZerosType) value; + } + } } else return "display.fraction must be an object"; @@ -810,6 +828,7 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) options->freqNdigits = 2; options->freqSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT; options->fractionNdigits = -1; + options->fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT; ffListInit(&options->constants, sizeof(FFstrbuf)); } diff --git a/src/options/display.h b/src/options/display.h index 4193cd2c6..c7bdef5b5 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -25,6 +25,13 @@ typedef enum __attribute__((__packed__)) FFSpaceBeforeUnitType FF_SPACE_BEFORE_UNIT_NEVER, } FFSpaceBeforeUnitType; +typedef enum __attribute__((__packed__)) FFFractionTrailingZerosType +{ + FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT, + FF_FRACTION_TRAILING_ZEROS_TYPE_SHOW, + FF_FRACTION_TRAILING_ZEROS_TYPE_HIDE, +} FFFractionTrailingZerosType; + typedef struct FFOptionsDisplay { //If one of those is empty, ffLogoPrint will set them @@ -81,6 +88,7 @@ typedef struct FFOptionsDisplay int8_t freqNdigits; FFSpaceBeforeUnitType freqSpaceBeforeUnit; int8_t fractionNdigits; + FFFractionTrailingZerosType fractionTrailingZeros; FFlist constants; // list of FFstrbuf } FFOptionsDisplay; diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index f0f85e61e..45db80a4c 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -571,7 +571,7 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value) strbuf->length += (uint32_t)(end - start); } -void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision) +void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros) { assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point @@ -598,18 +598,29 @@ void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision) return; } - if (precision > 1) + if (trailingZeros) { - for (char* p = end - 1; *p != '.' && p > start; --p) - --precision; - if (precision > 0) - ffStrbufAppendNC(strbuf, (uint32_t) precision, '0'); + if (precision > 1) + { + for (char* p = end - 1; *p != '.' && p > start; --p) + --precision; + if (precision > 0) + ffStrbufAppendNC(strbuf, (uint32_t) precision, '0'); + } + else if (precision == 0 || (precision < 0 && end[-1] == '0')) + { + goto removeDecimalPoint; + } } - else if (precision == 0 || (precision < 0 && end[-1] == '0')) + else { - // yyjson always appends ".0", so we need to remove it - strbuf->length -= 2; - strbuf->chars[strbuf->length] = '\0'; + if (end[-1] == '0') + { + removeDecimalPoint: + // yyjson always appends ".0" to make it a float point number. We need to remove it + strbuf->length -= 2; + strbuf->chars[strbuf->length] = '\0'; + } } } diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 704f2a332..7d50d6ad7 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -107,7 +107,7 @@ void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value); void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value); // Appends a double value to the string buffer with the specified precision (0~15). // if `precision < 0`, let yyjson decide the precision -void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision); +void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros); FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) { diff --git a/tests/strbuf.c b/tests/strbuf.c index 39c845a3b..f51f00cde 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -744,115 +744,230 @@ int main(void) } { - ffStrbufAppendDouble(&strbuf, 120.0, 0); + ffStrbufAppendDouble(&strbuf, 120.0, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.0, 1); + ffStrbufAppendDouble(&strbuf, 120.0, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "120.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.0, 5); + ffStrbufAppendDouble(&strbuf, 120.0, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "120.00000")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123456789, 5); + ffStrbufAppendDouble(&strbuf, 120.123456789, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "120.12346")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.888888, 0); + ffStrbufAppendDouble(&strbuf, 120.888888, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "121")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.999999, 2); + ffStrbufAppendDouble(&strbuf, 120.999999, 2, true); VERIFY(ffStrbufEqualS(&strbuf, "121.00")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123456789, 0); + ffStrbufAppendDouble(&strbuf, 120.123456789, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123456789, -1); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123, 5); + ffStrbufAppendDouble(&strbuf, 120.123, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "120.12300")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.0, 0); + ffStrbufAppendDouble(&strbuf, -120.0, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.0, 1); + ffStrbufAppendDouble(&strbuf, -120.0, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.0, 5); + ffStrbufAppendDouble(&strbuf, -120.0, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.00000")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123456789, 5); + ffStrbufAppendDouble(&strbuf, -120.123456789, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.12346")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123456789, 0); + ffStrbufAppendDouble(&strbuf, -120.123456789, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123456789, -1); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123, 5); + ffStrbufAppendDouble(&strbuf, -120.123, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.12300")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.888888, 0); + ffStrbufAppendDouble(&strbuf, -120.888888, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-121")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.999999, 2); + ffStrbufAppendDouble(&strbuf, -120.999999, 2, true); VERIFY(ffStrbufEqualS(&strbuf, "-121.00")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e50, 1); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e50, 1); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e50, 0); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e50, 0); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e50, -1); + ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e50, -1); + ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e20, 1); + ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e20, 1); + ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, +0.0, 0); + ffStrbufAppendDouble(&strbuf, +0.0, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -0.0, 0); + ffStrbufAppendDouble(&strbuf, -0.0, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-0")); + + ffStrbufDestroy(&strbuf); + } + + { + ffStrbufAppendDouble(&strbuf, 120.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.888888, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.999999, 2, false); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.123")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.888888, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.999999, 2, false); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, +0.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -0.0, 0, false); VERIFY(ffStrbufEqualS(&strbuf, "-0")); ffStrbufDestroy(&strbuf);