mirror of
https://github.com/tailix/libkernaux.git
synced 2026-08-15 11:00:07 -04:00
Main: include/kernaux/printf_fmt.h: Add function to parse type
This commit is contained in:
parent
c035485706
commit
841d6991e7
4 changed files with 161 additions and 85 deletions
|
|
@ -1,6 +1,7 @@
|
|||
2022-05-27 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
* include/kernaux/printf_fmt.h: Auxiliary API moved to a separate module
|
||||
* include/kernaux/printf_fmt.h: Add function to parse type
|
||||
|
||||
2022-05-24 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,26 @@ extern "C" {
|
|||
#define KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP (1u << 11u)
|
||||
#define KERNAUX_PRINTF_FMT_FLAGS_CUSTOM (1u << 12u)
|
||||
|
||||
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_CUSTOM,
|
||||
KERNAUX_PRINTF_FMT_TYPE_PTR,
|
||||
KERNAUX_PRINTF_FMT_TYPE_PERCENT,
|
||||
};
|
||||
|
||||
struct KernAux_PrintfFmt_Spec {
|
||||
unsigned int flags;
|
||||
unsigned int width;
|
||||
unsigned int precision;
|
||||
enum KernAux_PrintfFmt_Type type;
|
||||
|
||||
unsigned int base;
|
||||
};
|
||||
|
||||
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create();
|
||||
|
|
@ -36,6 +52,7 @@ void KernAux_PrintfFmt_Spec_eval_width2(struct KernAux_PrintfFmt_Spec *spec, con
|
|||
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);
|
||||
void KernAux_PrintfFmt_Spec_eval_type(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
120
src/printf.c
120
src/printf.c
|
|
@ -165,88 +165,45 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
|
||||
KernAux_PrintfFmt_Spec_eval_length(&spec, &format);
|
||||
|
||||
KernAux_PrintfFmt_Spec_eval_type(&spec, &format);
|
||||
|
||||
// evaluate specifier
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'o':
|
||||
case 'b':
|
||||
{
|
||||
// set the base
|
||||
unsigned int base;
|
||||
if (*format == 'x' || *format == 'X') {
|
||||
base = 16u;
|
||||
} else if (*format == 'o') {
|
||||
base = 8u;
|
||||
} else if (*format == 'b') {
|
||||
base = 2u;
|
||||
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 {
|
||||
base = 10u;
|
||||
spec.flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; // no hash for dec format
|
||||
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);
|
||||
}
|
||||
// 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')) {
|
||||
// signed
|
||||
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_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_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_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_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_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);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
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 'f':
|
||||
case 'F':
|
||||
if (*format == 'F') spec.flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
||||
case KERNAUX_PRINTF_FMT_TYPE_FLOAT:
|
||||
idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), spec.precision, spec.width, spec.flags);
|
||||
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;
|
||||
|
||||
case KERNAUX_PRINTF_FMT_TYPE_EXP:
|
||||
idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), spec.precision, spec.width, spec.flags);
|
||||
format++;
|
||||
break;
|
||||
#endif // ENABLE_FLOAT
|
||||
case 'c':
|
||||
|
||||
case KERNAUX_PRINTF_FMT_TYPE_CHAR:
|
||||
{
|
||||
unsigned int l = 1u;
|
||||
// pre padding
|
||||
|
|
@ -263,11 +220,10 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's':
|
||||
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);
|
||||
|
|
@ -290,14 +246,12 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BLOAT
|
||||
case 'S':
|
||||
if (spec.flags & KERNAUX_PRINTF_FMT_FLAGS_CUSTOM) {
|
||||
format++;
|
||||
case KERNAUX_PRINTF_FMT_TYPE_CUSTOM:
|
||||
{
|
||||
size_t index = 0;
|
||||
char c;
|
||||
while ((c = _custom(spec.flags, &index))) {
|
||||
|
|
@ -307,28 +261,24 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
|||
break;
|
||||
#endif // ENABLE_BLOAT
|
||||
|
||||
case 'p':
|
||||
case KERNAUX_PRINTF_FMT_TYPE_PTR:
|
||||
{
|
||||
spec.width = sizeof(void*) * 2u;
|
||||
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);
|
||||
} else {
|
||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16u, spec.precision, spec.width, spec.flags);
|
||||
}
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
|
||||
case '%':
|
||||
case KERNAUX_PRINTF_FMT_TYPE_PERCENT:
|
||||
out('%', buffer, idx++, maxlen);
|
||||
format++;
|
||||
break;
|
||||
|
||||
default:
|
||||
out(*format, buffer, idx++, maxlen);
|
||||
format++;
|
||||
++format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
108
src/printf_fmt.c
108
src/printf_fmt.c
|
|
@ -30,6 +30,9 @@ void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *const spec)
|
|||
spec->flags = 0u;
|
||||
spec->width = 0u;
|
||||
spec->precision = 0u;
|
||||
spec->type = KERNAUX_PRINTF_FMT_TYPE_NONE;
|
||||
|
||||
spec->base = 0;
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_flags(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
||||
|
|
@ -161,6 +164,111 @@ void KernAux_PrintfFmt_Spec_eval_length(struct KernAux_PrintfFmt_Spec *const spe
|
|||
}
|
||||
}
|
||||
|
||||
void KernAux_PrintfFmt_Spec_eval_type(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 '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;
|
||||
spec->flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; // no hash for dec format
|
||||
}
|
||||
// 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;
|
||||
|
||||
#ifdef ENABLE_BLOAT
|
||||
case 'S':
|
||||
if (spec->flags & KERNAUX_PRINTF_FMT_FLAGS_CUSTOM) {
|
||||
spec->type = KERNAUX_PRINTF_FMT_TYPE_CUSTOM;
|
||||
++(*format);
|
||||
}
|
||||
break;
|
||||
#endif // ENABLE_BLOAT
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue