mirror of
https://github.com/tailix/libkernaux.git
synced 2024-11-20 11:06:41 -05:00
Change printf format API (#122)
This commit is contained in:
parent
7ea1d4b2b1
commit
8add17e91c
9 changed files with 188 additions and 102 deletions
|
@ -4,6 +4,7 @@
|
||||||
"KERNAUX_PACKED"
|
"KERNAUX_PACKED"
|
||||||
* include/kernaux/macro.h: Add macros "KERNAUX_UNUSED", "KERNAUX_NORETURN",
|
* include/kernaux/macro.h: Add macros "KERNAUX_UNUSED", "KERNAUX_NORETURN",
|
||||||
"KERNAUX_RETURNS_TWICE", "KERNAUX_ASM"
|
"KERNAUX_RETURNS_TWICE", "KERNAUX_ASM"
|
||||||
|
* include/kernaux/printf_fmt.h: Make stable
|
||||||
|
|
||||||
2022-11-26 Alex Kotov <kotovalexarian@gmail.com>
|
2022-11-26 Alex Kotov <kotovalexarian@gmail.com>
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ zero). Work-in-progress APIs can change at any time.
|
||||||
* [Example: To human](/examples/units_human.c)
|
* [Example: To human](/examples/units_human.c)
|
||||||
* [Memory map](/include/kernaux/memmap.h) (*non-breaking since* **0.4.0**)
|
* [Memory map](/include/kernaux/memmap.h) (*non-breaking since* **0.4.0**)
|
||||||
* [Example](/examples/memmap.c)
|
* [Example](/examples/memmap.c)
|
||||||
* [printf format parser](/include/kernaux/printf_fmt.h) (*work in progress*)
|
* [printf format parser](/include/kernaux/printf_fmt.h) (*non-breaking since* **?.?.?**)
|
||||||
* [Example](/examples/printf_fmt.c)
|
* [Example](/examples/printf_fmt.c)
|
||||||
* Usual functions
|
* Usual functions
|
||||||
* [itoa/ftoa replacement](/include/kernaux/ntoa.h) (*non-breaking since* **0.4.0**)
|
* [itoa/ftoa replacement](/include/kernaux/ntoa.h) (*non-breaking since* **0.4.0**)
|
||||||
|
|
|
@ -56,9 +56,7 @@ mrb_value rb_KernAux_snprintf1(mrb_state *const mrb, mrb_value self)
|
||||||
while (*fmt && *fmt != '%') ++fmt;
|
while (*fmt && *fmt != '%') ++fmt;
|
||||||
if (*(fmt++) != '%') mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format");
|
if (*(fmt++) != '%') mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format");
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create_out(&fmt);
|
||||||
|
|
||||||
fmt = KernAux_PrintfFmt_Spec_parse(&spec, fmt);
|
|
||||||
|
|
||||||
while (*fmt) {
|
while (*fmt) {
|
||||||
if (*(fmt++) == '%') mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format");
|
if (*(fmt++) == '%') mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format");
|
||||||
|
|
|
@ -85,9 +85,7 @@ VALUE rb_KernAux_snprintf1(
|
||||||
while (*fmt && *fmt != '%') ++fmt;
|
while (*fmt && *fmt != '%') ++fmt;
|
||||||
if (*(fmt++) != '%') rb_raise(rb_eArgError, "invalid format");
|
if (*(fmt++) != '%') rb_raise(rb_eArgError, "invalid format");
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create_out(&fmt);
|
||||||
|
|
||||||
fmt = KernAux_PrintfFmt_Spec_parse(&spec, fmt);
|
|
||||||
|
|
||||||
while (*fmt) {
|
while (*fmt) {
|
||||||
if (*(fmt++) == '%') rb_raise(rb_eArgError, "invalid format");
|
if (*(fmt++) == '%') rb_raise(rb_eArgError, "invalid format");
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#include <kernaux/printf_fmt.h>
|
#include <kernaux/printf_fmt.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
void example_main()
|
void example_main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
const char *format = "s";
|
const char *const format = "s";
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create(format);
|
||||||
|
|
||||||
format = KernAux_PrintfFmt_Spec_parse(&spec, format);
|
|
||||||
|
|
||||||
if (spec.set_width) {
|
if (spec.set_width) {
|
||||||
// Actually this line won't be executed.
|
// Actually this line won't be executed.
|
||||||
|
@ -20,24 +19,23 @@ void example_main()
|
||||||
KernAux_PrintfFmt_Spec_set_precision(&spec, 0);
|
KernAux_PrintfFmt_Spec_set_precision(&spec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(spec.format_start == format);
|
||||||
|
assert(spec.format_limit == &format[1]);
|
||||||
|
|
||||||
assert(spec.flags == 0);
|
assert(spec.flags == 0);
|
||||||
assert(spec.width == 0);
|
assert(spec.width == 0);
|
||||||
assert(spec.precision == 0);
|
assert(spec.precision == 0);
|
||||||
assert(spec.type == KERNAUX_PRINTF_FMT_TYPE_STR);
|
assert(spec.type == KERNAUX_PRINTF_FMT_TYPE_STR);
|
||||||
assert(spec.base == 0);
|
assert(spec.base == 0);
|
||||||
|
|
||||||
|
assert(!spec.set_width);
|
||||||
|
assert(!spec.set_precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char *format = "012.34f";
|
const char *format = "012.34f";
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create_out(&format);
|
||||||
|
|
||||||
// Parsing of each part may be done separately.
|
|
||||||
KernAux_PrintfFmt_Spec_parse_flags(&spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_width(&spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_precision(&spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_length(&spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_type(&spec, &format);
|
|
||||||
|
|
||||||
if (spec.set_width) {
|
if (spec.set_width) {
|
||||||
// Actually this line won't be executed.
|
// Actually this line won't be executed.
|
||||||
|
@ -48,6 +46,9 @@ void example_main()
|
||||||
KernAux_PrintfFmt_Spec_set_precision(&spec, 0);
|
KernAux_PrintfFmt_Spec_set_precision(&spec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(spec.format_start == &format[-7]);
|
||||||
|
assert(spec.format_limit == format);
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
spec.flags ==
|
spec.flags ==
|
||||||
(
|
(
|
||||||
|
@ -59,15 +60,16 @@ void example_main()
|
||||||
assert(spec.precision == 34);
|
assert(spec.precision == 34);
|
||||||
assert(spec.type == KERNAUX_PRINTF_FMT_TYPE_FLOAT);
|
assert(spec.type == KERNAUX_PRINTF_FMT_TYPE_FLOAT);
|
||||||
assert(spec.base == 0);
|
assert(spec.base == 0);
|
||||||
|
|
||||||
|
assert(!spec.set_width);
|
||||||
|
assert(!spec.set_precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char *const format = " *.*ld";
|
const char *const format = " *.*ld";
|
||||||
|
const char *new_format = NULL;
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create_out_new(format, &new_format);
|
||||||
|
|
||||||
// Returning value may be ignored.
|
|
||||||
KernAux_PrintfFmt_Spec_parse(&spec, format);
|
|
||||||
|
|
||||||
if (spec.set_width) {
|
if (spec.set_width) {
|
||||||
KernAux_PrintfFmt_Spec_set_width(&spec, 12);
|
KernAux_PrintfFmt_Spec_set_width(&spec, 12);
|
||||||
|
@ -76,6 +78,10 @@ void example_main()
|
||||||
KernAux_PrintfFmt_Spec_set_precision(&spec, 34);
|
KernAux_PrintfFmt_Spec_set_precision(&spec, 34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(spec.format_start == format);
|
||||||
|
assert(spec.format_limit == &format[6]);
|
||||||
|
assert(new_format == &format[6]);
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
spec.flags ==
|
spec.flags ==
|
||||||
(
|
(
|
||||||
|
@ -88,5 +94,8 @@ void example_main()
|
||||||
assert(spec.precision == 34);
|
assert(spec.precision == 34);
|
||||||
assert(spec.type == KERNAUX_PRINTF_FMT_TYPE_INT);
|
assert(spec.type == KERNAUX_PRINTF_FMT_TYPE_INT);
|
||||||
assert(spec.base == 10);
|
assert(spec.base == 10);
|
||||||
|
|
||||||
|
assert(spec.set_width);
|
||||||
|
assert(spec.set_precision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ enum KernAux_PrintfFmt_Type {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec {
|
struct KernAux_PrintfFmt_Spec {
|
||||||
|
const char *format_start;
|
||||||
|
const char *format_limit;
|
||||||
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int precision;
|
unsigned int precision;
|
||||||
|
@ -45,19 +48,25 @@ struct KernAux_PrintfFmt_Spec {
|
||||||
bool set_precision;
|
bool set_precision;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create(
|
||||||
void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *spec);
|
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
|
||||||
|
);
|
||||||
|
|
||||||
const char *KernAux_PrintfFmt_Spec_parse(struct KernAux_PrintfFmt_Spec *spec, const char *format);
|
void KernAux_PrintfFmt_Spec_set_width(
|
||||||
|
struct KernAux_PrintfFmt_Spec *spec,
|
||||||
void KernAux_PrintfFmt_Spec_parse_flags(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
int width
|
||||||
void KernAux_PrintfFmt_Spec_parse_width(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
);
|
||||||
void KernAux_PrintfFmt_Spec_parse_precision(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
void KernAux_PrintfFmt_Spec_set_precision(
|
||||||
void KernAux_PrintfFmt_Spec_parse_length(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
struct KernAux_PrintfFmt_Spec *spec,
|
||||||
void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *spec, const char **format);
|
int precision
|
||||||
|
);
|
||||||
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,9 +151,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
||||||
format++;
|
format++;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create_out(&format);
|
||||||
|
|
||||||
format = KernAux_PrintfFmt_Spec_parse(&spec, format);
|
|
||||||
|
|
||||||
if (spec.set_width) {
|
if (spec.set_width) {
|
||||||
KernAux_PrintfFmt_Spec_set_width(&spec, va_arg(va, int));
|
KernAux_PrintfFmt_Spec_set_width(&spec, va_arg(va, int));
|
||||||
|
|
192
src/printf_fmt.c
192
src/printf_fmt.c
|
@ -18,44 +18,97 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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);
|
static unsigned int _atoi(const char** str);
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create()
|
/***********************************
|
||||||
{
|
* Public function implementations *
|
||||||
struct KernAux_PrintfFmt_Spec spec;
|
***********************************/
|
||||||
KernAux_PrintfFmt_Spec_init(&spec);
|
|
||||||
|
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create_out(
|
||||||
|
const char **const format
|
||||||
|
) {
|
||||||
|
KERNAUX_ASSERT(format);
|
||||||
|
|
||||||
|
const struct KernAux_PrintfFmt_Spec spec =
|
||||||
|
KernAux_PrintfFmt_Spec_create(*format);
|
||||||
|
*format = spec.format_limit;
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *const spec)
|
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create_out_new(
|
||||||
{
|
const char *const format,
|
||||||
KERNAUX_ASSERT(spec);
|
const char **const new_format
|
||||||
|
) {
|
||||||
|
KERNAUX_ASSERT(format);
|
||||||
|
KERNAUX_ASSERT(new_format);
|
||||||
|
|
||||||
spec->flags = 0u;
|
*new_format = NULL;
|
||||||
spec->width = 0u;
|
const struct KernAux_PrintfFmt_Spec spec =
|
||||||
spec->precision = 0u;
|
KernAux_PrintfFmt_Spec_create(format);
|
||||||
spec->type = KERNAUX_PRINTF_FMT_TYPE_NONE;
|
*new_format = spec.format_limit;
|
||||||
spec->base = 0;
|
return spec;
|
||||||
|
|
||||||
spec->set_width = false;
|
|
||||||
spec->set_precision = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *KernAux_PrintfFmt_Spec_parse(struct KernAux_PrintfFmt_Spec *spec, const char *format)
|
struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create(const char *format)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(spec);
|
|
||||||
KERNAUX_ASSERT(format);
|
KERNAUX_ASSERT(format);
|
||||||
|
|
||||||
KernAux_PrintfFmt_Spec_parse_flags(spec, &format);
|
struct KernAux_PrintfFmt_Spec spec;
|
||||||
KernAux_PrintfFmt_Spec_parse_width(spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_precision(spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_length(spec, &format);
|
|
||||||
KernAux_PrintfFmt_Spec_parse_type(spec, &format);
|
|
||||||
|
|
||||||
return format;
|
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_parse_flags(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
void KernAux_PrintfFmt_Spec_set_width(const Spec spec, const int width)
|
||||||
|
{
|
||||||
|
KERNAUX_ASSERT(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_ASSERT(spec);
|
||||||
|
|
||||||
|
spec->precision = precision > 0 ? (unsigned int)precision : 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
* Private function implementations *
|
||||||
|
************************************/
|
||||||
|
|
||||||
|
void parse_flags(const Spec spec, const char **const format)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(spec);
|
KERNAUX_ASSERT(spec);
|
||||||
KERNAUX_ASSERT(format);
|
KERNAUX_ASSERT(format);
|
||||||
|
@ -64,17 +117,32 @@ void KernAux_PrintfFmt_Spec_parse_flags(struct KernAux_PrintfFmt_Spec *const spe
|
||||||
bool running = true;
|
bool running = true;
|
||||||
do {
|
do {
|
||||||
switch (**format) {
|
switch (**format) {
|
||||||
case '0': spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD; ++(*format); break;
|
case '0':
|
||||||
case '-': spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LEFT; ++(*format); break;
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD;
|
||||||
case '+': spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_PLUS; ++(*format); break;
|
++(*format);
|
||||||
case ' ': spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_SPACE; ++(*format); break;
|
break;
|
||||||
case '#': spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_HASH; ++(*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;
|
default: running = false; break;
|
||||||
}
|
}
|
||||||
} while (running);
|
} while (running);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_PrintfFmt_Spec_parse_width(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
void parse_width(const Spec spec, const char **const format)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(spec);
|
KERNAUX_ASSERT(spec);
|
||||||
KERNAUX_ASSERT(format);
|
KERNAUX_ASSERT(format);
|
||||||
|
@ -91,7 +159,7 @@ void KernAux_PrintfFmt_Spec_parse_width(struct KernAux_PrintfFmt_Spec *const spe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_PrintfFmt_Spec_parse_precision(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
void parse_precision(const Spec spec, const char **const format)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(spec);
|
KERNAUX_ASSERT(spec);
|
||||||
KERNAUX_ASSERT(format);
|
KERNAUX_ASSERT(format);
|
||||||
|
@ -114,7 +182,7 @@ void KernAux_PrintfFmt_Spec_parse_precision(struct KernAux_PrintfFmt_Spec *const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_PrintfFmt_Spec_parse_length(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
void parse_length(const Spec spec, const char **const format)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(spec);
|
KERNAUX_ASSERT(spec);
|
||||||
KERNAUX_ASSERT(format);
|
KERNAUX_ASSERT(format);
|
||||||
|
@ -138,15 +206,27 @@ void KernAux_PrintfFmt_Spec_parse_length(struct KernAux_PrintfFmt_Spec *const sp
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
spec->flags |= (sizeof(ptrdiff_t) == sizeof(long) ? KERNAUX_PRINTF_FMT_FLAGS_LONG : KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG);
|
if (sizeof(ptrdiff_t) == sizeof(long)) {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG;
|
||||||
|
} else {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG;
|
||||||
|
}
|
||||||
++(*format);
|
++(*format);
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
spec->flags |= (sizeof(intmax_t) == sizeof(long) ? KERNAUX_PRINTF_FMT_FLAGS_LONG : KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG);
|
if (sizeof(ptrdiff_t) == sizeof(long)) {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG;
|
||||||
|
} else {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG;
|
||||||
|
}
|
||||||
++(*format);
|
++(*format);
|
||||||
break;
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
spec->flags |= (sizeof(size_t) == sizeof(long) ? KERNAUX_PRINTF_FMT_FLAGS_LONG : KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG);
|
if (sizeof(ptrdiff_t) == sizeof(long)) {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG;
|
||||||
|
} else {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LONG_LONG;
|
||||||
|
}
|
||||||
++(*format);
|
++(*format);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -154,7 +234,7 @@ void KernAux_PrintfFmt_Spec_parse_length(struct KernAux_PrintfFmt_Spec *const sp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
|
void parse_type(const Spec spec, const char **const format)
|
||||||
{
|
{
|
||||||
KERNAUX_ASSERT(spec);
|
KERNAUX_ASSERT(spec);
|
||||||
KERNAUX_ASSERT(format);
|
KERNAUX_ASSERT(format);
|
||||||
|
@ -177,7 +257,8 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
|
||||||
spec->base = 2u;
|
spec->base = 2u;
|
||||||
} else {
|
} else {
|
||||||
spec->base = 10u;
|
spec->base = 10u;
|
||||||
spec->flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH; // no hash for dec format
|
// no hash for dec format
|
||||||
|
spec->flags &= ~KERNAUX_PRINTF_FMT_FLAGS_HASH;
|
||||||
}
|
}
|
||||||
// uppercase
|
// uppercase
|
||||||
if (**format == 'X') {
|
if (**format == 'X') {
|
||||||
|
@ -186,7 +267,8 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
|
||||||
|
|
||||||
// no plus or space flag for u, x, X, o, b
|
// no plus or space flag for u, x, X, o, b
|
||||||
if ((**format != 'i') && (**format != 'd')) {
|
if ((**format != 'i') && (**format != 'd')) {
|
||||||
spec->flags &= ~(KERNAUX_PRINTF_FMT_FLAGS_PLUS | KERNAUX_PRINTF_FMT_FLAGS_SPACE);
|
spec->flags &= ~(KERNAUX_PRINTF_FMT_FLAGS_PLUS |
|
||||||
|
KERNAUX_PRINTF_FMT_FLAGS_SPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore '0' flag when precision is given
|
// ignore '0' flag when precision is given
|
||||||
|
@ -206,7 +288,9 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
|
||||||
#ifdef ENABLE_FLOAT
|
#ifdef ENABLE_FLOAT
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F':
|
||||||
if (**format == 'F') spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
if (**format == 'F') {
|
||||||
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
||||||
|
}
|
||||||
spec->type = KERNAUX_PRINTF_FMT_TYPE_FLOAT;
|
spec->type = KERNAUX_PRINTF_FMT_TYPE_FLOAT;
|
||||||
++(*format);
|
++(*format);
|
||||||
break;
|
break;
|
||||||
|
@ -215,8 +299,12 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
|
||||||
case 'E':
|
case 'E':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
if ((**format == 'g')||(**format == 'G')) spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ADAPT_EXP;
|
if ((**format == 'g') || (**format == 'G')) {
|
||||||
if ((**format == 'E')||(**format == 'G')) spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
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;
|
spec->type = KERNAUX_PRINTF_FMT_TYPE_EXP;
|
||||||
++(*format);
|
++(*format);
|
||||||
break;
|
break;
|
||||||
|
@ -234,7 +322,8 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
spec->width = sizeof(void*) * 2u;
|
spec->width = sizeof(void*) * 2u;
|
||||||
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD | KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_ZEROPAD |
|
||||||
|
KERNAUX_PRINTF_FMT_FLAGS_UPPERCASE;
|
||||||
spec->type = KERNAUX_PRINTF_FMT_TYPE_PTR;
|
spec->type = KERNAUX_PRINTF_FMT_TYPE_PTR;
|
||||||
++(*format);
|
++(*format);
|
||||||
break;
|
break;
|
||||||
|
@ -250,25 +339,6 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernAux_PrintfFmt_Spec_set_width(struct KernAux_PrintfFmt_Spec *const spec, const int width)
|
|
||||||
{
|
|
||||||
KERNAUX_ASSERT(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(struct KernAux_PrintfFmt_Spec *const spec, const int precision)
|
|
||||||
{
|
|
||||||
KERNAUX_ASSERT(spec);
|
|
||||||
|
|
||||||
spec->precision = precision > 0 ? (unsigned int)precision : 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
// internal ASCII string to unsigned int conversion
|
// internal ASCII string to unsigned int conversion
|
||||||
unsigned int _atoi(const char** str)
|
unsigned int _atoi(const char** str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include <kernaux/printf_fmt.h>
|
#include <kernaux/printf_fmt.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
void test_main()
|
void test_main()
|
||||||
{
|
{
|
||||||
|
@ -12,9 +15,7 @@ void test_main()
|
||||||
{
|
{
|
||||||
const char *const format = {{ escape_str(case.in.format) }};
|
const char *const format = {{ escape_str(case.in.format) }};
|
||||||
|
|
||||||
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create();
|
struct KernAux_PrintfFmt_Spec spec = KernAux_PrintfFmt_Spec_create(format);
|
||||||
|
|
||||||
KernAux_PrintfFmt_Spec_parse(&spec, format);
|
|
||||||
|
|
||||||
if (spec.set_width) {
|
if (spec.set_width) {
|
||||||
KernAux_PrintfFmt_Spec_set_width(&spec, {{ none_to_zero(case.in.width) }});
|
KernAux_PrintfFmt_Spec_set_width(&spec, {{ none_to_zero(case.in.width) }});
|
||||||
|
@ -23,6 +24,8 @@ void test_main()
|
||||||
KernAux_PrintfFmt_Spec_set_precision(&spec, {{ none_to_zero(case.in.precision) }});
|
KernAux_PrintfFmt_Spec_set_precision(&spec, {{ none_to_zero(case.in.precision) }});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(spec.format_start == format);
|
||||||
|
|
||||||
assert(spec.flags == {{ escape_flags(case.out.flags) }});
|
assert(spec.flags == {{ escape_flags(case.out.flags) }});
|
||||||
assert(spec.width == {{ case.out.width }});
|
assert(spec.width == {{ case.out.width }});
|
||||||
assert(spec.precision == {{ case.out.precision }});
|
assert(spec.precision == {{ case.out.precision }});
|
||||||
|
|
Loading…
Reference in a new issue