forked from Bananymous/banan-os
LibC: implement printf conversions e, E, f, F
This commit is contained in:
parent
ac12132ac0
commit
48edc38817
|
@ -1,6 +1,8 @@
|
||||||
#include <BAN/Traits.h>
|
#include <BAN/Traits.h>
|
||||||
|
#include <BAN/Math.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, const
|
||||||
}
|
}
|
||||||
else if (options.width != -1)
|
else if (options.width != -1)
|
||||||
width = options.width;
|
width = options.width;
|
||||||
|
|
||||||
auto digit_char = [](int digit, bool upper)
|
auto digit_char = [](int digit, bool upper)
|
||||||
{
|
{
|
||||||
if (digit < 10)
|
if (digit < 10)
|
||||||
|
@ -95,16 +97,6 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, const
|
||||||
buffer[offset++] = '\0';
|
buffer[offset++] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
template<BAN::floating_point T>
|
|
||||||
static void floating_point_to_exponent_string(char* buffer, T value, bool upper, const format_options_t options)
|
|
||||||
{
|
|
||||||
int percision = 6;
|
|
||||||
if (options.percision != -1)
|
|
||||||
percision = options.percision;
|
|
||||||
|
|
||||||
strcpy(buffer, "??e??");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<BAN::floating_point T>
|
template<BAN::floating_point T>
|
||||||
static void floating_point_to_string(char* buffer, T value, bool upper, const format_options_t options)
|
static void floating_point_to_string(char* buffer, T value, bool upper, const format_options_t options)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +106,8 @@ static void floating_point_to_string(char* buffer, T value, bool upper, const fo
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
if (value < 0)
|
// Add sign if needed
|
||||||
|
if (value < (T)0.0)
|
||||||
{
|
{
|
||||||
buffer[offset++] = '-';
|
buffer[offset++] = '-';
|
||||||
value = -value;
|
value = -value;
|
||||||
|
@ -124,42 +117,98 @@ static void floating_point_to_string(char* buffer, T value, bool upper, const fo
|
||||||
else if (options.show_plus_sign_as_space)
|
else if (options.show_plus_sign_as_space)
|
||||||
buffer[offset++] = ' ';
|
buffer[offset++] = ' ';
|
||||||
|
|
||||||
int exponent = 1;
|
// Round last digit
|
||||||
while (value > exponent * 10)
|
value += (T)0.5 * BAN::Math::pow<T>(10.0, -percision);
|
||||||
exponent *= 10;
|
|
||||||
|
|
||||||
T fractional = value;
|
// Add integer part of the decimal
|
||||||
while (exponent >= 1)
|
if (value < (T)1.0)
|
||||||
{
|
{
|
||||||
int scale = 0;
|
buffer[offset++] = '0';
|
||||||
for (; scale < 10; scale++)
|
value *= (T)10.0;
|
||||||
if (fractional < T(exponent * (scale + 1)))
|
}
|
||||||
break;
|
else
|
||||||
buffer[offset++] = '0' + scale;
|
{
|
||||||
fractional -= T(exponent * scale);
|
int exponent = (int)BAN::Math::log10<T>(value);
|
||||||
exponent /= 10;
|
T magnitude = BAN::Math::pow<T>(10, exponent);
|
||||||
|
|
||||||
|
value /= magnitude;
|
||||||
|
|
||||||
|
for (int i = 0; i <= exponent; i++)
|
||||||
|
{
|
||||||
|
int digit = 0;
|
||||||
|
for (; digit < 10; digit++)
|
||||||
|
if (value < digit + 1)
|
||||||
|
break;
|
||||||
|
buffer[offset++] = '0' + digit;
|
||||||
|
value -= (T)digit;
|
||||||
|
value *= (T)10.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.alternate_form && percision <= 0)
|
// We are done if the decimal part is not written
|
||||||
|
if (percision == 0 && !options.alternate_form)
|
||||||
{
|
{
|
||||||
buffer[offset++] = '\0';
|
buffer[offset++] = '\0';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[offset++] = '.';
|
buffer[offset++] = '.';
|
||||||
|
|
||||||
|
// Add the 'percision' digits after decimal point
|
||||||
for (int i = 0; i < percision; i++)
|
for (int i = 0; i < percision; i++)
|
||||||
{
|
{
|
||||||
fractional *= T(10.0);
|
int digit = 0;
|
||||||
if (i == percision - 1)
|
for (; digit < 10; digit++)
|
||||||
fractional += T(0.5);
|
if (value < digit + 1)
|
||||||
int digit = fractional;
|
break;
|
||||||
buffer[offset++] = '0' + digit;
|
buffer[offset++] = '0' + digit;
|
||||||
fractional -= T(digit);
|
value -= (T)digit;
|
||||||
|
value *= (T)10.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[offset++] = '\0';
|
buffer[offset++] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<BAN::floating_point T>
|
||||||
|
static void floating_point_to_exponent_string(char* buffer, T value, bool upper, const format_options_t options)
|
||||||
|
{
|
||||||
|
int percision = 6;
|
||||||
|
if (options.percision != -1)
|
||||||
|
percision = options.percision;
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
// Add sign if needed
|
||||||
|
if (value < (T)0.0)
|
||||||
|
{
|
||||||
|
buffer[offset++] = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
else if (options.show_plus_sign)
|
||||||
|
buffer[offset++] = '+';
|
||||||
|
else if (options.show_plus_sign_as_space)
|
||||||
|
buffer[offset++] = ' ';
|
||||||
|
|
||||||
|
// Calculate which number to put as exponent
|
||||||
|
int exponent = 0;
|
||||||
|
if (value != (T)0.0)
|
||||||
|
{
|
||||||
|
exponent = (int)floorl(BAN::Math::log10<T>(value));
|
||||||
|
value /= BAN::Math::pow<T>(10.0, exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add first numbers before 'e'
|
||||||
|
floating_point_to_string<T>(buffer + offset, value, upper, options);
|
||||||
|
offset = strlen(buffer);
|
||||||
|
|
||||||
|
// Add the exponent part
|
||||||
|
buffer[offset++] = (upper ? 'E' : 'e');
|
||||||
|
format_options_t exponent_options;
|
||||||
|
exponent_options.show_plus_sign = true;
|
||||||
|
exponent_options.zero_padded = true;
|
||||||
|
exponent_options.width = 3;
|
||||||
|
integer_to_string<int>(buffer + offset, exponent, 10, upper, exponent_options);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun)(int, void*), void* data)
|
extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun)(int, void*), void* data)
|
||||||
{
|
{
|
||||||
int written = 0;
|
int written = 0;
|
||||||
|
|
Loading…
Reference in New Issue