From 4143106a96e2b02fa820f3bc53874f5faac3b276 Mon Sep 17 00:00:00 2001 From: Vitaliy Nimych Date: Sat, 21 Sep 2024 12:55:02 +0300 Subject: [PATCH 1/4] Add support for float formatting with 'f' specifier in printf --- src/main/common/printf.c | 55 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/main/common/printf.c b/src/main/common/printf.c index 4c65e293ed..8492923577 100644 --- a/src/main/common/printf.c +++ b/src/main/common/printf.c @@ -69,10 +69,48 @@ static int putchw(void *putp, putcf putf, int n, char z, char *bf) return written; } -// retrun number of bytes written +// function to convert float to string +static void tfp_ftoa(double f, char *buf, int precision) { + int ipart = (int)f; + double fpart = f - (double)ipart; + int i = 0; + + // Convert integer part + if (ipart == 0) { + buf[i++] = '0'; + } else { + if (ipart < 0) { + buf[i++] = '-'; + ipart = -ipart; + } + char temp[10]; + int j = 0; + while (ipart) { + temp[j++] = (ipart % 10) + '0'; + ipart /= 10; + } + while (j > 0) { + buf[i++] = temp[--j]; + } + } + + buf[i++] = '.'; + + // Convert fractional part + for (int j = 0; j < precision; j++) { + fpart *= 10; + int digit = (int)fpart; + buf[i++] = digit + '0'; + fpart -= digit; + } + + buf[i] = '\0'; +} + +// return number of bytes written int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) { - char bf[12]; + char bf[32]; // Increased buffer size for float int written = 0; char ch; @@ -85,6 +123,7 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) char lng = 0; #endif int w = 0; + int precision = 6; // Default float precision ch = *(fmt++); if (ch == '0') { ch = *(fmt++); @@ -93,6 +132,12 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) if (ch >= '0' && ch <= '9') { ch = a2i(ch, &fmt, 10, &w); } + if (ch == '.') { + ch = *(fmt++); + if (ch >= '0' && ch <= '9') { + ch = a2i(ch, &fmt, 10, &precision); + } + } #ifdef REQUIRE_PRINTF_LONG_SUPPORT if (ch == 'l') { ch = *(fmt++); @@ -144,6 +189,12 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) case 'n': *va_arg(va, int*) = written; break; + case 'f': { + double f = va_arg(va, double); + tfp_ftoa(f, bf, precision); + written += putchw(putp, putf, w, lz, bf); + break; + } default: break; } From 3dbff981a0d770aadcf9f539342eaa08b1b10a7f Mon Sep 17 00:00:00 2001 From: Vitaliy Nimych Date: Mon, 23 Sep 2024 19:55:10 +0300 Subject: [PATCH 2/4] add round las digit, add check buffer overflow --- src/main/common/printf.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/main/common/printf.c b/src/main/common/printf.c index 8492923577..64f2a0d36c 100644 --- a/src/main/common/printf.c +++ b/src/main/common/printf.c @@ -71,22 +71,26 @@ static int putchw(void *putp, putcf putf, int n, char z, char *bf) // function to convert float to string static void tfp_ftoa(double f, char *buf, int precision) { + int i = 0; + + // Handle negative numbers + if (f < 0) { + buf[i++] = '-'; + f = -f; // Make f positive + } + + // Extract integer part int ipart = (int)f; double fpart = f - (double)ipart; - int i = 0; // Convert integer part if (ipart == 0) { buf[i++] = '0'; } else { - if (ipart < 0) { - buf[i++] = '-'; - ipart = -ipart; - } char temp[10]; int j = 0; while (ipart) { - temp[j++] = (ipart % 10) + '0'; + temp[j++] = (ipart % 10) + '0'; // + '0' ASCII 48 ipart /= 10; } while (j > 0) { @@ -104,15 +108,21 @@ static void tfp_ftoa(double f, char *buf, int precision) { fpart -= digit; } + // Round last digit in case of precision overflow + if ((int)(fpart * 10) >= 5) { + buf[i - 1] += 1; // Round up the last digit + } + buf[i] = '\0'; } // return number of bytes written int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) { - char bf[32]; // Increased buffer size for float + char bf[32]; int written = 0; char ch; + const int buffer_size = sizeof(bf) - 1; // Reserve one byte for '\0' while ((ch = *(fmt++))) { if (ch != '%') { @@ -192,7 +202,8 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) case 'f': { double f = va_arg(va, double); tfp_ftoa(f, bf, precision); - written += putchw(putp, putf, w, lz, bf); + written = putchw(putp, putf, w, lz, bf); + if (written > buffer_size) written = buffer_size; // buffer overflow break; } default: From 399807c054350f592feb8ec948ecac7a6e0df06b Mon Sep 17 00:00:00 2001 From: Vitaliy Nimych Date: Mon, 23 Sep 2024 21:17:51 +0300 Subject: [PATCH 3/4] buffer overflow, add check before write to buffer --- src/main/common/printf.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/common/printf.c b/src/main/common/printf.c index 64f2a0d36c..98cc386849 100644 --- a/src/main/common/printf.c +++ b/src/main/common/printf.c @@ -70,7 +70,7 @@ static int putchw(void *putp, putcf putf, int n, char z, char *bf) } // function to convert float to string -static void tfp_ftoa(double f, char *buf, int precision) { +static void tfp_ftoa(double f, char *buf, int buf_size, int precision) { int i = 0; // Handle negative numbers @@ -90,11 +90,15 @@ static void tfp_ftoa(double f, char *buf, int precision) { char temp[10]; int j = 0; while (ipart) { - temp[j++] = (ipart % 10) + '0'; // + '0' ASCII 48 + temp[j++] = (ipart % 10) + '0'; // part + '0' ASCII 48 ipart /= 10; } while (j > 0) { - buf[i++] = temp[--j]; + if (i < buf_size) { + buf[i++] = temp[--j]; + } else { + break; // buffer overflow + } } } @@ -104,16 +108,22 @@ static void tfp_ftoa(double f, char *buf, int precision) { for (int j = 0; j < precision; j++) { fpart *= 10; int digit = (int)fpart; - buf[i++] = digit + '0'; + if (i < buf_size) { + buf[i++] = digit + '0'; // part + '0' ASCII 48 + } fpart -= digit; } // Round last digit in case of precision overflow - if ((int)(fpart * 10) >= 5) { + if ((int)(fpart * 10) >= 5 && i > 0 && i < buf_size) { buf[i - 1] += 1; // Round up the last digit } - buf[i] = '\0'; + if (i < buf_size) { + buf[i] = '\0'; + } else { + buf[buf_size - 1] = '\0'; + } } // return number of bytes written @@ -201,9 +211,8 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) break; case 'f': { double f = va_arg(va, double); - tfp_ftoa(f, bf, precision); + tfp_ftoa(f, bf, buffer_size, precision); written = putchw(putp, putf, w, lz, bf); - if (written > buffer_size) written = buffer_size; // buffer overflow break; } default: From 256bf2109998ed78fbbdc813a690238019cb2ac5 Mon Sep 17 00:00:00 2001 From: Vitaliy Nimych Date: Thu, 26 Sep 2024 18:19:36 +0300 Subject: [PATCH 4/4] update round, update convert integer part to string without buff --- src/main/common/printf.c | 83 +++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/src/main/common/printf.c b/src/main/common/printf.c index 98cc386849..1b95983a60 100644 --- a/src/main/common/printf.c +++ b/src/main/common/printf.c @@ -47,6 +47,8 @@ #ifdef REQUIRE_CC_ARM_PRINTF_SUPPORT +#define DEFAULT_FLOAT_PRECISION 6 + putcf stdout_putf; void *stdout_putp; @@ -72,6 +74,7 @@ static int putchw(void *putp, putcf putf, int n, char z, char *bf) // function to convert float to string static void tfp_ftoa(double f, char *buf, int buf_size, int precision) { int i = 0; + const double scales[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6 }; // Handle negative numbers if (f < 0) { @@ -80,43 +83,63 @@ static void tfp_ftoa(double f, char *buf, int buf_size, int precision) { } // Extract integer part - int ipart = (int)f; - double fpart = f - (double)ipart; + long int_part = (long)f; - // Convert integer part - if (ipart == 0) { + // Extract fractional part + double frac_part = f - (double)int_part; + + // Scale the fractional part for rounding + double scaled_frac_part = frac_part * scales[precision]; + + // Get the rounded fractional part + long rounded_frac = (long)(scaled_frac_part); + double last_digit = scaled_frac_part - rounded_frac; // Get last digit for rounding + + // Handle rounding based on the last digit + if (last_digit >= (double)0.5) { + rounded_frac++; // Round up if the last digit is 5 or more + } + + // Check for overflow in the fractional part + if (rounded_frac >= scales[precision]) { + rounded_frac = 0; + int_part++; // Increment the integer part if necessary + } + + // Convert the integer part to string + if (int_part == 0) { buf[i++] = '0'; } else { - char temp[10]; - int j = 0; - while (ipart) { - temp[j++] = (ipart % 10) + '0'; // part + '0' ASCII 48 - ipart /= 10; + long num = int_part; + int digits = 0; + + // Calculate the number of digits in the integer part + long temp = num; + while (temp > 0) { + temp /= 10; + digits++; } - while (j > 0) { - if (i < buf_size) { - buf[i++] = temp[--j]; - } else { - break; // buffer overflow + + // Write digits starting from the highest digit + for (int j = digits - 1; j >= 0; j--) { + if (i < buf_size - 1) { + buf[i + j] = (num % 10) + '0'; + num /= 10; } } + i += digits; } - buf[i++] = '.'; + // Add decimal point and fractional part if precision > 0 + if (precision > 0 && i < buf_size - 1) { + buf[i++] = '.'; - // Convert fractional part - for (int j = 0; j < precision; j++) { - fpart *= 10; - int digit = (int)fpart; - if (i < buf_size) { - buf[i++] = digit + '0'; // part + '0' ASCII 48 + // Convert the fractional part to string + for (int j = 0; j < precision && i < buf_size - 1; j++) { + rounded_frac *= 10; // Shift left + buf[i++] = (char)(rounded_frac / scales[precision]) + '0'; + rounded_frac %= (long)scales[precision]; } - fpart -= digit; - } - - // Round last digit in case of precision overflow - if ((int)(fpart * 10) >= 5 && i > 0 && i < buf_size) { - buf[i - 1] += 1; // Round up the last digit } if (i < buf_size) { @@ -132,7 +155,6 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) char bf[32]; int written = 0; char ch; - const int buffer_size = sizeof(bf) - 1; // Reserve one byte for '\0' while ((ch = *(fmt++))) { if (ch != '%') { @@ -143,7 +165,7 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) char lng = 0; #endif int w = 0; - int precision = 6; // Default float precision + int precision = DEFAULT_FLOAT_PRECISION; // Default float precision ch = *(fmt++); if (ch == '0') { ch = *(fmt++); @@ -211,7 +233,8 @@ int tfp_format(void *putp, putcf putf, const char *fmt, va_list va) break; case 'f': { double f = va_arg(va, double); - tfp_ftoa(f, bf, buffer_size, precision); + if (precision > DEFAULT_FLOAT_PRECISION) precision = DEFAULT_FLOAT_PRECISION; + tfp_ftoa(f, bf, sizeof(bf) - 1, precision); written = putchw(putp, putf, w, lz, bf); break; }