Skip to content

Commit

Permalink
WIP sprintf
Browse files Browse the repository at this point in the history
TODO:
- finish test
- test denormals
- idea for precision: multiply with a power of 2 to not change the digits, then cast to int64, extract with some magic (compare against 10 << n)
  • Loading branch information
tkreuzer committed Oct 26, 2023
1 parent 1f91c2b commit 7e10476
Show file tree
Hide file tree
Showing 2 changed files with 597 additions and 122 deletions.
158 changes: 151 additions & 7 deletions modules/rostests/apitests/crt/sprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define WIN32_NO_STATUS
#include <stdio.h>
#include <tchar.h>
#include <float.h>
#include <pseh/pseh2.h>
#include <ndk/mmfuncs.h>
#include <ndk/rtlfuncs.h>
Expand All @@ -26,13 +27,30 @@
#endif
#endif

/* NOTE: This test is not only used for all the CRT apitests, but also for
* user32's wsprintf. Make sure to test them all */
START_TEST(sprintf)
#undef assert
#if DBG
#define assert(x) if (!(x)) __int2c()
#else
#define assert(x)
#endif

#define ok_sprintf_1_(line, format, arg, expected) \
{ \
char buffer[500]; \
int len = sprintf(buffer, format, arg); \
assert(len < _countof(buffer)); \
int expected_len = (int)strlen(expected); \
ok_str_(__FILE__, line, buffer, expected); \
ok_int_(__FILE__, line, len, expected_len); \
}

#define ok_sprintf_1(format, arg, expected) \
ok_sprintf_1_(__LINE__, format, arg, expected)

static void test_basic(void)
{
int Length;
CHAR Buffer[128];
PCHAR String;

/* basic parameter tests */
StartSeh()
Expand Down Expand Up @@ -73,10 +91,19 @@ START_TEST(sprintf)
Length = sprintf(Buffer, "%%%");
ok_str(Buffer, "%");
ok_int(Length, 1);
}

Length = sprintf(Buffer, "%d", 8);
ok_str(Buffer, "8");
ok_int(Length, 1);
static void test_int_d(void)
{
ok_sprintf_1("%d", 8, "8");

}

static void test_string(void)
{
int Length;
CHAR Buffer[128];
PCHAR String;

Length = sprintf(Buffer, "%s", "hello");
ok_str(Buffer, "hello");
Expand Down Expand Up @@ -258,3 +285,120 @@ START_TEST(sprintf)

FreeGuarded(String);
}


//
// Floating point values.
// The format pecifier: "%[flags][width][.precision][length]specifier"
// flags: '-', '+', ' ', '#', '0'
// specifier: 'e', 'E', 'f', 'F', 'g', 'G', 'a', 'A'
//
// The results is printed as:
// [left_ws_padding][sign][left_0_padding][integer_significant][integer_0_pad][.][fraction_significant][fraction_0_pad]
//

static const UINT64 g_Inf = 0x7FF0000000000000ULL;
static const UINT64 g_NegInf = 0xFFF0000000000000ULL;
static const UINT64 g_NaN1 = 0x7FF0000000000001ULL;
static const UINT64 g_NaN2 = 0x7FF8000000000001ULL;
static const UINT64 g_NaN3 = 0x7FFFFFFFFFFFFFFFULL;
static const UINT64 g_NaN4 = 0x7FF80000000000F1ULL;
static const UINT64 g_NegNaN1 = 0xFFF0000000000001ULL;

void test_float_f(void)
{
ok_sprintf_1("%f", 0.0, "0.000000");
ok_sprintf_1("%f", 1.0, "1.000000");
ok_sprintf_1("%f", -1.0, "-1.000000");
ok_sprintf_1("%f", 1.23456789, "1.234568");
ok_sprintf_1("%f", 0.00123456789, "0.001235");
ok_sprintf_1("%f", FLT_MAX, "340282346638528860000000000000000000000.000000");
ok_sprintf_1("%f", DBL_MAX, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000");
ok_sprintf_1("% f", 1.0, " 1.000000");
ok_sprintf_1("% f", -1.0, "-1.000000");
ok_sprintf_1("%4f", 1.0, "1.000000");
ok_sprintf_1("%8f", 1.0, "1.000000");
ok_sprintf_1("%9f", 1.0, " 1.000000");
ok_sprintf_1("% 9f", 1.0, " 1.000000");
ok_sprintf_1("%9f", -1.0, "-1.000000");
ok_sprintf_1("%10f", -1.0, " -1.000000");
ok_sprintf_1("% 10f", -1.0, " -1.000000");
ok_sprintf_1("%0f", 1.0, "1.000000");
ok_sprintf_1("%010f", -1.0, "-01.000000");
ok_sprintf_1("%.0f", 0.6, "1");
ok_sprintf_1("%.0f", 1.23456789, "1");
ok_sprintf_1("%.3f", 1.23456789, "1.235");
ok_sprintf_1("%.11f", 1.23456789, "1.23456789000");

ok_sprintf_1("%f", -123.45678, "-123.456780");
ok_sprintf_1("%f", -9.2559631349317830737e+061, "-92559631349317831000000000000000000000000000000000000000000000.000000");

ok_sprintf_1("%f", *(double*)&g_Inf, "1.#INF00");
ok_sprintf_1("%f", *(double*)&g_NegInf, "-1.#INF00");
ok_sprintf_1("%f", *(double*)&g_NaN1, "1.#SNAN0");
ok_sprintf_1("%f", *(double*)&g_NegNaN1, "-1.#SNAN0");
ok_sprintf_1("%f", *(double*)&g_NaN2, "1.#QNAN0");
ok_sprintf_1("%f", *(double*)&g_NaN3, "1.#QNAN0");
ok_sprintf_1("%f", *(double*)&g_NaN4, "1.#QNAN0");
ok_sprintf_1("%10f", *(double*)&g_Inf, " 1.#INF00");
ok_sprintf_1("%.10f", *(double*)&g_Inf, "1.#INF000000");
ok_sprintf_1("%.0f", *(double*)&g_Inf, "1");

// %lf (same as %f)
ok_sprintf_1("%lf", 0.0, "0.000000");
ok_sprintf_1("%lf", 1.0, "1.000000");
ok_sprintf_1("%lf", -1.0, "-1.000000");
ok_sprintf_1("%lf", -123.45678, "-123.456780");


}

void test_float_e(void)
{
ok_sprintf_1("%e", 1.0, "1.000000e+000");
ok_sprintf_1("% 13e", 1.0, " 1.000000e+000");
ok_sprintf_1("% 14e", 1.0, " 1.000000e+000");
ok_sprintf_1("% 15e", 1.0, " 1.000000e+000");
ok_sprintf_1("%013e", 1.0, "1.000000e+000");
ok_sprintf_1("%014e", 1.0, "01.000000e+000");
ok_sprintf_1("%015e", 1.0, "001.000000e+000");
ok_sprintf_1("%.0e", 1.23456789, "1e+000");
ok_sprintf_1("%.3e", 1.23456789, "1.235e+000");
ok_sprintf_1("%.11e", 1.23456789, "1.23456789000e+000");

ok_sprintf_1("%e", *(double*)&g_Inf, "1.#INF00e+000");
ok_sprintf_1("%e", *(double*)&g_NegInf, "-1.#INF00e+000");
ok_sprintf_1("%e", *(double*)&g_NaN1, "1.#SNAN0e+000");
ok_sprintf_1("%e", *(double*)&g_NegNaN1, "-1.#SNAN0e+000");
ok_sprintf_1("%e", *(double*)&g_NaN2, "1.#QNAN0e+000");
ok_sprintf_1("%e", *(double*)&g_NaN3, "1.#QNAN0e+000");
ok_sprintf_1("%e", *(double*)&g_NaN4, "1.#QNAN0e+000");
ok_sprintf_1("%14e", *(double*)&g_Inf, " 1.#INF00e+000");
ok_sprintf_1("%.10e", *(double*)&g_Inf, "1.#INF000000e+000");
ok_sprintf_1("%.0e", *(double*)&g_Inf, "1e+000");

char buffer[100];
int len = sprintf(buffer, "%-+.*E", 3, 999999999999.9);
ok_str(buffer, "+1.000E+012");
ok_int(len, 11);
}

void test_float_g(void)
{
ok_sprintf_1("%g", 1.123e+007, "8.123");

ok_sprintf_1("%.7G", 9.9999999747524270788e-007, "1E-006");

}

/* NOTE: This test is not only used for all the CRT apitests, but also for
* user32's wsprintf. Make sure to test them all */
START_TEST(sprintf)
{
//test_basic();
//test_int_d();
//test_string();
test_float_f();
test_float_e();
test_float_g();
}
Loading

0 comments on commit 7e10476

Please sign in to comment.