#include <errno.h>
#include <float.h>
#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
#define FBUF 8192
static void
check_d(const char *fmt, double val)
{
char got[FBUF], ref[FBUF];
int rlen, glen;
rlen = snprintf(ref, sizeof(ref), fmt, val);
glen = strfromd(got, sizeof(got), fmt, val);
ATF_CHECK_MSG(glen == rlen,
"strfromd(\"%s\", %g): return %d, want %d", fmt, val, glen, rlen);
ATF_CHECK_STREQ_MSG(ref, got, "strfromd(\"%s\", %g)", fmt, val);
}
static void
check_f(const char *fmt, float val)
{
char got[FBUF], ref[FBUF];
int rlen, glen;
rlen = snprintf(ref, sizeof(ref), fmt, (double)val);
glen = strfromf(got, sizeof(got), fmt, val);
ATF_CHECK_MSG(glen == rlen,
"strfromf(\"%s\", %g): return %d, want %d",
fmt, (double)val, glen, rlen);
ATF_CHECK_STREQ_MSG(ref, got, "strfromf(\"%s\", %g)", fmt, (double)val);
}
static void
check_l(const char *fmt, long double val)
{
char got[FBUF], ref[FBUF], lfmt[32];
int rlen, glen;
snprintf(lfmt, sizeof(lfmt), "%.*sL%c",
(int)(strlen(fmt) - 1), fmt, fmt[strlen(fmt) - 1]);
rlen = snprintf(ref, sizeof(ref), lfmt, val);
glen = strfroml(got, sizeof(got), fmt, val);
ATF_CHECK_MSG(glen == rlen,
"strfroml(\"%s\", %Lg): return %d, want %d", fmt, val, glen, rlen);
ATF_CHECK_STREQ_MSG(ref, got, "strfroml(\"%s\", %Lg)", fmt, val);
}
ATF_TC_WITHOUT_HEAD(strfromd_f);
ATF_TC_BODY(strfromd_f, tc)
{
char buf[FBUF];
check_d("%f", 0.0);
check_d("%f", 1.0);
check_d("%f", -1.0);
check_d("%f", 3.14159265358979);
check_d("%f", 1.0 / 3.0);
check_d("%f", 1e10);
check_d("%f", 1e-10);
check_d("%f", DBL_MAX);
check_d("%f", DBL_MIN);
check_d("%.0f", 3.14);
check_d("%.0f", 3.5);
check_d("%.0f", 4.5);
check_d("%.2f", 3.14159);
check_d("%.10f", 1.0 / 7.0);
check_d("%.20f", 1.0);
strfromd(buf, sizeof(buf), "%.6f", 0.0);
ATF_CHECK_STREQ("0.000000", buf);
strfromd(buf, sizeof(buf), "%.6f", -1.5);
ATF_CHECK_STREQ("-1.500000", buf);
}
ATF_TC_WITHOUT_HEAD(strfromd_e);
ATF_TC_BODY(strfromd_e, tc)
{
char buf[FBUF];
check_d("%e", 0.0);
check_d("%e", 1.0);
check_d("%e", -1.0);
check_d("%e", 3.14159265358979);
check_d("%e", 1e100);
check_d("%e", 1e-100);
check_d("%E", 2.718281828);
check_d("%.0e", 3.14);
check_d("%.2e", 12345.6789);
check_d("%.15e", 1.0 / 3.0);
strfromd(buf, sizeof(buf), "%e", 1.0);
ATF_CHECK_STREQ("1.000000e+00", buf);
strfromd(buf, sizeof(buf), "%E", 1.0);
ATF_CHECK_STREQ("1.000000E+00", buf);
}
ATF_TC_WITHOUT_HEAD(strfromd_g);
ATF_TC_BODY(strfromd_g, tc)
{
char buf[FBUF];
check_d("%g", 0.0);
check_d("%g", 1.0);
check_d("%g", 100000.0);
check_d("%g", 1000000.0);
check_d("%g", 0.0001);
check_d("%g", 0.00001);
check_d("%g", 3.14159265358979);
check_d("%G", 1.23e10);
check_d("%.2g", 3.14159);
check_d("%.0g", 3.14159);
check_d("%.10g", 1.0 / 7.0);
check_d("%g", DBL_MIN);
check_d("%g", DBL_MAX);
strfromd(buf, sizeof(buf), "%g", 1.0);
ATF_CHECK_STREQ("1", buf);
strfromd(buf, sizeof(buf), "%g", 100.0);
ATF_CHECK_STREQ("100", buf);
}
ATF_TC_WITHOUT_HEAD(strfromd_a);
ATF_TC_BODY(strfromd_a, tc)
{
char buf[FBUF];
check_d("%a", 0.0);
check_d("%a", 1.0);
check_d("%a", -1.0);
check_d("%a", 0.5);
check_d("%a", 1.5);
check_d("%a", DBL_MIN);
check_d("%a", DBL_MAX);
check_d("%A", 1.0);
check_d("%.4a", 1.0 / 3.0);
check_d("%.0a", 1.5);
strfromd(buf, sizeof(buf), "%a", 1.0);
ATF_CHECK_STREQ("0x1p+0", buf);
strfromd(buf, sizeof(buf), "%a", 0.5);
ATF_CHECK_STREQ("0x1p-1", buf);
strfromd(buf, sizeof(buf), "%A", 1.0);
ATF_CHECK_STREQ("0X1P+0", buf);
}
ATF_TC_WITHOUT_HEAD(strfromd_special);
ATF_TC_BODY(strfromd_special, tc)
{
char buf[FBUF];
check_d("%f", INFINITY);
check_d("%f", -INFINITY);
check_d("%f", NAN);
check_d("%e", INFINITY);
check_d("%e", -INFINITY);
check_d("%e", NAN);
check_d("%g", INFINITY);
check_d("%g", -INFINITY);
check_d("%g", NAN);
check_d("%a", INFINITY);
check_d("%a", -INFINITY);
check_d("%a", NAN);
check_d("%F", INFINITY);
check_d("%E", INFINITY);
check_d("%G", INFINITY);
check_d("%A", INFINITY);
check_d("%f", -0.0);
check_d("%g", -0.0);
check_d("%e", -0.0);
check_d("%a", -0.0);
strfromd(buf, sizeof(buf), "%f", INFINITY);
ATF_CHECK_STREQ("inf", buf);
strfromd(buf, sizeof(buf), "%F", INFINITY);
ATF_CHECK_STREQ("INF", buf);
strfromd(buf, sizeof(buf), "%f", -INFINITY);
ATF_CHECK_STREQ("-inf", buf);
strfromd(buf, sizeof(buf), "%f", NAN);
ATF_CHECK_STREQ("nan", buf);
strfromd(buf, sizeof(buf), "%F", NAN);
ATF_CHECK_STREQ("NAN", buf);
}
ATF_TC_WITHOUT_HEAD(strfromd_truncation);
ATF_TC_BODY(strfromd_truncation, tc)
{
char buf[FBUF];
int ret;
buf[0] = 'X';
ret = strfromd(buf, 0, "%f", 1.0);
ATF_CHECK(ret > 0);
ATF_CHECK_MSG(buf[0] == 'X', "buffer modified with n==0");
ret = strfromd(buf, 5, "%.6f", 1.0);
ATF_CHECK_MSG(ret == 8, "return %d, want 8", ret);
ATF_CHECK_MSG(buf[4] == '\0', "not null terminated at buf[4]");
ATF_CHECK_MSG(strncmp(buf, "1.00", 4) == 0,
"prefix mismatch: got \"%.*s\"", 4, buf);
}
ATF_TC_WITHOUT_HEAD(strfromf_f);
ATF_TC_BODY(strfromf_f, tc)
{
check_f("%f", 0.0f);
check_f("%f", 1.0f);
check_f("%f", -1.0f);
check_f("%f", 3.14159f);
check_f("%.0f", 3.5f);
check_f("%.2f", 3.14159f);
check_f("%.9f", 1.0f / 3.0f);
check_f("%f", FLT_MAX);
check_f("%f", FLT_MIN);
}
ATF_TC_WITHOUT_HEAD(strfromf_e);
ATF_TC_BODY(strfromf_e, tc)
{
char buf[FBUF];
check_f("%e", 0.0f);
check_f("%e", 1.0f);
check_f("%e", -1.0f);
check_f("%e", 3.14159f);
check_f("%E", 2.71828f);
check_f("%.2e", 12345.6f);
check_f("%.0e", 3.14f);
strfromf(buf, sizeof(buf), "%e", 1.0f);
ATF_CHECK_STREQ("1.000000e+00", buf);
}
ATF_TC_WITHOUT_HEAD(strfromf_g);
ATF_TC_BODY(strfromf_g, tc)
{
char buf[FBUF];
check_f("%g", 0.0f);
check_f("%g", 1.0f);
check_f("%g", 100000.0f);
check_f("%g", 1000000.0f);
check_f("%g", 0.0001f);
check_f("%g", 0.00001f);
check_f("%G", 1.23e10f);
check_f("%.2g", 3.14159f);
strfromf(buf, sizeof(buf), "%g", 1.0f);
ATF_CHECK_STREQ("1", buf);
}
ATF_TC_WITHOUT_HEAD(strfromf_a);
ATF_TC_BODY(strfromf_a, tc)
{
char buf[FBUF];
check_f("%a", 0.0f);
check_f("%a", 1.0f);
check_f("%a", 0.5f);
check_f("%a", -1.0f);
check_f("%A", 1.0f);
check_f("%.2a", 1.0f / 3.0f);
strfromf(buf, sizeof(buf), "%a", 1.0f);
ATF_CHECK_STREQ("0x1p+0", buf);
}
ATF_TC_WITHOUT_HEAD(strfromf_special);
ATF_TC_BODY(strfromf_special, tc)
{
check_f("%f", INFINITY);
check_f("%f", -INFINITY);
check_f("%f", NAN);
check_f("%e", INFINITY);
check_f("%g", INFINITY);
check_f("%a", INFINITY);
check_f("%F", INFINITY);
check_f("%f", -0.0f);
check_f("%g", -0.0f);
}
ATF_TC_WITHOUT_HEAD(strfromf_truncation);
ATF_TC_BODY(strfromf_truncation, tc)
{
char buf[FBUF];
int ret;
buf[0] = 'X';
ret = strfromf(buf, 0, "%f", 1.0f);
ATF_CHECK(ret > 0);
ATF_CHECK_MSG(buf[0] == 'X', "buffer modified with n==0");
ret = strfromf(buf, 5, "%.6f", 1.0f);
ATF_CHECK_MSG(ret == 8, "return %d, want 8", ret);
ATF_CHECK_MSG(buf[4] == '\0', "not null terminated at buf[4]");
}
ATF_TC_WITHOUT_HEAD(strfroml_f);
ATF_TC_BODY(strfroml_f, tc)
{
check_l("%f", 0.0L);
check_l("%f", 1.0L);
check_l("%f", -1.0L);
check_l("%f", 3.14159265358979323846L);
check_l("%.0f", 3.5L);
check_l("%.2f", 3.14159L);
check_l("%.15f", 1.0L / 3.0L);
check_l("%f", LDBL_MAX);
check_l("%f", LDBL_MIN);
}
ATF_TC_WITHOUT_HEAD(strfroml_e);
ATF_TC_BODY(strfroml_e, tc)
{
char buf[FBUF];
check_l("%e", 0.0L);
check_l("%e", 1.0L);
check_l("%e", -1.0L);
check_l("%e", 3.14159265358979323846L);
check_l("%E", 2.71828182845904523536L);
check_l("%.2e", 12345.6789L);
check_l("%.0e", 3.14L);
check_l("%e", LDBL_MAX);
check_l("%e", LDBL_MIN);
strfroml(buf, sizeof(buf), "%e", 1.0L);
ATF_CHECK_STREQ("1.000000e+00", buf);
}
ATF_TC_WITHOUT_HEAD(strfroml_g);
ATF_TC_BODY(strfroml_g, tc)
{
char buf[FBUF];
check_l("%g", 0.0L);
check_l("%g", 1.0L);
check_l("%g", 100000.0L);
check_l("%g", 1000000.0L);
check_l("%g", 0.0001L);
check_l("%g", 0.00001L);
check_l("%G", 1.23e10L);
check_l("%.2g", 3.14159L);
check_l("%.0g", 3.14159L);
strfroml(buf, sizeof(buf), "%g", 1.0L);
ATF_CHECK_STREQ("1", buf);
}
ATF_TC_WITHOUT_HEAD(strfroml_a);
ATF_TC_BODY(strfroml_a, tc)
{
char buf[FBUF];
check_l("%a", 0.0L);
check_l("%a", 1.0L);
check_l("%a", 0.5L);
check_l("%a", -1.0L);
check_l("%A", 1.0L);
check_l("%.4a", 1.0L / 3.0L);
check_l("%.0a", 1.5L);
check_l("%a", LDBL_MAX);
check_l("%a", LDBL_MIN);
strfroml(buf, sizeof(buf), "%a", 1.0L);
ATF_CHECK_STREQ("0x1p+0", buf);
}
ATF_TC_WITHOUT_HEAD(strfroml_special);
ATF_TC_BODY(strfroml_special, tc)
{
check_l("%f", INFINITY);
check_l("%f", -INFINITY);
check_l("%f", NAN);
check_l("%e", INFINITY);
check_l("%g", INFINITY);
check_l("%a", INFINITY);
check_l("%F", INFINITY);
check_l("%f", -0.0L);
check_l("%g", -0.0L);
#ifdef __HAVE_LONG_DOUBLE
check_l("%.20f", 1.0L / 3.0L);
check_l("%.20e", 1.0L / 7.0L);
#endif
}
ATF_TC_WITHOUT_HEAD(strfroml_truncation);
ATF_TC_BODY(strfroml_truncation, tc)
{
char buf[FBUF];
int ret;
buf[0] = 'X';
ret = strfroml(buf, 0, "%f", 1.0L);
ATF_CHECK(ret > 0);
ATF_CHECK_MSG(buf[0] == 'X', "buffer modified with n==0");
ret = strfroml(buf, 5, "%.6f", 1.0L);
ATF_CHECK_MSG(ret == 8, "return %d, want 8", ret);
ATF_CHECK_MSG(buf[4] == '\0', "not null terminated at buf[4]");
}
ATF_TC_WITHOUT_HEAD(strfrom_locale);
ATF_TC_BODY(strfrom_locale, tc)
{
char buf[FBUF];
if (setlocale(LC_NUMERIC, "de_DE.UTF-8") == NULL)
atf_tc_skip("de_DE.UTF-8 locale not available");
check_d("%f", 1.5);
check_d("%e", 1.5);
check_d("%g", 1.5);
check_d("%a", 1.5);
check_f("%f", 1.5f);
check_l("%f", 1.5L);
strfromd(buf, sizeof(buf), "%.1f", 1.5);
ATF_CHECK_STREQ("1,5", buf);
strfromd(buf, sizeof(buf), "%a", 1.5);
ATF_CHECK_STREQ("0x1,8p+0", buf);
}
static void
check_edoofus(const char *fmt, int ret, const char *buf)
{
ATF_CHECK_MSG(ret == 7, "%s: return %d, want 7", fmt, ret);
ATF_CHECK_STREQ_MSG("EDOOFUS", buf, "%s: got \"%s\"", fmt, buf);
ATF_CHECK_MSG(errno == EDOOFUS, "%s: errno %d, want %d", fmt, errno,
EDOOFUS);
}
ATF_TC_WITHOUT_HEAD(strfrom_empty_format);
ATF_TC_BODY(strfrom_empty_format, tc)
{
char buf[FBUF];
int ret;
errno = 0;
ret = strfromd(buf, sizeof(buf), "", 1.0);
check_edoofus("", ret, buf);
}
ATF_TC_WITHOUT_HEAD(strfrom_bad_specifier);
ATF_TC_BODY(strfrom_bad_specifier, tc)
{
char buf[FBUF];
int ret;
errno = 0;
ret = strfromd(buf, sizeof(buf), "%q", 1.0);
check_edoofus("%q", ret, buf);
errno = 0;
ret = strfromf(buf, sizeof(buf), "%.2q", 1.0f);
check_edoofus("%.2q", ret, buf);
errno = 0;
ret = strfroml(buf, sizeof(buf), "%", 1.0L);
check_edoofus("%", ret, buf);
errno = 0;
ret = strfromd(buf, sizeof(buf), "f", 1.0);
check_edoofus("f", ret, buf);
errno = 0;
ret = strfromd(buf, sizeof(buf), "%*f", 1.0);
check_edoofus("%*f", ret, buf);
errno = 0;
ret = strfromd(buf, sizeof(buf), "%f ", 1.0);
check_edoofus("%f ", ret, buf);
}
ATF_TC_WITHOUT_HEAD(strfrom_bad_format_truncation);
ATF_TC_BODY(strfrom_bad_format_truncation, tc)
{
char buf[FBUF];
int ret;
buf[0] = 'X';
errno = 0;
ret = strfromd(buf, 0, "%q", 1.0);
ATF_CHECK_MSG(ret == 7, "return %d, want 7", ret);
ATF_CHECK_MSG(buf[0] == 'X', "buffer modified with n==0");
ATF_CHECK_EQ(EDOOFUS, errno);
errno = 0;
ret = strfromd(buf, 4, "%q", 1.0);
ATF_CHECK_MSG(ret == 7, "return %d, want 7", ret);
ATF_CHECK_STREQ("EDO", buf);
ATF_CHECK_EQ(EDOOFUS, errno);
}
ATF_TC_WITHOUT_HEAD(strfrom_errno_preserved);
ATF_TC_BODY(strfrom_errno_preserved, tc)
{
char buf[FBUF];
errno = 0;
strfromd(buf, sizeof(buf), "%f", 1.0);
ATF_CHECK_EQ(0, errno);
strfromf(buf, sizeof(buf), "%a", 1.0f);
ATF_CHECK_EQ(0, errno);
strfroml(buf, sizeof(buf), "%.3g", 1.0L);
ATF_CHECK_EQ(0, errno);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, strfromd_f);
ATF_TP_ADD_TC(tp, strfromd_e);
ATF_TP_ADD_TC(tp, strfromd_g);
ATF_TP_ADD_TC(tp, strfromd_a);
ATF_TP_ADD_TC(tp, strfromd_special);
ATF_TP_ADD_TC(tp, strfromd_truncation);
ATF_TP_ADD_TC(tp, strfromf_f);
ATF_TP_ADD_TC(tp, strfromf_e);
ATF_TP_ADD_TC(tp, strfromf_g);
ATF_TP_ADD_TC(tp, strfromf_a);
ATF_TP_ADD_TC(tp, strfromf_special);
ATF_TP_ADD_TC(tp, strfromf_truncation);
ATF_TP_ADD_TC(tp, strfroml_f);
ATF_TP_ADD_TC(tp, strfroml_e);
ATF_TP_ADD_TC(tp, strfroml_g);
ATF_TP_ADD_TC(tp, strfroml_a);
ATF_TP_ADD_TC(tp, strfroml_special);
ATF_TP_ADD_TC(tp, strfroml_truncation);
ATF_TP_ADD_TC(tp, strfrom_locale);
ATF_TP_ADD_TC(tp, strfrom_empty_format);
ATF_TP_ADD_TC(tp, strfrom_bad_specifier);
ATF_TP_ADD_TC(tp, strfrom_bad_format_truncation);
ATF_TP_ADD_TC(tp, strfrom_errno_preserved);
return (atf_no_error());
}