1*538aa54dSGarrett D'Amore /*
2*538aa54dSGarrett D'Amore  * This file and its contents are supplied under the terms of the
3*538aa54dSGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
4*538aa54dSGarrett D'Amore  * You may only use this file in accordance with the terms of version
5*538aa54dSGarrett D'Amore  * 1.0 of the CDDL.
6*538aa54dSGarrett D'Amore  *
7*538aa54dSGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
8*538aa54dSGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
9*538aa54dSGarrett D'Amore  * http://www.illumos.org/license/CDDL.
10*538aa54dSGarrett D'Amore  */
11*538aa54dSGarrett D'Amore 
12*538aa54dSGarrett D'Amore /*
13*538aa54dSGarrett D'Amore  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
14*538aa54dSGarrett D'Amore  */
15*538aa54dSGarrett D'Amore 
16*538aa54dSGarrett D'Amore /*
17*538aa54dSGarrett D'Amore  * This program tests that newlocale and uselocale work properly in
18*538aa54dSGarrett D'Amore  * multi-threaded programs.  In order for it to work, it requires that
19*538aa54dSGarrett D'Amore  * some additional locales be installed.
20*538aa54dSGarrett D'Amore  */
21*538aa54dSGarrett D'Amore 
22*538aa54dSGarrett D'Amore #include <stdio.h>
23*538aa54dSGarrett D'Amore #include <stdlib.h>
24*538aa54dSGarrett D'Amore #include <string.h>
25*538aa54dSGarrett D'Amore #include <locale.h>
26*538aa54dSGarrett D'Amore #include <libintl.h>
27*538aa54dSGarrett D'Amore #include <langinfo.h>
28*538aa54dSGarrett D'Amore #include <nl_types.h>
29*538aa54dSGarrett D'Amore #include <err.h>
30*538aa54dSGarrett D'Amore #include <errno.h>
31*538aa54dSGarrett D'Amore #include <unistd.h>
32*538aa54dSGarrett D'Amore #include "test_common.h"
33*538aa54dSGarrett D'Amore 
34*538aa54dSGarrett D'Amore /*
35*538aa54dSGarrett D'Amore  * Note that on some platforms, different symbols are used.  For example,
36*538aa54dSGarrett D'Amore  * MacOS Mavericks uses "Eu" for Euro symbol, instead of €.  If the locale
37*538aa54dSGarrett D'Amore  * data changes, then this program will need to update to reflect that.
38*538aa54dSGarrett D'Amore  *
39*538aa54dSGarrett D'Amore  * Note also that this file is easiest edited with a UTF-8 capable editor,
40*538aa54dSGarrett D'Amore  * as there are embedded UTF-8 symbols in some of the strings.
41*538aa54dSGarrett D'Amore  */
42*538aa54dSGarrett D'Amore struct langinfo_test {
43*538aa54dSGarrett D'Amore 	nl_item		param;
44*538aa54dSGarrett D'Amore 	const char	*value;
45*538aa54dSGarrett D'Amore };
46*538aa54dSGarrett D'Amore 
47*538aa54dSGarrett D'Amore struct langinfo_test C_data[] = {
48*538aa54dSGarrett D'Amore 	{ CODESET,	"646" },
49*538aa54dSGarrett D'Amore 	{ D_T_FMT,	"%a %b %e %H:%M:%S %Y" },
50*538aa54dSGarrett D'Amore 	{ D_FMT,	"%m/%d/%y" },
51*538aa54dSGarrett D'Amore 	{ T_FMT,	"%H:%M:%S" },
52*538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
53*538aa54dSGarrett D'Amore 	{ AM_STR,	"AM" },
54*538aa54dSGarrett D'Amore 	{ PM_STR,	"PM" },
55*538aa54dSGarrett D'Amore 	{ ERA,		"" },
56*538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
57*538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
58*538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
59*538aa54dSGarrett D'Amore 	{ DAY_1,	"Sunday" },
60*538aa54dSGarrett D'Amore 	{ DAY_7,	"Saturday" },
61*538aa54dSGarrett D'Amore 	{ ABDAY_1,	"Sun" },
62*538aa54dSGarrett D'Amore 	{ ABDAY_7,	"Sat" },
63*538aa54dSGarrett D'Amore 	{ MON_1,	"January" },
64*538aa54dSGarrett D'Amore 	{ MON_12,	"December" },
65*538aa54dSGarrett D'Amore 	{ ABMON_1,	"Jan" },
66*538aa54dSGarrett D'Amore 	{ ABMON_12,	"Dec" },
67*538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"." },
68*538aa54dSGarrett D'Amore 	{ THOUSEP,	"" },
69*538aa54dSGarrett D'Amore 	{ YESSTR,	"yes" },
70*538aa54dSGarrett D'Amore 	{ NOSTR,	"no" },
71*538aa54dSGarrett D'Amore 	{ YESEXPR,	"^[yY]" },
72*538aa54dSGarrett D'Amore 	{ NOEXPR,	"^[nN]" },
73*538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"" },
74*538aa54dSGarrett D'Amore 	{ -1,		NULL }
75*538aa54dSGarrett D'Amore };
76*538aa54dSGarrett D'Amore 
77*538aa54dSGarrett D'Amore struct langinfo_test en_us_utf8_data[] = {
78*538aa54dSGarrett D'Amore 	{ CODESET,	"UTF-8" },
79*538aa54dSGarrett D'Amore 	{ D_T_FMT,	"%B %e, %Y %I:%M:%S %p %Z" },
80*538aa54dSGarrett D'Amore 	{ D_FMT,	"%m/%e/%y" },
81*538aa54dSGarrett D'Amore 	{ T_FMT,	"%I:%M:%S %p" },
82*538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
83*538aa54dSGarrett D'Amore 	{ AM_STR,	"AM" },
84*538aa54dSGarrett D'Amore 	{ PM_STR,	"PM" },
85*538aa54dSGarrett D'Amore 	{ ERA,		"" },
86*538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
87*538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
88*538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
89*538aa54dSGarrett D'Amore 	{ DAY_1,	"Sunday" },
90*538aa54dSGarrett D'Amore 	{ DAY_7,	"Saturday" },
91*538aa54dSGarrett D'Amore 	{ ABDAY_1,	"Sun" },
92*538aa54dSGarrett D'Amore 	{ ABDAY_7,	"Sat" },
93*538aa54dSGarrett D'Amore 	{ MON_1,	"January" },
94*538aa54dSGarrett D'Amore 	{ MON_12,	"December" },
95*538aa54dSGarrett D'Amore 	{ ABMON_1,	"Jan" },
96*538aa54dSGarrett D'Amore 	{ ABMON_12,	"Dec" },
97*538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"." },
98*538aa54dSGarrett D'Amore 	{ THOUSEP,	"," },
99*538aa54dSGarrett D'Amore 	{ YESSTR,	"yes" },
100*538aa54dSGarrett D'Amore 	{ NOSTR,	"no" },
101*538aa54dSGarrett D'Amore 	{ YESEXPR,	"^(([yY]([eE][sS])?))" },
102*538aa54dSGarrett D'Amore 	{ NOEXPR,	"^(([nN]([oO])?))" },
103*538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"-$" },
104*538aa54dSGarrett D'Amore 	{ -1,		NULL }
105*538aa54dSGarrett D'Amore };
106*538aa54dSGarrett D'Amore 
107*538aa54dSGarrett D'Amore struct langinfo_test en_gb_latin15_data[] = {
108*538aa54dSGarrett D'Amore 	{ CODESET,	"ISO8859-15" },
109*538aa54dSGarrett D'Amore 	{ D_T_FMT,	"%e %B %Y %H:%M:%S %Z" },
110*538aa54dSGarrett D'Amore 	{ D_FMT,	"%d/%m/%Y" },
111*538aa54dSGarrett D'Amore 	{ T_FMT,	"%H:%M:%S" },
112*538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
113*538aa54dSGarrett D'Amore 	{ AM_STR,	"AM" },
114*538aa54dSGarrett D'Amore 	{ PM_STR,	"PM" },
115*538aa54dSGarrett D'Amore 	{ ERA,		"" },
116*538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
117*538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
118*538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
119*538aa54dSGarrett D'Amore 	{ DAY_1,	"Sunday" },
120*538aa54dSGarrett D'Amore 	{ DAY_7,	"Saturday" },
121*538aa54dSGarrett D'Amore 	{ ABDAY_1,	"Sun" },
122*538aa54dSGarrett D'Amore 	{ ABDAY_7,	"Sat" },
123*538aa54dSGarrett D'Amore 	{ MON_1,	"January" },
124*538aa54dSGarrett D'Amore 	{ MON_12,	"December" },
125*538aa54dSGarrett D'Amore 	{ ABMON_1,	"Jan" },
126*538aa54dSGarrett D'Amore 	{ ABMON_12,	"Dec" },
127*538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"." },
128*538aa54dSGarrett D'Amore 	{ THOUSEP,	"," },
129*538aa54dSGarrett D'Amore 	{ YESSTR,	"yes" },
130*538aa54dSGarrett D'Amore 	{ NOSTR,	"no" },
131*538aa54dSGarrett D'Amore 	{ YESEXPR,	"^(([yY]([eE][sS])?))" },
132*538aa54dSGarrett D'Amore 	{ NOEXPR,	"^(([nN]([oO])?))" },
133*538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"-\243" },
134*538aa54dSGarrett D'Amore 	{ -1,		NULL }
135*538aa54dSGarrett D'Amore };
136*538aa54dSGarrett D'Amore 
137*538aa54dSGarrett D'Amore struct langinfo_test ru_ru_utf8_data[] = {
138*538aa54dSGarrett D'Amore 	{ CODESET,	"UTF-8" },
139*538aa54dSGarrett D'Amore 	{ D_T_FMT,	"%e %B %Y г. %H:%M:%S %Z"},
140*538aa54dSGarrett D'Amore 	{ D_FMT,	"%d.%m.%y" },
141*538aa54dSGarrett D'Amore 	{ T_FMT,	"%H:%M:%S" },
142*538aa54dSGarrett D'Amore 	{ T_FMT_AMPM,	"%I:%M:%S %p" },
143*538aa54dSGarrett D'Amore 	{ AM_STR,	"до полудня" },
144*538aa54dSGarrett D'Amore 	{ PM_STR,	"после полудня" },
145*538aa54dSGarrett D'Amore 	{ ERA,		"" },
146*538aa54dSGarrett D'Amore 	{ ERA_D_FMT,	"" },
147*538aa54dSGarrett D'Amore 	{ ERA_D_T_FMT,	"" },
148*538aa54dSGarrett D'Amore 	{ ERA_T_FMT,	"" },
149*538aa54dSGarrett D'Amore 	{ DAY_1,	"воскресенье" },
150*538aa54dSGarrett D'Amore 	{ DAY_7,	"суббота" },
151*538aa54dSGarrett D'Amore 	{ ABDAY_1,	"вс" },
152*538aa54dSGarrett D'Amore 	{ ABDAY_7,	"сб" },
153*538aa54dSGarrett D'Amore 	{ MON_1,	"января" },
154*538aa54dSGarrett D'Amore 	{ MON_12,	"декабря" },
155*538aa54dSGarrett D'Amore 	{ ABMON_1,	"янв" },
156*538aa54dSGarrett D'Amore 	{ ABMON_12,	"дек" },
157*538aa54dSGarrett D'Amore 	{ RADIXCHAR,	"," },
158*538aa54dSGarrett D'Amore 	{ THOUSEP,	" " },
159*538aa54dSGarrett D'Amore 	{ YESSTR,	"да" },
160*538aa54dSGarrett D'Amore 	{ NOSTR,	"нет" },
161*538aa54dSGarrett D'Amore 	{ YESEXPR,	"^(([дД]([аА])?)|([yY]([eE][sS])?))" },
162*538aa54dSGarrett D'Amore 	{ NOEXPR,	"^(([нН]([еЕ][тТ])?)|([nN]([oO])?))" },
163*538aa54dSGarrett D'Amore 	{ CRNCYSTR,	"+руб." },
164*538aa54dSGarrett D'Amore 	{ -1,		NULL }
165*538aa54dSGarrett D'Amore };
166*538aa54dSGarrett D'Amore 
167*538aa54dSGarrett D'Amore struct {
168*538aa54dSGarrett D'Amore 	const char *locale;
169*538aa54dSGarrett D'Amore 	struct langinfo_test *loctest;
170*538aa54dSGarrett D'Amore } locales[] =  {
171*538aa54dSGarrett D'Amore 	{ "C",			C_data },
172*538aa54dSGarrett D'Amore 	{ "en_US.UTF-8",	en_us_utf8_data },
173*538aa54dSGarrett D'Amore 	{ "en_GB.ISO8859-15",	en_gb_latin15_data },
174*538aa54dSGarrett D'Amore 	{ "ru_RU.UTF-8",	ru_ru_utf8_data },
175*538aa54dSGarrett D'Amore 	{ NULL, 		NULL }
176*538aa54dSGarrett D'Amore };
177*538aa54dSGarrett D'Amore 
178*538aa54dSGarrett D'Amore void
179*538aa54dSGarrett D'Amore test_nl_langinfo_1(const char *locale, struct langinfo_test *test)
180*538aa54dSGarrett D'Amore {
181*538aa54dSGarrett D'Amore 	char 	tname[128];
182*538aa54dSGarrett D'Amore 	char 	*v;
183*538aa54dSGarrett D'Amore 	test_t	t;
184*538aa54dSGarrett D'Amore 
185*538aa54dSGarrett D'Amore 	(void) snprintf(tname, sizeof (tname), "nl_langinfo (locale %s)",
186*538aa54dSGarrett D'Amore 	    locale);
187*538aa54dSGarrett D'Amore 	t = test_start(tname);
188*538aa54dSGarrett D'Amore 
189*538aa54dSGarrett D'Amore 	v = setlocale(LC_ALL, locale);
190*538aa54dSGarrett D'Amore 	if (v == NULL) {
191*538aa54dSGarrett D'Amore 		test_failed(t, "setlocale failed: %s", strerror(errno));
192*538aa54dSGarrett D'Amore 	}
193*538aa54dSGarrett D'Amore 	if (strcmp(v, locale) != 0) {
194*538aa54dSGarrett D'Amore 		test_failed(t, "setlocale got %s instead of %s", v, locale);
195*538aa54dSGarrett D'Amore 	}
196*538aa54dSGarrett D'Amore 
197*538aa54dSGarrett D'Amore 	for (int i = 0; test[i].value != NULL; i++) {
198*538aa54dSGarrett D'Amore 		v = nl_langinfo(test[i].param);
199*538aa54dSGarrett D'Amore 		test_debugf(t, "%d: expect [%s], got [%s]",
200*538aa54dSGarrett D'Amore 		    test[i].param, test[i].value, v);
201*538aa54dSGarrett D'Amore 		if (strcmp(v, test[i].value) != 0) {
202*538aa54dSGarrett D'Amore 			test_failed(t,
203*538aa54dSGarrett D'Amore 			    "param %d wrong, expected [%s], got [%s]",
204*538aa54dSGarrett D'Amore 			    test[i].param, test[i].value, v);
205*538aa54dSGarrett D'Amore 		}
206*538aa54dSGarrett D'Amore 	}
207*538aa54dSGarrett D'Amore 	test_passed(t);
208*538aa54dSGarrett D'Amore }
209*538aa54dSGarrett D'Amore 
210*538aa54dSGarrett D'Amore void
211*538aa54dSGarrett D'Amore test_nl_langinfo_l(const char *locale, struct langinfo_test *test)
212*538aa54dSGarrett D'Amore {
213*538aa54dSGarrett D'Amore 	char 		tname[128];
214*538aa54dSGarrett D'Amore 	char 		*v;
215*538aa54dSGarrett D'Amore 	test_t		t;
216*538aa54dSGarrett D'Amore 	locale_t	loc;
217*538aa54dSGarrett D'Amore 
218*538aa54dSGarrett D'Amore 	(void) snprintf(tname, sizeof (tname), "nl_langinfo_l (locale %s)",
219*538aa54dSGarrett D'Amore 	    locale);
220*538aa54dSGarrett D'Amore 	t = test_start(tname);
221*538aa54dSGarrett D'Amore 
222*538aa54dSGarrett D'Amore 	v = setlocale(LC_ALL, "C");
223*538aa54dSGarrett D'Amore 	if (v == NULL) {
224*538aa54dSGarrett D'Amore 		test_failed(t, "setlocale failed: %s", strerror(errno));
225*538aa54dSGarrett D'Amore 	}
226*538aa54dSGarrett D'Amore 	if (strcmp(v, "C") != 0) {
227*538aa54dSGarrett D'Amore 		test_failed(t, "setlocale got %s instead of %s", v, "C");
228*538aa54dSGarrett D'Amore 	}
229*538aa54dSGarrett D'Amore 
230*538aa54dSGarrett D'Amore 	loc = newlocale(LC_ALL_MASK, locale, NULL);
231*538aa54dSGarrett D'Amore 	if (loc == NULL) {
232*538aa54dSGarrett D'Amore 		test_failed(t, "newlocale failed: %s", strerror(errno));
233*538aa54dSGarrett D'Amore 	}
234*538aa54dSGarrett D'Amore 
235*538aa54dSGarrett D'Amore 	for (int i = 0; test[i].value != NULL; i++) {
236*538aa54dSGarrett D'Amore 		v = nl_langinfo_l(test[i].param, loc);
237*538aa54dSGarrett D'Amore 		test_debugf(t, "%d: expect [%s], got [%s]",
238*538aa54dSGarrett D'Amore 		    test[i].param, test[i].value, v);
239*538aa54dSGarrett D'Amore 		if (strcmp(v, test[i].value) != 0) {
240*538aa54dSGarrett D'Amore 			test_failed(t,
241*538aa54dSGarrett D'Amore 			    "param %d wrong, expected [%s], got [%s]",
242*538aa54dSGarrett D'Amore 			    test[i].param, test[i].value, v);
243*538aa54dSGarrett D'Amore 		}
244*538aa54dSGarrett D'Amore 	}
245*538aa54dSGarrett D'Amore 	test_passed(t);
246*538aa54dSGarrett D'Amore }
247*538aa54dSGarrett D'Amore void
248*538aa54dSGarrett D'Amore test_nl_langinfo(void)
249*538aa54dSGarrett D'Amore {
250*538aa54dSGarrett D'Amore 	for (int i = 0; locales[i].locale != NULL; i++) {
251*538aa54dSGarrett D'Amore 		test_nl_langinfo_1(locales[i].locale, locales[i].loctest);
252*538aa54dSGarrett D'Amore 		test_nl_langinfo_l(locales[i].locale, locales[i].loctest);
253*538aa54dSGarrett D'Amore 	}
254*538aa54dSGarrett D'Amore }
255*538aa54dSGarrett D'Amore 
256*538aa54dSGarrett D'Amore int
257*538aa54dSGarrett D'Amore main(int argc, char **argv)
258*538aa54dSGarrett D'Amore {
259*538aa54dSGarrett D'Amore 	int optc;
260*538aa54dSGarrett D'Amore 
261*538aa54dSGarrett D'Amore 	while ((optc = getopt(argc, argv, "df")) != EOF) {
262*538aa54dSGarrett D'Amore 		switch (optc) {
263*538aa54dSGarrett D'Amore 		case 'd':
264*538aa54dSGarrett D'Amore 			test_set_debug();
265*538aa54dSGarrett D'Amore 			break;
266*538aa54dSGarrett D'Amore 		case 'f':
267*538aa54dSGarrett D'Amore 			test_set_force();
268*538aa54dSGarrett D'Amore 			break;
269*538aa54dSGarrett D'Amore 		default:
270*538aa54dSGarrett D'Amore 			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
271*538aa54dSGarrett D'Amore 			exit(1);
272*538aa54dSGarrett D'Amore 		}
273*538aa54dSGarrett D'Amore 	}
274*538aa54dSGarrett D'Amore 
275*538aa54dSGarrett D'Amore 	test_nl_langinfo();
276*538aa54dSGarrett D'Amore 
277*538aa54dSGarrett D'Amore 	exit(0);
278*538aa54dSGarrett D'Amore }
279