From 56d1d8dab0aed7f781486a34f1f47de4d0c3648f Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 8 May 2021 10:28:53 +0200 Subject: [PATCH] MINOR: tools: implement trimming of floating point numbers When using "%f" to print a float, it automatically gets 6 digits after the decimal point and there's no way to automatically adjust to the required ones by dropping trailing zeroes. This function does exactly this and automatically drops the decimal point if all digits after it were zeroes. This will make numbers more friendly in stats and makes outputs shorter (e.g. JSON where everything is just a "number"). The function is designed to be easy to use with snprint() and chunks: snprintf: flt_trim(buf, 0, snprintf(buf, sizeof(buf), "%f", x)); chunk_printf: out->data = flt_trim(out->area, 0, chunk_printf(out, "%f", x)); chunk_appendf: size_t prev_data = out->data; out->data = flt_trim(out->area, prev_data, chunk_appendf(out, "%f", x)); --- include/haproxy/tools.h | 1 + src/tools.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 92d5b7081..948207a38 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -74,6 +74,7 @@ extern char *ultoa_r(unsigned long n, char *buffer, int size); extern char *lltoa_r(long long int n, char *buffer, int size); extern char *sltoa_r(long n, char *buffer, int size); extern const char *ulltoh_r(unsigned long long n, char *buffer, int size); +size_t flt_trim(char *buffer, size_t num_start, size_t len); static inline const char *ultoa(unsigned long n) { return ultoa_r(n, itoa_str[0], sizeof(itoa_str[0])); diff --git a/src/tools.c b/src/tools.c index c45358570..e94fed7e7 100644 --- a/src/tools.c +++ b/src/tools.c @@ -535,6 +535,39 @@ const char *limit_r(unsigned long n, char *buffer, int size, const char *alt) return (n) ? ultoa_r(n, buffer, size) : (alt ? alt : ""); } +/* Trims the first "%f" float in a string to its minimum number of digits after + * the decimal point by trimming trailing zeroes, even dropping the decimal + * point if not needed. The string is in of length , and the + * number is expected to start at or after position (the first + * point appearing there is considered). A NUL character is always placed at + * the end if some trimming occurs. The new buffer length is returned. + */ +size_t flt_trim(char *buffer, size_t num_start, size_t len) +{ + char *end = buffer + len; + char *p = buffer + num_start; + char *trim; + + do { + if (p >= end) + return len; + trim = p++; + } while (*trim != '.'); + + /* For now is on the decimal point. Let's look for any other + * meaningful digit after it. + */ + while (p < end) { + if (*p++ != '0') + trim = p; + } + + if (trim < end) + *trim = 0; + + return trim - buffer; +} + /* returns a locally allocated string containing the quoted encoding of the * input string. The output may be truncated to QSTR_SIZE chars, but it is * guaranteed that the string will always be properly terminated. Quotes are