LibC: Implement length modifiers to printf
This commit is contained in:
parent
c84b66d078
commit
1cd12b5f16
|
@ -15,6 +15,19 @@
|
||||||
written++; \
|
written++; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
enum class length_t
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
hh,
|
||||||
|
h,
|
||||||
|
l,
|
||||||
|
ll,
|
||||||
|
j,
|
||||||
|
z,
|
||||||
|
t,
|
||||||
|
L,
|
||||||
|
};
|
||||||
|
|
||||||
struct format_options_t
|
struct format_options_t
|
||||||
{
|
{
|
||||||
bool alternate_form { false };
|
bool alternate_form { false };
|
||||||
|
@ -24,6 +37,7 @@ struct format_options_t
|
||||||
bool show_plus_sign { false };
|
bool show_plus_sign { false };
|
||||||
int width { -1 };
|
int width { -1 };
|
||||||
int percision { -1 };
|
int percision { -1 };
|
||||||
|
length_t length { length_t::none };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<BAN::integral T>
|
template<BAN::integral T>
|
||||||
|
@ -308,45 +322,157 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
||||||
options.percision = percision;
|
options.percision = percision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Lenght modifier
|
// PARSE LENGTH
|
||||||
|
if (*format == 'h')
|
||||||
|
{
|
||||||
|
if (*(format + 1) == 'h')
|
||||||
|
{
|
||||||
|
format++;
|
||||||
|
options.length = length_t::hh;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
options.length = length_t::h;
|
||||||
|
}
|
||||||
|
else if (*format == 'l')
|
||||||
|
{
|
||||||
|
if (*(format + 1) == 'l')
|
||||||
|
{
|
||||||
|
format++;
|
||||||
|
options.length = length_t::ll;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
options.length = length_t::l;
|
||||||
|
}
|
||||||
|
else if (*format == 'j')
|
||||||
|
options.length = length_t::j;
|
||||||
|
else if (*format == 'z')
|
||||||
|
options.length = length_t::z;
|
||||||
|
else if (*format == 't')
|
||||||
|
options.length = length_t::t;
|
||||||
|
else if (*format == 'L')
|
||||||
|
options.length = length_t::L;
|
||||||
|
else
|
||||||
|
format--;
|
||||||
|
format++;
|
||||||
|
|
||||||
char conversion[128];
|
char conversion[128];
|
||||||
const char* string = nullptr;
|
const char* string = nullptr;
|
||||||
|
|
||||||
int length = -1;
|
int length = -1;
|
||||||
|
|
||||||
|
#define PARSE_INT_CASE(length, type) \
|
||||||
|
case length_t::length: integer_to_string<type>(conversion, va_arg(arguments, type), BASE_, UPPER_, options); break
|
||||||
|
|
||||||
|
#define PARSE_INT_CASE_CAST(length, cast, type) \
|
||||||
|
case length_t::length: integer_to_string<cast>(conversion, va_arg(arguments, type), BASE_, UPPER_, options); break
|
||||||
|
|
||||||
|
#define PARSE_INT_DEFAULT(type) \
|
||||||
|
default: integer_to_string<type>(conversion, va_arg(arguments, type), BASE_, UPPER_, options); break
|
||||||
|
|
||||||
switch (*format)
|
switch (*format)
|
||||||
{
|
{
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
int value = va_arg(arguments, int);
|
switch (options.length)
|
||||||
integer_to_string<int>(conversion, value, 10, false, options);
|
{
|
||||||
|
#define BASE_ 10
|
||||||
|
#define UPPER_ false
|
||||||
|
PARSE_INT_CASE_CAST(hh, signed char, int);
|
||||||
|
PARSE_INT_CASE_CAST(h, short, int);
|
||||||
|
PARSE_INT_CASE(l, long);
|
||||||
|
PARSE_INT_CASE(ll, long long);
|
||||||
|
PARSE_INT_CASE(j, intmax_t);
|
||||||
|
PARSE_INT_CASE(z, ssize_t);
|
||||||
|
PARSE_INT_CASE(t, ptrdiff_t);
|
||||||
|
PARSE_INT_DEFAULT(int);
|
||||||
|
#undef BASE_
|
||||||
|
#undef UPPER_
|
||||||
|
}
|
||||||
string = conversion;
|
string = conversion;
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'o':
|
case 'o':
|
||||||
{
|
{
|
||||||
unsigned int value = va_arg(arguments, unsigned int);
|
switch (options.length)
|
||||||
integer_to_string<unsigned int>(conversion, value, 8, false, options);
|
{
|
||||||
|
#define BASE_ 8
|
||||||
|
#define UPPER_ false
|
||||||
|
PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int);
|
||||||
|
PARSE_INT_CASE_CAST(h, unsigned short, unsigned int);
|
||||||
|
PARSE_INT_CASE(l, unsigned long);
|
||||||
|
PARSE_INT_CASE(ll, unsigned long long);
|
||||||
|
PARSE_INT_CASE(j, uintmax_t);
|
||||||
|
PARSE_INT_CASE(z, size_t);
|
||||||
|
PARSE_INT_CASE(t, uintptr_t);
|
||||||
|
PARSE_INT_DEFAULT(unsigned int);
|
||||||
|
#undef BASE_
|
||||||
|
#undef UPPER_
|
||||||
|
}
|
||||||
string = conversion;
|
string = conversion;
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'u':
|
case 'u':
|
||||||
{
|
{
|
||||||
unsigned int value = va_arg(arguments, unsigned int);
|
switch (options.length)
|
||||||
integer_to_string<unsigned int>(conversion, value, 10, false, options);
|
{
|
||||||
|
#define BASE_ 10
|
||||||
|
#define UPPER_ false
|
||||||
|
PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int);
|
||||||
|
PARSE_INT_CASE_CAST(h, unsigned short, unsigned int);
|
||||||
|
PARSE_INT_CASE(l, unsigned long);
|
||||||
|
PARSE_INT_CASE(ll, unsigned long long);
|
||||||
|
PARSE_INT_CASE(j, uintmax_t);
|
||||||
|
PARSE_INT_CASE(z, size_t);
|
||||||
|
PARSE_INT_CASE(t, uintptr_t);
|
||||||
|
PARSE_INT_DEFAULT(unsigned int);
|
||||||
|
#undef BASE_
|
||||||
|
#undef UPPER_
|
||||||
|
}
|
||||||
string = conversion;
|
string = conversion;
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'x':
|
case 'x':
|
||||||
|
{
|
||||||
|
switch (options.length)
|
||||||
|
{
|
||||||
|
#define BASE_ 16
|
||||||
|
#define UPPER_ false
|
||||||
|
PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int);
|
||||||
|
PARSE_INT_CASE_CAST(h, unsigned short, unsigned int);
|
||||||
|
PARSE_INT_CASE(l, unsigned long);
|
||||||
|
PARSE_INT_CASE(ll, unsigned long long);
|
||||||
|
PARSE_INT_CASE(j, uintmax_t);
|
||||||
|
PARSE_INT_CASE(z, size_t);
|
||||||
|
PARSE_INT_CASE(t, uintptr_t);
|
||||||
|
PARSE_INT_DEFAULT(unsigned int);
|
||||||
|
#undef BASE_
|
||||||
|
#undef UPPER_
|
||||||
|
}
|
||||||
|
string = conversion;
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'X':
|
case 'X':
|
||||||
{
|
{
|
||||||
unsigned int value = va_arg(arguments, unsigned int);
|
switch (options.length)
|
||||||
integer_to_string<unsigned int>(conversion, value, 16, *format == 'X', options);
|
{
|
||||||
|
#define BASE_ 16
|
||||||
|
#define UPPER_ true
|
||||||
|
PARSE_INT_CASE_CAST(hh, unsigned char, unsigned int);
|
||||||
|
PARSE_INT_CASE_CAST(h, unsigned short, unsigned int);
|
||||||
|
PARSE_INT_CASE(l, unsigned long);
|
||||||
|
PARSE_INT_CASE(ll, unsigned long long);
|
||||||
|
PARSE_INT_CASE(j, uintmax_t);
|
||||||
|
PARSE_INT_CASE(z, size_t);
|
||||||
|
PARSE_INT_CASE(t, uintptr_t);
|
||||||
|
PARSE_INT_DEFAULT(unsigned int);
|
||||||
|
#undef BASE_
|
||||||
|
#undef UPPER_
|
||||||
|
}
|
||||||
string = conversion;
|
string = conversion;
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
|
@ -355,8 +481,11 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'E':
|
case 'E':
|
||||||
{
|
{
|
||||||
double value = va_arg(arguments, double);
|
switch (options.length)
|
||||||
floating_point_to_exponent_string<double>(conversion, value, *format == 'E', options);
|
{
|
||||||
|
case length_t::L: floating_point_to_exponent_string<long double> (conversion, va_arg(arguments, long double), *format == 'E', options); break;
|
||||||
|
default: floating_point_to_exponent_string<double> (conversion, va_arg(arguments, double), *format == 'E', options); break;
|
||||||
|
}
|
||||||
string = conversion;
|
string = conversion;
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
|
@ -364,13 +493,15 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F':
|
||||||
{
|
{
|
||||||
double value = va_arg(arguments, double);
|
switch (options.length)
|
||||||
floating_point_to_string<double>(conversion, value, *format == 'F', options);
|
{
|
||||||
|
case length_t::L: floating_point_to_string<long double> (conversion, va_arg(arguments, long double), *format == 'F', options); break;
|
||||||
|
default: floating_point_to_string<double> (conversion, va_arg(arguments, double), *format == 'F', options); break;
|
||||||
|
}
|
||||||
string = conversion;
|
string = conversion;
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -379,6 +510,7 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
||||||
case 'A':
|
case 'A':
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
case 'c':
|
case 'c':
|
||||||
{
|
{
|
||||||
conversion[0] = va_arg(arguments, int);
|
conversion[0] = va_arg(arguments, int);
|
||||||
|
@ -416,8 +548,17 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
|
||||||
}
|
}
|
||||||
case 'n':
|
case 'n':
|
||||||
{
|
{
|
||||||
int* target = va_arg(arguments, int*);
|
switch (options.length)
|
||||||
*target = written;
|
{
|
||||||
|
case length_t::hh: *va_arg(arguments, signed char*) = written; break;
|
||||||
|
case length_t::h: *va_arg(arguments, short*) = written; break;
|
||||||
|
case length_t::l: *va_arg(arguments, long*) = written; break;
|
||||||
|
case length_t::ll: *va_arg(arguments, long long*) = written; break;
|
||||||
|
case length_t::j: *va_arg(arguments, intmax_t*) = written; break;
|
||||||
|
case length_t::z: *va_arg(arguments, ssize_t*) = written; break;
|
||||||
|
case length_t::t: *va_arg(arguments, ptrdiff_t*) = written; break;
|
||||||
|
default: *va_arg(arguments, int*) = written; break;
|
||||||
|
}
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue