From 2a5b57aaac4f12ccd68dcd88e16445fb912fab1d Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Sun, 25 Dec 2022 13:29:45 +0400 Subject: [PATCH] Remove printf --- .github/workflows/main.yml | 3 +- Makefile.am | 6 - README.md | 3 - configure.ac | 14 - include/Makefile.am | 2 - include/kernaux.h | 2 - include/kernaux/generic/display.h | 37 -- include/kernaux/macro.h | 5 +- include/kernaux/printf.h | 48 -- include/kernaux/printf_fmt.h | 75 --- include/kernaux/version.h.in | 2 - pkgs/freebsd/devel/libkernaux/pkg-plist | 2 - src/generic/display.c | 116 ----- src/printf.c | 665 ------------------------ src/printf_fmt.c | 349 ------------- tests/.gitignore | 1 - tests/Makefile.am | 12 - tests/test_printf.c | 34 -- 18 files changed, 3 insertions(+), 1373 deletions(-) delete mode 100644 include/kernaux/generic/display.h delete mode 100644 include/kernaux/printf.h delete mode 100644 include/kernaux/printf_fmt.h delete mode 100644 src/generic/display.c delete mode 100644 src/printf.c delete mode 100644 src/printf_fmt.c delete mode 100644 tests/test_printf.c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 16e8915..be0f5ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -92,8 +92,7 @@ jobs: - without: 'all' - without: 'io' - without: 'ntoa' - dependencies: '--without-printf --without-units' - - without: 'printf' + dependencies: '--without-units' - without: 'memmap' steps: - uses: actions/checkout@v2 diff --git a/Makefile.am b/Makefile.am index cd369c0..e6dbc94 100644 --- a/Makefile.am +++ b/Makefile.am @@ -95,12 +95,6 @@ endif if WITH_PFA libkernaux_la_SOURCES += src/pfa.c endif -if WITH_PRINTF -libkernaux_la_SOURCES += src/printf.c -endif -if WITH_PRINTF_FMT -libkernaux_la_SOURCES += src/printf_fmt.c -endif if WITH_UNITS libkernaux_la_SOURCES += src/units.c endif diff --git a/README.md b/README.md index b7b9388..753b0e1 100644 --- a/README.md +++ b/README.md @@ -56,10 +56,8 @@ zero). Work-in-progress APIs can change at any time. * Utilities * [Measurement units utils](/include/kernaux/units.h) (*work in progress*) * [Memory map](/include/kernaux/memmap.h) (*non-breaking since* **0.7.0**) - * [printf format parser](/include/kernaux/printf_fmt.h) (*non-breaking since* **0.6.0**) * Usual functions * [itoa/ftoa replacement](/include/kernaux/ntoa.h) (*non-breaking since* **0.4.0**) - * [printf replacement](/include/kernaux/printf.h) (*non-breaking since* **0.5.0**) * libc replacement (*work in progress*) * [ctype.h](/libc/include/ctype.h) * [errno.h](/libc/include/errno.h) @@ -145,7 +143,6 @@ explicitly included, use `--without-all`. * `--with[out]-free-list` - free list memory allocator * `--with[out]-memmap` - memory map * `--with[out]-ntoa` - itoa/ftoa -* `--with[out]-printf` - printf diff --git a/configure.ac b/configure.ac index c4bd856..31be682 100644 --- a/configure.ac +++ b/configure.ac @@ -72,8 +72,6 @@ AC_ARG_WITH( [mbr], AS_HELP_STRING([--without-mbr], [wit AC_ARG_WITH( [memmap], AS_HELP_STRING([--without-memmap], [without memory map])) AC_ARG_WITH( [ntoa], AS_HELP_STRING([--without-ntoa], [without itoa/ftoa])) AC_ARG_WITH( [pfa], AS_HELP_STRING([--without-pfa], [without Page Frame Allocator])) -AC_ARG_WITH( [printf], AS_HELP_STRING([--without-printf], [without printf])) -AC_ARG_WITH( [printf-fmt], AS_HELP_STRING([--without-printf-fmt], [without printf format parser])) AC_ARG_WITH( [units], AS_HELP_STRING([--without-units], [without measurement units utils])) dnl Packages (disabled by default) @@ -112,8 +110,6 @@ if test -z "$with_mbr"; then with_mbr=no; fi if test -z "$with_memmap"; then with_memmap=no; fi if test -z "$with_ntoa"; then with_ntoa=no; fi if test -z "$with_pfa"; then with_pfa=no; fi -if test -z "$with_printf"; then with_printf=no; fi -if test -z "$with_printf_fmt"; then with_printf_fmt=no; fi if test -z "$with_units"; then with_units=no; fi ]) AS_IF([test "$with_all" = no], do_without_all) @@ -153,8 +149,6 @@ AS_IF([test "$with_mbr" = no ], [with_mbr=no], [wit AS_IF([test "$with_memmap" = no ], [with_memmap=no], [with_memmap=yes]) AS_IF([test "$with_ntoa" = no ], [with_ntoa=no], [with_ntoa=yes]) AS_IF([test "$with_pfa" = no ], [with_pfa=no], [with_pfa=yes]) -AS_IF([test "$with_printf" = no ], [with_printf=no], [with_printf=yes]) -AS_IF([test "$with_printf_fmt" = no ], [with_printf_fmt=no], [with_printf_fmt=yes]) AS_IF([test "$with_units" = no ], [with_units=no], [with_units=yes]) dnl Packages (disabled by default) @@ -169,8 +163,6 @@ AS_IF([test "$with_libc" = yes], [with_libc=yes], [wit AS_IF([test "$enable_checks" = yes -a "$enable_freestanding" = yes], AC_MSG_ERROR([can not build freestanding tests])) AS_IF([test "$enable_checks" = yes -a "$with_libc" = yes], AC_MSG_ERROR([can not use package `libc' with tests])) -AS_IF([test "$with_printf" = yes -a "$with_ntoa" = no], AC_MSG_ERROR([package `printf' requires package `ntoa'])) -AS_IF([test "$with_printf" = yes -a "$with_printf_fmt" = no], AC_MSG_ERROR([package `printf' requires package `printf-fmt'])) AS_IF([test "$with_units" = yes -a "$with_ntoa" = no], AC_MSG_ERROR([package `units' requires package `ntoa'])) @@ -212,8 +204,6 @@ AM_CONDITIONAL([WITH_MBR], [test "$with_mbr" = yes]) AM_CONDITIONAL([WITH_MEMMAP], [test "$with_memmap" = yes]) AM_CONDITIONAL([WITH_NTOA], [test "$with_ntoa" = yes]) AM_CONDITIONAL([WITH_PFA], [test "$with_pfa" = yes]) -AM_CONDITIONAL([WITH_PRINTF], [test "$with_printf" = yes]) -AM_CONDITIONAL([WITH_PRINTF_FMT], [test "$with_printf_fmt" = yes]) AM_CONDITIONAL([WITH_UNITS], [test "$with_units" = yes]) dnl Packages (disabled by default) @@ -259,8 +249,6 @@ AS_IF([test "$with_mbr" = yes], [AC_DEFINE([WITH_MBR], AS_IF([test "$with_memmap" = yes], [AC_DEFINE([WITH_MEMMAP], [1], [with memory map])]) AS_IF([test "$with_ntoa" = yes], [AC_DEFINE([WITH_NTOA], [1], [with ntoa])]) AS_IF([test "$with_pfa" = yes], [AC_DEFINE([WITH_PFA], [1], [with Page Frame Allocator])]) -AS_IF([test "$with_printf" = yes], [AC_DEFINE([WITH_PRINTF], [1], [with printf])]) -AS_IF([test "$with_printf_fmt" = yes], [AC_DEFINE([WITH_PRINTF_FMT], [1], [with printf format parser])]) AS_IF([test "$with_units", = yes], [AC_DEFINE([WITH_UNITS], [1], [with measurement units utils])]) dnl Packages (disabled by default) @@ -289,8 +277,6 @@ AS_IF([test "$with_mbr" = no], [AC_SUBST([comment_line_mbr], [ AS_IF([test "$with_memmap" = no], [AC_SUBST([comment_line_memmap], [//])]) AS_IF([test "$with_ntoa" = no], [AC_SUBST([comment_line_ntoa], [//])]) AS_IF([test "$with_pfa" = no], [AC_SUBST([comment_line_pfa], [//])]) -AS_IF([test "$with_printf" = no], [AC_SUBST([comment_line_printf], [//])]) -AS_IF([test "$with_printf_fmt" = no], [AC_SUBST([comment_line_printf_fmt], [//])]) AS_IF([test "$with_units" = no], [AC_SUBST([comment_line_units], [//])]) diff --git a/include/Makefile.am b/include/Makefile.am index 597e400..21476bc 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -21,8 +21,6 @@ nobase_include_HEADERS = \ kernaux/memmap.h \ kernaux/ntoa.h \ kernaux/pfa.h \ - kernaux/printf.h \ - kernaux/printf_fmt.h \ kernaux/runtime.h \ kernaux/units.h \ kernaux/version.h diff --git a/include/kernaux.h b/include/kernaux.h index afa9b09..a404795 100644 --- a/include/kernaux.h +++ b/include/kernaux.h @@ -16,8 +16,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/include/kernaux/generic/display.h b/include/kernaux/generic/display.h deleted file mode 100644 index cbe1ed8..0000000 --- a/include/kernaux/generic/display.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef KERNAUX_INCLUDED_DISPLAY -#define KERNAUX_INCLUDED_DISPLAY - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include -#include - -typedef void (*KernAux_Display_Putc )(void *display, char c); -typedef void (*KernAux_Display_Vprintf)(void *display, const char *format, va_list va); - -typedef const struct KernAux_Display { - KernAux_Display_Putc KERNAUX_PROTECTED_FIELD(putc); - KernAux_Display_Vprintf KERNAUX_PROTECTED_FIELD(vprintf); -} *KernAux_Display; - -void KernAux_Display_putc (KernAux_Display display, char c); -void KernAux_Display_print (KernAux_Display display, const char *s); -void KernAux_Display_println (KernAux_Display display, const char *s); -void KernAux_Display_write (KernAux_Display display, const char *data, size_t size); -void KernAux_Display_writeln (KernAux_Display display, const char *data, size_t size); -KERNAUX_PRINTF(2, 3) -void KernAux_Display_printf (KernAux_Display display, const char *format, ...); -KERNAUX_PRINTF(2, 3) -void KernAux_Display_printlnf (KernAux_Display display, const char *format, ...); -void KernAux_Display_vprintf (KernAux_Display display, const char *format, va_list va); -void KernAux_Display_vprintlnf(KernAux_Display display, const char *format, va_list va); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/kernaux/macro.h b/include/kernaux/macro.h index 4fb1795..841d247 100644 --- a/include/kernaux/macro.h +++ b/include/kernaux/macro.h @@ -17,9 +17,8 @@ extern "C" { #define KERNAUX_UNUSED __attribute__((unused)) #define KERNAUX_USED __attribute__((used)) -#define KERNAUX_ALIGNED(num) __attribute__((aligned(num))) -#define KERNAUX_PRINTF(fmt, rest) __attribute__((format(printf, fmt, rest))) -#define KERNAUX_SECTION(name) __attribute__((section(name))) +#define KERNAUX_ALIGNED(num) __attribute__((aligned(num))) +#define KERNAUX_SECTION(name) __attribute__((section(name))) #ifdef __TINYC__ # define KERNAUX_PACKED diff --git a/include/kernaux/printf.h b/include/kernaux/printf.h deleted file mode 100644 index 19caedc..0000000 --- a/include/kernaux/printf.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef KERNAUX_INCLUDED_PRINTF -#define KERNAUX_INCLUDED_PRINTF - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** - * Tiny [v]fprintf implementation - * \param out An output function - * \param data Additional data for the output function - * \param format A string that specifies the format of the output - * \param va A value identifying a variable arguments list - * \return The number of characters that are sent to the output function, not counting the terminating null character - */ -int kernaux_fprintf(void (*out)(char, void*), void *data, const char* format, ...); -int kernaux_vfprintf(void (*out)(char, void*), void *data, const char* format, va_list va); - -/** - * Tiny [v]snprintf implementation - * \param buffer A pointer to the buffer where to store the formatted string - * \param count The maximum number of characters to store in the buffer, including a terminating null character - * \param format A string that specifies the format of the output - * \param va A value identifying a variable arguments list - * \return The number of characters that COULD have been written into the buffer, not counting the terminating - * null character. A value equal or larger than count indicates truncation. Only when the returned value - * is non-negative and less than count, the string has been completely written. - */ -int kernaux_snprintf(char* buffer, size_t count, const char* format, ...); -int kernaux_vsnprintf(char* buffer, size_t count, const char* format, va_list va); - -/** - * Tiny sprintf implementation - * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! - * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! - * \param format A string that specifies the format of the output - * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character - */ -int kernaux_sprintf(char* buffer, const char* format, ...); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/kernaux/printf_fmt.h b/include/kernaux/printf_fmt.h deleted file mode 100644 index e566922..0000000 --- a/include/kernaux/printf_fmt.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef KERNAUX_INCLUDED_PRINTF_FMT -#define KERNAUX_INCLUDED_PRINTF_FMT - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -#define KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD KERNAUX_BITS(0) -#define KERNAUX_PRINTF_FMT_FLAGS_LEFT KERNAUX_BITS(1) -#define KERNAUX_PRINTF_FMT_FLAGS_PLUS KERNAUX_BITS(2) -#define KERNAUX_PRINTF_FMT_FLAGS_SPACE KERNAUX_BITS(3) -#define KERNAUX_PRINTF_FMT_FLAGS_HASH KERNAUX_BITS(4) -#define KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE KERNAUX_BITS(5) -#define KERNAUX_PRINTF_FMT_FLAGS_CHAR KERNAUX_BITS(6) -#define KERNAUX_PRINTF_FMT_FLAGS_SHORT KERNAUX_BITS(7) -#define KERNAUX_PRINTF_FMT_FLAGS_LONG KERNAUX_BITS(8) -#define KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG KERNAUX_BITS(9) -#define KERNAUX_PRINTF_FMT_FLAGS_PRECISION KERNAUX_BITS(10) -#define KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP KERNAUX_BITS(11) - -enum KernAux_PrintfFmt_Type { - KERNAUX_PRINTF_FMT_TYPE_NONE, - KERNAUX_PRINTF_FMT_TYPE_INT, - KERNAUX_PRINTF_FMT_TYPE_UINT, - KERNAUX_PRINTF_FMT_TYPE_FLOAT, - KERNAUX_PRINTF_FMT_TYPE_EXP, - KERNAUX_PRINTF_FMT_TYPE_CHAR, - KERNAUX_PRINTF_FMT_TYPE_STR, - KERNAUX_PRINTF_FMT_TYPE_PTR, - KERNAUX_PRINTF_FMT_TYPE_PERCENT, -}; - -struct KernAux_PrintfFmt_Spec { - const char *format_start; - const char *format_limit; - - unsigned int flags; - unsigned int width; - unsigned int precision; - enum KernAux_PrintfFmt_Type type; - unsigned int base; - - bool set_width; - bool set_precision; -}; - -struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create( - const char *format -); -struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create_out( - const char **format -); -struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create_out_new( - const char *format, - const char **new_format -); - -void KernAux_PrintfFmt_Spec_set_width( - struct KernAux_PrintfFmt_Spec *spec, - int width -); -void KernAux_PrintfFmt_Spec_set_precision( - struct KernAux_PrintfFmt_Spec *spec, - int precision -); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/kernaux/version.h.in b/include/kernaux/version.h.in index 77c7ed2..4e32ff0 100644 --- a/include/kernaux/version.h.in +++ b/include/kernaux/version.h.in @@ -7,8 +7,6 @@ @comment_line_memmap@#define KERNAUX_VERSION_WITH_MEMMAP @comment_line_ntoa@#define KERNAUX_VERSION_WITH_NTOA @comment_line_pfa@#define KERNAUX_VERSION_WITH_PFA -@comment_line_printf@#define KERNAUX_VERSION_WITH_PRINTF -@comment_line_printf_fmt@#define KERNAUX_VERSION_WITH_PRINTF_FMT @comment_line_units@#define KERNAUX_VERSION_WITH_UNITS #endif diff --git a/pkgs/freebsd/devel/libkernaux/pkg-plist b/pkgs/freebsd/devel/libkernaux/pkg-plist index b26d3c4..d3bd2b8 100644 --- a/pkgs/freebsd/devel/libkernaux/pkg-plist +++ b/pkgs/freebsd/devel/libkernaux/pkg-plist @@ -20,8 +20,6 @@ include/kernaux/mbr.h include/kernaux/memmap.h include/kernaux/ntoa.h include/kernaux/pfa.h -include/kernaux/printf.h -include/kernaux/printf_fmt.h include/kernaux/runtime.h include/kernaux/units.h include/kernaux/version.h diff --git a/src/generic/display.c b/src/generic/display.c deleted file mode 100644 index 0fe5d3f..0000000 --- a/src/generic/display.c +++ /dev/null @@ -1,116 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "../assert.h" - -#include - -#include -#include - -void KernAux_Display_putc(const KernAux_Display display, const char c) -{ - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->putc); - - // Inherited implementation - display->putc((void*)display, c); -} - -void KernAux_Display_print(const KernAux_Display display, const char *const s) -{ - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->putc); - - // Default implementation - for (const char *c = s; *c; ++c) display->putc((void*)display, *c); -} - -void KernAux_Display_println(const KernAux_Display display, const char *const s) -{ - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->putc); - - // Default implementation - KernAux_Display_print(display, s); - display->putc((void*)display, '\n'); -} - -void KernAux_Display_write( - const KernAux_Display display, - const char *const data, - const size_t size -) { - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->putc); - - // Default implementation - for (size_t i = 0; i < size; ++i) display->putc((void*)display, data[i]); -} - -void KernAux_Display_writeln( - const KernAux_Display display, - const char *const data, - const size_t size -) { - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->putc); - - // Default implementation - KernAux_Display_write(display, data, size); - display->putc((void*)display, '\n'); -} - -void KernAux_Display_printf( - const KernAux_Display display, - const char *const format, - ... -) { - KERNAUX_NOTNULL(display); - - // Default implementation - va_list va; - va_start(va, format); - KernAux_Display_vprintf(display, format, va); - va_end(va); -} - -void KernAux_Display_printlnf( - const KernAux_Display display, - const char *const format, - ... -) { - KERNAUX_NOTNULL(display); - - // Default implementation - va_list va; - va_start(va, format); - KernAux_Display_vprintlnf(display, format, va); - va_end(va); -} - -void KernAux_Display_vprintf( - const KernAux_Display display, - const char *const format, - va_list va -) { - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->vprintf); - - // Inherited implementation - display->vprintf((void*)display, format, va); -} - -void KernAux_Display_vprintlnf( - const KernAux_Display display, - const char *const format, - va_list va -) { - KERNAUX_NOTNULL(display); - KERNAUX_ASSERT(display->putc); - - // Default implementation - KernAux_Display_vprintf(display, format, va); - display->putc((void*)display, '\n'); -} diff --git a/src/printf.c b/src/printf.c deleted file mode 100644 index d567c0f..0000000 --- a/src/printf.c +++ /dev/null @@ -1,665 +0,0 @@ -/** - * The code was taken from Marco Paland's printf. - * - * Copyright (c) 2014-2019 Marco Paland - * Copyright (c) 2021-2022 Alex Kotov - * - * Tiny [v]fprintf, sfprintf and [v]snprintf implementation, optimized for speed - * on embedded systems with a very limited resources. These routines are thread - * safe and reentrant! - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "assert.h" - -#include -#include - -#include -#include -#include - -// import float.h for DBL_MAX -#ifdef ENABLE_FLOAT -#include -#endif - -// 'ntoa' conversion buffer size, this must be big enough to hold one converted -// numeric number including padded zeros (dynamically created on stack) -#define PRINTF_NTOA_BUFFER_SIZE 32u - -// 'ftoa' conversion buffer size, this must be big enough to hold one converted -// float number including padded zeros (dynamically created on stack) -#define PRINTF_FTOA_BUFFER_SIZE 32u - -// define the default floating point precision -#define PRINTF_DEFAULT_FLOAT_PRECISION 6u - -// define the largest float suitable to print with %f -#define PRINTF_MAX_FLOAT 1e9 - -// output function type -typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); - -// wrapper (used as buffer) for output function type -typedef struct { - void (*fct)(char character, void* arg); - void* arg; -} out_fct_wrap_type; - -static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va); - -static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen); -static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen); -static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen); -static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags); -static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags); -static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags); -static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags); - -#ifdef ENABLE_FLOAT -static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); -static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); -#endif // ENABLE_FLOAT - -/***************************** - * Implementations: main API * - *****************************/ - -int kernaux_fprintf(void (*out)(char, void*), void *data, const char* format, ...) -{ - KERNAUX_NOTNULL(out); - KERNAUX_NOTNULL(format); - - va_list va; - va_start(va, format); - const out_fct_wrap_type out_fct_wrap = { out, data }; - const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); - va_end(va); - return ret; -} - -int kernaux_vfprintf(void (*out)(char, void*), void *data, const char* format, va_list va) -{ - KERNAUX_NOTNULL(out); - KERNAUX_NOTNULL(format); - - const out_fct_wrap_type out_fct_wrap = { out, data }; - return _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); -} - -int kernaux_snprintf(char* buffer, size_t count, const char* format, ...) -{ - KERNAUX_NOTNULL(buffer); - KERNAUX_NOTNULL(format); - - va_list va; - va_start(va, format); - const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); - va_end(va); - return ret; -} - -int kernaux_vsnprintf(char* buffer, size_t count, const char* format, va_list va) -{ - KERNAUX_NOTNULL(buffer); - KERNAUX_NOTNULL(format); - - return _vsnprintf(_out_buffer, buffer, count, format, va); -} - -int kernaux_sprintf(char* buffer, const char* format, ...) -{ - KERNAUX_NOTNULL(buffer); - KERNAUX_NOTNULL(format); - - va_list va; - va_start(va, format); - const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); - va_end(va); - return ret; -} - -/****************************************** - * Implementation: main internal function * - ******************************************/ - -int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) -{ - KERNAUX_NOTNULL(format); - - size_t idx = 0u; - - if (!buffer) { - // use null output function - out = _out_null; - } - - while (*format) - { - // format specifier? %[flags][width][.precision][length] - if (*format != '%') { - // no - out(*format, buffer, idx++, maxlen); - format++; - continue; - } else { - // yes, evaluate it - format++; - } - - struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create_out(&format); - - if (spec.set_width) { - KernAux_PrintfFmt_Spec_set_width(&spec, va_arg(va, int)); - } - if (spec.set_precision) { - KernAux_PrintfFmt_Spec_set_precision(&spec, va_arg(va, int)); - } - - // evaluate specifier - switch (spec.type) { - case KERNAUX_PRINTF_FMT_TYPE_INT: - if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG) { - const long long value = va_arg(va, long long); - idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, spec.base, spec.precision, spec.width, spec.flags); - } else if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LONG) { - const long value = va_arg(va, long); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, spec.base, spec.precision, spec.width, spec.flags); - } else { - const int value = (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_CHAR) ? (char)va_arg(va, int) : (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, spec.base, spec.precision, spec.width, spec.flags); - } - break; - - case KERNAUX_PRINTF_FMT_TYPE_UINT: - if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, spec.base, spec.precision, spec.width, spec.flags); - } else if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LONG) { - idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, spec.base, spec.precision, spec.width, spec.flags); - } else { - const unsigned int value = (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); - idx = _ntoa_long(out, buffer, idx, maxlen, value, false, spec.base, spec.precision, spec.width, spec.flags); - } - break; - -#ifdef ENABLE_FLOAT - case KERNAUX_PRINTF_FMT_TYPE_FLOAT: - idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), spec.precision, spec.width, spec.flags); - break; - - case KERNAUX_PRINTF_FMT_TYPE_EXP: - idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), spec.precision, spec.width, spec.flags); - break; -#endif // ENABLE_FLOAT - - case KERNAUX_PRINTF_FMT_TYPE_CHAR: - { - unsigned int l = 1u; - // pre padding - if (!(spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT)) { - while (l++ < spec.width) { - out(' ', buffer, idx++, maxlen); - } - } - // char output - out((char)va_arg(va, int), buffer, idx++, maxlen); - // post padding - if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) { - while (l++ < spec.width) { - out(' ', buffer, idx++, maxlen); - } - } - break; - } - - case KERNAUX_PRINTF_FMT_TYPE_STR: - { - const char* p = va_arg(va, char*); - unsigned int l = strnlen(p, spec.precision ? spec.precision : (size_t)-1); - // pre padding - if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) { - l = (l < spec.precision ? l : spec.precision); - } - if (!(spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT)) { - while (l++ < spec.width) { - out(' ', buffer, idx++, maxlen); - } - } - // string output - while ((*p != 0) && (!(spec.flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) || spec.precision--)) { - out(*(p++), buffer, idx++, maxlen); - } - // post padding - if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) { - while (l++ < spec.width) { - out(' ', buffer, idx++, maxlen); - } - } - break; - } - - case KERNAUX_PRINTF_FMT_TYPE_PTR: - { - const bool is_ll = sizeof(uintptr_t) == sizeof(long long); - // cppcheck-suppress knownConditionTrueFalse - if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16u, spec.precision, spec.width, spec.flags); - } else { - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16u, spec.precision, spec.width, spec.flags); - } - break; - } - - case KERNAUX_PRINTF_FMT_TYPE_PERCENT: - out('%', buffer, idx++, maxlen); - break; - - default: - out(*format, buffer, idx++, maxlen); - ++format; - break; - } - } - - // termination - out((char)0, buffer, idx < maxlen ? idx : maxlen - 1u, maxlen); - - // return written chars without terminating \0 - return (int)idx; -} - -/************************************* - * Implementations: helper functions * - *************************************/ - -// internal buffer output -void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) -{ - if (idx < maxlen) { - ((char*)buffer)[idx] = character; - } -} - -// internal null output -void _out_null(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)character; (void)buffer; (void)idx; (void)maxlen; -} - -// internal output function wrapper -void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) -{ - (void)idx; (void)maxlen; - if (character) { - // buffer is the output fct pointer - ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); - } -} - -// output the specified string in reverse, taking care of any zero-padding -size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) -{ - const size_t start_idx = idx; - - // pad spaces up to given width - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) && !(flags & KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); - } - } - - // reverse string - while (len) { - out(buf[--len], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) { - while (idx - start_idx < width) { - out(' ', buffer, idx++, maxlen); - } - } - - return idx; -} - -// internal itoa format -size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) -{ - // pad leading zeros - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT)) { - if (width && (flags & KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD) && (negative || (flags & (KERNAUX_PRINTF_FMT_FLAGS_PLUS | KERNAUX_PRINTF_FMT_FLAGS_SPACE)))) { - width--; - } - while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - while ((flags & KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - // handle hash - if (flags & KERNAUX_PRINTF_FMT_FLAGS_HASH) { - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { - len--; - if (len && (base == 16u)) { - len--; - } - } - if ((base == 16u) && !(flags & KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'x'; - } else if ((base == 16u) && (flags & KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'X'; - } else if ((base == 2u) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'b'; - } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_NTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } else if (flags & KERNAUX_PRINTF_FMT_FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } else if (flags & KERNAUX_PRINTF_FMT_FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} - -// internal itoa for 'long' type -size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0u; - - // no hash for 0 values - if (!value) { - flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : ((flags & KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE) ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } - - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} - -// internal itoa for 'long long' type -size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) -{ - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0u; - - // no hash for 0 values - if (!value) { - flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : ((flags & KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE) ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } - - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} - -#ifdef ENABLE_FLOAT -// internal ftoa for fixed decimal floating point -size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) -{ - // powers of 10 - static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; - - // test for special values - if (value != value) - return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); - if (value < -DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); - if (value > DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, (flags & KERNAUX_PRINTF_FMT_FLAGS_PLUS) ? "fni+" : "fni", (flags & KERNAUX_PRINTF_FMT_FLAGS_PLUS) ? 4u : 3u, width, flags); - - // test for very large values - // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad - if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { - return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); - } - - // test for negative - bool negative = false; - if (value < 0) { - negative = true; - value = 0 - value; - } - - // set default precision, if not set explicitly - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; - } - - char buf[PRINTF_FTOA_BUFFER_SIZE]; - size_t len = 0u; - - const unsigned int orig_prec = prec; - // limit precision to 9, cause a prec >= 10 can lead to overflow errors - if (prec > 9u) prec = 9u; - - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; - unsigned long frac = (unsigned long)tmp; - double diff = tmp - frac; - - if (diff > 0.5) { - ++frac; - // handle rollover, e.g. case 0.99 with prec 1 is 1.0 - if (frac >= pow10[prec]) { - frac = 0; - ++whole; - } - } else if (diff < 0.5) { - // TODO: do nothing? - } else if ((frac == 0u) || (frac & 1u)) { - // if halfway, round up if odd OR if last digit is 0 - ++frac; - } - - if (prec == 0u) { - diff = value - (double)whole; - // cppcheck-suppress redundantCondition - if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++whole; - } - } else { - unsigned int count = prec; - // now do fractional part, as an unsigned number - while (len < PRINTF_FTOA_BUFFER_SIZE) { - --count; - buf[len++] = (char)(48u + (frac % 10u)); - if (!(frac /= 10u)) { - break; - } - } - // add extra 0s - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0u)) { - buf[len++] = '0'; - } - if (len < PRINTF_FTOA_BUFFER_SIZE) { - // add decimal - buf[len++] = '.'; - } - } - - // do whole part, number is reversed - while (len < PRINTF_FTOA_BUFFER_SIZE) { - buf[len++] = (char)(48 + (whole % 10)); - if (!(whole /= 10)) { - break; - } - } - - // pad leading zeros - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) && (flags & KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD)) { - if (width && (negative || (flags & (KERNAUX_PRINTF_FMT_FLAGS_PLUS | KERNAUX_PRINTF_FMT_FLAGS_SPACE)))) { - width--; - } - while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_FTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } else if (flags & KERNAUX_PRINTF_FMT_FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } else if (flags & KERNAUX_PRINTF_FMT_FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - // This slows down the algorighm, but - // only if the precision was more than 9. - if (orig_prec > prec) { - const size_t space_left = PRINTF_FTOA_BUFFER_SIZE - len; - const size_t zeroes_wanted = orig_prec - prec; - const size_t delta = - space_left < zeroes_wanted ? space_left : zeroes_wanted; - - for (size_t rev_index = 0; rev_index < len; ++rev_index) { - const size_t index = len - 1 - rev_index; - buf[index + delta] = buf[index]; - } - - len += delta; - - for (size_t index = 0; index < delta; ++index) buf[index] = '0'; - } - - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} - -// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse -size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) -{ - // check for NaN and special values - if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { - return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); - } - - // determine the sign - const bool negative = value < 0; - if (negative) { - value = -value; - } - - // default precision - if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; - } - - // determine the decimal exponent - // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) - union { - uint64_t U; - double F; - } conv; - - conv.F = value; - int exp2 = (int)((conv.U >> 52u) & 0x07ffu) - 1023; // effectively log2 - conv.U = (conv.U & ((1ull << 52u) - 1u)) | (102ull << 52u); // drop the exponent so conv.F is now in [1,2) - // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 - int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); - // now we want to compute 10^expval but we want to be sure it won't overflow - exp2 = (int)(expval * 3.321928094887362 + 0.5); - const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - conv.U = (uint64_t)(exp2 + 1023) << 52u; - // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); - // correct for rounding errors - if (value < conv.F) { - expval--; - conv.F /= 10; - } - - // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters - unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4u : 5u; - - // in "%g" mode, "prec" is the number of *significant figures* not decimals - if (flags & KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP) { - // do we want to fall-back to "%f" mode? - if ((value >= 1e-4) && (value < 1e6)) { - if ((int)prec > expval) { - prec = (unsigned)((int)prec - expval - 1); - } else { - prec = 0; - } - flags |= KERNAUX_PRINTF_FMT_FLAGS_PRECISION; // make sure _ftoa respects precision - // no characters in exponent - minwidth = 0u; - expval = 0; - } else { - // we use one sigfig for the whole part - if ((prec > 0) && (flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) { - --prec; - } - } - } - - // will everything fit? - unsigned int fwidth = width; - if (width > minwidth) { - // we didn't fall-back so subtract the characters required for the exponent - fwidth -= minwidth; - } else { - // not enough characters, so go back to default sizing - fwidth = 0u; - } - if ((flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) && minwidth) { - // if we're padding on the right, DON'T pad the floating part - fwidth = 0u; - } - - // rescale the float value - if (expval) { - value /= conv.F; - } - - // output the floating part - const size_t start_idx = idx; - idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP); - - // output the exponent part - if (minwidth) { - // output the exponential symbol - out((flags & KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); - // output the exponent value - idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD | KERNAUX_PRINTF_FMT_FLAGS_PLUS); - // might need to right-pad spaces - if (flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) { - while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); - } - } - return idx; -} -#endif // ENABLE_FLOAT diff --git a/src/printf_fmt.c b/src/printf_fmt.c deleted file mode 100644 index 191ee36..0000000 --- a/src/printf_fmt.c +++ /dev/null @@ -1,349 +0,0 @@ -/** - * The code was taken from Marco Paland's printf. - * - * Copyright (c) 2014-2019 Marco Paland - * Copyright (c) 2021-2022 Alex Kotov - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "assert.h" - -#include - -#include -#include -#include -#include -#include - -typedef struct KernAux_PrintfFmt_Spec *Spec; - -static void parse_flags (Spec spec, const char **format); -static void parse_width (Spec spec, const char **format); -static void parse_precision(Spec spec, const char **format); -static void parse_length (Spec spec, const char **format); -static void parse_type (Spec spec, const char **format); - -static unsigned int _atoi(const char** str); - -/*********************************** - * Public function implementations * - ***********************************/ - -struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create_out( - const char **const format -) { - KERNAUX_NOTNULL(format); - - const struct KernAux_PrintfFmt_Spec spec = - KernAux_PrintfFmt_Spec_create(*format); - *format = spec.format_limit; - return spec; -} - -struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create_out_new( - const char *const format, - const char **const new_format -) { - KERNAUX_NOTNULL(format); - KERNAUX_NOTNULL(new_format); - - *new_format = NULL; - const struct KernAux_PrintfFmt_Spec spec = - KernAux_PrintfFmt_Spec_create(format); - *new_format = spec.format_limit; - return spec; -} - -struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create(const char *format) -{ - KERNAUX_NOTNULL(format); - - struct KernAux_PrintfFmt_Spec spec; - - spec.format_start = format; - - spec.flags = 0u; - spec.width = 0u; - spec.precision = 0u; - spec.type = KERNAUX_PRINTF_FMT_TYPE_NONE; - spec.base = 0; - - spec.set_width = false; - spec.set_precision = false; - - parse_flags(&spec, &format); - parse_width(&spec, &format); - parse_precision(&spec, &format); - parse_length(&spec, &format); - parse_type(&spec, &format); - - spec.format_limit = format; - - return spec; -} - -void KernAux_PrintfFmt_Spec_set_width(const Spec spec, const int width) -{ - KERNAUX_NOTNULL(spec); - - if (width < 0) { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LEFT; // reverse padding - spec->width = (unsigned int)-width; - } else { - spec->width = (unsigned int)width; - } -} - -void KernAux_PrintfFmt_Spec_set_precision(const Spec spec, const int precision) -{ - KERNAUX_NOTNULL(spec); - - spec->precision = precision > 0 ? (unsigned int)precision : 0u; -} - -/************************************ - * Private function implementations * - ************************************/ - -void parse_flags(const Spec spec, const char **const format) -{ - KERNAUX_NOTNULL(spec); - KERNAUX_NOTNULL(format); - KERNAUX_ASSERT(*format); - - bool running = true; - do { - switch (**format) { - case '0': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD; - ++(*format); - break; - case '-': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LEFT; - ++(*format); - break; - case '+': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_PLUS; - ++(*format); - break; - case ' ': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_SPACE; - ++(*format); - break; - case '#': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_HASH; - ++(*format); - break; - default: running = false; break; - } - } while (running); -} - -void parse_width(const Spec spec, const char **const format) -{ - KERNAUX_NOTNULL(spec); - KERNAUX_NOTNULL(format); - KERNAUX_ASSERT(*format); - - if (isdigit(**format)) { - spec->width = _atoi(format); - spec->set_width = false; - } else if (**format == '*') { - ++(*format); - spec->set_width = true; - } else { - spec->set_width = false; - } -} - -void parse_precision(const Spec spec, const char **const format) -{ - KERNAUX_NOTNULL(spec); - KERNAUX_NOTNULL(format); - KERNAUX_ASSERT(*format); - - if (**format == '.') { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_PRECISION; - ++(*format); - if (isdigit(**format)) { - spec->precision = _atoi(format); - spec->set_precision = false; - } else if (**format == '*') { - ++(*format); - spec->set_precision = true; - } else { - spec->set_precision = false; - } - } else { - spec->set_precision = false; - } -} - -void parse_length(const Spec spec, const char **const format) -{ - KERNAUX_NOTNULL(spec); - KERNAUX_NOTNULL(format); - KERNAUX_ASSERT(*format); - - switch (**format) { - case 'l': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG; - ++(*format); - if (**format == 'l') { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG; - ++(*format); - } - break; - case 'h': - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_SHORT; - ++(*format); - if (**format == 'h') { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_CHAR; - ++(*format); - } - break; - case 't': - if (sizeof(ptrdiff_t) == sizeof(long)) { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG; - } else { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG; - } - ++(*format); - break; - case 'j': - if (sizeof(ptrdiff_t) == sizeof(long)) { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG; - } else { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG; - } - ++(*format); - break; - case 'z': - if (sizeof(ptrdiff_t) == sizeof(long)) { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG; - } else { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG; - } - ++(*format); - break; - default: - break; - } -} - -void parse_type(const Spec spec, const char **const format) -{ - KERNAUX_NOTNULL(spec); - KERNAUX_NOTNULL(format); - KERNAUX_ASSERT(*format); - - switch (**format) { - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - case 'b': - // set the base - if (**format == 'x' || **format == 'X') { - spec->base = 16u; - } else if (**format == 'o') { - spec->base = 8u; - } else if (**format == 'b') { - spec->base = 2u; - } else { - spec->base = 10u; - // no hash for dec format - spec->flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; - } - // uppercase - if (**format == 'X') { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE; - } - - // no plus or space flag for u, x, X, o, b - if ((**format != 'i') && (**format != 'd')) { - spec->flags &= ~(KERNAUX_PRINTF_FMT_FLAGS_PLUS | - KERNAUX_PRINTF_FMT_FLAGS_SPACE); - } - - // ignore '0' flag when precision is given - if (spec->flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) { - spec->flags &= ~KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD; - } - - // convert the integer - if ((**format == 'i') || (**format == 'd')) { - spec->type = KERNAUX_PRINTF_FMT_TYPE_INT; - } else { - spec->type = KERNAUX_PRINTF_FMT_TYPE_UINT; - } - ++(*format); - break; - -#ifdef ENABLE_FLOAT - case 'f': - case 'F': - if (**format == 'F') { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE; - } - spec->type = KERNAUX_PRINTF_FMT_TYPE_FLOAT; - ++(*format); - break; - - case 'e': - case 'E': - case 'g': - case 'G': - if ((**format == 'g') || (**format == 'G')) { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP; - } - if ((**format == 'E') || (**format == 'G')) { - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE; - } - spec->type = KERNAUX_PRINTF_FMT_TYPE_EXP; - ++(*format); - break; -#endif // ENABLE_FLOAT - - case 'c': - spec->type = KERNAUX_PRINTF_FMT_TYPE_CHAR; - ++(*format); - break; - - case 's': - spec->type = KERNAUX_PRINTF_FMT_TYPE_STR; - ++(*format); - break; - - case 'p': - spec->width = sizeof(void*) * 2u; - spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD | - KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE; - spec->type = KERNAUX_PRINTF_FMT_TYPE_PTR; - ++(*format); - break; - - case '%': - spec->type = KERNAUX_PRINTF_FMT_TYPE_PERCENT; - ++(*format); - break; - - default: - spec->type = KERNAUX_PRINTF_FMT_TYPE_NONE; - break; - } -} - -// internal ASCII string to unsigned int conversion -unsigned int _atoi(const char** str) -{ - const int result = atoi(*str); - while (isdigit(**str)) (*str)++; - return result; -} diff --git a/tests/.gitignore b/tests/.gitignore index 610f6d1..170b7e4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -6,5 +6,4 @@ /test_ntoa_assert /test_pfa /test_pfa_assert -/test_printf /test_units_human diff --git a/tests/Makefile.am b/tests/Makefile.am index 3a92491..fd8ecce 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -104,18 +104,6 @@ test_pfa_assert_SOURCES = \ endif endif -############### -# test_printf # -############### - -if WITH_PRINTF -TESTS += test_printf -test_printf_LDADD = $(top_builddir)/libkernaux.la -test_printf_SOURCES = \ - main.c \ - test_printf.c -endif - #################### # test_units_human # #################### diff --git a/tests/test_printf.c b/tests/test_printf.c deleted file mode 100644 index 75f8ec5..0000000 --- a/tests/test_printf.c +++ /dev/null @@ -1,34 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include - -void test_main() -{ - char buffer[1000]; - - // Sanity check - { - memset(buffer, 0xff, sizeof(buffer)); - const int result = - kernaux_snprintf(buffer, sizeof(buffer), "%s", "Hello, World!"); - fprintf(stderr, "%d:%s\n", result, buffer); - assert(result == 13); - assert(strcmp(buffer, "Hello, World!") == 0); - } - - // i386 requires "(long long)0" instead of just "0" - { - memset(buffer, 0xff, sizeof(buffer)); - const int result = - kernaux_snprintf(buffer, sizeof(buffer), "%#.0llx", (long long)0); - fprintf(stderr, "%d:%s\n", result, buffer); - assert(result == 0); - assert(strcmp(buffer, "") == 0); - } -}