1538aa54dSGarrett D'Amore /*
2538aa54dSGarrett D'Amore  * This file and its contents are supplied under the terms of the
3538aa54dSGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
4538aa54dSGarrett D'Amore  * You may only use this file in accordance with the terms of version
5538aa54dSGarrett D'Amore  * 1.0 of the CDDL.
6538aa54dSGarrett D'Amore  *
7538aa54dSGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
8538aa54dSGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
9538aa54dSGarrett D'Amore  * http://www.illumos.org/license/CDDL.
10538aa54dSGarrett D'Amore  */
11538aa54dSGarrett D'Amore 
12538aa54dSGarrett D'Amore /*
13538aa54dSGarrett D'Amore  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
14538aa54dSGarrett D'Amore  */
15538aa54dSGarrett D'Amore 
16538aa54dSGarrett D'Amore /*
17538aa54dSGarrett D'Amore  * This program tests that newlocale and uselocale work properly in
18538aa54dSGarrett D'Amore  * multi-threaded programs.  In order for it to work, it requires that
19538aa54dSGarrett D'Amore  * some additional locales be installed.
20538aa54dSGarrett D'Amore  */
21538aa54dSGarrett D'Amore 
22538aa54dSGarrett D'Amore #include <stdio.h>
23538aa54dSGarrett D'Amore #include <stdlib.h>
24538aa54dSGarrett D'Amore #include <string.h>
25538aa54dSGarrett D'Amore #include <locale.h>
26538aa54dSGarrett D'Amore #include <libintl.h>
27538aa54dSGarrett D'Amore #include <langinfo.h>
28538aa54dSGarrett D'Amore #include <nl_types.h>
29538aa54dSGarrett D'Amore #include <err.h>
30538aa54dSGarrett D'Amore #include <errno.h>
31538aa54dSGarrett D'Amore #include <unistd.h>
32538aa54dSGarrett D'Amore #include "test_common.h"
33538aa54dSGarrett D'Amore 
34538aa54dSGarrett D'Amore /*
35538aa54dSGarrett D'Amore  * Note that on some platforms, different symbols are used.  For example,
36538aa54dSGarrett D'Amore  * MacOS Mavericks uses "Eu" for Euro symbol, instead of €.  If the locale
37538aa54dSGarrett D'Amore  * data changes, then this program will need to update to reflect that.
38538aa54dSGarrett D'Amore  *
39538aa54dSGarrett D'Amore  * Note also that this file is easiest edited with a UTF-8 capable editor,
40538aa54dSGarrett D'Amore  * as there are embedded UTF-8 symbols in some of the strings.
41538aa54dSGarrett D'Amore  */
42538aa54dSGarrett D'Amore struct langinfo_test {
43538aa54dSGarrett D'Amore 	nl_item		param;
44538aa54dSGarrett D'Amore 	const char	*value;
45538aa54dSGarrett D'Amore };
46538aa54dSGarrett D'Amore 
47538aa54dSGarrett D'Amore struct langinfo_test C_data[] = {
48538aa54dSGarrett D'Amore 	{ CODESET,	"646" },
49538aa54dSGarrett D'Amore 	{ D_T_FMT,	"%a %b %e %H:%M:%S %Y" },
50538aa54dSGarrett D'Amore 	{ D_FMT,	"%m/%d/%y" },
51538aa54dSGarrett D'Amore 	{ T_FMT,	"%H:%M:%S" },
52538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
53538aa54dSGarrett D'Amore 	{ AM_STR,	"AM" },
54538aa54dSGarrett D'Amore 	{ PM_STR,	"PM" },
55538aa54dSGarrett D'Amore 	{ ERA,		"" },
56538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
57538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
58538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
59538aa54dSGarrett D'Amore 	{ DAY_1,	"Sunday" },
60538aa54dSGarrett D'Amore 	{ DAY_7,	"Saturday" },
61538aa54dSGarrett D'Amore 	{ ABDAY_1,	"Sun" },
62538aa54dSGarrett D'Amore 	{ ABDAY_7,	"Sat" },
63538aa54dSGarrett D'Amore 	{ MON_1,	"January" },
64538aa54dSGarrett D'Amore 	{ MON_12,	"December" },
65538aa54dSGarrett D'Amore 	{ ABMON_1,	"Jan" },
66538aa54dSGarrett D'Amore 	{ ABMON_12,	"Dec" },
67538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"." },
68538aa54dSGarrett D'Amore 	{ THOUSEP,	"" },
69538aa54dSGarrett D'Amore 	{ YESSTR,	"yes" },
70538aa54dSGarrett D'Amore 	{ NOSTR,	"no" },
71538aa54dSGarrett D'Amore 	{ YESEXPR,	"^[yY]" },
72538aa54dSGarrett D'Amore 	{ NOEXPR,	"^[nN]" },
73538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"" },
74538aa54dSGarrett D'Amore 	{ -1,		NULL }
75538aa54dSGarrett D'Amore };
76538aa54dSGarrett D'Amore 
77538aa54dSGarrett D'Amore struct langinfo_test en_us_utf8_data[] = {
78538aa54dSGarrett D'Amore 	{ CODESET,	"UTF-8" },
796cf13876SYuri Pankov 	{ D_T_FMT,	"%B %e, %Y at %I:%M:%S %p %Z" },
80*1efcb034SYuri Pankov 	{ D_FMT,	"%m/%d/%y" },
81538aa54dSGarrett D'Amore 	{ T_FMT,	"%I:%M:%S %p" },
82538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
83538aa54dSGarrett D'Amore 	{ AM_STR,	"AM" },
84538aa54dSGarrett D'Amore 	{ PM_STR,	"PM" },
85538aa54dSGarrett D'Amore 	{ ERA,		"" },
86538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
87538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
88538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
89538aa54dSGarrett D'Amore 	{ DAY_1,	"Sunday" },
90538aa54dSGarrett D'Amore 	{ DAY_7,	"Saturday" },
91538aa54dSGarrett D'Amore 	{ ABDAY_1,	"Sun" },
92538aa54dSGarrett D'Amore 	{ ABDAY_7,	"Sat" },
93538aa54dSGarrett D'Amore 	{ MON_1,	"January" },
94538aa54dSGarrett D'Amore 	{ MON_12,	"December" },
95538aa54dSGarrett D'Amore 	{ ABMON_1,	"Jan" },
96538aa54dSGarrett D'Amore 	{ ABMON_12,	"Dec" },
97538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"." },
98538aa54dSGarrett D'Amore 	{ THOUSEP,	"," },
99538aa54dSGarrett D'Amore 	{ YESSTR,	"yes" },
100538aa54dSGarrett D'Amore 	{ NOSTR,	"no" },
1016cf13876SYuri Pankov 	{ YESEXPR,	"^(([yY]([eE][sS])?)|([yY]))" },
1026cf13876SYuri Pankov 	{ NOEXPR,	"^(([nN]([oO])?)|([nN]))" },
103538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"-$" },
104538aa54dSGarrett D'Amore 	{ -1,		NULL }
105538aa54dSGarrett D'Amore };
106538aa54dSGarrett D'Amore 
107538aa54dSGarrett D'Amore struct langinfo_test en_gb_latin15_data[] = {
108538aa54dSGarrett D'Amore 	{ CODESET,	"ISO8859-15" },
1096cf13876SYuri Pankov 	{ D_T_FMT,	"%e %B %Y at %H:%M:%S %Z" },
110538aa54dSGarrett D'Amore 	{ D_FMT,	"%d/%m/%Y" },
111538aa54dSGarrett D'Amore 	{ T_FMT,	"%H:%M:%S" },
112538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
1136cf13876SYuri Pankov 	{ AM_STR,	"am" },
1146cf13876SYuri Pankov 	{ PM_STR,	"pm" },
115538aa54dSGarrett D'Amore 	{ ERA,		"" },
116538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
117538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
118538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
119538aa54dSGarrett D'Amore 	{ DAY_1,	"Sunday" },
120538aa54dSGarrett D'Amore 	{ DAY_7,	"Saturday" },
121538aa54dSGarrett D'Amore 	{ ABDAY_1,	"Sun" },
122538aa54dSGarrett D'Amore 	{ ABDAY_7,	"Sat" },
123538aa54dSGarrett D'Amore 	{ MON_1,	"January" },
124538aa54dSGarrett D'Amore 	{ MON_12,	"December" },
125538aa54dSGarrett D'Amore 	{ ABMON_1,	"Jan" },
126538aa54dSGarrett D'Amore 	{ ABMON_12,	"Dec" },
127538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"." },
128538aa54dSGarrett D'Amore 	{ THOUSEP,	"," },
129538aa54dSGarrett D'Amore 	{ YESSTR,	"yes" },
130538aa54dSGarrett D'Amore 	{ NOSTR,	"no" },
1316cf13876SYuri Pankov 	{ YESEXPR,	"^(([yY]([eE][sS])?)|([yY]))" },
1326cf13876SYuri Pankov 	{ NOEXPR,	"^(([nN]([oO])?)|([nN]))" },
133538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"-\243" },
134538aa54dSGarrett D'Amore 	{ -1,		NULL }
135538aa54dSGarrett D'Amore };
136538aa54dSGarrett D'Amore 
137538aa54dSGarrett D'Amore struct langinfo_test ru_ru_utf8_data[] = {
138538aa54dSGarrett D'Amore 	{ CODESET,	"UTF-8" },
1396cf13876SYuri Pankov 	{ D_T_FMT,	"%e %B %Y г., %H:%M:%S %Z"},
1406cf13876SYuri Pankov 	{ D_FMT,	"%d.%m.%Y" },
141538aa54dSGarrett D'Amore 	{ T_FMT,	"%H:%M:%S" },
142538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
1436cf13876SYuri Pankov 	{ AM_STR,	"ДП" },
1446cf13876SYuri Pankov 	{ PM_STR,	"ПП" },
145538aa54dSGarrett D'Amore 	{ ERA,		"" },
146538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
147538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
148538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
149538aa54dSGarrett D'Amore 	{ DAY_1,	"воскресенье" },
150538aa54dSGarrett D'Amore 	{ DAY_7,	"суббота" },
151538aa54dSGarrett D'Amore 	{ ABDAY_1,	"вс" },
152538aa54dSGarrett D'Amore 	{ ABDAY_7,	"сб" },
153538aa54dSGarrett D'Amore 	{ MON_1,	"января" },
154538aa54dSGarrett D'Amore 	{ MON_12,	"декабря" },
1556cf13876SYuri Pankov 	{ ABMON_1,	"янв." },
1566cf13876SYuri Pankov 	{ ABMON_12,	"дек." },
157538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"," },
158538aa54dSGarrett D'Amore 	{ THOUSEP,	" " },
159538aa54dSGarrett D'Amore 	{ YESSTR,	"да" },
160538aa54dSGarrett D'Amore 	{ NOSTR,	"нет" },
1616cf13876SYuri Pankov 	{ YESEXPR,	"^(([дД]([аА])?)|([дД])|([yY]([eE][sS])?)|([yY]))" },
1626cf13876SYuri Pankov 	{ NOEXPR,	"^(([нН]([еЕ][тТ])?)|([нН])|([nN]([oO])?)|([nN]))" },
1636cf13876SYuri Pankov 	{ CRNCYSTR,	"+₽" },
164538aa54dSGarrett D'Amore 	{ -1,		NULL }
165538aa54dSGarrett D'Amore };
166538aa54dSGarrett D'Amore 
167538aa54dSGarrett D'Amore struct {
168538aa54dSGarrett D'Amore 	const char *locale;
169538aa54dSGarrett D'Amore 	struct langinfo_test *loctest;
170538aa54dSGarrett D'Amore } locales[] =  {
171538aa54dSGarrett D'Amore 	{ "C",			C_data },
172538aa54dSGarrett D'Amore 	{ "en_US.UTF-8",	en_us_utf8_data },
173538aa54dSGarrett D'Amore 	{ "en_GB.ISO8859-15",	en_gb_latin15_data },
174538aa54dSGarrett D'Amore 	{ "ru_RU.UTF-8",	ru_ru_utf8_data },
175538aa54dSGarrett D'Amore 	{ NULL, 		NULL }
176538aa54dSGarrett D'Amore };
177538aa54dSGarrett D'Amore 
178538aa54dSGarrett D'Amore void
test_nl_langinfo_1(const char * locale,struct langinfo_test * test)179538aa54dSGarrett D'Amore test_nl_langinfo_1(const char *locale, struct langinfo_test *test)
180538aa54dSGarrett D'Amore {
181538aa54dSGarrett D'Amore 	char 	tname[128];
182538aa54dSGarrett D'Amore 	char 	*v;
183538aa54dSGarrett D'Amore 	test_t	t;
184538aa54dSGarrett D'Amore 
185538aa54dSGarrett D'Amore 	(void) snprintf(tname, sizeof (tname), "nl_langinfo (locale %s)",
186538aa54dSGarrett D'Amore 	    locale);
187538aa54dSGarrett D'Amore 	t = test_start(tname);
188538aa54dSGarrett D'Amore 
189538aa54dSGarrett D'Amore 	v = setlocale(LC_ALL, locale);
190538aa54dSGarrett D'Amore 	if (v == NULL) {
191538aa54dSGarrett D'Amore 		test_failed(t, "setlocale failed: %s", strerror(errno));
192538aa54dSGarrett D'Amore 	}
193538aa54dSGarrett D'Amore 	if (strcmp(v, locale) != 0) {
194538aa54dSGarrett D'Amore 		test_failed(t, "setlocale got %s instead of %s", v, locale);
195538aa54dSGarrett D'Amore 	}
196538aa54dSGarrett D'Amore 
197538aa54dSGarrett D'Amore 	for (int i = 0; test[i].value != NULL; i++) {
198538aa54dSGarrett D'Amore 		v = nl_langinfo(test[i].param);
199538aa54dSGarrett D'Amore 		test_debugf(t, "%d: expect [%s], got [%s]",
200538aa54dSGarrett D'Amore 		    test[i].param, test[i].value, v);
201538aa54dSGarrett D'Amore 		if (strcmp(v, test[i].value) != 0) {
202538aa54dSGarrett D'Amore 			test_failed(t,
203538aa54dSGarrett D'Amore 			    "param %d wrong, expected [%s], got [%s]",
204538aa54dSGarrett D'Amore 			    test[i].param, test[i].value, v);
205538aa54dSGarrett D'Amore 		}
206538aa54dSGarrett D'Amore 	}
207538aa54dSGarrett D'Amore 	test_passed(t);
208538aa54dSGarrett D'Amore }
209538aa54dSGarrett D'Amore 
210538aa54dSGarrett D'Amore void
test_nl_langinfo_l(const char * locale,struct langinfo_test * test)211538aa54dSGarrett D'Amore test_nl_langinfo_l(const char *locale, struct langinfo_test *test)
212538aa54dSGarrett D'Amore {
213538aa54dSGarrett D'Amore 	char 		tname[128];
214538aa54dSGarrett D'Amore 	char 		*v;
215538aa54dSGarrett D'Amore 	test_t		t;
216538aa54dSGarrett D'Amore 	locale_t	loc;
217538aa54dSGarrett D'Amore 
218538aa54dSGarrett D'Amore 	(void) snprintf(tname, sizeof (tname), "nl_langinfo_l (locale %s)",
219538aa54dSGarrett D'Amore 	    locale);
220538aa54dSGarrett D'Amore 	t = test_start(tname);
221538aa54dSGarrett D'Amore 
222538aa54dSGarrett D'Amore 	v = setlocale(LC_ALL, "C");
223538aa54dSGarrett D'Amore 	if (v == NULL) {
224538aa54dSGarrett D'Amore 		test_failed(t, "setlocale failed: %s", strerror(errno));
225538aa54dSGarrett D'Amore 	}
226538aa54dSGarrett D'Amore 	if (strcmp(v, "C") != 0) {
227538aa54dSGarrett D'Amore 		test_failed(t, "setlocale got %s instead of %s", v, "C");
228538aa54dSGarrett D'Amore 	}
229538aa54dSGarrett D'Amore 
230538aa54dSGarrett D'Amore 	loc = newlocale(LC_ALL_MASK, locale, NULL);
231538aa54dSGarrett D'Amore 	if (loc == NULL) {
232538aa54dSGarrett D'Amore 		test_failed(t, "newlocale failed: %s", strerror(errno));
233538aa54dSGarrett D'Amore 	}
234538aa54dSGarrett D'Amore 
235538aa54dSGarrett D'Amore 	for (int i = 0; test[i].value != NULL; i++) {
236538aa54dSGarrett D'Amore 		v = nl_langinfo_l(test[i].param, loc);
237538aa54dSGarrett D'Amore 		test_debugf(t, "%d: expect [%s], got [%s]",
238538aa54dSGarrett D'Amore 		    test[i].param, test[i].value, v);
239538aa54dSGarrett D'Amore 		if (strcmp(v, test[i].value) != 0) {
240538aa54dSGarrett D'Amore 			test_failed(t,
241538aa54dSGarrett D'Amore 			    "param %d wrong, expected [%s], got [%s]",
242538aa54dSGarrett D'Amore 			    test[i].param, test[i].value, v);
243538aa54dSGarrett D'Amore 		}
244538aa54dSGarrett D'Amore 	}
245538aa54dSGarrett D'Amore 	test_passed(t);
246538aa54dSGarrett D'Amore }
247538aa54dSGarrett D'Amore void
test_nl_langinfo(void)248538aa54dSGarrett D'Amore test_nl_langinfo(void)
249538aa54dSGarrett D'Amore {
250538aa54dSGarrett D'Amore 	for (int i = 0; locales[i].locale != NULL; i++) {
251538aa54dSGarrett D'Amore 		test_nl_langinfo_1(locales[i].locale, locales[i].loctest);
252538aa54dSGarrett D'Amore 		test_nl_langinfo_l(locales[i].locale, locales[i].loctest);
253538aa54dSGarrett D'Amore 	}
254538aa54dSGarrett D'Amore }
255538aa54dSGarrett D'Amore 
256538aa54dSGarrett D'Amore int
main(int argc,char ** argv)257538aa54dSGarrett D'Amore main(int argc, char **argv)
258538aa54dSGarrett D'Amore {
259538aa54dSGarrett D'Amore 	int optc;
260538aa54dSGarrett D'Amore 
261538aa54dSGarrett D'Amore 	while ((optc = getopt(argc, argv, "df")) != EOF) {
262538aa54dSGarrett D'Amore 		switch (optc) {
263538aa54dSGarrett D'Amore 		case 'd':
264538aa54dSGarrett D'Amore 			test_set_debug();
265538aa54dSGarrett D'Amore 			break;
266538aa54dSGarrett D'Amore 		case 'f':
267538aa54dSGarrett D'Amore 			test_set_force();
268538aa54dSGarrett D'Amore 			break;
269538aa54dSGarrett D'Amore 		default:
270538aa54dSGarrett D'Amore 			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
271538aa54dSGarrett D'Amore 			exit(1);
272538aa54dSGarrett D'Amore 		}
273538aa54dSGarrett D'Amore 	}
274538aa54dSGarrett D'Amore 
275538aa54dSGarrett D'Amore 	test_nl_langinfo();
276538aa54dSGarrett D'Amore 
277538aa54dSGarrett D'Amore 	exit(0);
278538aa54dSGarrett D'Amore }
279