xref: /haiku/src/tests/system/libroot/posix/locale_test.cpp (revision 25a7b01d15612846f332751841da3579db313082)
1 /*
2  * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <ctype.h>
7 #include <errno.h>
8 #include <langinfo.h>
9 #include <locale.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 #include <wctype.h>
15 
16 
17 // #pragma mark - setlocale ----------------------------------------------------
18 
19 
20 void
test_setlocale()21 test_setlocale()
22 {
23 	const char* locales[] = {
24 		"POSIX",
25 		"C",
26 		"de_DE",
27 		"en_US",
28 		"en_US.US-ASCII",
29 		"hr_HR.ISO-8859-2",
30 		"nl_NL",
31 		"nb_NO",
32 		"fr_FR.UTF-8@collation=phonebook",
33 		"de_DE.iso8859-1",
34 		"De_dE.IsO8859-15",
35 		"de_DE.utf8",
36 		"de_DE.UTF-8",
37 		"de_DE@euro",
38 		"de_DE@EURO",
39 		"de_DE.utf-8@Euro",
40 		"POSIX",
41 		"C",
42 		NULL
43 	};
44 	const char* expectedLocales[] = {
45 		"POSIX",
46 		"POSIX",
47 		"de_DE",
48 		"en_US",
49 		"en_US.US-ASCII",
50 		"hr_HR.ISO-8859-2",
51 		"nl_NL",
52 		"nb_NO",
53 		"fr_FR.UTF-8@collation=phonebook",
54 		"de_DE.iso8859-1",
55 		"De_dE.IsO8859-15",
56 		"de_DE.utf8",
57 		"de_DE.UTF-8",
58 		"de_DE@euro",
59 		"de_DE@EURO",
60 		"de_DE.utf-8@Euro",
61 		"POSIX",
62 		"POSIX"
63 	};
64 	const char* categoryNames[] = {
65 		"LC_ALL",
66 		"LC_COLLATE",
67 		"LC_CTYPE",
68 		"LC_MONETARY",
69 		"LC_NUMERIC",
70 		"LC_TIME",
71 		"LC_MESSAGES"
72 	};
73 	printf("setlocale()\n");
74 
75 	int problemCount = 0;
76 	for (int i = 0; locales[i] != NULL; ++i) {
77 		char* result = setlocale(LC_ALL, locales[i]);
78 		if (!result || strcmp(result, expectedLocales[i]) != 0) {
79 			printf("\tPROBLEM: setlocale(LC_ALL, \"%s\") = \"%s\" "
80 					"(expected \"%s\")\n",
81 				locales[i], result, expectedLocales[i]);
82 			problemCount++;
83 		}
84 	}
85 
86 	for (int i = 1; i <= LC_LAST; ++i)
87 		setlocale(i, locales[i + 1]);
88 	char* result = setlocale(LC_ALL, NULL);
89 	const char* expectedResult
90 		= "LC_COLLATE=de_DE;LC_CTYPE=en_US;LC_MESSAGES=nb_NO;"
91 			"LC_MONETARY=en_US.US-ASCII;LC_NUMERIC=hr_HR.ISO-8859-2;"
92 			"LC_TIME=nl_NL";
93 	if (!result || strcmp(result, expectedResult) != 0) {
94 		printf("\tPROBLEM: setlocale(LC_ALL, NULL) = \"%s\" "
95 				"(expected \"%s\")\n", result, expectedResult);
96 		problemCount++;
97 	}
98 
99 	if (problemCount)
100 		printf("\t%d problem(s) found!\n", problemCount);
101 	else
102 		printf("\tall fine\n");
103 }
104 
105 
106 // #pragma mark - localeconv ---------------------------------------------------
107 
108 
109 void
dumpGrouping(const char * grouping,char * buf)110 dumpGrouping(const char* grouping, char* buf)
111 {
112 	for (char* bufPtr = buf; *grouping; ++grouping)
113 		bufPtr += sprintf(bufPtr, "\\x%02x", *grouping);
114 }
115 
116 
117 void
test_localeconv(const char * locale,const lconv * localeConv)118 test_localeconv(const char* locale, const lconv* localeConv)
119 {
120 	setlocale(LC_MONETARY, locale);
121 	setlocale(LC_NUMERIC, locale);
122 	printf("localeconv for '%s'\n", locale);
123 
124 	int problemCount = 0;
125 	struct lconv* lc = localeconv();
126 	if (!lc)
127 		printf("not ok - got no result from localeconv()\n");
128 	else {
129 		if (strcmp(lc->decimal_point, localeConv->decimal_point) != 0) {
130 			printf("\tPROBLEM: lc.decimal_point = \"%s\" (expected \"%s\")\n",
131 				lc->decimal_point, localeConv->decimal_point);
132 			problemCount++;
133 		}
134 		if (strcmp(lc->thousands_sep, localeConv->thousands_sep) != 0) {
135 			printf("\tPROBLEM: lc.thousands_sep = \"%s\" (expected \"%s\")\n",
136 				lc->thousands_sep, localeConv->thousands_sep);
137 			problemCount++;
138 		}
139 		if (strcmp(lc->grouping, localeConv->grouping) != 0) {
140 			char gotGrouping[20], expectedGrouping[20];
141 			dumpGrouping(lc->grouping, gotGrouping);
142 			dumpGrouping(localeConv->grouping, expectedGrouping);
143 			printf("\tPROBLEM: lc.grouping = \"%s\" (expected \"%s\")\n",
144 				gotGrouping, expectedGrouping);
145 			problemCount++;
146 		}
147 		if (strcmp(lc->int_curr_symbol, localeConv->int_curr_symbol) != 0) {
148 			printf("\tPROBLEM: lc.int_curr_symbol = \"%s\" (expected \"%s\")\n",
149 				lc->int_curr_symbol, localeConv->int_curr_symbol);
150 			problemCount++;
151 		}
152 		if (strcmp(lc->currency_symbol, localeConv->currency_symbol) != 0) {
153 			printf("\tPROBLEM: lc.currency_symbol = \"%s\" (expected \"%s\")\n",
154 				lc->currency_symbol, localeConv->currency_symbol);
155 			problemCount++;
156 		}
157 		if (strcmp(lc->mon_decimal_point, localeConv->mon_decimal_point) != 0) {
158 			printf("\tPROBLEM: lc.mon_decimal_point = \"%s\" "
159 					"(expected \"%s\")\n",
160 				lc->mon_decimal_point, localeConv->mon_decimal_point);
161 			problemCount++;
162 		}
163 		if (strcmp(lc->mon_thousands_sep, localeConv->mon_thousands_sep) != 0) {
164 			printf("\tPROBLEM: lc.mon_thousands_sep = \"%s\" "
165 					"(expected \"%s\")\n",
166 				lc->mon_thousands_sep, localeConv->mon_thousands_sep);
167 			problemCount++;
168 		}
169 		if (strcmp(lc->mon_grouping, localeConv->mon_grouping) != 0) {
170 			char gotGrouping[20], expectedGrouping[20];
171 			dumpGrouping(lc->mon_grouping, gotGrouping);
172 			dumpGrouping(localeConv->mon_grouping, expectedGrouping);
173 			printf("\tPROBLEM: lc.mon_grouping: \"%s\" (expected \"%s\")\n",
174 				gotGrouping, expectedGrouping);
175 			problemCount++;
176 		}
177 		if (strcmp(lc->positive_sign, localeConv->positive_sign) != 0) {
178 			printf("\tPROBLEM: lc.positive_sign = \"%s\" (expected \"%s\")\n",
179 				lc->positive_sign, localeConv->positive_sign);
180 			problemCount++;
181 		}
182 		if (strcmp(lc->negative_sign, localeConv->negative_sign) != 0) {
183 			printf("\tPROBLEM: lc.negative_sign = \"%s\" (expected \"%s\")\n",
184 				lc->negative_sign, localeConv->negative_sign);
185 			problemCount++;
186 		}
187 		if (lc->frac_digits != localeConv->frac_digits) {
188 			printf("\tPROBLEM: lc.frac_digits = %d (expected %d)\n",
189 				lc->frac_digits, localeConv->frac_digits);
190 			problemCount++;
191 		}
192 		if (lc->int_frac_digits != localeConv->int_frac_digits) {
193 			printf("\tPROBLEM: lc.int_frac_digits = %d (expected %d)\n",
194 				lc->int_frac_digits, localeConv->int_frac_digits);
195 			problemCount++;
196 		}
197 		if (lc->p_cs_precedes != localeConv->p_cs_precedes) {
198 			printf("\tPROBLEM: lc.p_cs_precedes = %d (expected %d)\n",
199 				lc->p_cs_precedes, localeConv->p_cs_precedes);
200 			problemCount++;
201 		}
202 		if (lc->p_sep_by_space != localeConv->p_sep_by_space) {
203 			printf("\tPROBLEM: lc.p_sep_by_space = %d (expected %d)\n",
204 				lc->p_sep_by_space, localeConv->p_sep_by_space);
205 			problemCount++;
206 		}
207 		if (lc->p_sign_posn != localeConv->p_sign_posn) {
208 			printf("\tPROBLEM: lc.p_sign_posn = %d (expected %d)\n",
209 				lc->p_sign_posn, localeConv->p_sign_posn);
210 			problemCount++;
211 		}
212 		if (lc->n_cs_precedes != localeConv->n_cs_precedes) {
213 			printf("\tPROBLEM: lc.n_cs_precedes = %d (expected %d)\n",
214 				lc->n_cs_precedes, localeConv->n_cs_precedes);
215 			problemCount++;
216 		}
217 		if (lc->n_sep_by_space != localeConv->n_sep_by_space) {
218 			printf("\tPROBLEM: lc.n_sep_by_space = %d (expected %d)\n",
219 				lc->n_sep_by_space, localeConv->n_sep_by_space);
220 			problemCount++;
221 		}
222 		if (lc->n_sign_posn != localeConv->n_sign_posn) {
223 			printf("\tPROBLEM: lc.n_sign_posn = %d (expected %d)\n",
224 				lc->n_sign_posn, localeConv->n_sign_posn);
225 			problemCount++;
226 		}
227 		if (lc->int_p_cs_precedes != localeConv->int_p_cs_precedes) {
228 			printf("\tPROBLEM: lc.int_p_cs_precedes = %d (expected %d)\n",
229 				lc->int_p_cs_precedes, localeConv->int_p_cs_precedes);
230 			problemCount++;
231 		}
232 		if (lc->int_p_sep_by_space != localeConv->int_p_sep_by_space) {
233 			printf("\tPROBLEM: lc.int_p_sep_by_space = %d (expected %d)\n",
234 				lc->int_p_sep_by_space, localeConv->int_p_sep_by_space);
235 			problemCount++;
236 		}
237 		if (lc->int_p_sign_posn != localeConv->int_p_sign_posn) {
238 			printf("\tPROBLEM: lc.int_p_sign_posn = %d (expected %d)\n",
239 				lc->int_p_sign_posn, localeConv->int_p_sign_posn);
240 			problemCount++;
241 		}
242 		if (lc->int_n_cs_precedes != localeConv->int_n_cs_precedes) {
243 			printf("\tPROBLEM: lc.int_n_cs_precedes = %d (expected %d)\n",
244 				lc->int_n_cs_precedes, localeConv->int_n_cs_precedes);
245 			problemCount++;
246 		}
247 		if (lc->int_n_sep_by_space != localeConv->int_n_sep_by_space) {
248 			printf("\tPROBLEM: lc.int_n_sep_by_space = %d (expected %d)\n",
249 				lc->int_n_sep_by_space, localeConv->int_n_sep_by_space);
250 			problemCount++;
251 		}
252 		if (lc->int_n_sign_posn != localeConv->int_n_sign_posn) {
253 			printf("\tPROBLEM: lc.int_n_sign_posn = %d (expected %d)\n",
254 				lc->int_n_sign_posn, localeConv->int_n_sign_posn);
255 			problemCount++;
256 		}
257 	}
258 	if (problemCount)
259 		printf("\t%d problem(s) found!\n", problemCount);
260 	else
261 		printf("\tall fine\n");
262 }
263 
264 
265 void
test_localeconv()266 test_localeconv()
267 {
268 	const lconv lconv_posix = {
269 		(char*)".",
270 		(char*)"",
271 		(char*)"",
272 		(char*)"",
273 		(char*)"",
274 		(char*)"",
275 		(char*)"",
276 		(char*)"",
277 		(char*)"",
278 		(char*)"",
279 		CHAR_MAX,
280 		CHAR_MAX,
281 		CHAR_MAX,
282 		CHAR_MAX,
283 		CHAR_MAX,
284 		CHAR_MAX,
285 		CHAR_MAX,
286 		CHAR_MAX,
287 		CHAR_MAX,
288 		CHAR_MAX,
289 		CHAR_MAX,
290 		CHAR_MAX,
291 		CHAR_MAX,
292 		CHAR_MAX
293 	};
294 	test_localeconv("POSIX", &lconv_posix);
295 
296 	const lconv lconv_de = {
297 		(char*)",",
298 		(char*)".",
299 		(char*)"\x03",
300 		(char*)"EUR ",
301 		(char*)"€",
302 		(char*)",",
303 		(char*)".",
304 		(char*)"\x03",
305 		(char*)"",
306 		(char*)"-",
307 		2,
308 		2,
309 		0,
310 		1,
311 		0,
312 		1,
313 		1,
314 		1,
315 		0,
316 		1,
317 		0,
318 		1,
319 		1,
320 		1
321 	};
322 	test_localeconv("de_DE", &lconv_de);
323 
324 	const lconv lconv_de_iso = {
325 		(char*)",",
326 		(char*)".",
327 		(char*)"\x03",
328 		(char*)"EUR ",
329 		(char*)"EUR",
330 		(char*)",",
331 		(char*)".",
332 		(char*)"\x03",
333 		(char*)"",
334 		(char*)"-",
335 		2,
336 		2,
337 		0,
338 		1,
339 		0,
340 		1,
341 		1,
342 		1,
343 		0,
344 		1,
345 		0,
346 		1,
347 		1,
348 		1
349 	};
350 	test_localeconv("de_DE.ISO8859-1", &lconv_de_iso);
351 
352 	const lconv lconv_hr = {
353 		(char*)",",
354 		(char*)".",
355 		(char*)"\x03",
356 		(char*)"HRK ",
357 		(char*)"kn",
358 		(char*)",",
359 		(char*)".",
360 		(char*)"\x03",
361 		(char*)"",
362 		(char*)"-",
363 		2,
364 		2,
365 		0,
366 		1,
367 		0,
368 		1,
369 		1,
370 		1,
371 		0,
372 		1,
373 		0,
374 		1,
375 		1,
376 		1
377 	};
378 	test_localeconv("hr_HR.ISO8859-2", &lconv_hr);
379 
380 	const lconv lconv_de_CH = {
381 		(char*)".",
382 		(char*)"'",
383 		(char*)"\x03",
384 		(char*)"CHF ",
385 		(char*)"CHF",
386 		(char*)".",
387 		(char*)"'",
388 		(char*)"\x03",
389 		(char*)"",
390 		(char*)"-",
391 		2,
392 		2,
393 		1,
394 		1,
395 		1,
396 		0,
397 		4,
398 		4,
399 		1,
400 		1,
401 		1,
402 		0,
403 		4,
404 		4
405 	};
406 	test_localeconv("de_CH", &lconv_de_CH);
407 
408 	const lconv lconv_gu_IN = {
409 		(char*)".",
410 		(char*)",",
411 		(char*)"\x03\x02",
412 		(char*)"INR ",
413 		(char*)"\xE2\x82\xB9",
414 		(char*)".",
415 		(char*)",",
416 		(char*)"\x03\x02",
417 		(char*)"",
418 		(char*)"-",
419 		2,
420 		2,
421 		1,
422 		1,
423 		1,
424 		1,
425 		1,
426 		1,
427 		1,
428 		1,
429 		1,
430 		1,
431 		1,
432 		1
433 	};
434 	test_localeconv("gu_IN", &lconv_gu_IN);
435 
436 	const lconv lconv_it = {
437 		(char*)",",
438 		(char*)".",
439 		(char*)"\x03",
440 		(char*)"EUR ",
441 		(char*)"€",
442 		(char*)",",
443 		(char*)".",
444 		(char*)"\x03",
445 		(char*)"",
446 		(char*)"-",
447 		2,
448 		2,
449 		1,
450 		1,
451 		1,
452 		1,
453 		1,
454 		1,
455 		1,
456 		1,
457 		1,
458 		1,
459 		1,
460 		1
461 	};
462 	test_localeconv("it_IT", &lconv_it);
463 
464 	const lconv lconv_nl = {
465 		(char*)",",
466 		(char*)".",
467 		(char*)"\x03",
468 		(char*)"EUR ",
469 		(char*)"€",
470 		(char*)",",
471 		(char*)".",
472 		(char*)"\x03",
473 		(char*)"",
474 		(char*)"-",
475 		2,
476 		2,
477 		1,
478 		1,
479 		1,
480 		1,
481 		2,
482 		2,
483 		1,
484 		1,
485 		1,
486 		1,
487 		2,
488 		2
489 	};
490 	test_localeconv("nl_NL", &lconv_nl);
491 
492 	const lconv lconv_nb = {
493 		(char*)",",
494 		(char*)" ",
495 		(char*)"\x03",
496 		(char*)"NOK ",
497 		(char*)"kr",
498 		(char*)",",
499 		(char*)" ",
500 		(char*)"\x03",
501 		(char*)"",
502 		(char*)"-",
503 		2,
504 		2,
505 		1,
506 		1,
507 		1,
508 		1,
509 		1,
510 		1,
511 		1,
512 		1,
513 		1,
514 		1,
515 		1,
516 		1
517 	};
518 	test_localeconv("nb_NO", &lconv_nb);
519 }
520 
521 
522 // #pragma mark - strftime -----------------------------------------------------
523 
524 
525 struct strftime_data {
526 	const char* format;
527 	const char* result;
528 };
529 
530 
531 void
test_strftime(const char * locale,const strftime_data data[])532 test_strftime(const char* locale, const strftime_data data[])
533 {
534 	setlocale(LC_TIME, locale);
535 	printf("strftime for '%s'\n", locale);
536 
537 	time_t testTimeInSecs = 1279391169;	// Sat Jul 17 18:26:09 2010 UTC
538 	tm* testTime = localtime(&testTimeInSecs);
539 	int problemCount = 0;
540 	for(int i = 0; data[i].format != NULL; ++i) {
541 		char buf[100];
542 		strftime(buf, 100, data[i].format, testTime);
543 		if (strcmp(buf, data[i].result) != 0) {
544 			printf("\tPROBLEM: strftime(\"%s\") = \"%s\" (expected \"%s\")\n",
545 				data[i].format, buf, data[i].result);
546 			problemCount++;
547 		}
548 	}
549 	if (problemCount)
550 		printf("\t%d problem(s) found!\n", problemCount);
551 	else
552 		printf("\tall fine\n");
553 }
554 
555 
556 void
test_strftime()557 test_strftime()
558 {
559 	setenv("TZ", "GMT", 1);
560 
561 	const strftime_data strftime_posix[] = {
562 		{ "%c", "Sat Jul 17 18:26:09 2010" },
563 		{ "%x", "07/17/10" },
564 		{ "%X", "18:26:09" },
565 		{ "%a", "Sat" },
566 		{ "%A", "Saturday" },
567 		{ "%b", "Jul" },
568 		{ "%B", "July" },
569 		{ NULL, NULL }
570 	};
571 	test_strftime("POSIX", strftime_posix);
572 
573 	const strftime_data strftime_de[] = {
574 		{ "%c", "Samstag, 17. Juli 2010 18:26:09 GMT" },
575 		{ "%x", "17.07.2010" },
576 		{ "%X", "18:26:09" },
577 		{ "%a", "Sa." },
578 		{ "%A", "Samstag" },
579 		{ "%b", "Jul" },
580 		{ "%B", "Juli" },
581 		{ NULL, NULL }
582 	};
583 	test_strftime("de_DE.UTF-8", strftime_de);
584 
585 	const strftime_data strftime_hr[] = {
586 		{ "%c", "subota, 17. srpnja 2010. 18:26:09 GMT" },
587 		{ "%x", "17. 07. 2010." },
588 		{ "%X", "18:26:09" },
589 		{ "%a", "sub" },
590 		{ "%A", "subota" },
591 		{ "%b", "srp" },
592 		{ "%B", "srpnja" },
593 		{ NULL, NULL }
594 	};
595 	test_strftime("hr_HR.ISO8859-2", strftime_hr);
596 
597 	const strftime_data strftime_gu[] = {
598 		{ "%c", "શનિવાર, 17 જુલાઈ, 2010 06:26:09 PM GMT" },
599 		{ "%x", "17 જુલાઈ, 2010" },
600 		{ "%X", "06:26:09 PM" },
601 		{ "%a", "શનિ" },
602 		{ "%A", "શનિવાર" },
603 		{ "%b", "જુલાઈ" },
604 		{ "%B", "જુલાઈ" },
605 		{ NULL, NULL }
606 	};
607 	test_strftime("gu_IN", strftime_gu);
608 
609 	const strftime_data strftime_it[] = {
610 		{ "%c", "sabato 17 luglio 2010 18:26:09 GMT" },
611 		{ "%x", "17/lug/2010" },
612 		{ "%X", "18:26:09" },
613 		{ "%a", "sab" },
614 		{ "%A", "sabato" },
615 		{ "%b", "lug" },
616 		{ "%B", "luglio" },
617 		{ NULL, NULL }
618 	};
619 	test_strftime("it_IT", strftime_it);
620 
621 	const strftime_data strftime_nl[] = {
622 		{ "%c", "zaterdag 17 juli 2010 18:26:09 GMT" },
623 		{ "%x", "17 jul. 2010" },
624 		{ "%X", "18:26:09" },
625 		{ "%a", "za" },
626 		{ "%A", "zaterdag" },
627 		{ "%b", "jul." },
628 		{ "%B", "juli" },
629 		{ NULL, NULL }
630 	};
631 	test_strftime("nl_NL", strftime_nl);
632 
633 	const strftime_data strftime_nb[] = {
634 		{ "%c", "kl. 18:26:09 GMT lørdag 17. juli 2010" },
635 		{ "%x", "17. juli 2010" },
636 		{ "%X", "18:26:09" },
637 		{ "%a", "lør." },
638 		{ "%A", "lørdag" },
639 		{ "%b", "juli" },
640 		{ "%B", "juli" },
641 		{ NULL, NULL }
642 	};
643 	test_strftime("nb_NO", strftime_nb);
644 }
645 
646 
647 // #pragma mark - strftime -----------------------------------------------------
648 
649 
650 struct strptime_data {
651 	const char* format;
652 	const char* dateString;
653 };
654 
655 
656 void
test_strptime(const char * locale,const strptime_data data[])657 test_strptime(const char* locale, const strptime_data data[])
658 {
659 	setlocale(LC_TIME, locale);
660 	printf("strptime for '%s'\n", locale);
661 
662 	time_t expectedTimeInSecs = 1279391169;	// Sat Jul 17 18:26:09 2010 UTC
663 	int problemCount = 0;
664 	for(int i = 0; data[i].format != NULL; ++i) {
665 		struct tm resultTime;
666 		if (strptime(data[i].dateString, data[i].format, &resultTime) == NULL) {
667 			printf("\tPROBLEM: strptime(\"%s\", \"%s\") failed\n",
668 				data[i].dateString, data[i].format);
669 			problemCount++;
670 		} else {
671 			time_t resultTimeInSecs = mktime(&resultTime);
672 			if (resultTimeInSecs != expectedTimeInSecs) {
673 				printf("\tPROBLEM: strptime(\"%s\", \"%s\") = \"%d\" (expected \"%d\")\n",
674 					data[i].dateString, data[i].format, resultTimeInSecs, expectedTimeInSecs);
675 				problemCount++;
676 			}
677 		}
678 	}
679 	if (problemCount)
680 		printf("\t%d problem(s) found!\n", problemCount);
681 	else
682 		printf("\tall fine\n");
683 }
684 
685 
686 void
test_strptime()687 test_strptime()
688 {
689 	setenv("TZ", "GMT", 1);
690 
691 	const strptime_data strptime_posix[] = {
692 		{ "%c", "Sat Jul 17 18:26:09 2010" },
693 		{ "%x", "07/17/10" },
694 		{ "%X", "18:26:09" },
695 		{ "%a", "Sat" },
696 		{ "%A", "Saturday" },
697 		{ "%b", "Jul" },
698 		{ "%B", "July" },
699 		{ NULL, NULL }
700 	};
701 	test_strptime("POSIX", strptime_posix);
702 
703 	const strptime_data strptime_de[] = {
704 		{ "%c", "Samstag, 17. Juli 2010 18:26:09 GMT" },
705 		{ "%x", "17.07.2010" },
706 		{ "%X", "18:26:09" },
707 		{ "%a", "Sa." },
708 		{ "%A", "Samstag" },
709 		{ "%b", "Jul" },
710 		{ "%B", "Juli" },
711 		{ NULL, NULL }
712 	};
713 	test_strptime("de_DE.UTF-8", strptime_de);
714 
715 	const strptime_data strptime_hr[] = {
716 		{ "%c", "subota, 17. srpnja 2010. 18:26:09 GMT" },
717 		{ "%x", "17. 07. 2010." },
718 		{ "%X", "18:26:09" },
719 		{ "%a", "sub" },
720 		{ "%A", "subota" },
721 		{ "%b", "srp" },
722 		{ "%B", "srpnja" },
723 		{ NULL, NULL }
724 	};
725 	test_strptime("hr_HR.ISO8859-2", strptime_hr);
726 
727 	const strptime_data strptime_gu[] = {
728 		{ "%c", "શનિવાર, 17 જુલાઈ, 2010 06:26:09 PM GMT" },
729 		{ "%x", "17 જુલાઈ, 2010" },
730 		{ "%X", "06:26:09 PM" },
731 		{ "%a", "શનિ" },
732 		{ "%A", "શનિવાર" },
733 		{ "%b", "જુલાઈ" },
734 		{ "%B", "જુલાઈ" },
735 		{ NULL, NULL }
736 	};
737 	test_strptime("gu_IN", strptime_gu);
738 
739 	const strptime_data strptime_it[] = {
740 		{ "%c", "sabato 17 luglio 2010 18:26:09 GMT" },
741 		{ "%x", "17/lug/2010" },
742 		{ "%X", "18:26:09" },
743 		{ "%a", "sab" },
744 		{ "%A", "sabato" },
745 		{ "%b", "lug" },
746 		{ "%B", "luglio" },
747 		{ NULL, NULL }
748 	};
749 	test_strptime("it_IT", strptime_it);
750 
751 	const strptime_data strptime_nl[] = {
752 		{ "%c", "zaterdag 17 juli 2010 18:26:09 GMT" },
753 		{ "%x", "17 jul. 2010" },
754 		{ "%X", "18:26:09" },
755 		{ "%a", "za" },
756 		{ "%A", "zaterdag" },
757 		{ "%b", "jul." },
758 		{ "%B", "juli" },
759 		{ NULL, NULL }
760 	};
761 	test_strptime("nl_NL", strptime_nl);
762 
763 	const strptime_data strptime_nb[] = {
764 		{ "%c", "kl. 18:26:09 GMT lørdag 17. juli 2010" },
765 		{ "%x", "17. juli 2010" },
766 		{ "%X", "18:26:09" },
767 		{ "%a", "lør." },
768 		{ "%A", "lørdag" },
769 		{ "%b", "juli" },
770 		{ "%B", "juli" },
771 		{ NULL, NULL }
772 	};
773 	test_strptime("nb_NO", strptime_nb);
774 }
775 
776 // #pragma mark - ctype --------------------------------------------------------
777 
778 
779 unsigned short
determineFullClassInfo(int i)780 determineFullClassInfo(int i)
781 {
782 	unsigned short classInfo = 0;
783 
784 	if (isblank(i))
785 		classInfo |= _ISblank;
786 	if (iscntrl(i))
787 		classInfo |= _IScntrl;
788 	if (ispunct(i))
789 		classInfo |= _ISpunct;
790 	if (isalnum(i))
791 		classInfo |= _ISalnum;
792 	if (isupper(i))
793 		classInfo |= _ISupper;
794 	if (islower(i))
795 		classInfo |= _ISlower;
796 	if (isalpha(i))
797 		classInfo |= _ISalpha;
798 	if (isdigit(i))
799 		classInfo |= _ISdigit;
800 	if (isxdigit(i))
801 		classInfo |= _ISxdigit;
802 	if (isspace(i))
803 		classInfo |= _ISspace;
804 	if (isprint(i))
805 		classInfo |= _ISprint;
806 	if (isgraph(i))
807 		classInfo |= _ISgraph;
808 
809 	return classInfo;
810 }
811 
812 
813 void
test_ctype(const char * locale,const unsigned short int classInfos[],const int toLowerMap[],const int toUpperMap[])814 test_ctype(const char* locale, const unsigned short int classInfos[],
815 	const int toLowerMap[], const int toUpperMap[])
816 {
817 	setlocale(LC_CTYPE, locale);
818 	printf("ctype of %s locale\n", locale);
819 
820 	int problemCount = 0;
821 	for (int i = -1; i < 256; ++i) {
822 		unsigned short classInfo = determineFullClassInfo(i);
823 
824 		if (i < 255) {
825 			char iAsChar = (char)i;
826 			unsigned short classInfoFromChar = determineFullClassInfo(iAsChar);
827 
828 			if (classInfo != classInfoFromChar) {
829 				printf("\tPROBLEM: ctype((int)%d)=%x, but ctype((char)%d)=%x\n",
830 					i, classInfo, i, classInfoFromChar);
831 				problemCount++;
832 			}
833 		}
834 		if (classInfo != classInfos[i + 1]) {
835 			printf("\tPROBLEM: ctype(%d) = %x (expected %x)\n", i, classInfo,
836 				classInfos[i + 1]);
837 			problemCount++;
838 		}
839 		int lower = tolower(i);
840 		if (lower != toLowerMap[i + 1]) {
841 			printf("\tPROBLEM: tolower(%d) = %x (expected %x)\n", i, lower,
842 				toLowerMap[i + 1]);
843 			problemCount++;
844 		}
845 		int upper = toupper(i);
846 		if (upper != toUpperMap[i + 1]) {
847 			printf("\tPROBLEM: toupper(%d) = %x (expected %x)\n", i, upper,
848 				toUpperMap[i + 1]);
849 			problemCount++;
850 		}
851 	}
852 	if (problemCount)
853 		printf("\t%d problem(s) found!\n", problemCount);
854 	else
855 		printf("\tall fine\n");
856 }
857 
858 
859 void
test_ctype()860 test_ctype()
861 {
862 	const unsigned short int classInfos_posix[257] = {
863 		/*  -1 */   0,	// neutral value
864 		/*   0 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
865 		/*   8 */	_IScntrl, _ISblank|_IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl, _IScntrl,
866 		/*  16 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
867 		/*  24 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
868 		/*  32 */	_ISblank|_ISspace|_ISprint, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
869 		/*  40 */	_ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
870 		/*  48 */	_ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph,
871 		/*  56 */	_ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
872 		/*  64 */	_ISpunct|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
873 		/*  72 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
874 		/*  80 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
875 		/*  88 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
876 		/*  96 */	_ISpunct|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
877 		/* 104 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
878 		/* 112 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
879 		/* 120 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _IScntrl,
880 		/* 128 */	0, 0, 0, 0, 0, 0, 0, 0,
881 		/* 136 */	0, 0, 0, 0, 0, 0, 0, 0,
882 		/* 144 */	0, 0, 0, 0, 0, 0, 0, 0,
883 		/* 152 */	0, 0, 0, 0, 0, 0, 0, 0,
884 		/* 160 */	0, 0, 0, 0, 0, 0, 0, 0,
885 		/* 168 */	0, 0, 0, 0, 0, 0, 0, 0,
886 		/* 176 */	0, 0, 0, 0, 0, 0, 0, 0,
887 		/* 184 */	0, 0, 0, 0, 0, 0, 0, 0,
888 		/* 192 */	0, 0, 0, 0, 0, 0, 0, 0,
889 		/* 200 */	0, 0, 0, 0, 0, 0, 0, 0,
890 		/* 208 */	0, 0, 0, 0, 0, 0, 0, 0,
891 		/* 216 */	0, 0, 0, 0, 0, 0, 0, 0,
892 		/* 224 */	0, 0, 0, 0, 0, 0, 0, 0,
893 		/* 232 */	0, 0, 0, 0, 0, 0, 0, 0,
894 		/* 240 */	0, 0, 0, 0, 0, 0, 0, 0,
895 		/* 248 */	0, 0, 0, 0, 0, 0, 0, 0,
896 	};
897 	const int toLowerMap_posix[257] = {
898 		/*  -1 */    -1,	// identity value
899 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
900 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
901 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
902 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
903 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
904 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
905 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
906 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
907 		/*  64 */	 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
908 		/*  72 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
909 		/*  80 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
910 		/*  88 */	'x', 'y', 'z',  91,  92,  93,  94,  95,
911 		/*  96 */	 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
912 		/* 104 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
913 		/* 112 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
914 		/* 120 */	'x', 'y', 'z', 123, 124, 125, 126, 127,
915 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
916 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
917 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
918 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
919 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
920 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
921 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
922 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
923 		/* 192 */	192, 193, 194, 195, 196, 197, 198, 199,
924 		/* 200 */	200, 201, 202, 203, 204, 205, 206, 207,
925 		/* 208 */	208, 209, 210, 211, 212, 213, 214, 215,
926 		/* 216 */	216, 217, 218, 219, 220, 221, 222, 223,
927 		/* 224 */	224, 225, 226, 227, 228, 229, 230, 231,
928 		/* 232 */	232, 233, 234, 235, 236, 237, 238, 239,
929 		/* 240 */	240, 241, 242, 243, 244, 245, 246, 247,
930 		/* 248 */	248, 249, 250, 251, 252, 253, 254, 255,
931 	};
932 	const int toUpperMap_posix[257] = {
933 		/*  -1 */    -1,	// identity value
934 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
935 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
936 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
937 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
938 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
939 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
940 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
941 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
942 		/*  64 */	 64, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
943 		/*  72 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
944 		/*  80 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
945 		/*  88 */	'X', 'Y', 'Z',  91,  92,  93,  94,  95,
946 		/*  96 */	 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
947 		/* 104 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
948 		/* 112 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
949 		/* 120 */	'X', 'Y', 'Z', 123, 124, 125, 126, 127,
950 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
951 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
952 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
953 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
954 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
955 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
956 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
957 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
958 		/* 192 */	192, 193, 194, 195, 196, 197, 198, 199,
959 		/* 200 */	200, 201, 202, 203, 204, 205, 206, 207,
960 		/* 208 */	208, 209, 210, 211, 212, 213, 214, 215,
961 		/* 216 */	216, 217, 218, 219, 220, 221, 222, 223,
962 		/* 224 */	224, 225, 226, 227, 228, 229, 230, 231,
963 		/* 232 */	232, 233, 234, 235, 236, 237, 238, 239,
964 		/* 240 */	240, 241, 242, 243, 244, 245, 246, 247,
965 		/* 248 */	248, 249, 250, 251, 252, 253, 254, 255,
966 	};
967 	test_ctype("POSIX", classInfos_posix, toLowerMap_posix, toUpperMap_posix);
968 
969 	const unsigned short int classInfos_de[257] = {
970 		/*  -1 */   0,	// neutral value
971 		/*   0 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
972 		/*   8 */	_IScntrl, _ISblank|_IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl, _IScntrl,
973 		/*  16 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
974 		/*  24 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
975 		/*  32 */	_ISblank|_ISspace|_ISprint, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
976 		/*  40 */	_ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
977 		/*  48 */	_ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph,
978 		/*  56 */	_ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
979 		/*  64 */	_ISpunct|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
980 		/*  72 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
981 		/*  80 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
982 		/*  88 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
983 		/*  96 */	_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
984 		/* 104 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
985 		/* 112 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
986 		/* 120 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _IScntrl,
987 		/* 128 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl|_ISspace, _IScntrl, _IScntrl,
988 		/* 136 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
989 		/* 144 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
990 		/* 152 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
991 		/* 160 */	_ISprint|_ISspace|_ISblank, _ISprint|_ISgraph|_ISpunct, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph,
992 		/* 168 */	_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISpunct, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph,
993 		/* 176 */	_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISpunct,
994 		/* 184 */	_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISpunct, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISpunct,
995 		/* 192 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper,
996 		/* 200 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper,
997 		/* 208 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph,
998 		/* 216 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower,
999 		/* 224 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower,
1000 		/* 232 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower,
1001 		/* 240 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph,
1002 		/* 248 */	_ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower,
1003 	};
1004 	const int toLowerMap_de[257] = {
1005 		/*  -1 */    -1,	// identity value
1006 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
1007 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
1008 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
1009 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
1010 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
1011 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
1012 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
1013 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
1014 		/*  64 */	 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
1015 		/*  72 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1016 		/*  80 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
1017 		/*  88 */	'x', 'y', 'z',  91,  92,  93,  94,  95,
1018 		/*  96 */	 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
1019 		/* 104 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1020 		/* 112 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
1021 		/* 120 */	'x', 'y', 'z', 123, 124, 125, 126, 127,
1022 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
1023 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
1024 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
1025 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
1026 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
1027 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
1028 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
1029 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
1030 		/* 192 */	224, 225, 226, 227, 228, 229, 230, 231,
1031 		/* 200 */	232, 233, 234, 235, 236, 237, 238, 239,
1032 		/* 208 */	240, 241, 242, 243, 244, 245, 246, 215,
1033 		/* 216 */	248, 249, 250, 251, 252, 253, 254, 223,
1034 		/* 224 */	224, 225, 226, 227, 228, 229, 230, 231,
1035 		/* 232 */	232, 233, 234, 235, 236, 237, 238, 239,
1036 		/* 240 */	240, 241, 242, 243, 244, 245, 246, 247,
1037 		/* 248 */	248, 249, 250, 251, 252, 253, 254, 255,
1038 	};
1039 	const int toUpperMap_de[257] = {
1040 		/*  -1 */    -1,	// identity value
1041 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
1042 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
1043 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
1044 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
1045 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
1046 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
1047 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
1048 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
1049 		/*  64 */	 64, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1050 		/*  72 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1051 		/*  80 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1052 		/*  88 */	'X', 'Y', 'Z',  91,  92,  93,  94,  95,
1053 		/*  96 */	 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1054 		/* 104 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1055 		/* 112 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1056 		/* 120 */	'X', 'Y', 'Z', 123, 124, 125, 126, 127,
1057 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
1058 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
1059 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
1060 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
1061 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
1062 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
1063 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
1064 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
1065 		/* 192 */	192, 193, 194, 195, 196, 197, 198, 199,
1066 		/* 200 */	200, 201, 202, 203, 204, 205, 206, 207,
1067 		/* 208 */	208, 209, 210, 211, 212, 213, 214, 215,
1068 		/* 216 */	216, 217, 218, 219, 220, 221, 222, 223,
1069 		/* 224 */	192, 193, 194, 195, 196, 197, 198, 199,
1070 		/* 232 */	200, 201, 202, 203, 204, 205, 206, 207,
1071 		/* 240 */	208, 209, 210, 211, 212, 213, 214, 247,
1072 		/* 248 */	216, 217, 218, 219, 220, 221, 222, 255,
1073 	};
1074 	test_ctype("de_DE.ISO8859-1", classInfos_de, toLowerMap_de, toUpperMap_de);
1075 
1076 	const unsigned short int classInfos_utf8[257] = {
1077 		/*  -1 */   0,	// neutral value
1078 		/*   0 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
1079 		/*   8 */	_IScntrl, _ISblank|_IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl, _IScntrl,
1080 		/*  16 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
1081 		/*  24 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
1082 		/*  32 */	_ISblank|_ISspace|_ISprint, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
1083 		/*  40 */	_ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
1084 		/*  48 */	_ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph,
1085 		/*  56 */	_ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISdigit|_ISxdigit|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
1086 		/*  64 */	_ISpunct|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
1087 		/*  72 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
1088 		/*  80 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph,
1089 		/*  88 */	_ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISupper|_ISalpha|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
1090 		/*  96 */	_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
1091 		/* 104 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
1092 		/* 112 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph,
1093 		/* 120 */	_ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISalnum|_ISlower|_ISalpha|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _IScntrl,
1094 		/* 128 */	0, 0, 0, 0, 0, 0, 0, 0,
1095 		/* 136 */	0, 0, 0, 0, 0, 0, 0, 0,
1096 		/* 144 */	0, 0, 0, 0, 0, 0, 0, 0,
1097 		/* 152 */	0, 0, 0, 0, 0, 0, 0, 0,
1098 		/* 160 */	0, 0, 0, 0, 0, 0, 0, 0,
1099 		/* 168 */	0, 0, 0, 0, 0, 0, 0, 0,
1100 		/* 176 */	0, 0, 0, 0, 0, 0, 0, 0,
1101 		/* 184 */	0, 0, 0, 0, 0, 0, 0, 0,
1102 		/* 192 */	0, 0, 0, 0, 0, 0, 0, 0,
1103 		/* 200 */	0, 0, 0, 0, 0, 0, 0, 0,
1104 		/* 208 */	0, 0, 0, 0, 0, 0, 0, 0,
1105 		/* 216 */	0, 0, 0, 0, 0, 0, 0, 0,
1106 		/* 224 */	0, 0, 0, 0, 0, 0, 0, 0,
1107 		/* 232 */	0, 0, 0, 0, 0, 0, 0, 0,
1108 		/* 240 */	0, 0, 0, 0, 0, 0, 0, 0,
1109 		/* 248 */	0, 0, 0, 0, 0, 0, 0, 0,
1110 	};
1111 	test_ctype("de_DE.UTF-8", classInfos_utf8, toLowerMap_posix,
1112 		toUpperMap_posix);
1113 }
1114 
1115 
1116 // #pragma mark - wctype -------------------------------------------------------
1117 
1118 
1119 unsigned short
determineWideFullClassInfo(int i)1120 determineWideFullClassInfo(int i)
1121 {
1122 	unsigned short classInfo = 0;
1123 
1124 	if (iswblank(i))
1125 		classInfo |= _ISblank;
1126 	if (iswcntrl(i))
1127 		classInfo |= _IScntrl;
1128 	if (iswpunct(i))
1129 		classInfo |= _ISpunct;
1130 	if (iswalnum(i))
1131 		classInfo |= _ISalnum;
1132 	if (iswupper(i))
1133 		classInfo |= _ISupper;
1134 	if (iswlower(i))
1135 		classInfo |= _ISlower;
1136 	if (iswalpha(i))
1137 		classInfo |= _ISalpha;
1138 	if (iswdigit(i))
1139 		classInfo |= _ISdigit;
1140 	if (iswxdigit(i))
1141 		classInfo |= _ISxdigit;
1142 	if (iswspace(i))
1143 		classInfo |= _ISspace;
1144 	if (iswprint(i))
1145 		classInfo |= _ISprint;
1146 	if (iswgraph(i))
1147 		classInfo |= _ISgraph;
1148 
1149 	return classInfo;
1150 }
1151 
1152 
1153 void
test_wctype(const char * locale,const wchar_t * text,const unsigned short int wcs[],const unsigned short int classInfos[])1154 test_wctype(const char* locale, const wchar_t* text,
1155 	const unsigned short int wcs[], const unsigned short int classInfos[])
1156 {
1157 	setlocale(LC_CTYPE, locale);
1158 	printf("wctype of %s locale\n", locale);
1159 
1160 	int problemCount = 0;
1161 	unsigned short classInfo = determineWideFullClassInfo(WEOF);
1162 	if (classInfo != 0) {
1163 		printf("\tPROBLEM: classinfo for WEOF = %x (expected 0)\n", classInfo);
1164 		problemCount++;
1165 	}
1166 	wint_t wc = *text;
1167 	for (int i = 0; i < 48; wc = *++text, ++i) {
1168 		classInfo = determineWideFullClassInfo(wc);
1169 		if (wc != wcs[i]) {
1170 			printf("\tPROBLEM: wc for char #%d = %x (expected %x)\n", i, wc,
1171 				wcs[i]);
1172 			problemCount++;
1173 		}
1174 
1175 		if (classInfo != classInfos[i]) {
1176 			printf("\tPROBLEM: classinfo for #%d = %x (expected %x)\n", i,
1177 				classInfo, classInfos[i]);
1178 			problemCount++;
1179 		}
1180 	}
1181 	if (problemCount)
1182 		printf("\t%d problem(s) found!\n", problemCount);
1183 	else
1184 		printf("\tall fine\n");
1185 }
1186 
1187 
1188 void
test_wctype()1189 test_wctype()
1190 {
1191 	// haiku wide chars are always in UTF32, so nothing should change between
1192 	// different locales
1193 
1194 	const wchar_t* text = L"Hi there, how do you do? (äÜößáéúíó€'¤¹²$%#@) 12";
1195 
1196 	const unsigned short int wcs[48] = {
1197 		0x48, 0x69, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65,
1198 		0x2c, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x64, 0x6f,
1199 		0x20, 0x79, 0x6f, 0x75, 0x20, 0x64, 0x6f, 0x3f,
1200 		0x20, 0x28, 0xe4, 0xdc, 0xf6, 0xdf, 0xe1, 0xe9,
1201 		0xfa, 0xed, 0xf3, 0x20ac, 0x27, 0xa4, 0xb9, 0xb2,
1202 		0x24, 0x25, 0x23, 0x40, 0x29, 0x20, 0x31, 0x32
1203 	};
1204 	const unsigned short int classInfos[48] = {
1205 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISupper,
1206 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1207 		_ISspace|_ISprint|_ISblank,
1208 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1209 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1210 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1211 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1212 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1213 		_ISprint|_ISgraph|_ISpunct,
1214 		_ISspace|_ISprint|_ISblank,
1215 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1216 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1217 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1218 		_ISspace|_ISprint|_ISblank,
1219 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1220 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1221 		_ISspace|_ISprint|_ISblank,
1222 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1223 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1224 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1225 		_ISspace|_ISprint|_ISblank,
1226 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1227 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1228 		_ISprint|_ISgraph|_ISpunct,
1229 		_ISspace|_ISprint|_ISblank,
1230 		_ISprint|_ISgraph|_ISpunct,
1231 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1232 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISupper,
1233 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1234 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1235 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1236 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1237 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1238 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1239 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1240 		_ISprint|_ISgraph,
1241 		_ISprint|_ISgraph|_ISpunct,
1242 		_ISprint|_ISgraph,
1243 		_ISprint|_ISgraph,
1244 		_ISprint|_ISgraph,
1245 		_ISprint|_ISgraph,
1246 		_ISpunct|_ISprint|_ISgraph,
1247 		_ISpunct|_ISprint|_ISgraph,
1248 		_ISpunct|_ISprint|_ISgraph,
1249 		_ISpunct|_ISprint|_ISgraph,
1250 		_ISspace|_ISprint|_ISblank,
1251 		_ISprint|_ISgraph|_ISalnum|_ISdigit|_ISxdigit,
1252 		_ISprint|_ISgraph|_ISalnum|_ISdigit|_ISxdigit
1253 	};
1254 
1255 	test_wctype("POSIX", text, wcs, classInfos);
1256 	test_wctype("de_DE.ISO8859-1", text, wcs, classInfos);
1257 	test_wctype("de_DE.ISO8859-15", text, wcs, classInfos);
1258 	test_wctype("de_DE.UTF-8", text, wcs, classInfos);
1259 }
1260 
1261 
1262 // #pragma mark - wctrans ------------------------------------------------------
1263 
1264 
1265 void
test_wctrans(const char * locale,const wchar_t * text,wctrans_t transition,const wchar_t * expectedResult)1266 test_wctrans(const char* locale, const wchar_t* text, wctrans_t transition,
1267 	const wchar_t* expectedResult)
1268 {
1269 	setlocale(LC_CTYPE, locale);
1270 	printf("towctrans(%s) of %s locale\n",
1271 		transition == _ISlower ? "tolower" : "toupper", locale);
1272 
1273 	int problemCount = 0;
1274 	wint_t wc = *text;
1275 	for (int i = 0; wc != 0; wc = *++text, ++i) {
1276 		errno = 0;
1277 		wint_t result = towctrans(wc, transition);
1278 		if (result != expectedResult[i] || errno != 0) {
1279 			printf("\tPROBLEM: result for char #%d = %x (expected %x), "
1280 					"errno = %x (expected %x)\n",
1281 				i, result, expectedResult[i], errno, 0);
1282 			problemCount++;
1283 		}
1284 	}
1285 	if (problemCount)
1286 		printf("\t%d problem(s) found!\n", problemCount);
1287 	else
1288 		printf("\tall fine\n");
1289 }
1290 
1291 
1292 void
test_wctrans()1293 test_wctrans()
1294 {
1295 	// haiku wide chars are always in UTF32, so nothing should change between
1296 	// different locales
1297 
1298 	setlocale(LC_CTYPE, "POSIX");
1299 	printf("wctrans setup\n");
1300 
1301 	int problemCount = 0;
1302 	errno = 0;
1303 	wctrans_t toU = wctrans("toupper");
1304 	if (errno != 0 || toU != _ISupper) {
1305 		printf("\tPROBLEM: wctrans(\"upper\") = %x (expected %x), "
1306 				"errno=%x (expected %x)\n",
1307 			toU, _ISupper, errno, 0);
1308 		problemCount++;
1309 	}
1310 	errno = 0;
1311 	wctrans_t toL = wctrans("tolower");
1312 	if (errno != 0 || toL != _ISlower) {
1313 		printf("\tPROBLEM: wctrans(\"lower\") = %x (expected %x), "
1314 				"errno=%x (expected %x)\n",
1315 			toL, _ISlower, errno, 0);
1316 		problemCount++;
1317 	}
1318 	errno = 0;
1319 	wctrans_t invalid1 = wctrans(NULL);
1320 	if (errno != EINVAL || invalid1 != 0) {
1321 		printf("\tPROBLEM: wctrans(NULL) = %x (expected %x), "
1322 				"errno=%x (expected %x)\n",
1323 			invalid1, 0, errno, EINVAL);
1324 		problemCount++;
1325 	}
1326 	errno = 0;
1327 	wctrans_t invalid2 = wctrans("invalid");
1328 	if (errno != EINVAL || invalid2 != 0) {
1329 		printf("\tPROBLEM: wctrans(\"invalid\") = %x (expected %x), "
1330 				"errno=%x (expected %x)\n",
1331 			invalid2, 0, errno, EINVAL);
1332 		problemCount++;
1333 	}
1334 	if (problemCount)
1335 		printf("\t%d problem(s) found!\n", problemCount);
1336 	else
1337 		printf("\tall fine\n");
1338 
1339 	const wchar_t* text = L"Hi there, how do you do? (äÜößáéúíó€'¤¹²$%#@) 12";
1340 	const wchar_t* textU = L"HI THERE, HOW DO YOU DO? (ÄÜÖßÁÉÚÍÓ€'¤¹²$%#@) 12";
1341 	const wchar_t* textL = L"hi there, how do you do? (äüößáéúíó€'¤¹²$%#@) 12";
1342 
1343 	test_wctrans("POSIX", text, toU, textU);
1344 	test_wctrans("de_DE.ISO8859-1", text, toU, textU);
1345 	test_wctrans("de_DE.ISO8859-15", text, toU, textU);
1346 	test_wctrans("de_DE.UTF-8", text, toU, textU);
1347 	test_wctrans("fr_Fr", text, toU, textU);
1348 
1349 	test_wctrans("POSIX", text, toL, textL);
1350 	test_wctrans("de_DE.ISO8859-1", text, toL, textL);
1351 	test_wctrans("de_DE.ISO8859-15", text, toL, textL);
1352 	test_wctrans("de_DE.UTF-8", text, toL, textL);
1353 	test_wctrans("fr_Fr", text, toL, textL);
1354 }
1355 
1356 
1357 // #pragma mark - wcwidth ------------------------------------------------------
1358 
1359 
1360 void
test_wcwidth()1361 test_wcwidth()
1362 {
1363 	setlocale(LC_ALL, "fr_FR.UTF-8");
1364 	printf("wcwidth()\n");
1365 
1366 	/* many of the following tests have been copied from gnulib */
1367 
1368 	int problemCount = 0;
1369 	int result = 0;
1370 
1371 	/* Test width of ASCII characters.  */
1372 	for (wchar_t wc = 0x20; wc < 0x7F; wc++) {
1373 		result = wcwidth(wc);
1374 		if (result != 1) {
1375 			printf("\tPROBLEM: wcwidth(%x)=%x (expected %x)\n", wc, result, 1);
1376 			problemCount++;
1377 		}
1378 	}
1379 
1380 	struct {
1381 		wchar_t wc;
1382 		int result;
1383 	} data[] = {
1384 		{ 0x0, 0 },
1385 		{ 0x1, -1 },
1386 		{ 0x1F, -1 },
1387 		{ 0x80, -1 },
1388 		{ 0x9F, -1 },
1389 		{ 0xA0, 1 },
1390 		{ 0x0301, 0 },
1391 		{ 0x05B0, 0 },
1392 		{ 0x200E, 0 },
1393 		{ 0x2060, 0 },
1394 		{ 0xE0001, 0 },
1395 		{ 0xE0044, 0 },
1396 		{ 0x200B, 0 },
1397 		{ 0xFEFF, 0 },
1398 		{ 0x3000, 2 },
1399 		{ 0xB250, 2 },
1400 		{ 0xFF1A, 2 },
1401 		{ 0x20369, 2 },
1402 		{ 0x2F876, 2 },
1403 		{ 0x0, 0 },
1404 	};
1405 	for (int i = 0; data[i].wc != 0 || i == 0; i++) {
1406 		result = wcwidth(data[i].wc);
1407 		if (result != data[i].result) {
1408 			printf("\tPROBLEM: wcwidth(%x)=%x (expected %x)\n", data[i].wc,
1409 				result, data[i].result);
1410 			problemCount++;
1411 		}
1412 	}
1413 
1414 	if (problemCount)
1415 		printf("\t%d problem(s) found!\n", problemCount);
1416 	else
1417 		printf("\tall fine\n");
1418 }
1419 
1420 
1421 // #pragma mark - nl_langinfo --------------------------------------------------
1422 
1423 
1424 void
test_langinfo(const char * locale,const char * langinfos[])1425 test_langinfo(const char* locale, const char* langinfos[])
1426 {
1427 	setlocale(LC_ALL, locale);
1428 	printf("langinfo of %s locale\n", locale);
1429 
1430 	int problemCount = 0;
1431 	for (int i = -1; langinfos[i + 1] != NULL; ++i) {
1432 		const char* langinfo = nl_langinfo(i);
1433 		if (strcmp(langinfo, langinfos[i + 1]) != 0) {
1434 			printf("\tPROBLEM: langinfo for #%d = '%s' (expected '%s')\n", i,
1435 				langinfo, langinfos[i + 1]);
1436 			problemCount++;
1437 		}
1438 	}
1439 	if (problemCount)
1440 		printf("\t%d problem(s) found!\n", problemCount);
1441 	else
1442 		printf("\tall fine\n");
1443 }
1444 
1445 
1446 void
test_langinfo()1447 test_langinfo()
1448 {
1449 	const char* li_posix[] = {
1450 		"", 	// out of bounds
1451 		"US-ASCII",
1452 		"%a %b %e %H:%M:%S %Y",
1453 		"%m/%d/%y",
1454 		"%H:%M:%S",
1455 		"%I:%M:%S %p",
1456 		"AM",
1457 		"PM",
1458 
1459 		"Sunday", "Monday", "Tuesday", "Wednesday",	"Thursday", "Friday",
1460 		"Saturday",
1461 
1462 		"Sun", "Mon", "Tue", "Wed",	"Thu", "Fri", "Sat",
1463 
1464 		"January", "February", "March", "April", "May", "June",
1465 		"July", "August", "September", "October", "November", "December",
1466 
1467 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1468 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1469 
1470 		"%EC, %Ey, %EY",
1471 		"%Ex",
1472 		"%Ec",
1473 		"%EX",
1474 		"%O",
1475 
1476 		".",
1477 		"",
1478 
1479 		"^[yY]",
1480 		"^[nN]",
1481 
1482 		"",
1483 
1484 		"", 	// out of bounds
1485 		NULL
1486 	};
1487 	test_langinfo("POSIX", li_posix);
1488 
1489 	const char* li_de[] = {
1490 		"", 	// out of bounds
1491 		"UTF-8",
1492 		"%A, %e. %B %Y %H:%M:%S %Z",
1493 		"%d.%m.%Y",
1494 		"%H:%M:%S",
1495 		"%I:%M:%S %p",
1496 		"vorm.",
1497 		"nachm.",
1498 
1499 		"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag",
1500 		"Samstag",
1501 
1502 		"So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.",
1503 
1504 		"Januar", "Februar", "März", "April", "Mai", "Juni",
1505 		"Juli", "August", "September", "Oktober", "November", "Dezember",
1506 
1507 		"Jan", "Feb", "Mär", "Apr", "Mai", "Jun",
1508 		"Jul", "Aug", "Sep", "Okt", "Nov", "Dez",
1509 
1510 		"%EC, %Ey, %EY",
1511 		"%Ex",
1512 		"%Ec",
1513 		"%EX",
1514 		"%O",
1515 
1516 		",",
1517 		".",
1518 
1519 		"^[yY]",
1520 		"^[nN]",
1521 
1522 		"€",
1523 
1524 		"", 	// out of bounds
1525 		NULL,
1526 	};
1527 	test_langinfo("de_DE.UTF-8", li_de);
1528 
1529 	const char* li_de_iso[] = {
1530 		"", 	// out of bounds
1531 		"ISO8859-15",
1532 		"%A, %e. %B %Y %H:%M:%S %Z",
1533 		"%d.%m.%Y",
1534 		"%H:%M:%S",
1535 		"%I:%M:%S %p",
1536 		"vorm.",
1537 		"nachm.",
1538 
1539 		"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag",
1540 		"Samstag",
1541 
1542 		"So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.",
1543 
1544 		"Januar", "Februar", "M\xE4rz", "April", "Mai", "Juni",
1545 		"Juli", "August", "September", "Oktober", "November", "Dezember",
1546 
1547 		"Jan", "Feb", "M\xE4r", "Apr", "Mai", "Jun",
1548 		"Jul", "Aug", "Sep", "Okt", "Nov", "Dez",
1549 
1550 		"%EC, %Ey, %EY",
1551 		"%Ex",
1552 		"%Ec",
1553 		"%EX",
1554 		"%O",
1555 
1556 		",",
1557 		".",
1558 
1559 		"^[yY]",
1560 		"^[nN]",
1561 
1562 		"\xA4",
1563 
1564 		"", 	// out of bounds
1565 		NULL
1566 	};
1567 	test_langinfo("de_DE.ISO8859-15", li_de_iso);
1568 }
1569 
1570 
1571 // #pragma mark - collation ----------------------------------------------------
1572 
1573 
1574 struct coll_data {
1575 	const char* a;
1576 	const char* b;
1577 	int result;
1578 	int err;
1579 };
1580 
1581 
sign(int a)1582 static int sign (int a)
1583 {
1584 	if (a < 0)
1585 		return -1;
1586 	if (a > 0)
1587 		return 1;
1588 	return 0;
1589 }
1590 
1591 
1592 void
test_coll(bool useStrxfrm,const char * locale,const coll_data * coll)1593 test_coll(bool useStrxfrm, const char* locale, const coll_data* coll)
1594 {
1595 	setlocale(LC_COLLATE, locale);
1596 	printf("%s in %s locale\n", useStrxfrm ? "strxfrm" : "strcoll", locale);
1597 
1598 	int problemCount = 0;
1599 	for (unsigned int i = 0; coll[i].a != NULL; ++i) {
1600 		errno = 0;
1601 		int result;
1602 		char funcCall[100];
1603 		if (useStrxfrm) {
1604 			char sortKeyA[100], sortKeyB[100];
1605 			strxfrm(sortKeyA, coll[i].a, 100);
1606 			strxfrm(sortKeyB, coll[i].b, 100);
1607 			result = sign(strcmp(sortKeyA, sortKeyB));
1608 			sprintf(funcCall, "strcmp(strxfrm(\"%s\"), strxfrm(\"%s\"))",
1609 				coll[i].a, coll[i].b);
1610 		} else {
1611 			result = sign(strcoll(coll[i].a, coll[i].b));
1612 			sprintf(funcCall, "strcoll(\"%s\", \"%s\")", coll[i].a, coll[i].b);
1613 		}
1614 
1615 		if (result != coll[i].result || errno != coll[i].err) {
1616 			printf(
1617 				"\tPROBLEM: %s = %d (expected %d), errno = %x (expected %x)\n",
1618 				funcCall, result, coll[i].result, errno, coll[i].err);
1619 			problemCount++;
1620 		}
1621 	}
1622 	if (problemCount)
1623 		printf("\t%d problem(s) found!\n", problemCount);
1624 	else
1625 		printf("\tall fine\n");
1626 }
1627 
1628 
1629 void
test_collation()1630 test_collation()
1631 {
1632 	const coll_data coll_posix[] = {
1633 		{ "", "", 0, 0 },
1634 		{ "test", "test", 0, 0 },
1635 		{ "tester", "test", 1, 0 },
1636 		{ "tEst", "teSt", -1, 0 },
1637 		{ "test", "tester", -1, 0 },
1638 		{ "tast", "täst", -1, EINVAL },
1639 		{ "tæst", "test", 1, EINVAL },
1640 		{ NULL, NULL, 0, 0 },
1641 	};
1642 	test_coll(0, "POSIX", coll_posix);
1643 	test_coll(1, "POSIX", coll_posix);
1644 
1645 	const coll_data coll_en[] = {
1646 		{ "", "", 0, 0 },
1647 		{ "test", "test", 0, 0 },
1648 		{ "tester", "test", 1, 0 },
1649 		{ "tEst", "test", 1, 0 },
1650 		{ "test", "tester", -1, 0 },
1651 		{ "täst", "täst", 0, 0 },
1652 		{ "tast", "täst", -1, 0 },
1653 		{ "tbst", "täst", 1, 0 },
1654 		{ "tbst", "tæst", 1, 0 },
1655 		{ "täst", "tÄst", -1, 0 },
1656 		{ "tBst", "tÄst", 1, 0 },
1657 		{ "tBst", "täst", 1, 0 },
1658 		{ "taest", "tæst", -1, 0 },
1659 		{ "tafst", "tæst", 1, 0 },
1660 		{ "taa", "täa", -1, 0 },
1661 		{ "tab", "täb", -1, 0 },
1662 		{ "tad", "täd", -1, 0 },
1663 		{ "tae", "täe", -1, 0 },
1664 		{ "taf", "täf", -1, 0 },
1665 		{ "cote", "coté", -1, 0 },
1666 		{ "coté", "côte", -1, 0 },
1667 		{ "côte", "côté", -1, 0 },
1668 		{ NULL, NULL, 0, 0 },
1669 	};
1670 	test_coll(0, "en_US.UTF-8", coll_en);
1671 	test_coll(1, "en_US.UTF-8", coll_en);
1672 
1673 	const coll_data coll_de[] = {
1674 		{ "", "", 0, 0 },
1675 		{ "test", "test", 0, 0 },
1676 		{ "tester", "test", 1, 0 },
1677 		{ "tEst", "test", 1, 0 },
1678 		{ "test", "tester", -1, 0 },
1679 		{ "täst", "täst", 0, 0 },
1680 		{ "tast", "täst", -1, 0 },
1681 		{ "tbst", "täst", 1, 0 },
1682 		{ "tbst", "tæst", 1, 0 },
1683 		{ "täst", "tÄst", -1, 0 },
1684 		{ "tBst", "tÄst", 1, 0 },
1685 		{ "tBst", "täst", 1, 0 },
1686 		{ "taest", "tæst", -1, 0 },
1687 		{ "tafst", "tæst", 1, 0 },
1688 		{ "taa", "tä", 1, 0 },
1689 		{ "tab", "tä", 1, 0 },
1690 		{ "tad", "tä", 1, 0 },
1691 		{ "tae", "tä", 1, 0 },
1692 		{ "taf", "tä", 1, 0 },
1693 		{ "cote", "coté", -1, 0 },
1694 		{ "coté", "côte", -1, 0 },
1695 		{ "côte", "côté", -1, 0 },
1696 		{ NULL, NULL, 0, 0 },
1697 	};
1698 	test_coll(0, "de_DE.UTF-8", coll_de);
1699 	test_coll(1, "de_DE.UTF-8", coll_de);
1700 
1701 	const coll_data coll_de_phonebook[] = {
1702 		{ "", "", 0, 0 },
1703 		{ "test", "test", 0, 0 },
1704 		{ "tester", "test", 1, 0 },
1705 		{ "tEst", "test", 1, 0 },
1706 		{ "test", "tester", -1, 0 },
1707 		{ "täst", "täst", 0, 0 },
1708 		{ "tast", "täst", 1, 0 },
1709 		{ "tbst", "täst", 1, 0 },
1710 		{ "tbst", "tæst", 1, 0 },
1711 		{ "täst", "tÄst", -1, 0 },
1712 		{ "tBst", "tÄst", 1, 0 },
1713 		{ "tBst", "täst", 1, 0 },
1714 		{ "taest", "tæst", -1, 0 },
1715 		{ "tafst", "tæst", 1, 0 },
1716 		{ "taa", "tä", -1, 0 },
1717 		{ "tab", "tä", -1, 0 },
1718 		{ "tad", "tä", -1, 0 },
1719 		{ "tae", "tä", -1, 0 },
1720 		{ "taf", "tä", 1, 0 },
1721 		{ "cote", "coté", -1, 0 },
1722 		{ "coté", "côte", -1, 0 },
1723 		{ "côte", "côté", -1, 0 },
1724 		{ NULL, NULL, 0, 0 },
1725 	};
1726 	test_coll(0, "de_DE.UTF-8@collation=phonebook", coll_de_phonebook);
1727 	test_coll(1, "de_DE.UTF-8@collation=phonebook", coll_de_phonebook);
1728 
1729 	const coll_data coll_fr[] = {
1730 		{ "", "", 0, 0 },
1731 		{ "test", "test", 0, 0 },
1732 		{ "tester", "test", 1, 0 },
1733 		{ "tEst", "test", 1, 0 },
1734 		{ "test", "tester", -1, 0 },
1735 		{ "täst", "täst", 0, 0 },
1736 		{ "tast", "täst", -1, 0 },
1737 		{ "tbst", "täst", 1, 0 },
1738 		{ "tbst", "tæst", 1, 0 },
1739 		{ "täst", "tÄst", -1, 0 },
1740 		{ "tBst", "tÄst", 1, 0 },
1741 		{ "tBst", "täst", 1, 0 },
1742 		{ "taest", "tæst", -1, 0 },
1743 		{ "tafst", "tæst", 1, 0 },
1744 		{ "taa", "tä", 1, 0 },
1745 		{ "tab", "tä", 1, 0 },
1746 		{ "tad", "tä", 1, 0 },
1747 		{ "tae", "tä", 1, 0 },
1748 		{ "taf", "tä", 1, 0 },
1749 		{ "cote", "coté", -1, 0 },
1750 		{ "coté", "côte", 1, 0 },
1751 		{ "côte", "côté", -1, 0 },
1752 		{ NULL, NULL, 0, 0 },
1753 	};
1754 	// CLDR-1.9 has adjusted the defaults of fr_FR to no longer do reverse
1755 	// ordering of secondary differences (accents), but fr_CA still does that
1756 	// by default
1757 	test_coll(0, "fr_CA.UTF-8", coll_fr);
1758 	test_coll(1, "fr_CA.UTF-8", coll_fr);
1759 }
1760 
1761 
1762 // #pragma mark - time conversion ----------------------------------------------
1763 
1764 
1765 void
test_localtime(const char * tz,time_t nowSecs,const tm & expected)1766 test_localtime(const char* tz, time_t nowSecs, const tm& expected)
1767 {
1768 	setenv("TZ", tz, 1);
1769 	printf("localtime for '%s'\n", tz);
1770 
1771 	tm now;
1772 	tm* result = localtime_r(&nowSecs, &now);
1773 	int problemCount = 0;
1774 	if (result == NULL) {
1775 		printf("\tPROBLEM: localtime(\"%ld\") = NULL\n", nowSecs);
1776 		problemCount++;
1777 	}
1778 	if (now.tm_year != expected.tm_year) {
1779 		printf("\tPROBLEM: localtime().tm_year = %d (expected %d)\n",
1780 			now.tm_year, expected.tm_year);
1781 		problemCount++;
1782 	}
1783 	if (now.tm_mon != expected.tm_mon) {
1784 		printf("\tPROBLEM: localtime().tm_mon = %d (expected %d)\n",
1785 			now.tm_mon, expected.tm_mon);
1786 		problemCount++;
1787 	}
1788 	if (now.tm_mday != expected.tm_mday) {
1789 		printf("\tPROBLEM: localtime().tm_mday = %d (expected %d)\n",
1790 			now.tm_mday, expected.tm_mday);
1791 		problemCount++;
1792 	}
1793 	if (now.tm_hour != expected.tm_hour) {
1794 		printf("\tPROBLEM: localtime().tm_hour = %d (expected %d)\n",
1795 			now.tm_hour, expected.tm_hour);
1796 		problemCount++;
1797 	}
1798 	if (now.tm_min != expected.tm_min) {
1799 		printf("\tPROBLEM: localtime().tm_min = %d (expected %d)\n",
1800 			now.tm_min, expected.tm_min);
1801 		problemCount++;
1802 	}
1803 	if (now.tm_sec != expected.tm_sec) {
1804 		printf("\tPROBLEM: localtime().tm_sec = %d (expected %d)\n",
1805 			now.tm_sec, expected.tm_sec);
1806 		problemCount++;
1807 	}
1808 	if (now.tm_wday != expected.tm_wday) {
1809 		printf("\tPROBLEM: localtime().tm_wday = %d (expected %d)\n",
1810 			now.tm_wday, expected.tm_wday);
1811 		problemCount++;
1812 	}
1813 	if (now.tm_yday != expected.tm_yday) {
1814 		printf("\tPROBLEM: localtime().tm_yday = %d (expected %d)\n",
1815 			now.tm_yday, expected.tm_yday);
1816 		problemCount++;
1817 	}
1818 	if (now.tm_isdst != expected.tm_isdst) {
1819 		printf("\tPROBLEM: localtime().tm_isdst = %d (expected %d)\n",
1820 			now.tm_isdst, expected.tm_isdst);
1821 		problemCount++;
1822 	}
1823 	if (now.tm_gmtoff != expected.tm_gmtoff) {
1824 		printf("\tPROBLEM: localtime().tm_gmtoff = %d (expected %d)\n",
1825 			now.tm_gmtoff, expected.tm_gmtoff);
1826 		problemCount++;
1827 	}
1828 	if (strcasecmp(now.tm_zone, expected.tm_zone) != 0) {
1829 		printf("\tPROBLEM: localtime().tm_zone = '%s' (expected '%s')\n",
1830 			now.tm_zone, expected.tm_zone);
1831 		problemCount++;
1832 	}
1833 	if (problemCount)
1834 		printf("\t%d problem(s) found!\n", problemCount);
1835 	else
1836 		printf("\tall fine\n");
1837 }
1838 
1839 
1840 void
test_gmtime(const char * tz,time_t nowSecs,const tm & expected)1841 test_gmtime(const char* tz, time_t nowSecs, const tm& expected)
1842 {
1843 	setenv("TZ", tz, 1);
1844 	printf("gmtime for '%s'\n", tz);
1845 
1846 	tm now;
1847 	tm* result = gmtime_r(&nowSecs, &now);
1848 	int problemCount = 0;
1849 	if (result == NULL) {
1850 		printf("\tPROBLEM: localtime(\"%ld\") = NULL\n", nowSecs);
1851 		problemCount++;
1852 	}
1853 	if (now.tm_year != expected.tm_year) {
1854 		printf("\tPROBLEM: localtime().tm_year = %d (expected %d)\n",
1855 			now.tm_year, expected.tm_year);
1856 		problemCount++;
1857 	}
1858 	if (now.tm_mon != expected.tm_mon) {
1859 		printf("\tPROBLEM: localtime().tm_mon = %d (expected %d)\n",
1860 			now.tm_mon, expected.tm_mon);
1861 		problemCount++;
1862 	}
1863 	if (now.tm_mday != expected.tm_mday) {
1864 		printf("\tPROBLEM: localtime().tm_mday = %d (expected %d)\n",
1865 			now.tm_mday, expected.tm_mday);
1866 		problemCount++;
1867 	}
1868 	if (now.tm_hour != expected.tm_hour) {
1869 		printf("\tPROBLEM: localtime().tm_hour = %d (expected %d)\n",
1870 			now.tm_hour, expected.tm_hour);
1871 		problemCount++;
1872 	}
1873 	if (now.tm_min != expected.tm_min) {
1874 		printf("\tPROBLEM: localtime().tm_min = %d (expected %d)\n",
1875 			now.tm_min, expected.tm_min);
1876 		problemCount++;
1877 	}
1878 	if (now.tm_sec != expected.tm_sec) {
1879 		printf("\tPROBLEM: localtime().tm_sec = %d (expected %d)\n",
1880 			now.tm_sec, expected.tm_sec);
1881 		problemCount++;
1882 	}
1883 	if (now.tm_wday != expected.tm_wday) {
1884 		printf("\tPROBLEM: localtime().tm_wday = %d (expected %d)\n",
1885 			now.tm_wday, expected.tm_wday);
1886 		problemCount++;
1887 	}
1888 	if (now.tm_yday != expected.tm_yday) {
1889 		printf("\tPROBLEM: localtime().tm_yday = %d (expected %d)\n",
1890 			now.tm_yday, expected.tm_yday);
1891 		problemCount++;
1892 	}
1893 	if (now.tm_isdst != expected.tm_isdst) {
1894 		printf("\tPROBLEM: localtime().tm_isdst = %d (expected %d)\n",
1895 			now.tm_isdst, expected.tm_isdst);
1896 		problemCount++;
1897 	}
1898 	if (now.tm_gmtoff != expected.tm_gmtoff) {
1899 		printf("\tPROBLEM: localtime().tm_gmtoff = %d (expected %d)\n",
1900 			now.tm_gmtoff, expected.tm_gmtoff);
1901 		problemCount++;
1902 	}
1903 	if (strcasecmp(now.tm_zone, expected.tm_zone) != 0) {
1904 		printf("\tPROBLEM: localtime().tm_zone = '%s' (expected '%s')\n",
1905 			now.tm_zone, expected.tm_zone);
1906 		problemCount++;
1907 	}
1908 	if (problemCount)
1909 		printf("\t%d problem(s) found!\n", problemCount);
1910 	else
1911 		printf("\tall fine\n");
1912 }
1913 
1914 
1915 void
test_mktime(const char * tz,tm & tm,time_t expected,int expectedWeekDay,int expectedYearDay)1916 test_mktime(const char* tz, tm& tm, time_t expected, int expectedWeekDay,
1917 	int expectedYearDay)
1918 {
1919 	setenv("TZ", tz, 1);
1920 	printf("mktime for '%s'\n", tz);
1921 
1922 	time_t result = mktime(&tm);
1923 	int problemCount = 0;
1924 	if (result != expected) {
1925 		printf("\tPROBLEM: mktime() = %ld (expected %ld)\n", result, expected);
1926 		problemCount++;
1927 	}
1928 	if (tm.tm_wday != expectedWeekDay) {
1929 		printf("\tPROBLEM: mktime().tm_wday = %d (expected %d)\n",
1930 			tm.tm_wday, expectedWeekDay);
1931 		problemCount++;
1932 	}
1933 	if (tm.tm_yday != expectedYearDay) {
1934 		printf("\tPROBLEM: mktime().tm_yday = %d (expected %d)\n",
1935 			tm.tm_yday, expectedYearDay);
1936 		problemCount++;
1937 	}
1938 	if (problemCount)
1939 		printf("\t%d problem(s) found!\n", problemCount);
1940 	else
1941 		printf("\tall fine\n");
1942 }
1943 
1944 
1945 void
test_timeconversions()1946 test_timeconversions()
1947 {
1948 	setlocale(LC_ALL, "en_US");
1949 	{
1950 		time_t testTime = 1279391169;	// Sat Jul 17 18:26:09 GMT 2010
1951 		tm gtm = {
1952 			9, 26, 18, 17, 6, 110, 6, 197, 0, 0, (char*)"GMT"
1953 		};
1954 		test_localtime("GMT", testTime, gtm);
1955 		test_gmtime("GMT", testTime, gtm);
1956 		gtm.tm_wday = -1;
1957 		gtm.tm_yday = -1;
1958 		test_mktime("GMT", gtm, testTime, 6, 197);
1959 
1960 		tm gtmplus2 = {
1961 			9, 26, 16, 17, 6, 110, 6, 197, 0, -2 * 3600, (char*)"GMT+2"
1962 		};
1963 		test_localtime("GMT+2", testTime, gtmplus2);
1964 		test_gmtime("GMT+2", testTime, gtm);
1965 		gtmplus2.tm_wday = -1;
1966 		gtmplus2.tm_yday = -1;
1967 		test_mktime("GMT+2", gtmplus2, testTime, 6, 197);
1968 
1969 		tm gtmminus2 = {
1970 			9, 26, 20, 17, 6, 110, 6, 197, 0, 2 * 3600, (char*)"GMT-2"
1971 		};
1972 		test_localtime("GMT-2", testTime, gtmminus2);
1973 		test_gmtime("GMT-2", testTime, gtm);
1974 		gtmminus2.tm_wday = -1;
1975 		gtmminus2.tm_yday = -1;
1976 		test_mktime("GMT-2", gtmminus2, testTime, 6, 197);
1977 
1978 		tm btm = {
1979 			9, 26, 20, 17, 6, 110, 6, 197, 1, 2 * 3600, (char*)"CEST"
1980 		};
1981 		test_localtime(":Europe/Berlin", testTime, btm);
1982 		test_gmtime(":Europe/Berlin", testTime, gtm);
1983 		btm.tm_wday = -1;
1984 		btm.tm_yday = -1;
1985 		test_mktime(":Europe/Berlin", btm, testTime, 6, 197);
1986 
1987 		tm ctm = {
1988 			9, 26, 20, 17, 6, 110, 6, 197, 1, 2 * 3600, (char*)"CEST"
1989 		};
1990 		test_localtime("CET", testTime, ctm);
1991 		test_gmtime("CET", testTime, gtm);
1992 		ctm.tm_wday = -1;
1993 		ctm.tm_yday = -1;
1994 		test_mktime("CET", ctm, testTime, 6, 197);
1995 
1996 		tm latm = {
1997 			9, 26, 11, 17, 6, 110, 6, 197, 1, -7 * 3600, (char*)"PDT"
1998 		};
1999 		test_localtime(":America/Los_Angeles", testTime, latm);
2000 		test_gmtime(":America/Los_Angeles", testTime, gtm);
2001 		latm.tm_wday = -1;
2002 		latm.tm_yday = -1;
2003 		test_mktime(":America/Los_Angeles", latm, testTime, 6, 197);
2004 
2005 		tm ttm = {
2006 			9, 26, 3, 18, 6, 110, 0, 198, 0, 9 * 3600, (char*)"GMT+09:00"
2007 		};
2008 		test_localtime(":Asia/Tokyo", testTime, ttm);
2009 		test_gmtime(":Asia/Tokyo", testTime, gtm);
2010 		ttm.tm_wday = -1;
2011 		ttm.tm_yday = -1;
2012 		test_mktime(":Asia/Tokyo", ttm, testTime, 0, 198);
2013 	}
2014 
2015 	{
2016 		time_t testTime = 1268159169;	// Tue Mar 9 18:26:09 GMT 2010
2017 		tm gtm = {
2018 			9, 26, 18, 9, 2, 110, 2, 67, 0, 0, (char*)"GMT"
2019 		};
2020 		test_localtime("GMT", testTime, gtm);
2021 		test_gmtime("GMT", testTime, gtm);
2022 		gtm.tm_wday = -1;
2023 		gtm.tm_yday = -1;
2024 		test_mktime("GMT", gtm, testTime, 2, 67);
2025 
2026 		tm btm = {
2027 			9, 26, 19, 9, 2, 110, 2, 67, 0, 3600, (char*)"CET"
2028 		};
2029 		test_localtime(":Europe/Berlin", testTime, btm);
2030 		test_gmtime(":Europe/Berlin", testTime, gtm);
2031 		btm.tm_wday = -1;
2032 		btm.tm_yday = -1;
2033 		test_mktime(":Europe/Berlin", btm, testTime, 2, 67);
2034 
2035 		tm ctm = {
2036 			9, 26, 19, 9, 2, 110, 2, 67, 0, 3600, (char*)"CET"
2037 		};
2038 		test_localtime("CET", testTime, ctm);
2039 		test_gmtime("CET", testTime, gtm);
2040 		ctm.tm_wday = -1;
2041 		ctm.tm_yday = -1;
2042 		test_mktime("CET", ctm, testTime, 2, 67);
2043 
2044 		tm latm = {
2045 			9, 26, 10, 9, 2, 110, 2, 67, 0, -8 * 3600, (char*)"PST"
2046 		};
2047 		test_localtime(":America/Los_Angeles", testTime, latm);
2048 		test_gmtime(":America/Los_Angeles", testTime, gtm);
2049 		latm.tm_wday = -1;
2050 		latm.tm_yday = -1;
2051 		test_mktime(":America/Los_Angeles", latm, testTime, 2, 67);
2052 
2053 		tm ttm = {
2054 			9, 26, 3, 10, 2, 110, 3, 68, 0, 9 * 3600, (char*)"GMT+09:00"
2055 		};
2056 		test_localtime(":Asia/Tokyo", testTime, ttm);
2057 		test_gmtime(":Asia/Tokyo", testTime, gtm);
2058 		ttm.tm_wday = -1;
2059 		ttm.tm_yday = -1;
2060 		test_mktime(":Asia/Tokyo", ttm, testTime, 3, 68);
2061 	}
2062 
2063 	{
2064 		time_t testTime = 0;	// Thu Jan 1 00:00:00 GMT 1970
2065 		tm gtm = {
2066 			0, 0, 0, 1, 0, 70, 4, 0, 0, 0, (char*)"GMT"
2067 		};
2068 		test_localtime("GMT", testTime, gtm);
2069 		test_gmtime("GMT", testTime, gtm);
2070 		gtm.tm_wday = -1;
2071 		gtm.tm_yday = -1;
2072 		test_mktime("GMT", gtm, testTime, 4, 0);
2073 
2074 		tm btm = {
2075 			0, 0, 1, 1, 0, 70, 4, 0, 0, 1 * 3600, (char*)"CET"
2076 		};
2077 		test_localtime(":Europe/Berlin", testTime, btm);
2078 		test_gmtime(":Europe/Berlin", testTime, gtm);
2079 		btm.tm_wday = -1;
2080 		btm.tm_yday = -1;
2081 		test_mktime(":Europe/Berlin", btm, testTime, 4, 0);
2082 
2083 		tm ctm = {
2084 			0, 0, 1, 1, 0, 70, 4, 0, 0, 1 * 3600, (char*)"CET"
2085 		};
2086 		test_localtime("CET", testTime, ctm);
2087 		test_gmtime("CET", testTime, gtm);
2088 		ctm.tm_wday = -1;
2089 		ctm.tm_yday = -1;
2090 		test_mktime("CET", ctm, testTime, 4, 0);
2091 
2092 		tm latm = {
2093 			0, 0, 16, 31, 11, 69, 3, 364, 0, -8 * 3600, (char*)"PST"
2094 		};
2095 		test_localtime(":America/Los_Angeles", testTime, latm);
2096 		test_gmtime(":America/Los_Angeles", testTime, gtm);
2097 		latm.tm_wday = -1;
2098 		latm.tm_yday = -1;
2099 		test_mktime(":America/Los_Angeles", latm, testTime, 3, 364);
2100 
2101 		tm ttm = {
2102 			0, 0, 9, 1, 0, 70, 4, 0, 0, 9 * 3600, (char*)"GMT+09:00"
2103 		};
2104 		test_localtime(":Asia/Tokyo", testTime, ttm);
2105 		test_gmtime(":Asia/Tokyo", testTime, gtm);
2106 		ttm.tm_wday = -1;
2107 		ttm.tm_yday = -1;
2108 		test_mktime(":Asia/Tokyo", ttm, testTime, 4, 0);
2109 	}
2110 }
2111 
2112 
2113 // #pragma mark - printf -------------------------------------------------------
2114 
2115 
2116 struct sprintf_data {
2117 	const char* format;
2118 	double value;
2119 	const char* result;
2120 };
2121 
2122 
2123 void
test_sprintf(const char * locale,const sprintf_data data[])2124 test_sprintf(const char* locale, const sprintf_data data[])
2125 {
2126 	setlocale(LC_ALL, locale);
2127 	printf("sprintf for '%s'\n", locale);
2128 
2129 	int problemCount = 0;
2130 	for(int i = 0; data[i].format != NULL; ++i) {
2131 		char buf[100];
2132 		if (strchr(data[i].format, 'd') != NULL)
2133 			sprintf(buf, data[i].format, (int)data[i].value);
2134 		else if (strchr(data[i].format, 'f') != NULL)
2135 			sprintf(buf, data[i].format, data[i].value);
2136 		if (strcmp(buf, data[i].result) != 0) {
2137 			printf("\tPROBLEM: sprintf(\"%s\") = \"%s\" (expected \"%s\")\n",
2138 				data[i].format, buf, data[i].result);
2139 			problemCount++;
2140 		}
2141 	}
2142 	if (problemCount)
2143 		printf("\t%d problem(s) found!\n", problemCount);
2144 	else
2145 		printf("\tall fine\n");
2146 }
2147 
2148 
2149 void
test_sprintf()2150 test_sprintf()
2151 {
2152 	const sprintf_data sprintf_posix[] = {
2153 		{ "%d", 123, "123" },
2154 		{ "%d", -123, "-123" },
2155 		{ "%d", 123456, "123456" },
2156 		{ "%'d", 123456, "123456" },
2157 		{ "%f", 123, "123.000000" },
2158 		{ "%f", -123, "-123.000000" },
2159 		{ "%.2f", 123456.789, "123456.79" },
2160 		{ "%'.2f", 123456.789, "123456.79" },
2161 		{ NULL, 0.0, NULL }
2162 	};
2163 	test_sprintf("POSIX", sprintf_posix);
2164 
2165 	const sprintf_data sprintf_de[] = {
2166 		{ "%d", 123, "123" },
2167 		{ "%d", -123, "-123" },
2168 		{ "%d", 123456, "123456" },
2169 		{ "%'d", 123456, "123.456" },
2170 		{ "%f", 123, "123,000000" },
2171 		{ "%f", -123, "-123,000000" },
2172 		{ "%.2f", 123456.789, "123456,79" },
2173 		{ "%'.2f", 123456.789, "123.456,79" },
2174 		{ NULL, 0.0, NULL }
2175 	};
2176 	test_sprintf("de_DE.UTF-8", sprintf_de);
2177 
2178 	const sprintf_data sprintf_gu[] = {
2179 		{ "%d", 123, "123" },
2180 		{ "%d", -123, "-123" },
2181 		{ "%d", 123456, "123456" },
2182 		{ "%'d", 123456, "123,456" },
2183 		{ "%f", 123, "123.000000" },
2184 		{ "%f", -123, "-123.000000" },
2185 		{ "%.2f", 123456.789, "123456.79" },
2186 		{ "%'.2f", 123456.789, "1,23,456.79" },
2187 		{ NULL, 0.0, NULL }
2188 	};
2189 	test_sprintf("gu_IN", sprintf_gu);
2190 
2191 	const sprintf_data sprintf_nb[] = {
2192 		{ "%d", 123, "123" },
2193 		{ "%d", -123, "-123" },
2194 		{ "%d", 123456, "123456" },
2195 		{ "%'d", 123456, "123 456" },
2196 		{ "%f", 123, "123,000000" },
2197 		{ "%f", -123, "-123,000000" },
2198 		{ "%.2f", 123456.789, "123456,79" },
2199 		{ "%'.2f", 123456.789, "123 456,79" },
2200 		{ NULL, 0.0, NULL }
2201 	};
2202 	test_sprintf("nb_NO", sprintf_nb);
2203 }
2204 
2205 
2206 // #pragma mark - main ---------------------------------------------------------
2207 
2208 
2209 /*
2210  * Test several different aspects of the POSIX locale and the functions
2211  * influenced by it.
2212  */
2213 int
main(void)2214 main(void)
2215 {
2216 	test_setlocale();
2217 	test_localeconv();
2218 	test_strftime();
2219 	test_strptime();
2220 	test_ctype();
2221 	test_wctype();
2222 	test_wctrans();
2223 	test_wcwidth();
2224 	test_langinfo();
2225 	test_collation();
2226 	test_timeconversions();
2227 	test_sprintf();
2228 
2229 	return 0;
2230 }
2231