Browse Source

[klibc] add rt_vsnprintf_std.c and rename RT_KLIBC_USING_VSNPRINTF_LONGLONG

Meco Man 7 months ago
parent
commit
8e10983c9b
38 changed files with 2102 additions and 842 deletions
  1. 1 1
      bsp/allwinner/d1/rtconfig.h
  2. 1 1
      bsp/allwinner/d1s/rtconfig.h
  3. 1 1
      bsp/bouffalo_lab/bl808/d0/rtconfig.h
  4. 1 1
      bsp/cvitek/c906_little/rtconfig.h
  5. 1 1
      bsp/cvitek/cv18xx_aarch64/rtconfig.h
  6. 1 1
      bsp/cvitek/cv18xx_risc-v/rtconfig.h
  7. 1 1
      bsp/k230/rtconfig.h
  8. 0 27
      bsp/nuvoton/numaker-iot-m467/.config
  9. 0 27
      bsp/nuvoton/numaker-iot-m487/.config
  10. 0 27
      bsp/nuvoton/numaker-m2354/.config
  11. 0 27
      bsp/nuvoton/numaker-m467hj/.config
  12. 0 26
      bsp/nxp/mcx/mcxa/frdm-mcxa153/.config
  13. 0 27
      bsp/nxp/mcx/mcxn/frdm-mcxn236/.config
  14. 0 20
      bsp/nxp/mcx/mcxn/frdm-mcxn947/.config
  15. 1 1
      bsp/phytium/aarch64/configs/e2000d_demo_rtsmart.h
  16. 1 1
      bsp/phytium/aarch64/configs/e2000d_demo_rtthread.h
  17. 1 1
      bsp/phytium/aarch64/configs/e2000d_demo_rtthread_pusb2_dc.h
  18. 1 1
      bsp/phytium/aarch64/configs/e2000q_demo_rtsmart.h
  19. 1 1
      bsp/phytium/aarch64/configs/e2000q_demo_rtthread.h
  20. 1 1
      bsp/phytium/aarch64/configs/phytium_pi_rtsmart.h
  21. 1 1
      bsp/phytium/aarch64/configs/phytium_pi_rtthread.h
  22. 1 1
      bsp/phytium/aarch64/configs/phytium_pi_rtthread_pusb2_hc.h
  23. 1 1
      bsp/phytium/aarch64/configs/phytium_pi_rtthread_xhci.h
  24. 1 1
      bsp/phytium/aarch64/rtconfig.h
  25. 1 1
      bsp/qemu-virt64-riscv/rtconfig.h
  26. 1 1
      bsp/raspberry-pi/raspi-dm2.0/rtconfig.h
  27. 1 1
      bsp/rockchip/rk3500/rtconfig.h
  28. 0 3
      bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-printf.attach
  29. 9 0
      bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-vsnprintf-std.attach
  30. 0 1
      bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/online-packages/system/enhanced-kservice.attach
  31. 1 1
      components/drivers/sensor/Kconfig
  32. 1 1
      components/utilities/Kconfig
  33. 99 10
      src/Kconfig
  34. 0 8
      src/klibc/kerrno.c
  35. 0 609
      src/klibc/kstdio.c
  36. 0 8
      src/klibc/kstring.c
  37. 1356 0
      src/klibc/rt_vsnprintf_std.c
  38. 616 0
      src/klibc/rt_vsnprintf_tiny.c

+ 1 - 1
bsp/allwinner/d1/rtconfig.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/allwinner/d1s/rtconfig.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/bouffalo_lab/bl808/d0/rtconfig.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/cvitek/c906_little/rtconfig.h

@@ -24,7 +24,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/cvitek/cv18xx_aarch64/rtconfig.h

@@ -24,7 +24,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/cvitek/cv18xx_risc-v/rtconfig.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/k230/rtconfig.h

@@ -27,7 +27,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 0 - 27
bsp/nuvoton/numaker-iot-m467/.config

@@ -821,33 +821,6 @@ CONFIG_PKG_AT_DEVICE_VER_NUM=0x99999
 # system packages
 # system packages
 #
 #
 
 
-#
-# enhanced kernel services
-#
-# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
-# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG=y
-CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER=y
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
-# end of enhanced kernel services
-
 # CONFIG_PKG_USING_AUNITY is not set
 # CONFIG_PKG_USING_AUNITY is not set
 
 
 #
 #

+ 0 - 27
bsp/nuvoton/numaker-iot-m487/.config

@@ -801,33 +801,6 @@ CONFIG_PKG_AT_DEVICE_VER_NUM=0x99999
 # system packages
 # system packages
 #
 #
 
 
-#
-# enhanced kernel services
-#
-# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
-# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG=y
-CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER=y
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
-# end of enhanced kernel services
-
 # CONFIG_PKG_USING_AUNITY is not set
 # CONFIG_PKG_USING_AUNITY is not set
 
 
 #
 #

+ 0 - 27
bsp/nuvoton/numaker-m2354/.config

@@ -735,33 +735,6 @@ CONFIG_PKG_AT_DEVICE_VER_NUM=0x99999
 # system packages
 # system packages
 #
 #
 
 
-#
-# enhanced kernel services
-#
-# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
-# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG=y
-CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER=y
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
-# end of enhanced kernel services
-
 # CONFIG_PKG_USING_AUNITY is not set
 # CONFIG_PKG_USING_AUNITY is not set
 
 
 #
 #

+ 0 - 27
bsp/nuvoton/numaker-m467hj/.config

@@ -773,33 +773,6 @@ CONFIG_RT_USB_MSTORAGE_DISK_NAME="ramdisk1"
 # system packages
 # system packages
 #
 #
 
 
-#
-# enhanced kernel services
-#
-# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
-# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER=y
-CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG=y
-CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER=y
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
-# end of enhanced kernel services
-
 # CONFIG_PKG_USING_AUNITY is not set
 # CONFIG_PKG_USING_AUNITY is not set
 
 
 #
 #

+ 0 - 26
bsp/nxp/mcx/mcxa/frdm-mcxa153/.config

@@ -507,32 +507,6 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y
 # system packages
 # system packages
 #
 #
 
 
-#
-# enhanced kernel services
-#
-# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
-# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-# CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG is not set
-# CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
-
 #
 #
 # acceleration: Assembly language or algorithmic acceleration packages
 # acceleration: Assembly language or algorithmic acceleration packages
 #
 #

+ 0 - 27
bsp/nxp/mcx/mcxn/frdm-mcxn236/.config

@@ -558,33 +558,6 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y
 # system packages
 # system packages
 #
 #
 
 
-#
-# enhanced kernel services
-#
-# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
-# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-# CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG is not set
-# CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
-# end of enhanced kernel services
-
 # CONFIG_PKG_USING_AUNITY is not set
 # CONFIG_PKG_USING_AUNITY is not set
 
 
 #
 #

+ 0 - 20
bsp/nxp/mcx/mcxn/frdm-mcxn947/.config

@@ -512,26 +512,6 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y
 #
 #
 # CONFIG_PKG_USING_RT_MEMCPY_CM is not set
 # CONFIG_PKG_USING_RT_MEMCPY_CM is not set
 # CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
 # CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
-# CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG is not set
-# CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER is not set
-# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
-CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
-CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
-CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
-CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
-# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
-CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
 
 
 #
 #
 # acceleration: Assembly language or algorithmic acceleration packages
 # acceleration: Assembly language or algorithmic acceleration packages

+ 1 - 1
bsp/phytium/aarch64/configs/e2000d_demo_rtsmart.h

@@ -28,7 +28,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/e2000d_demo_rtthread.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/e2000d_demo_rtthread_pusb2_dc.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/e2000q_demo_rtsmart.h

@@ -28,7 +28,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/e2000q_demo_rtthread.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/phytium_pi_rtsmart.h

@@ -28,7 +28,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/phytium_pi_rtthread.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/phytium_pi_rtthread_pusb2_hc.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/configs/phytium_pi_rtthread_xhci.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/phytium/aarch64/rtconfig.h

@@ -26,7 +26,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/qemu-virt64-riscv/rtconfig.h

@@ -25,7 +25,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_ASSERT

+ 1 - 1
bsp/raspberry-pi/raspi-dm2.0/rtconfig.h

@@ -28,7 +28,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_COLOR
 #define RT_DEBUGING_COLOR

+ 1 - 1
bsp/rockchip/rk3500/rtconfig.h

@@ -30,7 +30,7 @@
 
 
 /* klibc optimization */
 /* klibc optimization */
 
 
-#define RT_KLIBC_USING_PRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
 /* end of klibc optimization */
 /* end of klibc optimization */
 #define RT_USING_DEBUG
 #define RT_USING_DEBUG
 #define RT_DEBUGING_COLOR
 #define RT_DEBUGING_COLOR

+ 0 - 3
bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-printf.attach

@@ -1,3 +0,0 @@
-# scons: --strict
-
-CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG=y

+ 9 - 0
bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-vsnprintf-std.attach

@@ -0,0 +1,9 @@
+# scons: --strict
+
+CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y
+CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG=y
+CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y
+CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y
+CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y
+CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y
+CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS=y

+ 0 - 1
bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/online-packages/system/enhanced-kservice.attach

@@ -1,4 +1,3 @@
 # scons: --strict
 # scons: --strict
 CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE=y
 CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE=y
 CONFIG_PKG_USING_RT_MEMCPY_CM=y
 CONFIG_PKG_USING_RT_MEMCPY_CM=y
-CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y

+ 1 - 1
components/drivers/sensor/Kconfig

@@ -10,6 +10,6 @@ if RT_USING_SENSOR
 
 
     config RT_USING_SENSOR_CMD
     config RT_USING_SENSOR_CMD
         bool "Using Sensor cmd"
         bool "Using Sensor cmd"
-        select PKG_USING_RT_VSNPRINTF_FULL if RT_USING_SENSOR_V2
+        select RT_KLIBC_USING_VSNPRINTF_STANDARD if RT_USING_SENSOR_V2
         default y
         default y
 endif
 endif

+ 1 - 1
components/utilities/Kconfig

@@ -137,7 +137,7 @@ menuconfig RT_USING_ULOG
             config ULOG_OUTPUT_FLOAT
             config ULOG_OUTPUT_FLOAT
                 bool "Enable float number support. It will using more thread stack."
                 bool "Enable float number support. It will using more thread stack."
                 default n
                 default n
-                select PKG_USING_RT_VSNPRINTF_FULL
+                select RT_KLIBC_USING_VSNPRINTF_STANDARD
                 help
                 help
                     The default formater is using rt_vsnprint and it not supported float number.
                     The default formater is using rt_vsnprint and it not supported float number.
                     When enable this option then it will enable libc. The formater will change to vsnprint on libc.
                     When enable this option then it will enable libc. The formater will change to vsnprint on libc.

+ 99 - 10
src/Kconfig

@@ -189,13 +189,13 @@ config RT_USING_CPU_USAGE_TRACER
     default y if RT_USING_SMART
     default y if RT_USING_SMART
     default n
     default n
 
 
-menu "kservice optimization"
+menu "kservice options"
     config RT_USING_TINY_FFS
     config RT_USING_TINY_FFS
         bool "Enable kservice to use tiny finding first bit set method"
         bool "Enable kservice to use tiny finding first bit set method"
         default n
         default n
 endmenu
 endmenu
 
 
-menu "klibc optimization"
+menu "klibc options"
 
 
     config RT_KLIBC_USING_STDLIB
     config RT_KLIBC_USING_STDLIB
         bool "Enable klibc to use standard C library"
         bool "Enable klibc to use standard C library"
@@ -213,15 +213,104 @@ menu "klibc optimization"
         bool "Enable tiny size of klibc"
         bool "Enable tiny size of klibc"
         default n
         default n
 
 
-    config RT_KLIBC_USING_PRINTF_LONGLONG
-        bool "Enable rt_printf-family functions to support long-long format"
-        default y if ARCH_CPU_64BIT
-        default n
-        help
-            Enable rt_printf()/rt_snprintf()/rt_sprintf()/rt_vsnprintf()/rt_vsprintf()
-            functions to support long-long format
+    menu "rt_vsnprintf options"
+        config RT_KLIBC_USING_VSNPRINTF_STANDARD
+            bool "standard rt_vsnprintf version"
+            default y if ARCH_CPU_64BIT
+            default n
+            help
+                Standard version of rt_vsnprintf, which is full function but higher stack usage.
 
 
-endmenu
+        config RT_KLIBC_USING_VSNPRINTF_LONGLONG
+            bool "Enable rt_vsnprintf function to support long-long format"
+            default y if RT_KLIBC_USING_VSNPRINTF_STANDARD
+            default n
+                help
+                    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.
+
+        if RT_KLIBC_USING_VSNPRINTF_STANDARD
+
+            config RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
+                bool "Support decimal notation floating point conversion specifiers (%f, %F)"
+                default y
+                help
+                    Support for the decimal notation floating point conversion specifiers (%f, %F)
+
+            config RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+                bool "Support exponential notation floating point conversion specifiers (%e, %g, %E, %G)"
+                default y
+                help
+                    Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G)
+
+            config RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
+                bool "Support length write-back specifier (%n)"
+                default y
+                help
+                    Support for the length write-back specifier (%n)
+
+            config RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER
+                bool "safety check: no NULL end string"
+                default y if RT_USING_DEBUG
+                default n
+                help
+                    Be extra-safe, and don't assume format specifiers are completed correctly
+                    before the format string end.
+
+            config RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
+                bool "Support MSVC style integer specifiers"
+                default n
+                help
+                    the integer format specifiers used in Microsoft's Visual C++ (MSVC) compiler.
+                    These specifiers, like %I64d for 64-bit integers, deviate slightly from the standard
+                    C format specifiers and are specific to MSVC. They allow for controlled formatting of
+                    integers in printf()-like functions, accommodating different integer sizes and ensuring
+                    compatibility with MSVC's environment. It's important to note that these specifiers might
+                    not be recognized or function in other compilers due to their MSVC-specific nature.
+
+            config RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE
+                int "'ntoa' conversion buffer size"
+                default 32
+                help
+                    'ntoa' conversion buffer size, this must be big enough to hold one converted
+                    numeric number including padded zeros (dynamically created on stack)
+
+            config RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE
+                int "printing individual decimal numbers buffer size"
+                default 32
+                help
+                    size of the fixed (on-stack) buffer for printing individual decimal numbers.
+                    this must be big enough to hold one converted floating-point value including
+                    padded zeros.
+
+            config RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION
+                int "floating point conversion specifiers"
+                default 6
+                help
+                    Default precision for the floating point conversion specifiers (the C standard sets this at 6)
+
+            config RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL
+                int "integral nums printed as float in rt_vsnprint"
+                default 9
+                help
+                    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.
+
+            config RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS
+                int "the number of terms in a Taylor series expansion of log_10(x)"
+                default 4
+                range 2 99
+                help
+                    The number of terms in a Taylor series expansion of log_10(x) to
+                    use for approximation - including the power-zero term (i.e. the
+                    value at the point of expansion).
+
+        endif
+    endmenu # rt_vsnprintf options
+
+endmenu # klibc options
 
 
 menuconfig RT_USING_DEBUG
 menuconfig RT_USING_DEBUG
     bool "Enable debugging features"
     bool "Enable debugging features"

+ 0 - 8
src/klibc/kerrno.c

@@ -10,14 +10,6 @@
 
 
 #include <rtthread.h>
 #include <rtthread.h>
 
 
-#define DBG_TAG           "kernel.errno"
-#ifdef RT_DEBUG_DEVICE
-#define DBG_LVL           DBG_LOG
-#else
-#define DBG_LVL           DBG_WARNING
-#endif /* defined (RT_DEBUG_DEVICE) */
-#include <rtdbg.h>
-
 /**
 /**
  * @brief A global variable used to store the error code.
  * @brief A global variable used to store the error code.
  *
  *

+ 0 - 609
src/klibc/kstdio.c

@@ -10,615 +10,6 @@
 
 
 #include <rtthread.h>
 #include <rtthread.h>
 
 
-#define DBG_TAG           "kernel.stdio"
-#ifdef RT_DEBUG_DEVICE
-#define DBG_LVL           DBG_LOG
-#else
-#define DBG_LVL           DBG_WARNING
-#endif /* defined (RT_DEBUG_DEVICE) */
-#include <rtdbg.h>
-
-#define _ISDIGIT(c)  ((unsigned)((c) - '0') < 10)
-
-/**
- * @brief  This function will duplicate a string.
- *
- * @param  n is the string to be duplicated.
- *
- * @param  base is support divide instructions value.
- *
- * @return the duplicated string pointer.
- */
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-rt_inline int divide(unsigned long long *n, int base)
-#else
-rt_inline int divide(unsigned long *n, int base)
-#endif /* RT_KLIBC_USING_PRINTF_LONGLONG */
-{
-    int res;
-
-    /* optimized for processor which does not support divide instructions. */
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-    res = (int)((*n) % base);
-    *n = (long long)((*n) / base);
-#else
-    res = (int)((*n) % base);
-    *n = (long)((*n) / base);
-#endif
-
-    return res;
-}
-
-rt_inline int skip_atoi(const char **s)
-{
-    int i = 0;
-    while (_ISDIGIT(**s))
-        i = i * 10 + *((*s)++) - '0';
-
-    return i;
-}
-
-#define ZEROPAD     (1 << 0)    /* pad with zero */
-#define SIGN        (1 << 1)    /* unsigned/signed long */
-#define PLUS        (1 << 2)    /* show plus */
-#define SPACE       (1 << 3)    /* space if plus */
-#define LEFT        (1 << 4)    /* left justified */
-#define SPECIAL     (1 << 5)    /* 0x */
-#define LARGE       (1 << 6)    /* use 'ABCDEF' instead of 'abcdef' */
-
-static char *print_number(char *buf,
-                          char *end,
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-                          unsigned long long  num,
-#else
-                          unsigned long  num,
-#endif /* RT_KLIBC_USING_PRINTF_LONGLONG */
-                          int   base,
-                          int   qualifier,
-                          int   s,
-                          int   precision,
-                          int   type)
-{
-    char c = 0, sign = 0;
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-    char tmp[64] = {0};
-#else
-    char tmp[32] = {0};
-#endif /* RT_KLIBC_USING_PRINTF_LONGLONG */
-    int precision_bak = precision;
-    const char *digits = RT_NULL;
-    static const char small_digits[] = "0123456789abcdef";
-    static const char large_digits[] = "0123456789ABCDEF";
-    int i = 0;
-    int size = 0;
-
-    size = s;
-
-    digits = (type & LARGE) ? large_digits : small_digits;
-    if (type & LEFT)
-    {
-        type &= ~ZEROPAD;
-    }
-
-    c = (type & ZEROPAD) ? '0' : ' ';
-
-    /* get sign */
-    sign = 0;
-    if (type & SIGN)
-    {
-        switch (qualifier)
-        {
-        case 'h':
-            if ((rt_int16_t)num < 0)
-            {
-                sign = '-';
-                num = (rt_uint16_t)-num;
-            }
-            break;
-        case 'L':
-        case 'l':
-            if ((long)num < 0)
-            {
-                sign = '-';
-                num = (unsigned long)-num;
-            }
-            break;
-        case 0:
-        default:
-            if ((rt_int32_t)num < 0)
-            {
-                sign = '-';
-                num = (rt_uint32_t)-num;
-            }
-            break;
-        }
-
-        if (sign != '-')
-        {
-            if (type & PLUS)
-            {
-                sign = '+';
-            }
-            else if (type & SPACE)
-            {
-                sign = ' ';
-            }
-        }
-    }
-
-    if (type & SPECIAL)
-    {
-        if (base == 2 || base == 16)
-        {
-            size -= 2;
-        }
-        else if (base == 8)
-        {
-            size--;
-        }
-    }
-
-    i = 0;
-    if (num == 0)
-    {
-        tmp[i++] = '0';
-    }
-    else
-    {
-        while (num != 0)
-            tmp[i++] = digits[divide(&num, base)];
-    }
-
-    if (i > precision)
-    {
-        precision = i;
-    }
-    size -= precision;
-
-    if (!(type & (ZEROPAD | LEFT)))
-    {
-        if ((sign) && (size > 0))
-        {
-            size--;
-        }
-
-        while (size-- > 0)
-        {
-            if (buf < end)
-            {
-                *buf = ' ';
-            }
-
-            ++ buf;
-        }
-    }
-
-    if (sign)
-    {
-        if (buf < end)
-        {
-            *buf = sign;
-        }
-        -- size;
-        ++ buf;
-    }
-
-    if (type & SPECIAL)
-    {
-        if (base == 2)
-        {
-            if (buf < end)
-                *buf = '0';
-            ++ buf;
-            if (buf < end)
-                *buf = 'b';
-            ++ buf;
-        }
-        else if (base == 8)
-        {
-            if (buf < end)
-                *buf = '0';
-            ++ buf;
-        }
-        else if (base == 16)
-        {
-            if (buf < end)
-            {
-                *buf = '0';
-            }
-
-            ++ buf;
-            if (buf < end)
-            {
-                *buf = type & LARGE ? 'X' : 'x';
-            }
-            ++ buf;
-        }
-    }
-
-    /* no align to the left */
-    if (!(type & LEFT))
-    {
-        while (size-- > 0)
-        {
-            if (buf < end)
-            {
-                *buf = c;
-            }
-
-            ++ buf;
-        }
-    }
-
-    while (i < precision--)
-    {
-        if (buf < end)
-        {
-            *buf = '0';
-        }
-
-        ++ buf;
-    }
-
-    /* put number in the temporary buffer */
-    while (i-- > 0 && (precision_bak != 0))
-    {
-        if (buf < end)
-        {
-            *buf = tmp[i];
-        }
-
-        ++ buf;
-    }
-
-    while (size-- > 0)
-    {
-        if (buf < end)
-        {
-            *buf = ' ';
-        }
-
-        ++ buf;
-    }
-
-    return buf;
-}
-
-#if (defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */) && (__GNUC__ >= 7)
-/* Disable "-Wimplicit-fallthrough" below GNUC V7 */
-#pragma GCC diagnostic push
-/* ignore warning: this statement may fall through */
-#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
-#endif /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) && (__GNUC__ >= 7 */
-/**
- * @brief  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.
- */
-rt_weak int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
-{
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-    unsigned long long num = 0;
-#else
-    unsigned long num = 0;
-#endif /* RT_KLIBC_USING_PRINTF_LONGLONG */
-    int i = 0, len = 0;
-    char *str = RT_NULL, *end = RT_NULL, c = 0;
-    const char *s = RT_NULL;
-
-    rt_uint8_t base = 0;            /* the base of number */
-    rt_uint8_t flags = 0;           /* flags to print number */
-    rt_uint8_t qualifier = 0;       /* 'h', 'l', or 'L' for integer fields */
-    rt_int32_t field_width = 0;     /* width of output field */
-    int precision = 0;      /* min. # of digits for integers and max for a string */
-
-    str = buf;
-    end = buf + size;
-
-    /* Make sure end is always >= buf */
-    if (end < buf)
-    {
-        end  = ((char *) - 1);
-        size = end - buf;
-    }
-
-    for (; *fmt ; ++fmt)
-    {
-        if (*fmt != '%')
-        {
-            if (str < end)
-            {
-                *str = *fmt;
-            }
-
-            ++ str;
-            continue;
-        }
-
-        /* process flags */
-        flags = 0;
-
-        while (1)
-        {
-            /* skips the first '%' also */
-            ++fmt;
-            if (*fmt == '-') flags |= LEFT;
-            else if (*fmt == '+') flags |= PLUS;
-            else if (*fmt == ' ') flags |= SPACE;
-            else if (*fmt == '#') flags |= SPECIAL;
-            else if (*fmt == '0') flags |= ZEROPAD;
-            else break;
-        }
-
-        /* get field width */
-        field_width = -1;
-        if (_ISDIGIT(*fmt))
-        {
-            field_width = skip_atoi(&fmt);
-        }
-        else if (*fmt == '*')
-        {
-            ++fmt;
-            /* it's the next argument */
-            field_width = va_arg(args, int);
-            if (field_width < 0)
-            {
-                field_width = -field_width;
-                flags |= LEFT;
-            }
-        }
-
-        /* get the precision */
-        precision = -1;
-        if (*fmt == '.')
-        {
-            ++fmt;
-            if (_ISDIGIT(*fmt))
-            {
-                precision = skip_atoi(&fmt);
-            }
-            else if (*fmt == '*')
-            {
-                ++fmt;
-                /* it's the next argument */
-                precision = va_arg(args, int);
-            }
-            if (precision < 0)
-            {
-                precision = 0;
-            }
-        }
-
-        qualifier = 0; /* get the conversion qualifier */
-
-        if (*fmt == 'h' || *fmt == 'l' ||
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-            *fmt == 'L' ||
-#endif /* RT_KLIBC_USING_PRINTF_LONGLONG */
-            *fmt == 'z')
-        {
-            qualifier = *fmt;
-            ++fmt;
-#ifdef RT_KLIBC_USING_PRINTF_LONGLONG
-            if (qualifier == 'l' && *fmt == 'l')
-            {
-                qualifier = 'L';
-                ++fmt;
-            }
-#endif /* RT_KLIBC_USING_PRINTF_LONGLONG */
-            if (qualifier == 'h' && *fmt == 'h')
-            {
-                qualifier = 'H';
-                ++fmt;
-            }
-        }
-
-        /* the default base */
-        base = 10;
-
-        switch (*fmt)
-        {
-        case 'c':
-            if (!(flags & LEFT))
-            {
-                while (--field_width > 0)
-                {
-                    if (str < end) *str = ' ';
-                    ++ str;
-                }
-            }
-
-            /* get character */
-            c = (rt_uint8_t)va_arg(args, int);
-            if (str < end)
-            {
-                *str = c;
-            }
-            ++ str;
-
-            /* put width */
-            while (--field_width > 0)
-            {
-                if (str < end) *str = ' ';
-                ++ str;
-            }
-            continue;
-
-        case 's':
-            s = va_arg(args, char *);
-            if (!s)
-            {
-                s = "(NULL)";
-            }
-
-            for (len = 0; (len != field_width) && (s[len] != '\0'); len++);
-
-            if (precision > 0 && len > precision)
-            {
-                len = precision;
-            }
-
-            if (!(flags & LEFT))
-            {
-                while (len < field_width--)
-                {
-                    if (str < end) *str = ' ';
-                    ++ str;
-                }
-            }
-
-            for (i = 0; i < len; ++i)
-            {
-                if (str < end) *str = *s;
-                ++ str;
-                ++ s;
-            }
-
-            while (len < field_width--)
-            {
-                if (str < end) *str = ' ';
-                ++ str;
-            }
-            continue;
-
-        case 'p':
-            if (field_width == -1)
-            {
-                field_width = sizeof(void *) << 1;
-                field_width += 2; /* `0x` prefix */
-                flags |= SPECIAL;
-                flags |= ZEROPAD;
-            }
-            str = print_number(str, end, (unsigned long)va_arg(args, void *),
-                               16, qualifier, field_width, precision, flags);
-            continue;
-
-        case '%':
-            if (str < end)
-            {
-                *str = '%';
-            }
-            ++ str;
-            continue;
-
-        /* integer number formats - set up the flags and "break" */
-        case 'b':
-            base = 2;
-            break;
-        case 'o':
-            base = 8;
-            break;
-
-        case 'X':
-            flags |= LARGE;
-        case 'x':
-            base = 16;
-            break;
-
-        case 'd':
-        case 'i':
-            flags |= SIGN;
-        case 'u':
-            break;
-
-        case 'e':
-        case 'E':
-        case 'G':
-        case 'g':
-        case 'f':
-        case 'F':
-            va_arg(args, double);
-        default:
-            if (str < end)
-            {
-                *str = '%';
-            }
-            ++ str;
-
-            if (*fmt)
-            {
-                if (str < end)
-                {
-                    *str = *fmt;
-                }
-                ++ str;
-            }
-            else
-            {
-                -- fmt;
-            }
-            continue;
-        }
-
-        if (qualifier == 'L')
-        {
-            num = va_arg(args, unsigned long long);
-        }
-        else if (qualifier == 'l')
-        {
-            num = va_arg(args, unsigned long);
-        }
-        else if (qualifier == 'H')
-        {
-            num = (rt_int8_t)va_arg(args, rt_int32_t);
-            if (flags & SIGN)
-            {
-                num = (rt_int8_t)num;
-            }
-        }
-        else if (qualifier == 'h')
-        {
-            num = (rt_uint16_t)va_arg(args, rt_int32_t);
-            if (flags & SIGN)
-            {
-                num = (rt_int16_t)num;
-            }
-        }
-        else if (qualifier == 'z')
-        {
-            num = va_arg(args, rt_size_t);
-            if (flags & SIGN)
-            {
-                num = (rt_ssize_t)num;
-            }
-        }
-        else
-        {
-            num = (rt_uint32_t)va_arg(args, unsigned long);
-        }
-        str = print_number(str, end, num, base, qualifier, field_width, precision, flags);
-    }
-
-    if (size > 0)
-    {
-        if (str < end)
-        {
-            *str = '\0';
-        }
-        else
-        {
-            end[-1] = '\0';
-        }
-    }
-
-    /* the trailing null byte doesn't count towards the total
-    * ++str;
-    */
-    return str - buf;
-}
-RTM_EXPORT(rt_vsnprintf);
-#if (defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */) && (__GNUC__ >= 7)
-#pragma GCC diagnostic pop /* ignored "-Wimplicit-fallthrough" */
-#endif /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) && (__GNUC__ >= 7 */
-
 /**
 /**
  * @brief  This function will fill a formatted string to buffer.
  * @brief  This function will fill a formatted string to buffer.
  *
  *

+ 0 - 8
src/klibc/kstring.c

@@ -13,14 +13,6 @@
 #include <string.h>
 #include <string.h>
 #endif /* RT_KLIBC_USING_STDLIB */
 #endif /* RT_KLIBC_USING_STDLIB */
 
 
-#define DBG_TAG           "kernel.string"
-#ifdef RT_DEBUG_DEVICE
-#define DBG_LVL           DBG_LOG
-#else
-#define DBG_LVL           DBG_WARNING
-#endif /* defined (RT_DEBUG_DEVICE) */
-#include <rtdbg.h>
-
 /**
 /**
  * @brief  This function will set the content of memory to specified value.
  * @brief  This function will set the content of memory to specified value.
  *
  *

+ 1356 - 0
src/klibc/rt_vsnprintf_std.c

@@ -0,0 +1,1356 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * 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
+ * 2024-11-19     Meco Man     move into rtklibc
+ */
+
+/**
+ * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
+ *             2021-2022, 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. The original code for exponential specifiers was
+ * contributed by Martijn Jasperse <m.jasperse@gmail.com>.
+ *
+ * @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 <rtthread.h>
+
+#ifdef RT_KLIBC_USING_VSNPRINTF_STANDARD
+
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+#include <stdbool.h>
+
+// 'ntoa' conversion buffer size, this must be big enough to hold one converted
+// numeric number including padded zeros (dynamically created on stack)
+#ifndef RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE
+#define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE    32
+#endif
+
+// size of the fixed (on-stack) buffer for printing individual decimal numbers.
+// this must be big enough to hold one converted floating-point value including
+// padded zeros.
+#ifndef RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE
+#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE    32
+#endif
+
+// Support for the decimal notation floating point conversion specifiers (%f, %F)
+#ifndef RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
+#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
+#endif
+
+// Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G)
+#ifndef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+#define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+#endif
+
+// Support for the length write-back specifier (%n)
+#ifndef RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
+#define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
+#endif
+
+// Default precision for the floating point conversion specifiers (the C standard sets this at 6)
+#ifndef RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION
+#define RT_KLIBC_USING_VSNPRINTF_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 RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL
+#define RT_KLIBC_USING_VSNPRINTF_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 RT_KLIBC_USING_VSNPRINTF_LONGLONG
+#define RT_KLIBC_USING_VSNPRINTF_LONGLONG
+#endif
+
+// The number of terms in a Taylor series expansion of log_10(x) to
+// use for approximation - including the power-zero term (i.e. the
+// value at the point of expansion).
+#ifndef RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS
+#define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4
+#endif
+
+// Be extra-safe, and don't assume format specifiers are completed correctly
+// before the format string end.
+#if !defined(RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER) || defined(RT_USING_DEBUG)
+#define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER
+#endif
+
+#if RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS <= 1
+#error "At least one non-constant Taylor expansion is necessary for the log10() calculation"
+#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,RT_KLIBC_USING_VSNPRINTF_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_INT       (1U <<  8U)
+// Only used with RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
+#define FLAGS_LONG      (1U <<  9U)
+#define FLAGS_LONG_LONG (1U << 10U)
+#define FLAGS_PRECISION (1U << 11U)
+#define FLAGS_ADAPT_EXP (1U << 12U)
+#define FLAGS_POINTER   (1U << 13U)
+// Note: Similar, but not identical, effect as FLAGS_HASH
+#define FLAGS_SIGNED    (1U << 14U)
+// Only used with RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
+
+#ifdef RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
+
+#define FLAGS_INT8 FLAGS_CHAR
+
+#if   (SHRT_MAX   == 32767LL)
+#define FLAGS_INT16       FLAGS_SHORT
+#elif (INT_MAX    == 32767LL)
+#define FLAGS_INT16       FLAGS_INT
+#elif (LONG_MAX   == 32767LL)
+#define FLAGS_INT16       FLAGS_LONG
+#elif (LLONG_MAX  == 32767LL)
+#define FLAGS_INT16       FLAGS_LONG_LONG
+#else
+#error "No basic integer type has a size of 16 bits exactly"
+#endif
+
+#if   (SHRT_MAX   == 2147483647LL)
+#define FLAGS_INT32       FLAGS_SHORT
+#elif (INT_MAX    == 2147483647LL)
+#define FLAGS_INT32       FLAGS_INT
+#elif (LONG_MAX   == 2147483647LL)
+#define FLAGS_INT32       FLAGS_LONG
+#elif (LLONG_MAX  == 2147483647LL)
+#define FLAGS_INT32       FLAGS_LONG_LONG
+#else
+#error "No basic integer type has a size of 32 bits exactly"
+#endif
+
+#if   (SHRT_MAX   == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_SHORT
+#elif (INT_MAX    == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_INT
+#elif (LONG_MAX   == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_LONG
+#elif (LLONG_MAX  == 9223372036854775807LL)
+#define FLAGS_INT64       FLAGS_LONG_LONG
+#else
+#error "No basic integer type has a size of 64 bits exactly"
+#endif
+
+#endif // RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
+
+
+typedef unsigned int printf_flags_t;
+
+#define BASE_BINARY    2
+#define BASE_OCTAL     8
+#define BASE_DECIMAL  10
+#define BASE_HEX      16
+
+typedef uint8_t numeric_base_t;
+
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+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
+
+// The printf()-family functions return an `int`; it is therefore
+// unnecessary/inappropriate to use size_t - often larger than int
+// in practice - for non-negative related values, such as widths,
+// precisions, offsets into buffers used for printing and the sizes
+// of these buffers. instead, we use:
+typedef unsigned int printf_size_t;
+#define PRINTF_MAX_POSSIBLE_BUFFER_SIZE INT_MAX
+  // If we were to nitpick, this would actually be INT_MAX + 1,
+  // since INT_MAX is the maximum return value, which excludes the
+  // trailing '\0'.
+
+#if defined(RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS) || defined(RT_KLIBC_USING_VSNPRINTF_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
+#define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -38
+#define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 1e-38
+
+#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
+#define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -308
+#define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 ((double)1e-308L)
+
+#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_bit(double x)
+{
+  // The sign is stored in the highest bit
+  return (int) (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 // (RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS || RT_KLIBC_USING_VSNPRINTF_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) ))
+
+// wrapper (used as buffer) for output function type
+//
+// One of the following must hold:
+// 1. max_chars is 0
+// 2. buffer is non-null
+// 3. function is non-null
+//
+// ... otherwise bad things will happen.
+typedef struct {
+  void (*function)(char c, void* extra_arg);
+  void* extra_function_arg;
+  char* buffer;
+  printf_size_t pos;
+  printf_size_t max_chars;
+} output_gadget_t;
+
+// Note: This function currently assumes it is not passed a '\0' c,
+// or alternatively, that '\0' can be passed to the function in the output
+// gadget. The former assumption holds within the printf library. It also
+// assumes that the output gadget has been properly initialized.
+static inline void putchar_via_gadget(output_gadget_t* gadget, char c)
+{
+  printf_size_t write_pos = gadget->pos++;
+    // We're _always_ increasing pos, so as to count how may characters
+    // _would_ have been written if not for the max_chars limitation
+  if (write_pos >= gadget->max_chars) {
+    return;
+  }
+  if (gadget->function != NULL) {
+    // No check for c == '\0' .
+    gadget->function(c, gadget->extra_function_arg);
+  }
+  else {
+    // it must be the case that gadget->buffer != NULL , due to the constraint
+    // on output_gadget_t ; and note we're relying on write_pos being non-negative.
+    gadget->buffer[write_pos] = c;
+  }
+}
+
+// Possibly-write the string-terminating '\0' character
+static inline void append_termination_with_gadget(output_gadget_t* gadget)
+{
+  if (gadget->function != NULL || gadget->max_chars == 0) {
+    return;
+  }
+  if (gadget->buffer == NULL) {
+    return;
+  }
+  printf_size_t null_char_pos = gadget->pos < gadget->max_chars ? gadget->pos : gadget->max_chars - 1;
+  gadget->buffer[null_char_pos] = '\0';
+}
+
+static inline output_gadget_t discarding_gadget(void)
+{
+  output_gadget_t gadget;
+  gadget.function = NULL;
+  gadget.extra_function_arg = NULL;
+  gadget.buffer = NULL;
+  gadget.pos = 0;
+  gadget.max_chars = 0;
+  return gadget;
+}
+
+static inline output_gadget_t buffer_gadget(char* buffer, size_t buffer_size)
+{
+  printf_size_t usable_buffer_size = (buffer_size > PRINTF_MAX_POSSIBLE_BUFFER_SIZE) ?
+    PRINTF_MAX_POSSIBLE_BUFFER_SIZE : (printf_size_t) buffer_size;
+  output_gadget_t result = discarding_gadget();
+  if (buffer != NULL) {
+    result.buffer = buffer;
+    result.max_chars = usable_buffer_size;
+  }
+  return result;
+}
+
+// internal secure strlen
+// @return The length of the string (excluding the terminating 0) limited by 'maxsize'
+// @note strlen uses size_t, but wes only use this function with printf_size_t
+// variables - hence the signature.
+static inline printf_size_t strnlen_s_(const char* str, printf_size_t maxsize)
+{
+  const char* s;
+  for (s = str; *s && maxsize--; ++s);
+  return (printf_size_t)(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 printf_size_t conversion
+static printf_size_t atou_(const char** str)
+{
+  printf_size_t i = 0U;
+  while (is_digit_(**str)) {
+    i = i * 10U + (printf_size_t)(*((*str)++) - '0');
+  }
+  return i;
+}
+
+
+// output the specified string in reverse, taking care of any zero-padding
+static void out_rev_(output_gadget_t* output, const char* buf, printf_size_t len, printf_size_t width, printf_flags_t flags)
+{
+  const printf_size_t start_pos = output->pos;
+
+  // pad spaces up to given width
+  if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
+    for (printf_size_t i = len; i < width; i++) {
+      putchar_via_gadget(output, ' ');
+    }
+  }
+
+  // reverse string
+  while (len) {
+    putchar_via_gadget(output, buf[--len]);
+  }
+
+  // append pad spaces up to given width
+  if (flags & FLAGS_LEFT) {
+    while (output->pos - start_pos < width) {
+      putchar_via_gadget(output, ' ');
+    }
+  }
+}
+
+
+// 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 void print_integer_finalization(output_gadget_t* output, char* buf, printf_size_t len, bool negative, numeric_base_t base, printf_size_t precision, printf_size_t width, printf_flags_t flags)
+{
+  printf_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 < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
+        buf[len++] = '0';
+      }
+    }
+
+    while ((len < precision) && (len < RT_KLIBC_USING_VSNPRINTF_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--; // This should suffice for BASE_OCTAL
+      }
+      if (len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) {
+        len--; // ... and an extra one for 0x or 0b
+      }
+    }
+    if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = 'x';
+    }
+    else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = 'X';
+    }
+    else if ((base == BASE_BINARY) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
+      buf[len++] = 'b';
+    }
+    if (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE) {
+      buf[len++] = '0';
+    }
+  }
+
+  if (len < RT_KLIBC_USING_VSNPRINTF_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++] = ' ';
+    }
+  }
+
+  out_rev_(output, buf, len, width, flags);
+}
+
+// An internal itoa-like function
+static void print_integer(output_gadget_t* output, printf_unsigned_value_t value, bool negative, numeric_base_t base, printf_size_t precision, printf_size_t width, printf_flags_t flags)
+{
+  char buf[RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE];
+  printf_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 < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE));
+  }
+
+  print_integer_finalization(output, buf, len, negative, base, precision, width, flags);
+}
+
+#if defined(RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS) || defined(RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS)
+
+// Stores a fixed-precision representation of a double relative
+// to a fixed precision (which cannot be determined by examining this structure)
+struct double_components {
+  int_fast64_t integral;
+  int_fast64_t fractional;
+    // ... truncation of the actual fractional part of the double value, scaled
+    // by the precision value
+  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, printf_size_t precision)
+{
+  struct double_components number_;
+  number_.is_negative = get_sign_bit(number);
+  double abs_number = (number_.is_negative) ? -number : number;
+  number_.integral = (int_fast64_t)abs_number;
+  double remainder = (abs_number - (double) 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) && ((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_;
+}
+
+#ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+struct scaling_factor {
+  double raw_factor;
+  bool multiply; // if true, need to multiply by raw_factor; otherwise need to divide by it
+};
+
+static double apply_scaling(double num, struct scaling_factor normalization)
+{
+  return normalization.multiply ? num * normalization.raw_factor : num / normalization.raw_factor;
+}
+
+static double unapply_scaling(double normalized, struct scaling_factor normalization)
+{
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */
+// accounting for a static analysis bug in GCC 6.x and earlier
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+  return normalization.multiply ? normalized / normalization.raw_factor : normalized * normalization.raw_factor;
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */
+#pragma GCC diagnostic pop
+#endif
+}
+
+static 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;
+}
+
+static struct double_components get_normalized_components(bool negative, printf_size_t precision, double non_normalized, struct scaling_factor normalization, int floored_exp10)
+{
+  struct double_components components;
+  components.is_negative = negative;
+  double scaled = apply_scaling(non_normalized, normalization);
+
+  bool close_to_representation_extremum = ( (-floored_exp10 + (int) precision) >= DBL_MAX_10_EXP - 1 );
+  if (close_to_representation_extremum) {
+    // We can't have a normalization factor which also accounts for the precision, i.e. moves
+    // some decimal digits into the mantissa, since it's unrepresentable, or nearly unrepresentable.
+    // So, we'll give up early on getting extra precision...
+    return get_components(negative ? -scaled : scaled, precision);
+  }
+  components.integral = (int_fast64_t) scaled;
+  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;
+
+  components.fractional = (int_fast64_t) scaled_remainder; // when precision == 0, the assigned value should be 0
+  scaled_remainder -= (double) components.fractional; //when precision == 0, this will not change scaled_remainder
+
+  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).
+  // Note: for precision = 0, this will "translate" the rounding effect from
+  // the fractional part to the integral part where it should actually be
+  // felt (as prec_power_of_10 is 1)
+  if ((double) components.fractional >= prec_power_of_10) {
+    components.fractional = 0;
+    ++components.integral;
+  }
+  return components;
+}
+#endif // RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+
+static void print_broken_up_decimal(
+  struct double_components number_, output_gadget_t* output, printf_size_t precision,
+  printf_size_t width, printf_flags_t flags, char *buf, printf_size_t len)
+{
+  if (precision != 0U) {
+    // do fractional part, as an unsigned number
+
+    printf_size_t count = precision;
+
+    // %g/%G mandates we skip the trailing 0 digits...
+    if ((flags & FLAGS_ADAPT_EXP) && !(flags & FLAGS_HASH) && (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 < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) {
+        --count;
+        buf[len++] = (char)('0' + number_.fractional % 10U);
+        if (!(number_.fractional /= 10U)) {
+          break;
+        }
+      }
+      // add extra 0s
+      while ((len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) && (count > 0U)) {
+        buf[len++] = '0';
+        --count;
+      }
+      if (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) {
+        buf[len++] = '.';
+      }
+    }
+  }
+  else {
+    if ((flags & FLAGS_HASH) && (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE)) {
+      buf[len++] = '.';
+    }
+  }
+
+  // Write the integer part of the number (it comes after the fractional
+  // since the character order is reversed)
+  while (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_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 < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE)) {
+      buf[len++] = '0';
+    }
+  }
+
+  if (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_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++] = ' ';
+    }
+  }
+
+  out_rev_(output, buf, len, width, flags);
+}
+
+      // internal ftoa for fixed decimal floating point
+static void print_decimal_number(output_gadget_t* output, double number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len)
+{
+  struct double_components value_ = get_components(number, precision);
+  print_broken_up_decimal(value_, output, precision, width, flags, buf, len);
+}
+
+#ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+
+// A floor function - but one which only works for numbers whose
+// floor value is representable by an int.
+static int bastardized_floor(double x)
+{
+  if (x >= 0) { return (int) x; }
+  int n = (int) x;
+  return ( ((double) n) == x ) ? n : n-1;
+}
+
+// Computes the base-10 logarithm of the input number - which must be an actual
+// positive number (not infinity or NaN, nor a sub-normal)
+static double log10_of_positive(double positive_number)
+{
+  // The implementation follows David Gay (https://www.ampl.com/netlib/fp/dtoa.c).
+  //
+  // Since log_10 ( M * 2^x ) = log_10(M) + x , we can separate the components of
+  // our input number, and need only solve log_10(M) for M between 1 and 2 (as
+  // the base-2 mantissa is always 1-point-something). In that limited range, a
+  // Taylor series expansion of log10(x) should serve us well enough; and we'll
+  // take the mid-point, 1.5, as the point of expansion.
+
+  double_with_bit_access dwba = get_bit_access(positive_number);
+  // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
+  int exp2 = get_exp2(dwba);
+  // drop the exponent, so dwba.F comes into the range [1,2)
+  dwba.U = (dwba.U & (((double_uint_t) (1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) |
+           ((double_uint_t) DOUBLE_BASE_EXPONENT << DOUBLE_STORED_MANTISSA_BITS);
+  double z = (dwba.F - 1.5);
+  return (
+    // Taylor expansion around 1.5:
+    0.1760912590556812420           // Expansion term 0: ln(1.5)            / ln(10)
+    + z     * 0.2895296546021678851 // Expansion term 1: (M - 1.5)   * 2/3  / ln(10)
+#if RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS > 2
+    - z*z   * 0.0965098848673892950 // Expansion term 2: (M - 1.5)^2 * 2/9  / ln(10)
+#if RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS > 3
+    + z*z*z * 0.0428932821632841311 // Expansion term 2: (M - 1.5)^3 * 8/81 / ln(10)
+#endif
+#endif
+    // exact log_2 of the exponent x, with logarithm base change
+    + exp2 * 0.30102999566398119521 // = exp2 * log_10(2) = exp2 * ln(2)/ln(10)
+  );
+}
+
+
+static double pow10_of_int(int floored_exp10)
+{
+  // A crude hack for avoiding undesired behavior with barely-normal or slightly-subnormal values.
+  if (floored_exp10 == DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10) {
+    return DOUBLE_MAX_SUBNORMAL_POWER_OF_10;
+  }
+  // Compute 10^(floored_exp10) but (try to) make sure that doesn't overflow
+  double_with_bit_access dwba;
+  int exp2 = bastardized_floor(floored_exp10 * 3.321928094887362 + 0.5);
+  const double z  = floored_exp10 * 2.302585092994046 - exp2 * 0.6931471805599453;
+  const double z2 = z * z;
+  dwba.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
+  dwba.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
+  return dwba.F;
+}
+
+static void print_exponential_number(output_gadget_t* output, double number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len)
+{
+  const bool negative = get_sign_bit(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 floored_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.
+    floored_exp10 = 0; // ... and no need to set a normalization factor or check the powers table
+  }
+  else  {
+    double exp10 = log10_of_positive(abs_number);
+    floored_exp10 = bastardized_floor(exp10);
+    double p10 = pow10_of_int(floored_exp10);
+    // correct for rounding errors
+    if (abs_number < p10) {
+      floored_exp10--;
+      p10 /= 10;
+    }
+    abs_exp10_covered_by_powers_table = PRINTF_ABS(floored_exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10;
+    normalization.raw_factor = abs_exp10_covered_by_powers_table ? powers_of_10[PRINTF_ABS(floored_exp10)] : p10;
+  }
+
+  // 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 = (floored_exp10 >= -4 && floored_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 - floored_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 = (floored_exp10 < 0 && abs_exp10_covered_by_powers_table);
+  bool should_skip_normalization = (fall_back_to_decimal_only_mode || floored_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, floored_exp10);
+
+  // 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) && floored_exp10 >= -1 && decimal_part_components.integral == powers_of_10[floored_exp10 + 1]) {
+      floored_exp10++; // Not strictly necessary, since floored_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) {
+      floored_exp10++;
+      decimal_part_components.integral = 1;
+      decimal_part_components.fractional = 0;
+    }
+  }
+
+  // the floored_exp10 format is "E%+03d" and largest possible floored_exp10 value for a 64-bit double
+  // is "307" (for 2^1023), so we set aside 4-5 characters overall
+  printf_size_t exp10_part_width = fall_back_to_decimal_only_mode ? 0U : (PRINTF_ABS(floored_exp10) < 100) ? 4U : 5U;
+
+  printf_size_t 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 printf_size_t printed_exponential_start_pos = output->pos;
+  print_broken_up_decimal(decimal_part_components, output, precision, decimal_part_width, flags, buf, len);
+
+  if (! fall_back_to_decimal_only_mode) {
+    putchar_via_gadget(output, (flags & FLAGS_UPPERCASE) ? 'E' : 'e');
+    print_integer(output,
+                  ABS_FOR_PRINTING(floored_exp10),
+                  floored_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 (output->pos - printed_exponential_start_pos < width) {
+        putchar_via_gadget(output, ' ');
+      }
+    }
+  }
+}
+#endif  // RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+
+static void print_floating_point(output_gadget_t* output, double value, printf_size_t precision, printf_size_t width, printf_flags_t flags, bool prefer_exponential)
+{
+  char buf[RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE];
+  printf_size_t len = 0U;
+
+  // test for special values
+  if (value != value) {
+    out_rev_(output, "nan", 3, width, flags);
+    return;
+  }
+  if (value < -DBL_MAX) {
+    out_rev_(output, "fni-", 4, width, flags);
+    return;
+  }
+  if (value > DBL_MAX) {
+    out_rev_(output, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
+    return;
+  }
+
+  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.
+#ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+    print_exponential_number(output, value, precision, width, flags, buf, len);
+#endif
+    return;
+  }
+
+  // set default precision, if not set explicitly
+  if (!(flags & FLAGS_PRECISION)) {
+    precision = RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION;
+  }
+
+  // limit precision so that our integer holding the fractional part does not overflow
+  while ((len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) && (precision > PRINTF_MAX_SUPPORTED_PRECISION)) {
+    buf[len++] = '0'; // This respects the precision in terms of result length only
+    precision--;
+  }
+
+#ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+  if (prefer_exponential)
+    print_exponential_number(output, value, precision, width, flags, buf, len);
+  else
+#endif
+    print_decimal_number(output, value, precision, width, flags, buf, len);
+}
+
+#endif  // (RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS || RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS)
+
+// Advances the format pointer past the flags, and returns the parsed flags
+// due to the characters passed
+static printf_flags_t parse_flags(const char** format)
+{
+  printf_flags_t flags = 0U;
+  do {
+    switch (**format) {
+      case '0': flags |= FLAGS_ZEROPAD; (*format)++; break;
+      case '-': flags |= FLAGS_LEFT;    (*format)++; break;
+      case '+': flags |= FLAGS_PLUS;    (*format)++; break;
+      case ' ': flags |= FLAGS_SPACE;   (*format)++; break;
+      case '#': flags |= FLAGS_HASH;    (*format)++; break;
+      default : return flags;
+    }
+  } while (true);
+}
+
+static inline void format_string_loop(output_gadget_t* output, const char* format, va_list args)
+{
+#ifdef RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER
+#define ADVANCE_IN_FORMAT_STRING(cptr_) do { (cptr_)++; if (!*(cptr_)) return; } while(0)
+#else
+#define ADVANCE_IN_FORMAT_STRING(cptr_) (cptr_)++
+#endif
+
+
+  while (*format)
+  {
+    if (*format != '%') {
+      // A regular content character
+      putchar_via_gadget(output, *format);
+      format++;
+      continue;
+    }
+    // We're parsing a format specifier: %[flags][width][.precision][length]
+    ADVANCE_IN_FORMAT_STRING(format);
+
+    printf_flags_t flags = parse_flags(&format);
+
+    // evaluate width field
+    printf_size_t width = 0U;
+    if (is_digit_(*format)) {
+      width = (printf_size_t) atou_(&format);
+    }
+    else if (*format == '*') {
+      const int w = va_arg(args, int);
+      if (w < 0) {
+        flags |= FLAGS_LEFT;    // reverse padding
+        width = (printf_size_t)-w;
+      }
+      else {
+        width = (printf_size_t)w;
+      }
+      ADVANCE_IN_FORMAT_STRING(format);
+    }
+
+    // evaluate precision field
+    printf_size_t precision = 0U;
+    if (*format == '.') {
+      flags |= FLAGS_PRECISION;
+      ADVANCE_IN_FORMAT_STRING(format);
+      if (is_digit_(*format)) {
+        precision = (printf_size_t) atou_(&format);
+      }
+      else if (*format == '*') {
+        const int precision_ = va_arg(args, int);
+        precision = precision_ > 0 ? (printf_size_t) precision_ : 0U;
+        ADVANCE_IN_FORMAT_STRING(format);
+      }
+    }
+
+    // evaluate length field
+    switch (*format) {
+#ifdef RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
+      case 'I' : {
+        ADVANCE_IN_FORMAT_STRING(format);
+        // Greedily parse for size in bits: 8, 16, 32 or 64
+        switch(*format) {
+          case '8':               flags |= FLAGS_INT8;
+            ADVANCE_IN_FORMAT_STRING(format);
+            break;
+          case '1':
+            ADVANCE_IN_FORMAT_STRING(format);
+          if (*format == '6') { format++; flags |= FLAGS_INT16; }
+            break;
+          case '3':
+            ADVANCE_IN_FORMAT_STRING(format);
+            if (*format == '2') { ADVANCE_IN_FORMAT_STRING(format); flags |= FLAGS_INT32; }
+            break;
+          case '6':
+            ADVANCE_IN_FORMAT_STRING(format);
+            if (*format == '4') { ADVANCE_IN_FORMAT_STRING(format); flags |= FLAGS_INT64; }
+            break;
+          default: break;
+        }
+        break;
+      }
+#endif
+      case 'l' :
+        flags |= FLAGS_LONG;
+        ADVANCE_IN_FORMAT_STRING(format);
+        if (*format == 'l') {
+          flags |= FLAGS_LONG_LONG;
+          ADVANCE_IN_FORMAT_STRING(format);
+        }
+        break;
+      case 'h' :
+        flags |= FLAGS_SHORT;
+        ADVANCE_IN_FORMAT_STRING(format);
+        if (*format == 'h') {
+          flags |= FLAGS_CHAR;
+          ADVANCE_IN_FORMAT_STRING(format);
+        }
+        break;
+      case 't' :
+        flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      case 'j' :
+        flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      case 'z' :
+        flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+        ADVANCE_IN_FORMAT_STRING(format);
+        break;
+      default:
+        break;
+    }
+
+    // evaluate specifier
+    switch (*format) {
+      case 'd' :
+      case 'i' :
+      case 'u' :
+      case 'x' :
+      case 'X' :
+      case 'o' :
+      case 'b' : {
+
+        if (*format == 'd' || *format == 'i') {
+          flags |= FLAGS_SIGNED;
+        }
+
+        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; // decimal integers have no alternative presentation
+        }
+
+        if (*format == 'X') {
+          flags |= FLAGS_UPPERCASE;
+        }
+
+        format++;
+        // ignore '0' flag when precision is given
+        if (flags & FLAGS_PRECISION) {
+          flags &= ~FLAGS_ZEROPAD;
+        }
+
+        if (flags & FLAGS_SIGNED) {
+          // A signed specifier: d, i or possibly I + bit size if enabled
+
+          if (flags & FLAGS_LONG_LONG) {
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+            const long long value = va_arg(args, long long);
+            print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
+#endif
+          }
+          else if (flags & FLAGS_LONG) {
+            const long value = va_arg(args, long);
+            print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
+          }
+          else {
+            // We never try to interpret the argument as something potentially-smaller than int,
+            // due to integer promotion rules: Even if the user passed a short int, short unsigned
+            // etc. - these will come in after promotion, as int's (or unsigned for the case of
+            // short unsigned when it has the same size as int)
+            const int value =
+              (flags & FLAGS_CHAR) ? (signed char) va_arg(args, int) :
+              (flags & FLAGS_SHORT) ? (short int) va_arg(args, int) :
+              va_arg(args, int);
+            print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
+          }
+        }
+        else {
+          // An unsigned specifier: u, x, X, o, b
+
+          flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
+
+          if (flags & FLAGS_LONG_LONG) {
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+            print_integer(output, (printf_unsigned_value_t) va_arg(args, unsigned long long), false, base, precision, width, flags);
+#endif
+          }
+          else if (flags & FLAGS_LONG) {
+            print_integer(output, (printf_unsigned_value_t) va_arg(args, unsigned long), false, base, precision, width, flags);
+          }
+          else {
+            const unsigned int value =
+              (flags & FLAGS_CHAR) ? (unsigned char)va_arg(args, unsigned int) :
+              (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(args, unsigned int) :
+              va_arg(args, unsigned int);
+            print_integer(output, (printf_unsigned_value_t) value, false, base, precision, width, flags);
+          }
+        }
+        break;
+      }
+#ifdef RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
+      case 'f' :
+      case 'F' :
+        if (*format == 'F') flags |= FLAGS_UPPERCASE;
+        print_floating_point(output, va_arg(args, double), precision, width, flags, PRINTF_PREFER_DECIMAL);
+        format++;
+        break;
+#endif
+#ifdef RT_KLIBC_USING_VSNPRINTF_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;
+        print_floating_point(output, va_arg(args, double), precision, width, flags, PRINTF_PREFER_EXPONENTIAL);
+        format++;
+        break;
+#endif  // RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
+      case 'c' : {
+        printf_size_t l = 1U;
+        // pre padding
+        if (!(flags & FLAGS_LEFT)) {
+          while (l++ < width) {
+            putchar_via_gadget(output, ' ');
+          }
+        }
+        // char output
+        putchar_via_gadget(output, (char) va_arg(args, int) );
+        // post padding
+        if (flags & FLAGS_LEFT) {
+          while (l++ < width) {
+            putchar_via_gadget(output, ' ');
+          }
+        }
+        format++;
+        break;
+      }
+
+      case 's' : {
+        const char* p = va_arg(args, char*);
+        if (p == NULL) {
+          out_rev_(output, ")llun(", 6, width, flags);
+        }
+        else {
+          printf_size_t l = strnlen_s_(p, precision ? precision : PRINTF_MAX_POSSIBLE_BUFFER_SIZE);
+          // pre padding
+          if (flags & FLAGS_PRECISION) {
+            l = (l < precision ? l : precision);
+          }
+          if (!(flags & FLAGS_LEFT)) {
+            while (l++ < width) {
+              putchar_via_gadget(output, ' ');
+            }
+          }
+          // string output
+          while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision)) {
+            putchar_via_gadget(output, *(p++));
+            --precision;
+          }
+          // post padding
+          if (flags & FLAGS_LEFT) {
+            while (l++ < width) {
+              putchar_via_gadget(output, ' ');
+            }
+          }
+        }
+        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(args, void*);
+        (value == (uintptr_t) NULL) ?
+          out_rev_(output, ")lin(", 5, width, flags) :
+          print_integer(output, (printf_unsigned_value_t) value, false, BASE_HEX, precision, width, flags);
+        format++;
+        break;
+      }
+
+      case '%' :
+        putchar_via_gadget(output, '%');
+        format++;
+        break;
+
+      // Many people prefer to disable support for %n, as it lets the caller
+      // engineer a write to an arbitrary location, of a value the caller
+      // effectively controls - which could be a security concern in some cases.
+#ifdef RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
+      case 'n' : {
+        if       (flags & FLAGS_CHAR)      *(va_arg(args, char*))      = (char) output->pos;
+        else if  (flags & FLAGS_SHORT)     *(va_arg(args, short*))     = (short) output->pos;
+        else if  (flags & FLAGS_LONG)      *(va_arg(args, long*))      = (long) output->pos;
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+        else if  (flags & FLAGS_LONG_LONG) *(va_arg(args, long long*)) = (long long int) output->pos;
+#endif // RT_KLIBC_USING_VSNPRINTF_LONGLONG
+        else                               *(va_arg(args, int*))       = (int) output->pos;
+        format++;
+        break;
+      }
+#endif // RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
+
+      default :
+        putchar_via_gadget(output, *format);
+        format++;
+        break;
+    }
+  }
+}
+
+// internal vsnprintf - used for implementing _all library functions
+static int vsnprintf_impl(output_gadget_t* output, const char* format, va_list args)
+{
+  // Note: The library only calls vsnprintf_impl() with output->pos being 0. However, it is
+  // possible to call this function with a non-zero pos value for some "remedial printing".
+  format_string_loop(output, format, args);
+
+  // termination
+  append_termination_with_gadget(output);
+
+  // return written chars without terminating \0
+  return (int)output->pos;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief  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 rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
+{
+  output_gadget_t gadget = buffer_gadget(buf, size);
+  return vsnprintf_impl(&gadget, fmt, args);
+}
+
+#endif /* RT_KLIBC_USING_VSNPRINTF_STANDARD */

+ 616 - 0
src/klibc/rt_vsnprintf_tiny.c

@@ -0,0 +1,616 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2024-11-19     Meco Man     the first version
+ */
+
+#include <rtthread.h>
+
+#ifndef RT_KLIBC_USING_VSNPRINTF_STANDARD
+
+#define _ISDIGIT(c)  ((unsigned)((c) - '0') < 10)
+
+/**
+ * @brief  This function will duplicate a string.
+ *
+ * @param  n is the string to be duplicated.
+ *
+ * @param  base is support divide instructions value.
+ *
+ * @return the duplicated string pointer.
+ */
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+rt_inline int divide(unsigned long long *n, int base)
+#else
+rt_inline int divide(unsigned long *n, int base)
+#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
+{
+    int res;
+
+    /* optimized for processor which does not support divide instructions. */
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+    res = (int)((*n) % base);
+    *n = (long long)((*n) / base);
+#else
+    res = (int)((*n) % base);
+    *n = (long)((*n) / base);
+#endif
+
+    return res;
+}
+
+rt_inline int skip_atoi(const char **s)
+{
+    int i = 0;
+    while (_ISDIGIT(**s))
+        i = i * 10 + *((*s)++) - '0';
+
+    return i;
+}
+
+#define ZEROPAD     (1 << 0)    /* pad with zero */
+#define SIGN        (1 << 1)    /* unsigned/signed long */
+#define PLUS        (1 << 2)    /* show plus */
+#define SPACE       (1 << 3)    /* space if plus */
+#define LEFT        (1 << 4)    /* left justified */
+#define SPECIAL     (1 << 5)    /* 0x */
+#define LARGE       (1 << 6)    /* use 'ABCDEF' instead of 'abcdef' */
+
+static char *print_number(char *buf,
+                          char *end,
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+                          unsigned long long  num,
+#else
+                          unsigned long  num,
+#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
+                          int   base,
+                          int   qualifier,
+                          int   s,
+                          int   precision,
+                          int   type)
+{
+    char c = 0, sign = 0;
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+    char tmp[64] = {0};
+#else
+    char tmp[32] = {0};
+#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
+    int precision_bak = precision;
+    const char *digits = RT_NULL;
+    static const char small_digits[] = "0123456789abcdef";
+    static const char large_digits[] = "0123456789ABCDEF";
+    int i = 0;
+    int size = 0;
+
+    size = s;
+
+    digits = (type & LARGE) ? large_digits : small_digits;
+    if (type & LEFT)
+    {
+        type &= ~ZEROPAD;
+    }
+
+    c = (type & ZEROPAD) ? '0' : ' ';
+
+    /* get sign */
+    sign = 0;
+    if (type & SIGN)
+    {
+        switch (qualifier)
+        {
+        case 'h':
+            if ((rt_int16_t)num < 0)
+            {
+                sign = '-';
+                num = (rt_uint16_t)-num;
+            }
+            break;
+        case 'L':
+        case 'l':
+            if ((long)num < 0)
+            {
+                sign = '-';
+                num = (unsigned long)-num;
+            }
+            break;
+        case 0:
+        default:
+            if ((rt_int32_t)num < 0)
+            {
+                sign = '-';
+                num = (rt_uint32_t)-num;
+            }
+            break;
+        }
+
+        if (sign != '-')
+        {
+            if (type & PLUS)
+            {
+                sign = '+';
+            }
+            else if (type & SPACE)
+            {
+                sign = ' ';
+            }
+        }
+    }
+
+    if (type & SPECIAL)
+    {
+        if (base == 2 || base == 16)
+        {
+            size -= 2;
+        }
+        else if (base == 8)
+        {
+            size--;
+        }
+    }
+
+    i = 0;
+    if (num == 0)
+    {
+        tmp[i++] = '0';
+    }
+    else
+    {
+        while (num != 0)
+            tmp[i++] = digits[divide(&num, base)];
+    }
+
+    if (i > precision)
+    {
+        precision = i;
+    }
+    size -= precision;
+
+    if (!(type & (ZEROPAD | LEFT)))
+    {
+        if ((sign) && (size > 0))
+        {
+            size--;
+        }
+
+        while (size-- > 0)
+        {
+            if (buf < end)
+            {
+                *buf = ' ';
+            }
+
+            ++ buf;
+        }
+    }
+
+    if (sign)
+    {
+        if (buf < end)
+        {
+            *buf = sign;
+        }
+        -- size;
+        ++ buf;
+    }
+
+    if (type & SPECIAL)
+    {
+        if (base == 2)
+        {
+            if (buf < end)
+                *buf = '0';
+            ++ buf;
+            if (buf < end)
+                *buf = 'b';
+            ++ buf;
+        }
+        else if (base == 8)
+        {
+            if (buf < end)
+                *buf = '0';
+            ++ buf;
+        }
+        else if (base == 16)
+        {
+            if (buf < end)
+            {
+                *buf = '0';
+            }
+
+            ++ buf;
+            if (buf < end)
+            {
+                *buf = type & LARGE ? 'X' : 'x';
+            }
+            ++ buf;
+        }
+    }
+
+    /* no align to the left */
+    if (!(type & LEFT))
+    {
+        while (size-- > 0)
+        {
+            if (buf < end)
+            {
+                *buf = c;
+            }
+
+            ++ buf;
+        }
+    }
+
+    while (i < precision--)
+    {
+        if (buf < end)
+        {
+            *buf = '0';
+        }
+
+        ++ buf;
+    }
+
+    /* put number in the temporary buffer */
+    while (i-- > 0 && (precision_bak != 0))
+    {
+        if (buf < end)
+        {
+            *buf = tmp[i];
+        }
+
+        ++ buf;
+    }
+
+    while (size-- > 0)
+    {
+        if (buf < end)
+        {
+            *buf = ' ';
+        }
+
+        ++ buf;
+    }
+
+    return buf;
+}
+
+#if (defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */) && (__GNUC__ >= 7)
+/* Disable "-Wimplicit-fallthrough" below GNUC V7 */
+#pragma GCC diagnostic push
+/* ignore warning: this statement may fall through */
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#endif /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) && (__GNUC__ >= 7 */
+/**
+ * @brief  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 rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
+{
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+    unsigned long long num = 0;
+#else
+    unsigned long num = 0;
+#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
+    int i = 0, len = 0;
+    char *str = RT_NULL, *end = RT_NULL, c = 0;
+    const char *s = RT_NULL;
+
+    rt_uint8_t base = 0;            /* the base of number */
+    rt_uint8_t flags = 0;           /* flags to print number */
+    rt_uint8_t qualifier = 0;       /* 'h', 'l', or 'L' for integer fields */
+    rt_int32_t field_width = 0;     /* width of output field */
+    int precision = 0;      /* min. # of digits for integers and max for a string */
+
+    str = buf;
+    end = buf + size;
+
+    /* Make sure end is always >= buf */
+    if (end < buf)
+    {
+        end  = ((char *) - 1);
+        size = end - buf;
+    }
+
+    for (; *fmt ; ++fmt)
+    {
+        if (*fmt != '%')
+        {
+            if (str < end)
+            {
+                *str = *fmt;
+            }
+
+            ++ str;
+            continue;
+        }
+
+        /* process flags */
+        flags = 0;
+
+        while (1)
+        {
+            /* skips the first '%' also */
+            ++fmt;
+            if (*fmt == '-') flags |= LEFT;
+            else if (*fmt == '+') flags |= PLUS;
+            else if (*fmt == ' ') flags |= SPACE;
+            else if (*fmt == '#') flags |= SPECIAL;
+            else if (*fmt == '0') flags |= ZEROPAD;
+            else break;
+        }
+
+        /* get field width */
+        field_width = -1;
+        if (_ISDIGIT(*fmt))
+        {
+            field_width = skip_atoi(&fmt);
+        }
+        else if (*fmt == '*')
+        {
+            ++fmt;
+            /* it's the next argument */
+            field_width = va_arg(args, int);
+            if (field_width < 0)
+            {
+                field_width = -field_width;
+                flags |= LEFT;
+            }
+        }
+
+        /* get the precision */
+        precision = -1;
+        if (*fmt == '.')
+        {
+            ++fmt;
+            if (_ISDIGIT(*fmt))
+            {
+                precision = skip_atoi(&fmt);
+            }
+            else if (*fmt == '*')
+            {
+                ++fmt;
+                /* it's the next argument */
+                precision = va_arg(args, int);
+            }
+            if (precision < 0)
+            {
+                precision = 0;
+            }
+        }
+
+        qualifier = 0; /* get the conversion qualifier */
+
+        if (*fmt == 'h' || *fmt == 'l' ||
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+            *fmt == 'L' ||
+#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
+            *fmt == 'z')
+        {
+            qualifier = *fmt;
+            ++fmt;
+#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
+            if (qualifier == 'l' && *fmt == 'l')
+            {
+                qualifier = 'L';
+                ++fmt;
+            }
+#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
+            if (qualifier == 'h' && *fmt == 'h')
+            {
+                qualifier = 'H';
+                ++fmt;
+            }
+        }
+
+        /* the default base */
+        base = 10;
+
+        switch (*fmt)
+        {
+        case 'c':
+            if (!(flags & LEFT))
+            {
+                while (--field_width > 0)
+                {
+                    if (str < end) *str = ' ';
+                    ++ str;
+                }
+            }
+
+            /* get character */
+            c = (rt_uint8_t)va_arg(args, int);
+            if (str < end)
+            {
+                *str = c;
+            }
+            ++ str;
+
+            /* put width */
+            while (--field_width > 0)
+            {
+                if (str < end) *str = ' ';
+                ++ str;
+            }
+            continue;
+
+        case 's':
+            s = va_arg(args, char *);
+            if (!s)
+            {
+                s = "(NULL)";
+            }
+
+            for (len = 0; (len != field_width) && (s[len] != '\0'); len++);
+
+            if (precision > 0 && len > precision)
+            {
+                len = precision;
+            }
+
+            if (!(flags & LEFT))
+            {
+                while (len < field_width--)
+                {
+                    if (str < end) *str = ' ';
+                    ++ str;
+                }
+            }
+
+            for (i = 0; i < len; ++i)
+            {
+                if (str < end) *str = *s;
+                ++ str;
+                ++ s;
+            }
+
+            while (len < field_width--)
+            {
+                if (str < end) *str = ' ';
+                ++ str;
+            }
+            continue;
+
+        case 'p':
+            if (field_width == -1)
+            {
+                field_width = sizeof(void *) << 1;
+                field_width += 2; /* `0x` prefix */
+                flags |= SPECIAL;
+                flags |= ZEROPAD;
+            }
+            str = print_number(str, end, (unsigned long)va_arg(args, void *),
+                               16, qualifier, field_width, precision, flags);
+            continue;
+
+        case '%':
+            if (str < end)
+            {
+                *str = '%';
+            }
+            ++ str;
+            continue;
+
+        /* integer number formats - set up the flags and "break" */
+        case 'b':
+            base = 2;
+            break;
+        case 'o':
+            base = 8;
+            break;
+
+        case 'X':
+            flags |= LARGE;
+        case 'x':
+            base = 16;
+            break;
+
+        case 'd':
+        case 'i':
+            flags |= SIGN;
+        case 'u':
+            break;
+
+        case 'e':
+        case 'E':
+        case 'G':
+        case 'g':
+        case 'f':
+        case 'F':
+            va_arg(args, double);
+        default:
+            if (str < end)
+            {
+                *str = '%';
+            }
+            ++ str;
+
+            if (*fmt)
+            {
+                if (str < end)
+                {
+                    *str = *fmt;
+                }
+                ++ str;
+            }
+            else
+            {
+                -- fmt;
+            }
+            continue;
+        }
+
+        if (qualifier == 'L')
+        {
+            num = va_arg(args, unsigned long long);
+        }
+        else if (qualifier == 'l')
+        {
+            num = va_arg(args, unsigned long);
+        }
+        else if (qualifier == 'H')
+        {
+            num = (rt_int8_t)va_arg(args, rt_int32_t);
+            if (flags & SIGN)
+            {
+                num = (rt_int8_t)num;
+            }
+        }
+        else if (qualifier == 'h')
+        {
+            num = (rt_uint16_t)va_arg(args, rt_int32_t);
+            if (flags & SIGN)
+            {
+                num = (rt_int16_t)num;
+            }
+        }
+        else if (qualifier == 'z')
+        {
+            num = va_arg(args, rt_size_t);
+            if (flags & SIGN)
+            {
+                num = (rt_ssize_t)num;
+            }
+        }
+        else
+        {
+            num = (rt_uint32_t)va_arg(args, unsigned long);
+        }
+        str = print_number(str, end, num, base, qualifier, field_width, precision, flags);
+    }
+
+    if (size > 0)
+    {
+        if (str < end)
+        {
+            *str = '\0';
+        }
+        else
+        {
+            end[-1] = '\0';
+        }
+    }
+
+    /* the trailing null byte doesn't count towards the total
+    * ++str;
+    */
+    return str - buf;
+}
+RTM_EXPORT(rt_vsnprintf);
+#if (defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */) && (__GNUC__ >= 7)
+#pragma GCC diagnostic pop /* ignored "-Wimplicit-fallthrough" */
+#endif /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) && (__GNUC__ >= 7 */
+
+#endif /* !RT_KLIBC_USING_VSNPRINTF_STANDARD */