1
0
Fork 0
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:
Alex Kotov 2022-05-27 01:54:01 +03:00
parent c035485706
commit 841d6991e7
Signed by: kotovalexarian
GPG key ID: 553C0EBBEB5D5F08
4 changed files with 161 additions and 85 deletions

View file

@ -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>

View file

@ -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
}

View file

@ -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;
}
}

View file

@ -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)
{