diff --git a/bsp/allwinner/d1/rtconfig.h b/bsp/allwinner/d1/rtconfig.h index 8d1cb4a1c0..1347758102 100644 --- a/bsp/allwinner/d1/rtconfig.h +++ b/bsp/allwinner/d1/rtconfig.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/allwinner/d1s/rtconfig.h b/bsp/allwinner/d1s/rtconfig.h index 00a4cb2162..db2b99a22a 100644 --- a/bsp/allwinner/d1s/rtconfig.h +++ b/bsp/allwinner/d1s/rtconfig.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/bouffalo_lab/bl808/d0/rtconfig.h b/bsp/bouffalo_lab/bl808/d0/rtconfig.h index 6c4bcecf93..db36a29246 100755 --- a/bsp/bouffalo_lab/bl808/d0/rtconfig.h +++ b/bsp/bouffalo_lab/bl808/d0/rtconfig.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/cvitek/c906_little/rtconfig.h b/bsp/cvitek/c906_little/rtconfig.h index ddb70c1a2e..1718865220 100755 --- a/bsp/cvitek/c906_little/rtconfig.h +++ b/bsp/cvitek/c906_little/rtconfig.h @@ -24,7 +24,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/cvitek/cv18xx_aarch64/rtconfig.h b/bsp/cvitek/cv18xx_aarch64/rtconfig.h index dff46c203f..14f429b483 100644 --- a/bsp/cvitek/cv18xx_aarch64/rtconfig.h +++ b/bsp/cvitek/cv18xx_aarch64/rtconfig.h @@ -24,7 +24,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/cvitek/cv18xx_risc-v/rtconfig.h b/bsp/cvitek/cv18xx_risc-v/rtconfig.h index 8792605247..38b60f936f 100755 --- a/bsp/cvitek/cv18xx_risc-v/rtconfig.h +++ b/bsp/cvitek/cv18xx_risc-v/rtconfig.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/k230/rtconfig.h b/bsp/k230/rtconfig.h index 20caf68381..3aead3a8b4 100644 --- a/bsp/k230/rtconfig.h +++ b/bsp/k230/rtconfig.h @@ -27,7 +27,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/nuvoton/numaker-iot-m467/.config b/bsp/nuvoton/numaker-iot-m467/.config index bee0aab1d0..9f6c4ca954 100644 --- a/bsp/nuvoton/numaker-iot-m467/.config +++ b/bsp/nuvoton/numaker-iot-m467/.config @@ -821,33 +821,6 @@ CONFIG_PKG_AT_DEVICE_VER_NUM=0x99999 # 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 # diff --git a/bsp/nuvoton/numaker-iot-m487/.config b/bsp/nuvoton/numaker-iot-m487/.config index c6cd6392db..1c7218bc68 100644 --- a/bsp/nuvoton/numaker-iot-m487/.config +++ b/bsp/nuvoton/numaker-iot-m487/.config @@ -801,33 +801,6 @@ CONFIG_PKG_AT_DEVICE_VER_NUM=0x99999 # 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 # diff --git a/bsp/nuvoton/numaker-m2354/.config b/bsp/nuvoton/numaker-m2354/.config index a709f83d65..d819347e1a 100644 --- a/bsp/nuvoton/numaker-m2354/.config +++ b/bsp/nuvoton/numaker-m2354/.config @@ -735,33 +735,6 @@ CONFIG_PKG_AT_DEVICE_VER_NUM=0x99999 # 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 # diff --git a/bsp/nuvoton/numaker-m467hj/.config b/bsp/nuvoton/numaker-m467hj/.config index 265336a258..8b2a91cc2a 100644 --- a/bsp/nuvoton/numaker-m467hj/.config +++ b/bsp/nuvoton/numaker-m467hj/.config @@ -773,33 +773,6 @@ CONFIG_RT_USB_MSTORAGE_DISK_NAME="ramdisk1" # 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 # diff --git a/bsp/nxp/mcx/mcxa/frdm-mcxa153/.config b/bsp/nxp/mcx/mcxa/frdm-mcxa153/.config index 75c47d9cd5..fc6b742604 100644 --- a/bsp/nxp/mcx/mcxa/frdm-mcxa153/.config +++ b/bsp/nxp/mcx/mcxa/frdm-mcxa153/.config @@ -507,32 +507,6 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y # 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 # diff --git a/bsp/nxp/mcx/mcxn/frdm-mcxn236/.config b/bsp/nxp/mcx/mcxn/frdm-mcxn236/.config index 6c3226ebde..30b78c0966 100644 --- a/bsp/nxp/mcx/mcxn/frdm-mcxn236/.config +++ b/bsp/nxp/mcx/mcxn/frdm-mcxn236/.config @@ -558,33 +558,6 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y # 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 # diff --git a/bsp/nxp/mcx/mcxn/frdm-mcxn947/.config b/bsp/nxp/mcx/mcxn/frdm-mcxn947/.config index 52f3664bed..8d92cb6332 100644 --- a/bsp/nxp/mcx/mcxn/frdm-mcxn947/.config +++ b/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_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 diff --git a/bsp/phytium/aarch64/configs/e2000d_demo_rtsmart.h b/bsp/phytium/aarch64/configs/e2000d_demo_rtsmart.h index f187242bcb..4392c9bf89 100644 --- a/bsp/phytium/aarch64/configs/e2000d_demo_rtsmart.h +++ b/bsp/phytium/aarch64/configs/e2000d_demo_rtsmart.h @@ -28,7 +28,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/e2000d_demo_rtthread.h b/bsp/phytium/aarch64/configs/e2000d_demo_rtthread.h index e2317b90dc..ffa79f701e 100644 --- a/bsp/phytium/aarch64/configs/e2000d_demo_rtthread.h +++ b/bsp/phytium/aarch64/configs/e2000d_demo_rtthread.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/e2000d_demo_rtthread_pusb2_dc.h b/bsp/phytium/aarch64/configs/e2000d_demo_rtthread_pusb2_dc.h index 9c20ef1eb0..c4346f7bf7 100644 --- a/bsp/phytium/aarch64/configs/e2000d_demo_rtthread_pusb2_dc.h +++ b/bsp/phytium/aarch64/configs/e2000d_demo_rtthread_pusb2_dc.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/e2000q_demo_rtsmart.h b/bsp/phytium/aarch64/configs/e2000q_demo_rtsmart.h index 3555e49825..7fa168f7b5 100644 --- a/bsp/phytium/aarch64/configs/e2000q_demo_rtsmart.h +++ b/bsp/phytium/aarch64/configs/e2000q_demo_rtsmart.h @@ -28,7 +28,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/e2000q_demo_rtthread.h b/bsp/phytium/aarch64/configs/e2000q_demo_rtthread.h index 96bd956a1d..13136f66fe 100644 --- a/bsp/phytium/aarch64/configs/e2000q_demo_rtthread.h +++ b/bsp/phytium/aarch64/configs/e2000q_demo_rtthread.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/phytium_pi_rtsmart.h b/bsp/phytium/aarch64/configs/phytium_pi_rtsmart.h index 063e6f3d30..e35ce870c3 100644 --- a/bsp/phytium/aarch64/configs/phytium_pi_rtsmart.h +++ b/bsp/phytium/aarch64/configs/phytium_pi_rtsmart.h @@ -28,7 +28,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/phytium_pi_rtthread.h b/bsp/phytium/aarch64/configs/phytium_pi_rtthread.h index 2f3e33e293..4f7b4629d1 100644 --- a/bsp/phytium/aarch64/configs/phytium_pi_rtthread.h +++ b/bsp/phytium/aarch64/configs/phytium_pi_rtthread.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/phytium_pi_rtthread_pusb2_hc.h b/bsp/phytium/aarch64/configs/phytium_pi_rtthread_pusb2_hc.h index 81d9947912..d65ba17f88 100644 --- a/bsp/phytium/aarch64/configs/phytium_pi_rtthread_pusb2_hc.h +++ b/bsp/phytium/aarch64/configs/phytium_pi_rtthread_pusb2_hc.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/configs/phytium_pi_rtthread_xhci.h b/bsp/phytium/aarch64/configs/phytium_pi_rtthread_xhci.h index 4be8358df0..7607e6ac09 100644 --- a/bsp/phytium/aarch64/configs/phytium_pi_rtthread_xhci.h +++ b/bsp/phytium/aarch64/configs/phytium_pi_rtthread_xhci.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/phytium/aarch64/rtconfig.h b/bsp/phytium/aarch64/rtconfig.h index e2317b90dc..ffa79f701e 100644 --- a/bsp/phytium/aarch64/rtconfig.h +++ b/bsp/phytium/aarch64/rtconfig.h @@ -26,7 +26,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/qemu-virt64-riscv/rtconfig.h b/bsp/qemu-virt64-riscv/rtconfig.h index 44ce692d6a..6fe5f0db35 100644 --- a/bsp/qemu-virt64-riscv/rtconfig.h +++ b/bsp/qemu-virt64-riscv/rtconfig.h @@ -25,7 +25,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT diff --git a/bsp/raspberry-pi/raspi-dm2.0/rtconfig.h b/bsp/raspberry-pi/raspi-dm2.0/rtconfig.h index a1a0ca4169..38802e60bf 100644 --- a/bsp/raspberry-pi/raspi-dm2.0/rtconfig.h +++ b/bsp/raspberry-pi/raspi-dm2.0/rtconfig.h @@ -28,7 +28,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_COLOR diff --git a/bsp/rockchip/rk3500/rtconfig.h b/bsp/rockchip/rk3500/rtconfig.h index 5500e2c1da..c2fb908793 100644 --- a/bsp/rockchip/rk3500/rtconfig.h +++ b/bsp/rockchip/rk3500/rtconfig.h @@ -30,7 +30,7 @@ /* klibc optimization */ -#define RT_KLIBC_USING_PRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG /* end of klibc optimization */ #define RT_USING_DEBUG #define RT_DEBUGING_COLOR diff --git a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-printf.attach b/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-printf.attach deleted file mode 100644 index 7cdb5205ac..0000000000 --- a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-printf.attach +++ /dev/null @@ -1,3 +0,0 @@ -# scons: --strict - -CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG=y diff --git a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-vsnprintf-std.attach b/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/kernel/klibc-vsnprintf-std.attach new file mode 100644 index 0000000000..560367ef34 --- /dev/null +++ b/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 diff --git a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/online-packages/system/enhanced-kservice.attach b/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/online-packages/system/enhanced-kservice.attach index 7571f1664b..12a310f9ed 100644 --- a/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/online-packages/system/enhanced-kservice.attach +++ b/bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/online-packages/system/enhanced-kservice.attach @@ -1,4 +1,3 @@ # scons: --strict CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE=y CONFIG_PKG_USING_RT_MEMCPY_CM=y -CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y diff --git a/components/drivers/sensor/Kconfig b/components/drivers/sensor/Kconfig index 86f8711197..976e6a7f23 100644 --- a/components/drivers/sensor/Kconfig +++ b/components/drivers/sensor/Kconfig @@ -10,6 +10,6 @@ if RT_USING_SENSOR config RT_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 endif diff --git a/components/utilities/Kconfig b/components/utilities/Kconfig index b64b319360..cade1ba06c 100644 --- a/components/utilities/Kconfig +++ b/components/utilities/Kconfig @@ -137,7 +137,7 @@ menuconfig RT_USING_ULOG config ULOG_OUTPUT_FLOAT bool "Enable float number support. It will using more thread stack." default n - select PKG_USING_RT_VSNPRINTF_FULL + select RT_KLIBC_USING_VSNPRINTF_STANDARD help 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. diff --git a/src/Kconfig b/src/Kconfig index 7ce1985d48..ab3e55c1cf 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -189,13 +189,13 @@ config RT_USING_CPU_USAGE_TRACER default y if RT_USING_SMART default n -menu "kservice optimization" +menu "kservice options" config RT_USING_TINY_FFS bool "Enable kservice to use tiny finding first bit set method" default n endmenu -menu "klibc optimization" +menu "klibc options" config RT_KLIBC_USING_STDLIB bool "Enable klibc to use standard C library" @@ -213,15 +213,104 @@ menu "klibc optimization" bool "Enable tiny size of klibc" 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 bool "Enable debugging features" diff --git a/src/klibc/kerrno.c b/src/klibc/kerrno.c index 4d83b133cb..49a73c6d40 100644 --- a/src/klibc/kerrno.c +++ b/src/klibc/kerrno.c @@ -10,14 +10,6 @@ #include -#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 - /** * @brief A global variable used to store the error code. * diff --git a/src/klibc/kstdio.c b/src/klibc/kstdio.c index 4bcd5d460a..0da07ec0bc 100644 --- a/src/klibc/kstdio.c +++ b/src/klibc/kstdio.c @@ -10,615 +10,6 @@ #include -#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 - -#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. * diff --git a/src/klibc/kstring.c b/src/klibc/kstring.c index 562c3f7ccd..9eba5e5710 100644 --- a/src/klibc/kstring.c +++ b/src/klibc/kstring.c @@ -13,14 +13,6 @@ #include #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 - /** * @brief This function will set the content of memory to specified value. * diff --git a/src/klibc/rt_vsnprintf_std.c b/src/klibc/rt_vsnprintf_std.c new file mode 100644 index 0000000000..3d919d522e --- /dev/null +++ b/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 + * 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 . + * + * @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 + +#ifdef RT_KLIBC_USING_VSNPRINTF_STANDARD + +#include +#include +#include +#include + +// '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 +#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 */ diff --git a/src/klibc/rt_vsnprintf_tiny.c b/src/klibc/rt_vsnprintf_tiny.c new file mode 100644 index 0000000000..a91e1498d5 --- /dev/null +++ b/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 + +#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 */