1 /* $NetBSD: t_sprintf.c,v 1.5 2017/11/24 21:30:43 kre Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad Schroder. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __COPYRIGHT("@(#) Copyright (c) 2017\ 34 The NetBSD Foundation, inc. All rights reserved."); 35 __RCSID("$NetBSD: t_sprintf.c,v 1.5 2017/11/24 21:30:43 kre Exp $"); 36 37 #include <locale.h> 38 #include <math.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <limits.h> 43 #include <ctype.h> 44 45 #include <atf-c.h> 46 47 static struct test { 48 const char *locale; 49 const int int_value; 50 const char *int_result; 51 const char *int_input; 52 const double double_value; 53 const char *double_result; 54 const char *double_input; 55 } tests[] = { 56 { 57 "en_US.UTF-8", 58 -12345, 59 "-12,345", 60 "-12345", 61 -12345.6789, 62 "-12,345.678900", 63 "-12345.678900", 64 }, { 65 "fr_FR.ISO8859-1", 66 -12345, 67 "-12\240345", 68 "-12345", 69 -12345.6789, 70 "-12\240345,678900", 71 "-12345,678900", 72 }, { 73 "it_IT.ISO8859-1", 74 -12345, 75 "-12.345", 76 "-12345", 77 -12345.6789, 78 "-12.345,678900", 79 "-12345,678900", 80 }, { 81 "POSIX", 82 /* 83 * POSIX-1.2008 specifies that the C and POSIX 84 * locales shall be identical (section 7.2) and 85 * that the POSIX locale shall have an empty 86 * thousands separator and "<period>" as its 87 * decimal point (section 7.3.4). *printf 88 * ought to honor these settings. 89 */ 90 -12345, 91 "-12345", 92 "-12345", 93 -12345.6789, 94 "-12345.678900", 95 "-12345.678900", 96 }, { 97 NULL, 98 0, 99 NULL, 100 NULL, 101 0.0, 102 NULL, 103 NULL, 104 } 105 }; 106 107 static void 108 h_sprintf(const struct test *t) 109 { 110 char buf[1024]; 111 112 ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C"); 113 printf("Trying locale %s...\n", t->locale); 114 ATF_REQUIRE(setlocale(LC_NUMERIC, t->locale) != NULL); 115 printf("Using locale: %s\n", setlocale(LC_ALL, NULL)); 116 117 sprintf(buf, "%'f", t->double_value); 118 ATF_REQUIRE_STREQ(buf, t->double_result); 119 120 sprintf(buf, "%'d", t->int_value); 121 ATF_REQUIRE_STREQ(buf, t->int_result); 122 123 atf_tc_expect_pass(); 124 } 125 126 static void 127 h_strto(const struct test *t) 128 { 129 double d, diff; 130 131 ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C"); 132 printf("Trying locale %s...\n", t->locale); 133 ATF_REQUIRE(setlocale(LC_NUMERIC, t->locale) != NULL); 134 135 ATF_REQUIRE_EQ((int)strtol(t->int_input, NULL, 10), t->int_value); 136 d = strtod(t->double_input, NULL); 137 if ((diff = fabs(d - t->double_value)) > 1e-7) 138 ATF_REQUIRE_EQ_MSG(d, t->double_value, "In %s: d=strtod(" 139 "t->double_input[%s], NULL)[%.9g] != t->double_value[%.9g]" 140 ": diff=%g", t->locale, t->double_input, d, 141 t->double_value, diff); 142 } 143 144 static void 145 h_sscanf(const struct test *t) 146 { 147 int int_reported; 148 double double_reported; 149 150 ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C"); 151 printf("Trying locale %s...\n", t->locale); 152 ATF_REQUIRE(setlocale(LC_NUMERIC, t->locale) != NULL); 153 154 sscanf(t->int_input, "%d", &int_reported); 155 ATF_REQUIRE_EQ(int_reported, t->int_value); 156 sscanf(t->double_input, "%lf", &double_reported); 157 ATF_REQUIRE_EQ(double_reported, t->double_value); 158 } 159 160 ATF_TC(sprintf); 161 ATF_TC_HEAD(sprintf, tc) 162 { 163 atf_tc_set_md_var(tc, "descr", 164 "Checks sprintf %%'d and %%'f under diferent locales"); 165 } 166 ATF_TC_BODY(sprintf, tc) 167 { 168 struct test *t; 169 170 for (t = &tests[0]; t->locale != NULL; ++t) 171 h_sprintf(t); 172 } 173 174 ATF_TC(strto); 175 ATF_TC_HEAD(strto, tc) 176 { 177 atf_tc_set_md_var(tc, "descr", 178 "Checks strtol and strtod under diferent locales"); 179 } 180 ATF_TC_BODY(strto, tc) 181 { 182 struct test *t; 183 184 for (t = &tests[0]; t->locale != NULL; ++t) 185 h_strto(t); 186 } 187 188 ATF_TC(sscanf); 189 ATF_TC_HEAD(sscanf, tc) 190 { 191 atf_tc_set_md_var(tc, "descr", 192 "Checks sscanf under diferent locales"); 193 } 194 ATF_TC_BODY(sscanf, tc) 195 { 196 struct test *t; 197 198 for (t = &tests[0]; t->locale != NULL; ++t) 199 h_sscanf(t); 200 } 201 202 ATF_TP_ADD_TCS(tp) 203 { 204 205 ATF_TP_ADD_TC(tp, sprintf); 206 ATF_TP_ADD_TC(tp, sscanf); 207 ATF_TP_ADD_TC(tp, strto); 208 209 return atf_no_error(); 210 } 211