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