From 298761e5e40ae8c223b63d70d284d6f4382d6434 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Mon, 7 Dec 2020 04:12:09 +0500 Subject: [PATCH] Parse printf formatter --- src/printf.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 197 insertions(+), 9 deletions(-) diff --git a/src/printf.c b/src/printf.c index 278b49a..b234eaa 100644 --- a/src/printf.c +++ b/src/printf.c @@ -3,6 +3,49 @@ #include #include +#include + +enum NoneNumberDynamic { NONE, NUMBER, DYNAMIC }; + +enum Length { LEN0, LEN_hh, LEN_h, LEN_l, LEN_ll, LEN_L, LEN_z, LEN_j, LEN_t }; + +enum Type { + TYPE0, + TYPE_PERCENT, + TYPE_di, + TYPE_u, + TYPE_fF, + TYPE_eE, + TYPE_gG, + TYPE_xX, + TYPE_o, + TYPE_s, + TYPE_c, + TYPE_p, + TYPE_aA, + TYPE_n, +}; + +struct Formatter { + bool flag_minus; // - + bool flag_plus; // + + bool flag_space; // space + bool flag_zero; // 0 + bool flag_apostrophe; // ' + bool flag_hash; // # + + enum NoneNumberDynamic width; + unsigned int width_number; + + enum NoneNumberDynamic precision; + unsigned int precision_number; + + enum Length length; + enum Type type; +}; + +inline static struct Formatter Formatter_new(); + void kernaux_printf(void (*putchar)(char), const char *const format, ...) { va_list va; @@ -16,25 +59,170 @@ void kernaux_printf_va( const char *const format, va_list va ) { - for (const char *current_ptr = format; *current_ptr; ++current_ptr) { - const char current = *current_ptr; + struct Formatter formatter = Formatter_new(); - if (current != '%') { - putchar(current); + for (const char *current = format; *current;) { + if (*current != '%') { + putchar(*current); + ++current; continue; } - if (*(++current_ptr) == 's') { - const char *const arg = va_arg(va, const char*); + ++current; // skip % + formatter = Formatter_new(); + + for (bool loop = true; loop;) { + switch (*current) { + case '-': formatter.flag_minus = true; break; + case '+': formatter.flag_plus = true; break; + case ' ': formatter.flag_space = true; break; + case '0': formatter.flag_zero = true; break; + case '\'': formatter.flag_apostrophe = true; break; + case '#': formatter.flag_hash = true; break; + default: loop = false; + } + if (loop) ++current; + } + + for (; *current >= '1' && *current <= '9'; ++current) { + // TODO: implement width parsing + } + + if (*current == '.') { + for (++current; *current >= '1' && *current <= '9'; ++current) { + // TODO: implement precision parsing + } + } + + switch (*current) { + case 'h': + if (*(++current) == 'h') { + formatter.length = LEN_hh; + ++current; + } + else { + formatter.length = LEN_h; + } + break; + case 'l': + if (*(++current) == 'l') { + formatter.length = LEN_ll; + ++current; + } + else { + formatter.length = LEN_l; + } + break; + case 'L': + formatter.length = LEN_L; + ++current; + break; + case 'z': + formatter.length = LEN_z; + ++current; + break; + case 'j': + formatter.length = LEN_j; + ++current; + break; + case 't': + formatter.length = LEN_t; + ++current; + break; + } + + switch (*current) { + case '%': + formatter.type = TYPE_PERCENT; + ++current; + break; + case 'd': + case 'i': + formatter.type = TYPE_di; + ++current; + break; + case 'u': + formatter.type = TYPE_u; + ++current; + break; + case 'f': + case 'F': + formatter.type = TYPE_fF; + ++current; + break; + case 'e': + case 'E': + formatter.type = TYPE_eE; + ++current; + break; + case 'g': + case 'G': + formatter.type = TYPE_gG; + ++current; + break; + case 'x': + case 'X': + formatter.type = TYPE_xX; + ++current; + break; + case 'o': + formatter.type = TYPE_o; + ++current; + break; + case 's': + formatter.type = TYPE_s; + ++current; + break; + case 'c': + formatter.type = TYPE_c; + ++current; + break; + case 'p': + formatter.type = TYPE_p; + ++current; + break; + case 'a': + case 'A': + formatter.type = TYPE_aA; + ++current; + break; + case 'n': + formatter.type = TYPE_n; + ++current; + break; + } + + if (formatter.type == TYPE_s) { + const char *const arg = va_arg(va, char*); for (const char *arg_ptr = arg; *arg_ptr; ++arg_ptr) { putchar(*arg_ptr); } } - else { - break; - } } putchar('\0'); } + +struct Formatter Formatter_new() +{ + struct Formatter result = { + .flag_minus = false, + .flag_plus = false, + .flag_space = false, + .flag_zero = false, + .flag_apostrophe = false, + .flag_hash = false, + + .width = NONE, + .width_number = 0, + + .precision = NONE, + .precision_number = 0, + + .length = LEN0, + .type = TYPE0, + }; + + return result; +}