xref: /haiku/src/tests/system/libroot/posix/locale_test.cpp (revision a3f665982e2e078ba42e7bf941bd5f3dd8989c55)
1 /*
2  * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #define B_USE_POSITIVE_POSIX_ERRORS
7 
8 #include <ctype.h>
9 #include <errno.h>
10 #include <langinfo.h>
11 #include <locale.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16 #include <wctype.h>
17 
18 
19 // #pragma mark - setlocale ----------------------------------------------------
20 
21 
22 void
23 test_setlocale()
24 {
25 	const char* locales[] = {
26 		"POSIX",
27 		"C",
28 		"de_DE",
29 		"en_US",
30 		"en_US.US-ASCII",
31 		"hr_HR.ISO-8859-2",
32 		"nl_NL",
33 		"nb_NO",
34 		"fr_FR.UTF-8@collation=phonebook",
35 		"de_DE.iso8859-1",
36 		"De_dE.IsO8859-15",
37 		"de_DE.utf8",
38 		"de_DE.UTF-8",
39 		"de_DE@euro",
40 		"de_DE@EURO",
41 		"de_DE.utf-8@Euro",
42 		"POSIX",
43 		"C",
44 		NULL
45 	};
46 	const char* expectedLocales[] = {
47 		"POSIX",
48 		"POSIX",
49 		"de_DE",
50 		"en_US",
51 		"en_US.US-ASCII",
52 		"hr_HR.ISO-8859-2",
53 		"nl_NL",
54 		"nb_NO",
55 		"fr_FR.UTF-8@collation=phonebook",
56 		"de_DE.iso8859-1",
57 		"De_dE.IsO8859-15",
58 		"de_DE.utf8",
59 		"de_DE.UTF-8",
60 		"de_DE@euro",
61 		"de_DE@EURO",
62 		"de_DE.utf-8@Euro",
63 		"POSIX",
64 		"POSIX"
65 	};
66 	const char* categoryNames[] = {
67 		"LC_ALL",
68 		"LC_COLLATE",
69 		"LC_CTYPE",
70 		"LC_MONETARY",
71 		"LC_NUMERIC",
72 		"LC_TIME",
73 		"LC_MESSAGES"
74 	};
75 	printf("setlocale()\n");
76 
77 	int problemCount = 0;
78 	for (int i = 0; locales[i] != NULL; ++i) {
79 		char* result = setlocale(LC_ALL, locales[i]);
80 		if (!result || strcmp(result, expectedLocales[i]) != 0) {
81 			printf("\tPROBLEM: setlocale(LC_ALL, \"%s\") = \"%s\" "
82 					"(expected \"%s\")\n",
83 				locales[i], result, expectedLocales[i]);
84 			problemCount++;
85 		}
86 	}
87 
88 	for (int i = 1; i <= LC_LAST; ++i)
89 		setlocale(i, locales[i + 1]);
90 	char* result = setlocale(LC_ALL, NULL);
91 	const char* expectedResult
92 		= "LC_COLLATE=de_DE;LC_CTYPE=en_US;LC_MESSAGES=nb_NO;"
93 			"LC_MONETARY=en_US.US-ASCII;LC_NUMERIC=hr_HR.ISO-8859-2;"
94 			"LC_TIME=nl_NL";
95 	if (!result || strcmp(result, expectedResult) != 0) {
96 		printf("\tPROBLEM: setlocale(LC_ALL, NULL) = \"%s\" "
97 				"(expected \"%s\")\n", result, expectedResult);
98 		problemCount++;
99 	}
100 
101 	if (problemCount)
102 		printf("\t%d problem(s) found!\n", problemCount);
103 	else
104 		printf("\tall fine\n");
105 }
106 
107 
108 // #pragma mark - localeconv ---------------------------------------------------
109 
110 
111 void
112 dumpGrouping(const char* grouping, char* buf)
113 {
114 	for (char* bufPtr = buf; *grouping; ++grouping)
115 		bufPtr += sprintf(bufPtr, "\\x%02x", *grouping);
116 }
117 
118 
119 void
120 test_localeconv(const char* locale, const lconv* localeConv)
121 {
122 	setlocale(LC_MONETARY, locale);
123 	setlocale(LC_NUMERIC, locale);
124 	printf("localeconv for '%s'\n", locale);
125 
126 	int problemCount = 0;
127 	struct lconv* lc = localeconv();
128 	if (!lc)
129 		printf("not ok - got no result from localeconv()\n");
130 	else {
131 		if (strcmp(lc->decimal_point, localeConv->decimal_point) != 0) {
132 			printf("\tPROBLEM: lc.decimal_point = \"%s\" (expected \"%s\")\n",
133 				lc->decimal_point, localeConv->decimal_point);
134 			problemCount++;
135 		}
136 		if (strcmp(lc->thousands_sep, localeConv->thousands_sep) != 0) {
137 			printf("\tPROBLEM: lc.thousands_sep = \"%s\" (expected \"%s\")\n",
138 				lc->thousands_sep, localeConv->thousands_sep);
139 			problemCount++;
140 		}
141 		if (strcmp(lc->grouping, localeConv->grouping) != 0) {
142 			char gotGrouping[20], expectedGrouping[20];
143 			dumpGrouping(lc->grouping, gotGrouping);
144 			dumpGrouping(localeConv->grouping, expectedGrouping);
145 			printf("\tPROBLEM: lc.grouping = \"%s\" (expected \"%s\")\n",
146 				gotGrouping, expectedGrouping);
147 			problemCount++;
148 		}
149 		if (strcmp(lc->int_curr_symbol, localeConv->int_curr_symbol) != 0) {
150 			printf("\tPROBLEM: lc.int_curr_symbol = \"%s\" (expected \"%s\")\n",
151 				lc->int_curr_symbol, localeConv->int_curr_symbol);
152 			problemCount++;
153 		}
154 		if (strcmp(lc->currency_symbol, localeConv->currency_symbol) != 0) {
155 			printf("\tPROBLEM: lc.currency_symbol = \"%s\" (expected \"%s\")\n",
156 				lc->currency_symbol, localeConv->currency_symbol);
157 			problemCount++;
158 		}
159 		if (strcmp(lc->mon_decimal_point, localeConv->mon_decimal_point) != 0) {
160 			printf("\tPROBLEM: lc.mon_decimal_point = \"%s\" "
161 					"(expected \"%s\")\n",
162 				lc->mon_decimal_point, localeConv->mon_decimal_point);
163 			problemCount++;
164 		}
165 		if (strcmp(lc->mon_thousands_sep, localeConv->mon_thousands_sep) != 0) {
166 			printf("\tPROBLEM: lc.mon_thousands_sep = \"%s\" "
167 					"(expected \"%s\")\n",
168 				lc->mon_thousands_sep, localeConv->mon_thousands_sep);
169 			problemCount++;
170 		}
171 		if (strcmp(lc->mon_grouping, localeConv->mon_grouping) != 0) {
172 			char gotGrouping[20], expectedGrouping[20];
173 			dumpGrouping(lc->mon_grouping, gotGrouping);
174 			dumpGrouping(localeConv->mon_grouping, expectedGrouping);
175 			printf("\tPROBLEM: lc.mon_grouping: \"%s\" (expected \"%s\")\n",
176 				gotGrouping, expectedGrouping);
177 			problemCount++;
178 		}
179 		if (strcmp(lc->positive_sign, localeConv->positive_sign) != 0) {
180 			printf("\tPROBLEM: lc.positive_sign = \"%s\" (expected \"%s\")\n",
181 				lc->positive_sign, localeConv->positive_sign);
182 			problemCount++;
183 		}
184 		if (strcmp(lc->negative_sign, localeConv->negative_sign) != 0) {
185 			printf("\tPROBLEM: lc.negative_sign = \"%s\" (expected \"%s\")\n",
186 				lc->negative_sign, localeConv->negative_sign);
187 			problemCount++;
188 		}
189 		if (lc->frac_digits != localeConv->frac_digits) {
190 			printf("\tPROBLEM: lc.frac_digits = %d (expected %d)\n",
191 				lc->frac_digits, localeConv->frac_digits);
192 			problemCount++;
193 		}
194 		if (lc->int_frac_digits != localeConv->int_frac_digits) {
195 			printf("\tPROBLEM: lc.int_frac_digits = %d (expected %d)\n",
196 				lc->int_frac_digits, localeConv->int_frac_digits);
197 			problemCount++;
198 		}
199 		if (lc->p_cs_precedes != localeConv->p_cs_precedes) {
200 			printf("\tPROBLEM: lc.p_cs_precedes = %d (expected %d)\n",
201 				lc->p_cs_precedes, localeConv->p_cs_precedes);
202 			problemCount++;
203 		}
204 		if (lc->p_sep_by_space != localeConv->p_sep_by_space) {
205 			printf("\tPROBLEM: lc.p_sep_by_space = %d (expected %d)\n",
206 				lc->p_sep_by_space, localeConv->p_sep_by_space);
207 			problemCount++;
208 		}
209 		if (lc->p_sign_posn != localeConv->p_sign_posn) {
210 			printf("\tPROBLEM: lc.p_sign_posn = %d (expected %d)\n",
211 				lc->p_sign_posn, localeConv->p_sign_posn);
212 			problemCount++;
213 		}
214 		if (lc->n_cs_precedes != localeConv->n_cs_precedes) {
215 			printf("\tPROBLEM: lc.n_cs_precedes = %d (expected %d)\n",
216 				lc->n_cs_precedes, localeConv->n_cs_precedes);
217 			problemCount++;
218 		}
219 		if (lc->n_sep_by_space != localeConv->n_sep_by_space) {
220 			printf("\tPROBLEM: lc.n_sep_by_space = %d (expected %d)\n",
221 				lc->n_sep_by_space, localeConv->n_sep_by_space);
222 			problemCount++;
223 		}
224 		if (lc->n_sign_posn != localeConv->n_sign_posn) {
225 			printf("\tPROBLEM: lc.n_sign_posn = %d (expected %d)\n",
226 				lc->n_sign_posn, localeConv->n_sign_posn);
227 			problemCount++;
228 		}
229 		if (lc->int_p_cs_precedes != localeConv->int_p_cs_precedes) {
230 			printf("\tPROBLEM: lc.int_p_cs_precedes = %d (expected %d)\n",
231 				lc->int_p_cs_precedes, localeConv->int_p_cs_precedes);
232 			problemCount++;
233 		}
234 		if (lc->int_p_sep_by_space != localeConv->int_p_sep_by_space) {
235 			printf("\tPROBLEM: lc.int_p_sep_by_space = %d (expected %d)\n",
236 				lc->int_p_sep_by_space, localeConv->int_p_sep_by_space);
237 			problemCount++;
238 		}
239 		if (lc->int_p_sign_posn != localeConv->int_p_sign_posn) {
240 			printf("\tPROBLEM: lc.int_p_sign_posn = %d (expected %d)\n",
241 				lc->int_p_sign_posn, localeConv->int_p_sign_posn);
242 			problemCount++;
243 		}
244 		if (lc->int_n_cs_precedes != localeConv->int_n_cs_precedes) {
245 			printf("\tPROBLEM: lc.int_n_cs_precedes = %d (expected %d)\n",
246 				lc->int_n_cs_precedes, localeConv->int_n_cs_precedes);
247 			problemCount++;
248 		}
249 		if (lc->int_n_sep_by_space != localeConv->int_n_sep_by_space) {
250 			printf("\tPROBLEM: lc.int_n_sep_by_space = %d (expected %d)\n",
251 				lc->int_n_sep_by_space, localeConv->int_n_sep_by_space);
252 			problemCount++;
253 		}
254 		if (lc->int_n_sign_posn != localeConv->int_n_sign_posn) {
255 			printf("\tPROBLEM: lc.int_n_sign_posn = %d (expected %d)\n",
256 				lc->int_n_sign_posn, localeConv->int_n_sign_posn);
257 			problemCount++;
258 		}
259 	}
260 	if (problemCount)
261 		printf("\t%d problem(s) found!\n", problemCount);
262 	else
263 		printf("\tall fine\n");
264 }
265 
266 
267 void
268 test_localeconv()
269 {
270 	const lconv lconv_posix = {
271 		(char*)".",
272 		(char*)"",
273 		(char*)"",
274 		(char*)"",
275 		(char*)"",
276 		(char*)"",
277 		(char*)"",
278 		(char*)"",
279 		(char*)"",
280 		(char*)"",
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 		CHAR_MAX,
294 		CHAR_MAX
295 	};
296 	test_localeconv("POSIX", &lconv_posix);
297 
298 	const lconv lconv_de = {
299 		(char*)",",
300 		(char*)".",
301 		(char*)"\x03",
302 		(char*)"EUR ",
303 		(char*)"€",
304 		(char*)",",
305 		(char*)".",
306 		(char*)"\x03",
307 		(char*)"",
308 		(char*)"-",
309 		2,
310 		2,
311 		0,
312 		1,
313 		0,
314 		1,
315 		1,
316 		1,
317 		0,
318 		1,
319 		0,
320 		1,
321 		1,
322 		1
323 	};
324 	test_localeconv("de_DE", &lconv_de);
325 
326 	const lconv lconv_de_iso = {
327 		(char*)",",
328 		(char*)".",
329 		(char*)"\x03",
330 		(char*)"EUR ",
331 		(char*)"EUR",
332 		(char*)",",
333 		(char*)".",
334 		(char*)"\x03",
335 		(char*)"",
336 		(char*)"-",
337 		2,
338 		2,
339 		0,
340 		1,
341 		0,
342 		1,
343 		1,
344 		1,
345 		0,
346 		1,
347 		0,
348 		1,
349 		1,
350 		1
351 	};
352 	test_localeconv("de_DE.ISO8859-1", &lconv_de_iso);
353 
354 	const lconv lconv_hr = {
355 		(char*)",",
356 		(char*)".",
357 		(char*)"\x03",
358 		(char*)"HRK ",
359 		(char*)"kn",
360 		(char*)",",
361 		(char*)".",
362 		(char*)"\x03",
363 		(char*)"",
364 		(char*)"-",
365 		2,
366 		2,
367 		0,
368 		1,
369 		0,
370 		1,
371 		1,
372 		1,
373 		0,
374 		1,
375 		0,
376 		1,
377 		1,
378 		1
379 	};
380 	test_localeconv("hr_HR.ISO8859-2", &lconv_hr);
381 
382 	const lconv lconv_de_CH = {
383 		(char*)".",
384 		(char*)"'",
385 		(char*)"\x03",
386 		(char*)"CHF ",
387 		(char*)"CHF",
388 		(char*)".",
389 		(char*)"'",
390 		(char*)"\x03",
391 		(char*)"",
392 		(char*)"-",
393 		2,
394 		2,
395 		1,
396 		1,
397 		1,
398 		0,
399 		4,
400 		4,
401 		1,
402 		1,
403 		1,
404 		0,
405 		4,
406 		4
407 	};
408 	test_localeconv("de_CH", &lconv_de_CH);
409 
410 	const lconv lconv_gu_IN = {
411 		(char*)".",
412 		(char*)",",
413 		(char*)"\x03\x02",
414 		(char*)"INR ",
415 		(char*)"રુ",
416 		(char*)".",
417 		(char*)",",
418 		(char*)"\x03\x02",
419 		(char*)"",
420 		(char*)"-",
421 		2,
422 		2,
423 		1,
424 		1,
425 		1,
426 		1,
427 		1,
428 		1,
429 		1,
430 		1,
431 		1,
432 		1,
433 		1,
434 		1
435 	};
436 	test_localeconv("gu_IN", &lconv_gu_IN);
437 
438 	const lconv lconv_it = {
439 		(char*)",",
440 		(char*)".",
441 		(char*)"\x03",
442 		(char*)"EUR ",
443 		(char*)"€",
444 		(char*)",",
445 		(char*)".",
446 		(char*)"\x03",
447 		(char*)"",
448 		(char*)"-",
449 		2,
450 		2,
451 		1,
452 		1,
453 		1,
454 		1,
455 		1,
456 		1,
457 		1,
458 		1,
459 		1,
460 		1,
461 		1,
462 		1
463 	};
464 	test_localeconv("it_IT", &lconv_it);
465 
466 	const lconv lconv_nl = {
467 		(char*)",",
468 		(char*)".",
469 		(char*)"\x03",
470 		(char*)"EUR ",
471 		(char*)"€",
472 		(char*)",",
473 		(char*)".",
474 		(char*)"\x03",
475 		(char*)"",
476 		(char*)"-",
477 		2,
478 		2,
479 		1,
480 		1,
481 		1,
482 		1,
483 		2,
484 		2,
485 		1,
486 		1,
487 		1,
488 		1,
489 		2,
490 		2
491 	};
492 	test_localeconv("nl_NL", &lconv_nl);
493 
494 	const lconv lconv_nb = {
495 		(char*)",",
496 		(char*)" ",
497 		(char*)"\x03",
498 		(char*)"NOK ",
499 		(char*)"kr",
500 		(char*)",",
501 		(char*)" ",
502 		(char*)"\x03",
503 		(char*)"",
504 		(char*)"-",
505 		2,
506 		2,
507 		1,
508 		1,
509 		1,
510 		1,
511 		1,
512 		1,
513 		1,
514 		1,
515 		1,
516 		1,
517 		1,
518 		1
519 	};
520 	test_localeconv("nb_NO", &lconv_nb);
521 }
522 
523 
524 // #pragma mark - strftime -----------------------------------------------------
525 
526 
527 struct strftime_data {
528 	const char* format;
529 	const char* result;
530 };
531 
532 
533 void
534 test_strftime(const char* locale, const strftime_data data[])
535 {
536 	setlocale(LC_TIME, locale);
537 	printf("strftime for '%s'\n", locale);
538 
539 	time_t nowSecs = 1279391169;	// pure magic
540 	tm* now = localtime(&nowSecs);
541 	int problemCount = 0;
542 	for(int i = 0; data[i].format != NULL; ++i) {
543 		char buf[100];
544 		strftime(buf, 100, data[i].format, now);
545 		if (strcmp(buf, data[i].result) != 0) {
546 			printf("\tPROBLEM: strftime(\"%s\") = \"%s\" (expected \"%s\")\n",
547 				data[i].format, buf, data[i].result);
548 			problemCount++;
549 		}
550 	}
551 	if (problemCount)
552 		printf("\t%d problem(s) found!\n", problemCount);
553 	else
554 		printf("\tall fine\n");
555 }
556 
557 
558 void
559 test_strftime()
560 {
561 	setenv("TZ", "GMT", 1);
562 
563 	const strftime_data strftime_posix[] = {
564 		{ "%c", "Sat Jul 17 18:26:09 2010" },
565 		{ "%x", "07/17/10" },
566 		{ "%X", "18:26:09" },
567 		{ "%a", "Sat" },
568 		{ "%A", "Saturday" },
569 		{ "%b", "Jul" },
570 		{ "%B", "July" },
571 		{ NULL, NULL }
572 	};
573 	test_strftime("POSIX", strftime_posix);
574 
575 	const strftime_data strftime_de[] = {
576 		{ "%c", "Samstag, 17. Juli 2010 18:26:09 GMT" },
577 		{ "%x", "17.07.2010" },
578 		{ "%X", "18:26:09" },
579 		{ "%a", "Sa." },
580 		{ "%A", "Samstag" },
581 		{ "%b", "Jul" },
582 		{ "%B", "Juli" },
583 		{ NULL, NULL }
584 	};
585 	test_strftime("de_DE.UTF-8", strftime_de);
586 
587 	const strftime_data strftime_hr[] = {
588 		{ "%c", "subota, 17. srpnja 2010. 18:26:09 GMT" },
589 		{ "%x", "17. 07. 2010." },
590 		{ "%X", "18:26:09" },
591 		{ "%a", "sub" },
592 		{ "%A", "subota" },
593 		{ "%b", "srp" },
594 		{ "%B", "srpnja" },
595 		{ NULL, NULL }
596 	};
597 	test_strftime("hr_HR.ISO8859-2", strftime_hr);
598 
599 	const strftime_data strftime_gu[] = {
600 		{ "%c", "શનિવાર, 17 જુલાઈ, 2010 06:26:09 PM GMT" },
601 		{ "%x", "17 જુલાઈ, 2010" },
602 		{ "%X", "06:26:09 PM" },
603 		{ "%a", "શનિ" },
604 		{ "%A", "શનિવાર" },
605 		{ "%b", "જુલાઈ" },
606 		{ "%B", "જુલાઈ" },
607 		{ NULL, NULL }
608 	};
609 	test_strftime("gu_IN", strftime_gu);
610 
611 	const strftime_data strftime_it[] = {
612 		{ "%c", "sabato 17 luglio 2010 18:26:09 GMT" },
613 		{ "%x", "17/lug/2010" },
614 		{ "%X", "18:26:09" },
615 		{ "%a", "sab" },
616 		{ "%A", "sabato" },
617 		{ "%b", "lug" },
618 		{ "%B", "luglio" },
619 		{ NULL, NULL }
620 	};
621 	test_strftime("it_IT", strftime_it);
622 
623 	const strftime_data strftime_nl[] = {
624 		{ "%c", "zaterdag 17 juli 2010 18:26:09 GMT" },
625 		{ "%x", "17 jul. 2010" },
626 		{ "%X", "18:26:09" },
627 		{ "%a", "za" },
628 		{ "%A", "zaterdag" },
629 		{ "%b", "jul." },
630 		{ "%B", "juli" },
631 		{ NULL, NULL }
632 	};
633 	test_strftime("nl_NL", strftime_nl);
634 
635 	const strftime_data strftime_nb[] = {
636 		{ "%c", "lørdag 17. juli 2010 kl. 18:26:09 GMT" },
637 		{ "%x", "17. juli 2010" },
638 		{ "%X", "18:26:09" },
639 		{ "%a", "lør." },
640 		{ "%A", "lørdag" },
641 		{ "%b", "juli" },
642 		{ "%B", "juli" },
643 		{ NULL, NULL }
644 	};
645 	test_strftime("nb_NO", strftime_nb);
646 }
647 
648 
649 // #pragma mark - ctype --------------------------------------------------------
650 
651 
652 unsigned short
653 determineFullClassInfo(int i)
654 {
655 	unsigned short classInfo = 0;
656 
657 	if (isblank(i))
658 		classInfo |= _ISblank;
659 	if (iscntrl(i))
660 		classInfo |= _IScntrl;
661 	if (ispunct(i))
662 		classInfo |= _ISpunct;
663 	if (isalnum(i))
664 		classInfo |= _ISalnum;
665 	if (isupper(i))
666 		classInfo |= _ISupper;
667 	if (islower(i))
668 		classInfo |= _ISlower;
669 	if (isalpha(i))
670 		classInfo |= _ISalpha;
671 	if (isdigit(i))
672 		classInfo |= _ISdigit;
673 	if (isxdigit(i))
674 		classInfo |= _ISxdigit;
675 	if (isspace(i))
676 		classInfo |= _ISspace;
677 	if (isprint(i))
678 		classInfo |= _ISprint;
679 	if (isgraph(i))
680 		classInfo |= _ISgraph;
681 
682 	return classInfo;
683 }
684 
685 
686 void
687 test_ctype(const char* locale, const unsigned short int classInfos[],
688 	const int toLowerMap[], const int toUpperMap[])
689 {
690 	setlocale(LC_CTYPE, locale);
691 	printf("ctype of %s locale\n", locale);
692 
693 	int problemCount = 0;
694 	for (int i = 0; i < 256; ++i) {
695 		unsigned short classInfo = determineFullClassInfo(i);
696 
697 		if (classInfo != classInfos[i]) {
698 			printf("\tPROBLEM: %d = %x (expected %x)\n", i, classInfo,
699 				classInfos[i]);
700 			problemCount++;
701 		}
702 		int lower = tolower(i);
703 		if (lower != toLowerMap[i]) {
704 			printf("\tPROBLEM: tolower(%d) = %x (expected %x)\n", i, lower,
705 				toLowerMap[i]);
706 			problemCount++;
707 		}
708 		int upper = toupper(i);
709 		if (upper != toUpperMap[i]) {
710 			printf("\tPROBLEM: toupper(%d) = %x (expected %x)\n", i, upper,
711 				toUpperMap[i]);
712 			problemCount++;
713 		}
714 	}
715 	if (problemCount)
716 		printf("\t%d problem(s) found!\n", problemCount);
717 	else
718 		printf("\tall fine\n");
719 }
720 
721 
722 void
723 test_ctype()
724 {
725 	const unsigned short int classInfos_posix[256] = {
726 		/*   0 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
727 		/*   8 */	_IScntrl, _ISblank|_IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl, _IScntrl,
728 		/*  16 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
729 		/*  24 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
730 		/*  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,
731 		/*  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,
732 		/*  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,
733 		/*  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,
734 		/*  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,
735 		/*  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,
736 		/*  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,
737 		/*  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,
738 		/*  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,
739 		/* 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,
740 		/* 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,
741 		/* 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,
742 		/* 128 */	0, 0, 0, 0, 0, 0, 0, 0,
743 		/* 136 */	0, 0, 0, 0, 0, 0, 0, 0,
744 		/* 144 */	0, 0, 0, 0, 0, 0, 0, 0,
745 		/* 152 */	0, 0, 0, 0, 0, 0, 0, 0,
746 		/* 160 */	0, 0, 0, 0, 0, 0, 0, 0,
747 		/* 168 */	0, 0, 0, 0, 0, 0, 0, 0,
748 		/* 176 */	0, 0, 0, 0, 0, 0, 0, 0,
749 		/* 184 */	0, 0, 0, 0, 0, 0, 0, 0,
750 		/* 192 */	0, 0, 0, 0, 0, 0, 0, 0,
751 		/* 200 */	0, 0, 0, 0, 0, 0, 0, 0,
752 		/* 208 */	0, 0, 0, 0, 0, 0, 0, 0,
753 		/* 216 */	0, 0, 0, 0, 0, 0, 0, 0,
754 		/* 224 */	0, 0, 0, 0, 0, 0, 0, 0,
755 		/* 232 */	0, 0, 0, 0, 0, 0, 0, 0,
756 		/* 240 */	0, 0, 0, 0, 0, 0, 0, 0,
757 		/* 248 */	0, 0, 0, 0, 0, 0, 0, 0,
758 	};
759 	const int toLowerMap_posix[256] = {
760 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
761 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
762 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
763 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
764 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
765 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
766 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
767 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
768 		/*  64 */	 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
769 		/*  72 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
770 		/*  80 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
771 		/*  88 */	'x', 'y', 'z',  91,  92,  93,  94,  95,
772 		/*  96 */	 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
773 		/* 104 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
774 		/* 112 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
775 		/* 120 */	'x', 'y', 'z', 123, 124, 125, 126, 127,
776 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
777 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
778 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
779 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
780 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
781 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
782 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
783 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
784 		/* 192 */	192, 193, 194, 195, 196, 197, 198, 199,
785 		/* 200 */	200, 201, 202, 203, 204, 205, 206, 207,
786 		/* 208 */	208, 209, 210, 211, 212, 213, 214, 215,
787 		/* 216 */	216, 217, 218, 219, 220, 221, 222, 223,
788 		/* 224 */	224, 225, 226, 227, 228, 229, 230, 231,
789 		/* 232 */	232, 233, 234, 235, 236, 237, 238, 239,
790 		/* 240 */	240, 241, 242, 243, 244, 245, 246, 247,
791 		/* 248 */	248, 249, 250, 251, 252, 253, 254, 255,
792 	};
793 	const int toUpperMap_posix[256] = {
794 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
795 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
796 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
797 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
798 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
799 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
800 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
801 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
802 		/*  64 */	 64, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
803 		/*  72 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
804 		/*  80 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
805 		/*  88 */	'X', 'Y', 'Z',  91,  92,  93,  94,  95,
806 		/*  96 */	 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
807 		/* 104 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
808 		/* 112 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
809 		/* 120 */	'X', 'Y', 'Z', 123, 124, 125, 126, 127,
810 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
811 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
812 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
813 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
814 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
815 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
816 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
817 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
818 		/* 192 */	192, 193, 194, 195, 196, 197, 198, 199,
819 		/* 200 */	200, 201, 202, 203, 204, 205, 206, 207,
820 		/* 208 */	208, 209, 210, 211, 212, 213, 214, 215,
821 		/* 216 */	216, 217, 218, 219, 220, 221, 222, 223,
822 		/* 224 */	224, 225, 226, 227, 228, 229, 230, 231,
823 		/* 232 */	232, 233, 234, 235, 236, 237, 238, 239,
824 		/* 240 */	240, 241, 242, 243, 244, 245, 246, 247,
825 		/* 248 */	248, 249, 250, 251, 252, 253, 254, 255,
826 	};
827 	test_ctype("POSIX", classInfos_posix, toLowerMap_posix, toUpperMap_posix);
828 
829 	const unsigned short int classInfos_de[256] = {
830 		/*   0 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
831 		/*   8 */	_IScntrl, _ISblank|_IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl, _IScntrl,
832 		/*  16 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
833 		/*  24 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
834 		/*  32 */	_ISblank|_ISspace|_ISprint, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
835 		/*  40 */	_ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
836 		/*  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,
837 		/*  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,
838 		/*  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,
839 		/*  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,
840 		/*  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,
841 		/*  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,
842 		/*  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,
843 		/* 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,
844 		/* 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,
845 		/* 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,
846 		/* 128 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl|_ISspace, _IScntrl, _IScntrl,
847 		/* 136 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
848 		/* 144 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
849 		/* 152 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
850 		/* 160 */	_ISprint|_ISspace|_ISblank, _ISprint|_ISgraph|_ISpunct, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph,
851 		/* 168 */	_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISpunct, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph,
852 		/* 176 */	_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISpunct,
853 		/* 184 */	_ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, _ISprint|_ISgraph|_ISpunct, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph, _ISprint|_ISgraph|_ISpunct,
854 		/* 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,
855 		/* 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,
856 		/* 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,
857 		/* 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,
858 		/* 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,
859 		/* 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,
860 		/* 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,
861 		/* 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,
862 	};
863 	const int toLowerMap_de[256] = {
864 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
865 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
866 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
867 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
868 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
869 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
870 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
871 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
872 		/*  64 */	 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
873 		/*  72 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
874 		/*  80 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
875 		/*  88 */	'x', 'y', 'z',  91,  92,  93,  94,  95,
876 		/*  96 */	 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
877 		/* 104 */	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
878 		/* 112 */	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
879 		/* 120 */	'x', 'y', 'z', 123, 124, 125, 126, 127,
880 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
881 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
882 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
883 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
884 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
885 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
886 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
887 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
888 		/* 192 */	224, 225, 226, 227, 228, 229, 230, 231,
889 		/* 200 */	232, 233, 234, 235, 236, 237, 238, 239,
890 		/* 208 */	240, 241, 242, 243, 244, 245, 246, 215,
891 		/* 216 */	248, 249, 250, 251, 252, 253, 254, 223,
892 		/* 224 */	224, 225, 226, 227, 228, 229, 230, 231,
893 		/* 232 */	232, 233, 234, 235, 236, 237, 238, 239,
894 		/* 240 */	240, 241, 242, 243, 244, 245, 246, 247,
895 		/* 248 */	248, 249, 250, 251, 252, 253, 254, 255,
896 	};
897 	const int toUpperMap_de[256] = {
898 		/*   0 */	  0,   1,   2,   3,   4,   5,   6,   7,
899 		/*   8 */	  8,   9,  10,  11,  12,  13,  14,  15,
900 		/*  16 */	 16,  17,  18,  19,  20,  21,  22,  23,
901 		/*  24 */	 24,  25,  26,  27,  28,  29,  30,  31,
902 		/*  32 */	 32,  33,  34,  35,  36,  37,  38,  39,
903 		/*  40 */	 40,  41,  42,  43,  44,  45,  46,  47,
904 		/*  48 */	'0', '1', '2', '3', '4', '5', '6', '7',
905 		/*  56 */	'8', '9',  58,  59,  60,  61,  62,  63,
906 		/*  64 */	 64, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
907 		/*  72 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
908 		/*  80 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
909 		/*  88 */	'X', 'Y', 'Z',  91,  92,  93,  94,  95,
910 		/*  96 */	 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
911 		/* 104 */	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
912 		/* 112 */	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
913 		/* 120 */	'X', 'Y', 'Z', 123, 124, 125, 126, 127,
914 		/* 128 */	128, 129, 130, 131, 132, 133, 134, 135,
915 		/* 136 */	136, 137, 138, 139, 140, 141, 142, 143,
916 		/* 144 */	144, 145, 146, 147, 148, 149, 150, 151,
917 		/* 152 */	152, 153, 154, 155, 156, 157, 158, 159,
918 		/* 160 */	160, 161, 162, 163, 164, 165, 166, 167,
919 		/* 168 */	168, 169, 170, 171, 172, 173, 174, 175,
920 		/* 176 */	176, 177, 178, 179, 180, 181, 182, 183,
921 		/* 184 */	184, 185, 186, 187, 188, 189, 190, 191,
922 		/* 192 */	192, 193, 194, 195, 196, 197, 198, 199,
923 		/* 200 */	200, 201, 202, 203, 204, 205, 206, 207,
924 		/* 208 */	208, 209, 210, 211, 212, 213, 214, 215,
925 		/* 216 */	216, 217, 218, 219, 220, 221, 222, 223,
926 		/* 224 */	192, 193, 194, 195, 196, 197, 198, 199,
927 		/* 232 */	200, 201, 202, 203, 204, 205, 206, 207,
928 		/* 240 */	208, 209, 210, 211, 212, 213, 214, 247,
929 		/* 248 */	216, 217, 218, 219, 220, 221, 222, 255,
930 	};
931 	test_ctype("de_DE.ISO8859-1", classInfos_de, toLowerMap_de, toUpperMap_de);
932 
933 	const unsigned short int classInfos_utf8[256] = {
934 		/*   0 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
935 		/*   8 */	_IScntrl, _ISblank|_IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl|_ISspace, _IScntrl, _IScntrl,
936 		/*  16 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
937 		/*  24 */	_IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl, _IScntrl,
938 		/*  32 */	_ISblank|_ISspace|_ISprint, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
939 		/*  40 */	_ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph, _ISpunct|_ISprint|_ISgraph,
940 		/*  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,
941 		/*  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,
942 		/*  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,
943 		/*  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,
944 		/*  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,
945 		/*  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,
946 		/*  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,
947 		/* 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,
948 		/* 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,
949 		/* 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,
950 		/* 128 */	0, 0, 0, 0, 0, 0, 0, 0,
951 		/* 136 */	0, 0, 0, 0, 0, 0, 0, 0,
952 		/* 144 */	0, 0, 0, 0, 0, 0, 0, 0,
953 		/* 152 */	0, 0, 0, 0, 0, 0, 0, 0,
954 		/* 160 */	0, 0, 0, 0, 0, 0, 0, 0,
955 		/* 168 */	0, 0, 0, 0, 0, 0, 0, 0,
956 		/* 176 */	0, 0, 0, 0, 0, 0, 0, 0,
957 		/* 184 */	0, 0, 0, 0, 0, 0, 0, 0,
958 		/* 192 */	0, 0, 0, 0, 0, 0, 0, 0,
959 		/* 200 */	0, 0, 0, 0, 0, 0, 0, 0,
960 		/* 208 */	0, 0, 0, 0, 0, 0, 0, 0,
961 		/* 216 */	0, 0, 0, 0, 0, 0, 0, 0,
962 		/* 224 */	0, 0, 0, 0, 0, 0, 0, 0,
963 		/* 232 */	0, 0, 0, 0, 0, 0, 0, 0,
964 		/* 240 */	0, 0, 0, 0, 0, 0, 0, 0,
965 		/* 248 */	0, 0, 0, 0, 0, 0, 0, 0,
966 	};
967 	test_ctype("de_DE.UTF-8", classInfos_utf8, toLowerMap_posix,
968 		toUpperMap_posix);
969 }
970 
971 
972 // #pragma mark - wctype -------------------------------------------------------
973 
974 
975 unsigned short
976 determineWideFullClassInfo(int i)
977 {
978 	unsigned short classInfo = 0;
979 
980 	if (iswblank(i))
981 		classInfo |= _ISblank;
982 	if (iswcntrl(i))
983 		classInfo |= _IScntrl;
984 	if (iswpunct(i))
985 		classInfo |= _ISpunct;
986 	if (iswalnum(i))
987 		classInfo |= _ISalnum;
988 	if (iswupper(i))
989 		classInfo |= _ISupper;
990 	if (iswlower(i))
991 		classInfo |= _ISlower;
992 	if (iswalpha(i))
993 		classInfo |= _ISalpha;
994 	if (iswdigit(i))
995 		classInfo |= _ISdigit;
996 	if (iswxdigit(i))
997 		classInfo |= _ISxdigit;
998 	if (iswspace(i))
999 		classInfo |= _ISspace;
1000 	if (iswprint(i))
1001 		classInfo |= _ISprint;
1002 	if (iswgraph(i))
1003 		classInfo |= _ISgraph;
1004 
1005 	return classInfo;
1006 }
1007 
1008 
1009 void
1010 test_wctype(const char* locale, const wchar_t* text,
1011 	const unsigned short int wcs[], const unsigned short int classInfos[])
1012 {
1013 	setlocale(LC_CTYPE, locale);
1014 	printf("wctype of %s locale\n", locale);
1015 
1016 	int problemCount = 0;
1017 	wint_t wc = *text;
1018 	for (int i = 0; i < 48; wc = *++text, ++i) {
1019 		unsigned short classInfo = determineWideFullClassInfo(wc);
1020 		if (wc != wcs[i]) {
1021 			printf("\tPROBLEM: wc for char #%d = %x (expected %x)\n", i, wc,
1022 				wcs[i]);
1023 			problemCount++;
1024 		}
1025 
1026 		if (classInfo != classInfos[i]) {
1027 			printf("\tPROBLEM: classinfo for #%d = %x (expected %x)\n", i,
1028 				classInfo, classInfos[i]);
1029 			problemCount++;
1030 		}
1031 	}
1032 	if (problemCount)
1033 		printf("\t%d problem(s) found!\n", problemCount);
1034 	else
1035 		printf("\tall fine\n");
1036 }
1037 
1038 
1039 void
1040 test_wctype()
1041 {
1042 	// haiku wide chars are always in UTF32, so nothing should change between
1043 	// different locales
1044 
1045 	const wchar_t* text = L"Hi there, how do you do? (äÜößáéúíó€'¤¹²$%#@) 12";
1046 
1047 	const unsigned short int wcs[48] = {
1048 		0x48, 0x69, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65,
1049 		0x2c, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x64, 0x6f,
1050 		0x20, 0x79, 0x6f, 0x75, 0x20, 0x64, 0x6f, 0x3f,
1051 		0x20, 0x28, 0xe4, 0xdc, 0xf6, 0xdf, 0xe1, 0xe9,
1052 		0xfa, 0xed, 0xf3, 0x20ac, 0x27, 0xa4, 0xb9, 0xb2,
1053 		0x24, 0x25, 0x23, 0x40, 0x29, 0x20, 0x31, 0x32
1054 	};
1055 	const unsigned short int classInfos[48] = {
1056 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISupper,
1057 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1058 		_ISspace|_ISprint|_ISblank,
1059 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1060 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1061 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1062 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1063 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1064 		_ISprint|_ISgraph|_ISpunct,
1065 		_ISspace|_ISprint|_ISblank,
1066 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1067 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1068 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1069 		_ISspace|_ISprint|_ISblank,
1070 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1071 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1072 		_ISspace|_ISprint|_ISblank,
1073 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1074 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1075 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1076 		_ISspace|_ISprint|_ISblank,
1077 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower|_ISxdigit,
1078 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1079 		_ISprint|_ISgraph|_ISpunct,
1080 		_ISspace|_ISprint|_ISblank,
1081 		_ISprint|_ISgraph|_ISpunct,
1082 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1083 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISupper,
1084 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1085 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1086 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1087 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1088 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1089 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1090 		_ISprint|_ISgraph|_ISalpha|_ISalnum|_ISlower,
1091 		_ISprint|_ISgraph,
1092 		_ISprint|_ISgraph|_ISpunct,
1093 		_ISprint|_ISgraph,
1094 		_ISprint|_ISgraph,
1095 		_ISprint|_ISgraph,
1096 		_ISprint|_ISgraph,
1097 		_ISpunct|_ISprint|_ISgraph,
1098 		_ISpunct|_ISprint|_ISgraph,
1099 		_ISpunct|_ISprint|_ISgraph,
1100 		_ISpunct|_ISprint|_ISgraph,
1101 		_ISspace|_ISprint|_ISblank,
1102 		_ISprint|_ISgraph|_ISalnum|_ISdigit|_ISxdigit,
1103 		_ISprint|_ISgraph|_ISalnum|_ISdigit|_ISxdigit
1104 	};
1105 
1106 	test_wctype("POSIX", text, wcs, classInfos);
1107 	test_wctype("de_DE.ISO8859-1", text, wcs, classInfos);
1108 	test_wctype("de_DE.ISO8859-15", text, wcs, classInfos);
1109 	test_wctype("de_DE.UTF-8", text, wcs, classInfos);
1110 }
1111 
1112 
1113 void
1114 test_wctrans(const char* locale, const wchar_t* text, wctrans_t transition,
1115 	const wchar_t* expectedResult)
1116 {
1117 	setlocale(LC_CTYPE, locale);
1118 	printf("towctrans(%s) of %s locale\n",
1119 		transition == _ISlower ? "tolower" : "toupper", locale);
1120 
1121 	int problemCount = 0;
1122 	wint_t wc = *text;
1123 	for (int i = 0; wc != 0; wc = *++text, ++i) {
1124 		errno = 0;
1125 		wint_t result = towctrans(wc, transition);
1126 		if (result != expectedResult[i] || errno != 0) {
1127 			printf("\tPROBLEM: result for char #%d = %x (expected %x), "
1128 					"errno = %x (expected %x)\n",
1129 				i, result, expectedResult[i], errno, 0);
1130 			problemCount++;
1131 		}
1132 	}
1133 	if (problemCount)
1134 		printf("\t%d problem(s) found!\n", problemCount);
1135 	else
1136 		printf("\tall fine\n");
1137 }
1138 
1139 
1140 void
1141 test_wctrans()
1142 {
1143 	// haiku wide chars are always in UTF32, so nothing should change between
1144 	// different locales
1145 
1146 	setlocale(LC_CTYPE, "POSIX");
1147 	printf("wctrans setup\n");
1148 
1149 	int problemCount = 0;
1150 	errno = 0;
1151 	wctrans_t toU = wctrans("toupper");
1152 	if (errno != 0 || toU != _ISupper) {
1153 		printf("\tPROBLEM: wctrans(\"upper\") = %x (expected %x), "
1154 				"errno=%x (expected %x)\n",
1155 			toU, _ISupper, errno, 0);
1156 		problemCount++;
1157 	}
1158 	errno = 0;
1159 	wctrans_t toL = wctrans("tolower");
1160 	if (errno != 0 || toL != _ISlower) {
1161 		printf("\tPROBLEM: wctrans(\"lower\") = %x (expected %x), "
1162 				"errno=%x (expected %x)\n",
1163 			toL, _ISlower, errno, 0);
1164 		problemCount++;
1165 	}
1166 	errno = 0;
1167 	wctrans_t invalid1 = wctrans(NULL);
1168 	if (errno != EINVAL || invalid1 != 0) {
1169 		printf("\tPROBLEM: wctrans(NULL) = %x (expected %x), "
1170 				"errno=%x (expected %x)\n",
1171 			invalid1, 0, errno, EINVAL);
1172 		problemCount++;
1173 	}
1174 	errno = 0;
1175 	wctrans_t invalid2 = wctrans("invalid");
1176 	if (errno != EINVAL || invalid2 != 0) {
1177 		printf("\tPROBLEM: wctrans(\"invalid\") = %x (expected %x), "
1178 				"errno=%x (expected %x)\n",
1179 			invalid2, 0, errno, EINVAL);
1180 		problemCount++;
1181 	}
1182 	if (problemCount)
1183 		printf("\t%d problem(s) found!\n", problemCount);
1184 	else
1185 		printf("\tall fine\n");
1186 
1187 	const wchar_t* text = L"Hi there, how do you do? (äÜößáéúíó€'¤¹²$%#@) 12";
1188 	const wchar_t* textU = L"HI THERE, HOW DO YOU DO? (ÄÜÖßÁÉÚÍÓ€'¤¹²$%#@) 12";
1189 	const wchar_t* textL = L"hi there, how do you do? (äüößáéúíó€'¤¹²$%#@) 12";
1190 
1191 	test_wctrans("POSIX", text, toU, textU);
1192 	test_wctrans("de_DE.ISO8859-1", text, toU, textU);
1193 	test_wctrans("de_DE.ISO8859-15", text, toU, textU);
1194 	test_wctrans("de_DE.UTF-8", text, toU, textU);
1195 	test_wctrans("fr_Fr", text, toU, textU);
1196 
1197 	test_wctrans("POSIX", text, toL, textL);
1198 	test_wctrans("de_DE.ISO8859-1", text, toL, textL);
1199 	test_wctrans("de_DE.ISO8859-15", text, toL, textL);
1200 	test_wctrans("de_DE.UTF-8", text, toL, textL);
1201 	test_wctrans("fr_Fr", text, toL, textL);
1202 }
1203 
1204 
1205 // #pragma mark - nl_langinfo --------------------------------------------------
1206 
1207 
1208 void
1209 test_langinfo(const char* locale, const char* langinfos[])
1210 {
1211 	setlocale(LC_ALL, locale);
1212 	printf("langinfo of %s locale\n", locale);
1213 
1214 	int problemCount = 0;
1215 	for (int i = -1; langinfos[i + 1] != NULL; ++i) {
1216 		const char* langinfo = nl_langinfo(i);
1217 		if (strcmp(langinfo, langinfos[i + 1]) != 0) {
1218 			printf("\tPROBLEM: langinfo for #%d = '%s' (expected '%s')\n", i,
1219 				langinfo, langinfos[i + 1]);
1220 			problemCount++;
1221 		}
1222 	}
1223 	if (problemCount)
1224 		printf("\t%d problem(s) found!\n", problemCount);
1225 	else
1226 		printf("\tall fine\n");
1227 }
1228 
1229 
1230 void
1231 test_langinfo()
1232 {
1233 	const char* li_posix[] = {
1234 		"", 	// out of bounds
1235 		"US-ASCII",
1236 		"%a %b %e %H:%M:%S %Y",
1237 		"%m/%d/%y",
1238 		"%H:%M:%S",
1239 		"%I:%M:%S %p",
1240 		"AM",
1241 		"PM",
1242 
1243 		"Sunday", "Monday", "Tuesday", "Wednesday",	"Thursday", "Friday",
1244 		"Saturday",
1245 
1246 		"Sun", "Mon", "Tue", "Wed",	"Thu", "Fri", "Sat",
1247 
1248 		"January", "February", "March", "April", "May", "June",
1249 		"July", "August", "September", "October", "November", "December",
1250 
1251 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1252 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1253 
1254 		"%EC, %Ey, %EY",
1255 		"%Ex",
1256 		"%Ec",
1257 		"%EX",
1258 		"%O",
1259 
1260 		".",
1261 		"",
1262 
1263 		"^[yY]",
1264 		"^[nN]",
1265 
1266 		"",
1267 
1268 		"", 	// out of bounds
1269 		NULL
1270 	};
1271 	test_langinfo("POSIX", li_posix);
1272 
1273 	const char* li_de[] = {
1274 		"", 	// out of bounds
1275 		"UTF-8",
1276 		"%A, %e. %B %Y %H:%M:%S %Z",
1277 		"%d.%m.%Y",
1278 		"%H:%M:%S",
1279 		"%I:%M:%S %p",
1280 		"vorm.",
1281 		"nachm.",
1282 
1283 		"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag",
1284 		"Samstag",
1285 
1286 		"So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.",
1287 
1288 		"Januar", "Februar", "März", "April", "Mai", "Juni",
1289 		"Juli", "August", "September", "Oktober", "November", "Dezember",
1290 
1291 		"Jan", "Feb", "Mär", "Apr", "Mai", "Jun",
1292 		"Jul", "Aug", "Sep", "Okt", "Nov", "Dez",
1293 
1294 		"%EC, %Ey, %EY",
1295 		"%Ex",
1296 		"%Ec",
1297 		"%EX",
1298 		"%O",
1299 
1300 		",",
1301 		".",
1302 
1303 		"^[yY]",
1304 		"^[nN]",
1305 
1306 		"€",
1307 
1308 		"", 	// out of bounds
1309 		NULL,
1310 	};
1311 	test_langinfo("de_DE.UTF-8", li_de);
1312 
1313 	const char* li_de_iso[] = {
1314 		"", 	// out of bounds
1315 		"ISO8859-15",
1316 		"%A, %e. %B %Y %H:%M:%S %Z",
1317 		"%d.%m.%Y",
1318 		"%H:%M:%S",
1319 		"%I:%M:%S %p",
1320 		"vorm.",
1321 		"nachm.",
1322 
1323 		"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag",
1324 		"Samstag",
1325 
1326 		"So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.",
1327 
1328 		"Januar", "Februar", "M\xE4rz", "April", "Mai", "Juni",
1329 		"Juli", "August", "September", "Oktober", "November", "Dezember",
1330 
1331 		"Jan", "Feb", "M\xE4r", "Apr", "Mai", "Jun",
1332 		"Jul", "Aug", "Sep", "Okt", "Nov", "Dez",
1333 
1334 		"%EC, %Ey, %EY",
1335 		"%Ex",
1336 		"%Ec",
1337 		"%EX",
1338 		"%O",
1339 
1340 		",",
1341 		".",
1342 
1343 		"^[yY]",
1344 		"^[nN]",
1345 
1346 		"\xA4",
1347 
1348 		"", 	// out of bounds
1349 		NULL
1350 	};
1351 	test_langinfo("de_DE.ISO8859-15", li_de_iso);
1352 }
1353 
1354 
1355 // #pragma mark - collation ----------------------------------------------------
1356 
1357 
1358 struct coll_data {
1359 	const char* a;
1360 	const char* b;
1361 	int result;
1362 	int err;
1363 };
1364 
1365 
1366 static int sign (int a)
1367 {
1368 	if (a < 0)
1369 		return -1;
1370 	if (a > 0)
1371 		return 1;
1372 	return 0;
1373 }
1374 
1375 
1376 void
1377 test_coll(bool useStrxfrm, const char* locale, const coll_data coll[])
1378 {
1379 	setlocale(LC_COLLATE, locale);
1380 	printf("%s in %s locale\n", useStrxfrm ? "strxfrm" : "strcoll", locale);
1381 
1382 	int problemCount = 0;
1383 	for (unsigned int i = 0; i < sizeof(coll) / sizeof(coll_data); ++i) {
1384 		errno = 0;
1385 		int result;
1386 		char funcCall[100];
1387 		if (useStrxfrm) {
1388 			char sortKeyA[100], sortKeyB[100];
1389 			strxfrm(sortKeyA, coll[i].a, 100);
1390 			strxfrm(sortKeyB, coll[i].b, 100);
1391 			result = sign(strcmp(sortKeyA, sortKeyB));
1392 			sprintf(funcCall, "strcmp(strxfrm(\"%s\"), strxfrm(\"%s\"))",
1393 				coll[i].a, coll[i].b);
1394 		} else {
1395 			result = sign(strcoll(coll[i].a, coll[i].b));
1396 			sprintf(funcCall, "strcoll(\"%s\", \"%s\")", coll[i].a, coll[i].b);
1397 		}
1398 
1399 		if (result != coll[i].result || errno != coll[i].err) {
1400 			printf(
1401 				"\tPROBLEM: %s = %d (expected %d), errno = %x (expected %x)\n",
1402 				funcCall, result, coll[i].result, errno, coll[i].err);
1403 			problemCount++;
1404 		}
1405 	}
1406 	if (problemCount)
1407 		printf("\t%d problem(s) found!\n", problemCount);
1408 	else
1409 		printf("\tall fine\n");
1410 }
1411 
1412 
1413 void
1414 test_collation()
1415 {
1416 	const coll_data coll_posix[] = {
1417 		{ "", "", 0, 0 },
1418 		{ "test", "test", 0, 0 },
1419 		{ "tester", "test", 1, 0 },
1420 		{ "tEst", "teSt", -1, 0 },
1421 		{ "test", "tester", -1, 0 },
1422 		{ "tast", "täst", -1, EINVAL },
1423 		{ "tæst", "test", 1, EINVAL },
1424 	};
1425 	test_coll(0, "POSIX", coll_posix);
1426 	test_coll(1, "POSIX", coll_posix);
1427 
1428 	const coll_data coll_en[] = {
1429 		{ "", "", 0, 0 },
1430 		{ "test", "test", 0, 0 },
1431 		{ "tester", "test", 1, 0 },
1432 		{ "tEst", "test", 1, 0 },
1433 		{ "test", "tester", -1, 0 },
1434 		{ "täst", "täst", 0, 0 },
1435 		{ "tast", "täst", -1, 0 },
1436 		{ "tbst", "täst", 1, 0 },
1437 		{ "tbst", "tæst", 1, 0 },
1438 		{ "täst", "tÄst", -1, 0 },
1439 		{ "tBst", "tÄst", 1, 0 },
1440 		{ "tBst", "täst", 1, 0 },
1441 		{ "taest", "tæst", -1, 0 },
1442 		{ "tafst", "tæst", 1, 0 },
1443 		{ "taa", "täa", -1, 0 },
1444 		{ "tab", "täb", -1, 0 },
1445 		{ "tad", "täd", -1, 0 },
1446 		{ "tae", "täe", -1, 0 },
1447 		{ "taf", "täf", -1, 0 },
1448 		{ "cote", "coté", -1, 0 },
1449 		{ "coté", "côte", -1, 0 },
1450 		{ "côte", "côté", -1, 0 },
1451 	};
1452 	test_coll(0, "en_US.UTF-8", coll_en);
1453 	test_coll(1, "en_US.UTF-8", coll_en);
1454 
1455 	const coll_data coll_de[] = {
1456 		{ "", "", 0, 0 },
1457 		{ "test", "test", 0, 0 },
1458 		{ "tester", "test", 1, 0 },
1459 		{ "tEst", "test", 1, 0 },
1460 		{ "test", "tester", -1, 0 },
1461 		{ "täst", "täst", 0, 0 },
1462 		{ "tast", "täst", -1, 0 },
1463 		{ "tbst", "täst", 1, 0 },
1464 		{ "tbst", "tæst", 1, 0 },
1465 		{ "täst", "tÄst", -1, 0 },
1466 		{ "tBst", "tÄst", 1, 0 },
1467 		{ "tBst", "täst", 1, 0 },
1468 		{ "taest", "tæst", -1, 0 },
1469 		{ "tafst", "tæst", 1, 0 },
1470 		{ "taa", "tä", 1, 0 },
1471 		{ "tab", "tä", 1, 0 },
1472 		{ "tad", "tä", 1, 0 },
1473 		{ "tae", "tä", 1, 0 },
1474 		{ "taf", "tä", 1, 0 },
1475 		{ "cote", "coté", -1, 0 },
1476 		{ "coté", "côte", -1, 0 },
1477 		{ "côte", "côté", -1, 0 },
1478 	};
1479 	test_coll(0, "de_DE.UTF-8", coll_de);
1480 	test_coll(1, "de_DE.UTF-8", coll_de);
1481 
1482 	const coll_data coll_de_phonebook[] = {
1483 		{ "", "", 0, 0 },
1484 		{ "test", "test", 0, 0 },
1485 		{ "tester", "test", 1, 0 },
1486 		{ "tEst", "test", 1, 0 },
1487 		{ "test", "tester", -1, 0 },
1488 		{ "täst", "täst", 0, 0 },
1489 		{ "tast", "täst", 1, 0 },
1490 		{ "tbst", "täst", 1, 0 },
1491 		{ "tbst", "tæst", 1, 0 },
1492 		{ "täst", "tÄst", -1, 0 },
1493 		{ "tBst", "tÄst", 1, 0 },
1494 		{ "tBst", "täst", 1, 0 },
1495 		{ "taest", "tæst", -1, 0 },
1496 		{ "tafst", "tæst", 1, 0 },
1497 		{ "taa", "tä", -1, 0 },
1498 		{ "tab", "tä", -1, 0 },
1499 		{ "tad", "tä", -1, 0 },
1500 		{ "tae", "tä", -1, 0 },
1501 		{ "taf", "tä", 1, 0 },
1502 		{ "cote", "coté", -1, 0 },
1503 		{ "coté", "côte", -1, 0 },
1504 		{ "côte", "côté", -1, 0 },
1505 	};
1506 	test_coll(0, "de_DE.UTF-8@collation=phonebook", coll_de_phonebook);
1507 	test_coll(1, "de_DE.UTF-8@collation=phonebook", coll_de_phonebook);
1508 
1509 	const coll_data coll_fr[] = {
1510 		{ "", "", 0, 0 },
1511 		{ "test", "test", 0, 0 },
1512 		{ "tester", "test", 1, 0 },
1513 		{ "tEst", "test", 1, 0 },
1514 		{ "test", "tester", -1, 0 },
1515 		{ "täst", "täst", 0, 0 },
1516 		{ "tast", "täst", -1, 0 },
1517 		{ "tbst", "täst", 1, 0 },
1518 		{ "tbst", "tæst", 1, 0 },
1519 		{ "täst", "tÄst", -1, 0 },
1520 		{ "tBst", "tÄst", 1, 0 },
1521 		{ "tBst", "täst", 1, 0 },
1522 		{ "taest", "tæst", -1, 0 },
1523 		{ "tafst", "tæst", 1, 0 },
1524 		{ "taa", "tä", 1, 0 },
1525 		{ "tab", "tä", 1, 0 },
1526 		{ "tad", "tä", 1, 0 },
1527 		{ "tae", "tä", 1, 0 },
1528 		{ "taf", "tä", 1, 0 },
1529 		{ "cote", "coté", -1, 0 },
1530 		{ "coté", "côte", 1, 0 },
1531 		{ "côte", "côté", -1, 0 },
1532 	};
1533 	test_coll(0, "fr_FR.UTF-8", coll_fr);
1534 	test_coll(1, "fr_FR.UTF-8", coll_fr);
1535 }
1536 
1537 
1538 // #pragma mark - main ---------------------------------------------------------
1539 
1540 
1541 /*
1542  * Test several different aspects of the POSIX locale and the functions
1543  * influenced by it.
1544  */
1545 int
1546 main(void)
1547 {
1548 	test_setlocale();
1549 	test_localeconv();
1550 	test_strftime();
1551 	test_ctype();
1552 	test_wctype();
1553 	test_wctrans();
1554 	test_langinfo();
1555 	test_collation();
1556 
1557 	return 0;
1558 }
1559