mirror of https://github.com/tailix/libkernaux.git
Main: include/kernaux/printf_fmt.h: Auxiliary API moved to a separate module
This commit is contained in:
parent
5c607ca9bd
commit
fc01ec69ac
|
@ -1,3 +1,7 @@
|
|||
2022-05-27 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
* include/kernaux/printf_fmt.h: Auxiliary API moved to a separate module
|
||||
|
||||
2022-05-24 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
* src/multiboot2/info_is_valid.c: Fix division by zero
|
||||
|
|
|
@ -138,6 +138,10 @@ TESTS += tests/test_printf_gen
|
|||
endif
|
||||
endif
|
||||
|
||||
if WITH_PRINTF
|
||||
libkernaux_a_SOURCES += src/printf_fmt.c
|
||||
endif
|
||||
|
||||
if WITH_UNITS
|
||||
libkernaux_a_SOURCES += src/units.c
|
||||
if ENABLE_TESTS
|
||||
|
|
|
@ -61,6 +61,8 @@ zero). Work-in-progress APIs can change at any time.
|
|||
* Utilities
|
||||
* [Measurement units utils](/include/kernaux/units.h) (*work in progress*)
|
||||
* [To human](/examples/units_human.c)
|
||||
* [printf format parser](/include/kernaux/printf_fmt.h)
|
||||
* Code from [https://github.com/mpaland/printf](https://github.com/mpaland/printf). Thank you!
|
||||
* Usual functions
|
||||
* [libc replacement](/include/kernaux/libc.h) (*stable since* **0.1.0**)
|
||||
* [itoa/ftoa replacement](/include/kernaux/ntoa.h) (*stable since* **0.1.0**)
|
||||
|
|
11
configure.ac
11
configure.ac
|
@ -39,6 +39,7 @@ AC_ARG_WITH( [multiboot2], AS_HELP_STRING([--without-multiboot2], [without M
|
|||
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)
|
||||
|
@ -75,6 +76,7 @@ if test -z "$with_multiboot2"; then with_multiboot2=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)
|
||||
|
@ -119,6 +121,7 @@ AS_IF([test "$with_multiboot2" = no ], [with_multiboot2=no], [with_mult
|
|||
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)
|
||||
|
@ -138,8 +141,9 @@ AS_IF([test "$with_libc_strnlen" = yes], [with_libc_strnlen=yes], [with_libc
|
|||
#############
|
||||
|
||||
AS_IF([test "$enable_tests" = yes -a "$host_cpu" != "$build_cpu"], AC_MSG_ERROR([can not build cross-platform tests]))
|
||||
AS_IF([test "$with_printf" = yes -a "$with_ntoa" = no ], AC_MSG_ERROR([package `printf' requires package `ntoa']))
|
||||
AS_IF([test "$with_units" = yes -a "$with_ntoa" = no ], AC_MSG_ERROR([package `units' requires package `ntoa']))
|
||||
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']))
|
||||
|
||||
|
||||
|
||||
|
@ -172,6 +176,7 @@ AM_CONDITIONAL([WITH_MULTIBOOT2], [test "$with_multiboot2" = 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)
|
||||
|
@ -214,6 +219,7 @@ AS_IF([test "$with_multiboot2" = yes], [AC_DEFINE([WITH_MULTIBOOT2], [1]
|
|||
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)
|
||||
|
@ -246,6 +252,7 @@ AS_IF([test "$with_multiboot2" = no], [AC_SUBST([comment_line_multiboot2], [
|
|||
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], [//])])
|
||||
|
||||
dnl Packages (disabled by default)
|
||||
|
|
|
@ -43,6 +43,9 @@ endif
|
|||
if WITH_PRINTF
|
||||
nobase_include_HEADERS += kernaux/printf.h
|
||||
endif
|
||||
if WITH_PRINTF_FMT
|
||||
nobase_include_HEADERS += kernaux/printf_fmt.h
|
||||
endif
|
||||
if WITH_UNITS
|
||||
nobase_include_HEADERS += kernaux/units.h
|
||||
endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
@comment_line_ntoa@#include <kernaux/ntoa.h>
|
||||
@comment_line_pfa@#include <kernaux/pfa.h>
|
||||
@comment_line_printf@#include <kernaux/printf.h>
|
||||
@comment_line_printf_fmt@#include <kernaux/printf_fmt.h>
|
||||
@comment_line_units@#include <kernaux/units.h>
|
||||
|
||||
#include <kernaux/arch/i386.h>
|
||||
|
|
|
@ -6,7 +6,6 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
|
@ -42,40 +41,6 @@ int kernaux_vsnprintf(char* buffer, size_t count, const char* format, va_list va
|
|||
*/
|
||||
int kernaux_sprintf(char* buffer, const char* format, ...);
|
||||
|
||||
/*****************
|
||||
* Auxiliary API *
|
||||
*****************/
|
||||
|
||||
#define KERNAUX_PRINTF_FLAGS_ZEROPAD (1u << 0u)
|
||||
#define KERNAUX_PRINTF_FLAGS_LEFT (1u << 1u)
|
||||
#define KERNAUX_PRINTF_FLAGS_PLUS (1u << 2u)
|
||||
#define KERNAUX_PRINTF_FLAGS_SPACE (1u << 3u)
|
||||
#define KERNAUX_PRINTF_FLAGS_HASH (1u << 4u)
|
||||
#define KERNAUX_PRINTF_FLAGS_UPPERCASE (1u << 5u)
|
||||
#define KERNAUX_PRINTF_FLAGS_CHAR (1u << 6u)
|
||||
#define KERNAUX_PRINTF_FLAGS_SHORT (1u << 7u)
|
||||
#define KERNAUX_PRINTF_FLAGS_LONG (1u << 8u)
|
||||
#define KERNAUX_PRINTF_FLAGS_LONG_LONG (1u << 9u)
|
||||
#define KERNAUX_PRINTF_FLAGS_PRECISION (1u << 10u)
|
||||
#define KERNAUX_PRINTF_FLAGS_ADAPT_EXP (1u << 11u)
|
||||
#define KERNAUX_PRINTF_FLAGS_CUSTOM (1u << 12u)
|
||||
|
||||
struct KernAux_Printf_Spec {
|
||||
unsigned int flags;
|
||||
unsigned int width;
|
||||
unsigned int precision;
|
||||
};
|
||||
|
||||
struct KernAux_Printf_Spec KernAux_Printf_Spec_create();
|
||||
void KernAux_Printf_Spec_init(struct KernAux_Printf_Spec *spec);
|
||||
|
||||
void KernAux_Printf_Spec_eval_flags(struct KernAux_Printf_Spec *spec, const char **format);
|
||||
bool KernAux_Printf_Spec_eval_width1(struct KernAux_Printf_Spec *spec, const char **format);
|
||||
void KernAux_Printf_Spec_eval_width2(struct KernAux_Printf_Spec *spec, const char **format, int w);
|
||||
bool KernAux_Printf_Spec_eval_precision1(struct KernAux_Printf_Spec *spec, const char **format);
|
||||
void KernAux_Printf_Spec_eval_precision2(struct KernAux_Printf_Spec *spec, const char **format, int prec);
|
||||
void KernAux_Printf_Spec_eval_length(struct KernAux_Printf_Spec *spec, const char **format);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef KERNAUX_INCLUDED_PRINTF_FMT
|
||||
#define KERNAUX_INCLUDED_PRINTF_FMT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD (1u << 0u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_LEFT (1u << 1u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_PLUS (1u << 2u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_SPACE (1u << 3u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_HASH (1u << 4u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE (1u << 5u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_CHAR (1u << 6u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_SHORT (1u << 7u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_LONG (1u << 8u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG (1u << 9u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_PRECISION (1u << 10u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP (1u << 11u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_CUSTOM (1u << 12u)
|
||||
|
||||
struct KernAux_PrintfFmt_Spec {
|
||||
unsigned int flags;
|
||||
unsigned int width;
|
||||
unsigned int precision;
|
||||
};
|
||||
|
||||
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create();
|
||||
void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *spec);
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_flags(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
||||
bool KernAux_PrintfFmt_Spec_eval_width1(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
||||
void KernAux_PrintfFmt_Spec_eval_width2(struct KernAux_PrintfFmt_Spec *spec, const char **format, int w);
|
||||
bool KernAux_PrintfFmt_Spec_eval_precision1(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
||||
void KernAux_PrintfFmt_Spec_eval_precision2(struct KernAux_PrintfFmt_Spec *spec, const char **format, int prec);
|
||||
void KernAux_PrintfFmt_Spec_eval_length(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
282
src/printf.c
282
src/printf.c
|
@ -13,9 +13,9 @@
|
|||
#include <kernaux/assert.h>
|
||||
#include <kernaux/libc.h>
|
||||
#include <kernaux/printf.h>
|
||||
#include <kernaux/printf_fmt.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// import float.h for DBL_MAX
|
||||
|
@ -51,7 +51,6 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const
|
|||
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 unsigned int _atoi(const char** str);
|
||||
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);
|
||||
|
@ -124,155 +123,6 @@ int kernaux_sprintf(char* buffer, const char* format, ...)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Implementations: auxiliary API *
|
||||
**********************************/
|
||||
|
||||
struct KernAux_Printf_Spec KernAux_Printf_Spec_create()
|
||||
{
|
||||
struct KernAux_Printf_Spec spec;
|
||||
KernAux_Printf_Spec_init(&spec);
|
||||
return spec;
|
||||
}
|
||||
|
||||
void KernAux_Printf_Spec_init(struct KernAux_Printf_Spec *const spec)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
|
||||
spec->flags = 0u;
|
||||
spec->width = 0u;
|
||||
spec->precision = 0u;
|
||||
}
|
||||
|
||||
void KernAux_Printf_Spec_eval_flags(struct KernAux_Printf_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*format);
|
||||
|
||||
bool running = true;
|
||||
do {
|
||||
switch (**format) {
|
||||
case '0': spec->flags |= KERNAUX_PRINTF_FLAGS_ZEROPAD; ++(*format); break;
|
||||
case '-': spec->flags |= KERNAUX_PRINTF_FLAGS_LEFT; ++(*format); break;
|
||||
case '+': spec->flags |= KERNAUX_PRINTF_FLAGS_PLUS; ++(*format); break;
|
||||
case ' ': spec->flags |= KERNAUX_PRINTF_FLAGS_SPACE; ++(*format); break;
|
||||
case '#': spec->flags |= KERNAUX_PRINTF_FLAGS_HASH; ++(*format); break;
|
||||
default: running = false; break;
|
||||
}
|
||||
} while (running);
|
||||
}
|
||||
|
||||
bool KernAux_Printf_Spec_eval_width1(struct KernAux_Printf_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETVAL(spec, false);
|
||||
KERNAUX_NOTNULL_RETVAL(format, false);
|
||||
KERNAUX_NOTNULL_RETVAL(*format, false);
|
||||
|
||||
if (isdigit(**format)) {
|
||||
spec->width = _atoi(format);
|
||||
return false;
|
||||
} else {
|
||||
return **format == '*';
|
||||
}
|
||||
}
|
||||
|
||||
void KernAux_Printf_Spec_eval_width2(struct KernAux_Printf_Spec *const spec, const char **const format, const int w)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*format);
|
||||
|
||||
if (w < 0) {
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_LEFT; // reverse padding
|
||||
spec->width = (unsigned int)-w;
|
||||
} else {
|
||||
spec->width = (unsigned int)w;
|
||||
}
|
||||
|
||||
++(*format);
|
||||
}
|
||||
|
||||
bool KernAux_Printf_Spec_eval_precision1(struct KernAux_Printf_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETVAL(spec, false);
|
||||
KERNAUX_NOTNULL_RETVAL(format, false);
|
||||
KERNAUX_NOTNULL_RETVAL(*format, false);
|
||||
|
||||
if (**format == '.') {
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_PRECISION;
|
||||
++(*format);
|
||||
if (isdigit(**format)) {
|
||||
spec->precision = _atoi(format);
|
||||
return false;
|
||||
} else {
|
||||
return **format == '*';
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void KernAux_Printf_Spec_eval_precision2(struct KernAux_Printf_Spec *const spec, const char **const format, const int prec)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*format);
|
||||
|
||||
spec->precision = prec > 0 ? (unsigned int)prec : 0u;
|
||||
++(*format);
|
||||
}
|
||||
|
||||
void KernAux_Printf_Spec_eval_length(struct KernAux_Printf_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*format);
|
||||
|
||||
switch (**format) {
|
||||
case 'l':
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_LONG;
|
||||
++(*format);
|
||||
if (**format == 'l') {
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_LONG_LONG;
|
||||
++(*format);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_SHORT;
|
||||
++(*format);
|
||||
if (**format == 'h') {
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_CHAR;
|
||||
++(*format);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
spec->flags |= (sizeof(ptrdiff_t) == sizeof(long) ? KERNAUX_PRINTF_FLAGS_LONG : KERNAUX_PRINTF_FLAGS_LONG_LONG);
|
||||
++(*format);
|
||||
break;
|
||||
case 'j':
|
||||
spec->flags |= (sizeof(intmax_t) == sizeof(long) ? KERNAUX_PRINTF_FLAGS_LONG : KERNAUX_PRINTF_FLAGS_LONG_LONG);
|
||||
++(*format);
|
||||
break;
|
||||
case 'z':
|
||||
spec->flags |= (sizeof(size_t) == sizeof(long) ? KERNAUX_PRINTF_FLAGS_LONG : KERNAUX_PRINTF_FLAGS_LONG_LONG);
|
||||
++(*format);
|
||||
break;
|
||||
#ifdef ENABLE_BLOAT
|
||||
case 'S':
|
||||
if (*(++(*format)) == 'U') {
|
||||
spec->flags |= KERNAUX_PRINTF_FLAGS_CUSTOM;
|
||||
++(*format);
|
||||
} else {
|
||||
--(*format);
|
||||
}
|
||||
break;
|
||||
#endif // ENABLE_BLOAT
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Implementation: main internal function *
|
||||
******************************************/
|
||||
|
@ -301,19 +151,19 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
format++;
|
||||
}
|
||||
|
||||
struct KernAux_Printf_Spec spec = KernAux_Printf_Spec_create();
|
||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
||||
|
||||
KernAux_Printf_Spec_eval_flags(&spec, &format);
|
||||
KernAux_PrintfFmt_Spec_eval_flags(&spec, &format);
|
||||
|
||||
if (KernAux_Printf_Spec_eval_width1(&spec, &format)) {
|
||||
KernAux_Printf_Spec_eval_width2(&spec, &format, va_arg(va, int));
|
||||
if (KernAux_PrintfFmt_Spec_eval_width1(&spec, &format)) {
|
||||
KernAux_PrintfFmt_Spec_eval_width2(&spec, &format, va_arg(va, int));
|
||||
}
|
||||
|
||||
if (KernAux_Printf_Spec_eval_precision1(&spec, &format)) {
|
||||
KernAux_Printf_Spec_eval_precision2(&spec, &format, va_arg(va, int));
|
||||
if (KernAux_PrintfFmt_Spec_eval_precision1(&spec, &format)) {
|
||||
KernAux_PrintfFmt_Spec_eval_precision2(&spec, &format, va_arg(va, int));
|
||||
}
|
||||
|
||||
KernAux_Printf_Spec_eval_length(&spec, &format);
|
||||
KernAux_PrintfFmt_Spec_eval_length(&spec, &format);
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
|
@ -335,44 +185,44 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
base = 2u;
|
||||
} else {
|
||||
base = 10u;
|
||||
spec.flags &= ~KERNAUX_PRINTF_FLAGS_HASH; // no hash for dec format
|
||||
spec.flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// uppercase
|
||||
if (*format == 'X') {
|
||||
spec.flags |= KERNAUX_PRINTF_FLAGS_UPPERCASE;
|
||||
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_FLAGS_PLUS | KERNAUX_PRINTF_FLAGS_SPACE);
|
||||
spec.flags &= ~(KERNAUX_PRINTF_FMT_FLAGS_PLUS | KERNAUX_PRINTF_FMT_FLAGS_SPACE);
|
||||
}
|
||||
|
||||
// ignore '0' flag when precision is given
|
||||
if (spec.flags & KERNAUX_PRINTF_FLAGS_PRECISION) {
|
||||
spec.flags &= ~KERNAUX_PRINTF_FLAGS_ZEROPAD;
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) {
|
||||
spec.flags &= ~KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
// convert the integer
|
||||
if ((*format == 'i') || (*format == 'd')) {
|
||||
// signed
|
||||
if (spec.flags & KERNAUX_PRINTF_FLAGS_LONG_LONG) {
|
||||
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, base, spec.precision, spec.width, spec.flags);
|
||||
} else if (spec.flags & KERNAUX_PRINTF_FLAGS_LONG) {
|
||||
} 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, base, spec.precision, spec.width, spec.flags);
|
||||
} else {
|
||||
const int value = (spec.flags & KERNAUX_PRINTF_FLAGS_CHAR) ? (char)va_arg(va, int) : (spec.flags & KERNAUX_PRINTF_FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
|
||||
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, base, spec.precision, spec.width, spec.flags);
|
||||
}
|
||||
} else {
|
||||
// unsigned
|
||||
if (spec.flags & KERNAUX_PRINTF_FLAGS_LONG_LONG) {
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG) {
|
||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, spec.precision, spec.width, spec.flags);
|
||||
} else if (spec.flags & KERNAUX_PRINTF_FLAGS_LONG) {
|
||||
} else if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LONG) {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, spec.precision, spec.width, spec.flags);
|
||||
} else {
|
||||
const unsigned int value = (spec.flags & KERNAUX_PRINTF_FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (spec.flags & KERNAUX_PRINTF_FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
|
||||
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, base, spec.precision, spec.width, spec.flags);
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +232,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
#ifdef ENABLE_FLOAT
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (*format == 'F') spec.flags |= KERNAUX_PRINTF_FLAGS_UPPERCASE;
|
||||
if (*format == 'F') spec.flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), spec.precision, spec.width, spec.flags);
|
||||
format++;
|
||||
break;
|
||||
|
@ -390,8 +240,8 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if ((*format == 'g')||(*format == 'G')) spec.flags |= KERNAUX_PRINTF_FLAGS_ADAPT_EXP;
|
||||
if ((*format == 'E')||(*format == 'G')) spec.flags |= KERNAUX_PRINTF_FLAGS_UPPERCASE;
|
||||
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;
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), spec.precision, spec.width, spec.flags);
|
||||
format++;
|
||||
break;
|
||||
|
@ -400,7 +250,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
{
|
||||
unsigned int l = 1u;
|
||||
// pre padding
|
||||
if (!(spec.flags & KERNAUX_PRINTF_FLAGS_LEFT)) {
|
||||
if (!(spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT)) {
|
||||
while (l++ < spec.width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
|
@ -408,7 +258,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
// char output
|
||||
out((char)va_arg(va, int), buffer, idx++, maxlen);
|
||||
// post padding
|
||||
if (spec.flags & KERNAUX_PRINTF_FLAGS_LEFT) {
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) {
|
||||
while (l++ < spec.width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
|
@ -422,20 +272,20 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
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_FLAGS_PRECISION) {
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) {
|
||||
l = (l < spec.precision ? l : spec.precision);
|
||||
}
|
||||
if (!(spec.flags & KERNAUX_PRINTF_FLAGS_LEFT)) {
|
||||
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_FLAGS_PRECISION) || spec.precision--)) {
|
||||
while ((*p != 0) && (!(spec.flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) || spec.precision--)) {
|
||||
out(*(p++), buffer, idx++, maxlen);
|
||||
}
|
||||
// post padding
|
||||
if (spec.flags & KERNAUX_PRINTF_FLAGS_LEFT) {
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) {
|
||||
while (l++ < spec.width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
|
@ -446,7 +296,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
|
||||
#ifdef ENABLE_BLOAT
|
||||
case 'S':
|
||||
if (spec.flags & KERNAUX_PRINTF_FLAGS_CUSTOM) {
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_CUSTOM) {
|
||||
format++;
|
||||
size_t index = 0;
|
||||
char c;
|
||||
|
@ -460,7 +310,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
case 'p':
|
||||
{
|
||||
spec.width = sizeof(void*) * 2u;
|
||||
spec.flags |= KERNAUX_PRINTF_FLAGS_ZEROPAD | KERNAUX_PRINTF_FLAGS_UPPERCASE;
|
||||
spec.flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD | KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||
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);
|
||||
|
@ -518,21 +368,13 @@ void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
|
|||
}
|
||||
}
|
||||
|
||||
// internal ASCII string to unsigned int conversion
|
||||
unsigned int _atoi(const char** str)
|
||||
{
|
||||
const int result = atoi(*str);
|
||||
while (isdigit(**str)) (*str)++;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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_FLAGS_LEFT) && !(flags & KERNAUX_PRINTF_FLAGS_ZEROPAD)) {
|
||||
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);
|
||||
}
|
||||
|
@ -544,7 +386,7 @@ size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const
|
|||
}
|
||||
|
||||
// append pad spaces up to given width
|
||||
if (flags & KERNAUX_PRINTF_FLAGS_LEFT) {
|
||||
if (flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) {
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
|
@ -557,29 +399,29 @@ size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const
|
|||
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_FLAGS_LEFT)) {
|
||||
if (width && (flags & KERNAUX_PRINTF_FLAGS_ZEROPAD) && (negative || (flags & (KERNAUX_PRINTF_FLAGS_PLUS | KERNAUX_PRINTF_FLAGS_SPACE)))) {
|
||||
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_FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
while ((flags & KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
// handle hash
|
||||
if (flags & KERNAUX_PRINTF_FLAGS_HASH) {
|
||||
if (!(flags & KERNAUX_PRINTF_FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
|
||||
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_FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
if ((base == 16u) && !(flags & KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = 'x';
|
||||
} else if ((base == 16u) && (flags & KERNAUX_PRINTF_FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
} 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';
|
||||
|
@ -592,9 +434,9 @@ size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, c
|
|||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & KERNAUX_PRINTF_FLAGS_PLUS) {
|
||||
} else if (flags & KERNAUX_PRINTF_FMT_FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & KERNAUX_PRINTF_FLAGS_SPACE) {
|
||||
} else if (flags & KERNAUX_PRINTF_FMT_FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
@ -610,14 +452,14 @@ size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, uns
|
|||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~KERNAUX_PRINTF_FLAGS_HASH;
|
||||
flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & KERNAUX_PRINTF_FLAGS_PRECISION) || value) {
|
||||
if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & KERNAUX_PRINTF_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
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));
|
||||
}
|
||||
|
@ -633,14 +475,14 @@ size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen
|
|||
|
||||
// no hash for 0 values
|
||||
if (!value) {
|
||||
flags &= ~KERNAUX_PRINTF_FLAGS_HASH;
|
||||
flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH;
|
||||
}
|
||||
|
||||
// write if precision != 0 and value is != 0
|
||||
if (!(flags & KERNAUX_PRINTF_FLAGS_PRECISION) || value) {
|
||||
if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION) || value) {
|
||||
do {
|
||||
const char digit = (char)(value % base);
|
||||
buf[len++] = digit < 10 ? '0' + digit : (flags & KERNAUX_PRINTF_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||
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));
|
||||
}
|
||||
|
@ -715,7 +557,7 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
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_FLAGS_PLUS) ? "fni+" : "fni", (flags & KERNAUX_PRINTF_FLAGS_PLUS) ? 4u : 3u, width, flags);
|
||||
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
|
||||
|
@ -731,7 +573,7 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
}
|
||||
|
||||
// set default precision, if not set explicitly
|
||||
if (!(flags & KERNAUX_PRINTF_FLAGS_PRECISION)) {
|
||||
if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||
|
@ -795,8 +637,8 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
}
|
||||
|
||||
// pad leading zeros
|
||||
if (!(flags & KERNAUX_PRINTF_FLAGS_LEFT) && (flags & KERNAUX_PRINTF_FLAGS_ZEROPAD)) {
|
||||
if (width && (negative || (flags & (KERNAUX_PRINTF_FLAGS_PLUS | KERNAUX_PRINTF_FLAGS_SPACE)))) {
|
||||
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)) {
|
||||
|
@ -807,9 +649,9 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & KERNAUX_PRINTF_FLAGS_PLUS) {
|
||||
} else if (flags & KERNAUX_PRINTF_FMT_FLAGS_PLUS) {
|
||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||
} else if (flags & KERNAUX_PRINTF_FLAGS_SPACE) {
|
||||
} else if (flags & KERNAUX_PRINTF_FMT_FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +674,7 @@ size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
}
|
||||
|
||||
// default precision
|
||||
if (!(flags & KERNAUX_PRINTF_FLAGS_PRECISION)) {
|
||||
if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) {
|
||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
|
@ -865,7 +707,7 @@ size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
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_FLAGS_ADAPT_EXP) {
|
||||
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) {
|
||||
|
@ -873,13 +715,13 @@ size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
} else {
|
||||
prec = 0;
|
||||
}
|
||||
flags |= KERNAUX_PRINTF_FLAGS_PRECISION; // make sure _ftoa respects precision
|
||||
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_FLAGS_PRECISION)) {
|
||||
if ((prec > 0) && (flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) {
|
||||
--prec;
|
||||
}
|
||||
}
|
||||
|
@ -894,7 +736,7 @@ size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
// not enough characters, so go back to default sizing
|
||||
fwidth = 0u;
|
||||
}
|
||||
if ((flags & KERNAUX_PRINTF_FLAGS_LEFT) && minwidth) {
|
||||
if ((flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) && minwidth) {
|
||||
// if we're padding on the right, DON'T pad the floating part
|
||||
fwidth = 0u;
|
||||
}
|
||||
|
@ -906,16 +748,16 @@ size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
|||
|
||||
// output the floating part
|
||||
const size_t start_idx = idx;
|
||||
idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~KERNAUX_PRINTF_FLAGS_ADAPT_EXP);
|
||||
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_FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
|
||||
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_FLAGS_ZEROPAD | KERNAUX_PRINTF_FLAGS_PLUS);
|
||||
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_FLAGS_LEFT) {
|
||||
if (flags & KERNAUX_PRINTF_FMT_FLAGS_LEFT) {
|
||||
while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* Copyright (c) 2014-2019 Marco Paland <info@paland.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <kernaux/assert.h>
|
||||
#include <kernaux/libc.h>
|
||||
#include <kernaux/printf_fmt.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static unsigned int _atoi(const char** str);
|
||||
|
||||
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create()
|
||||
{
|
||||
struct KernAux_PrintfFmt_Spec spec;
|
||||
KernAux_PrintfFmt_Spec_init(&spec);
|
||||
return spec;
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *const spec)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
|
||||
spec->flags = 0u;
|
||||
spec->width = 0u;
|
||||
spec->precision = 0u;
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_flags(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*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);
|
||||
}
|
||||
|
||||
bool KernAux_PrintfFmt_Spec_eval_width1(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETVAL(spec, false);
|
||||
KERNAUX_NOTNULL_RETVAL(format, false);
|
||||
KERNAUX_NOTNULL_RETVAL(*format, false);
|
||||
|
||||
if (isdigit(**format)) {
|
||||
spec->width = _atoi(format);
|
||||
return false;
|
||||
} else {
|
||||
return **format == '*';
|
||||
}
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_width2(struct KernAux_PrintfFmt_Spec *const spec, const char **const format, const int w)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*format);
|
||||
|
||||
if (w < 0) {
|
||||
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LEFT; // reverse padding
|
||||
spec->width = (unsigned int)-w;
|
||||
} else {
|
||||
spec->width = (unsigned int)w;
|
||||
}
|
||||
|
||||
++(*format);
|
||||
}
|
||||
|
||||
bool KernAux_PrintfFmt_Spec_eval_precision1(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETVAL(spec, false);
|
||||
KERNAUX_NOTNULL_RETVAL(format, false);
|
||||
KERNAUX_NOTNULL_RETVAL(*format, false);
|
||||
|
||||
if (**format == '.') {
|
||||
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_PRECISION;
|
||||
++(*format);
|
||||
if (isdigit(**format)) {
|
||||
spec->precision = _atoi(format);
|
||||
return false;
|
||||
} else {
|
||||
return **format == '*';
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_precision2(struct KernAux_PrintfFmt_Spec *const spec, const char **const format, const int prec)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*format);
|
||||
|
||||
spec->precision = prec > 0 ? (unsigned int)prec : 0u;
|
||||
++(*format);
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_length(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETURN(spec);
|
||||
KERNAUX_NOTNULL_RETURN(format);
|
||||
KERNAUX_NOTNULL_RETURN(*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':
|
||||
spec->flags |= (sizeof(ptrdiff_t) == sizeof(long) ? KERNAUX_PRINTF_FMT_FLAGS_LONG : KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG);
|
||||
++(*format);
|
||||
break;
|
||||
case 'j':
|
||||
spec->flags |= (sizeof(intmax_t) == sizeof(long) ? KERNAUX_PRINTF_FMT_FLAGS_LONG : KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG);
|
||||
++(*format);
|
||||
break;
|
||||
case 'z':
|
||||
spec->flags |= (sizeof(size_t) == sizeof(long) ? KERNAUX_PRINTF_FMT_FLAGS_LONG : KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG);
|
||||
++(*format);
|
||||
break;
|
||||
#ifdef ENABLE_BLOAT
|
||||
case 'S':
|
||||
if (*(++(*format)) == 'U') {
|
||||
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_CUSTOM;
|
||||
++(*format);
|
||||
} else {
|
||||
--(*format);
|
||||
}
|
||||
break;
|
||||
#endif // ENABLE_BLOAT
|
||||
default:
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue