mbrtowc: Add more tests for native Windows platforms.
[pspp] / tests / test-mbrtowc-w32.c
1 /* Test of conversion of multibyte character to wide character.
2    Copyright (C) 2008-2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 #include <wchar.h>
20
21 #include <locale.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "macros.h"
27
28 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
29
30 static int
31 test_one_locale (const char *name, int codepage)
32 {
33   mbstate_t state;
34   wchar_t wc;
35   size_t ret;
36
37 # if 1
38   /* Portable code to set the locale.  */
39   {
40     char name_with_codepage[1024];
41
42     sprintf (name_with_codepage, "%s.%d", name, codepage);
43
44     /* Set the locale.  */
45     if (setlocale (LC_ALL, name_with_codepage) == NULL)
46       return 77;
47   }
48 # else
49   /* Hacky way to set a locale.codepage combination that setlocale() refuses
50      to set.  */
51   {
52     /* Codepage of the current locale, set with setlocale().
53        Not necessarily the same as GetACP().  */
54     extern __declspec(dllimport) unsigned int __lc_codepage;
55
56     /* Set the locale.  */
57     if (setlocale (LC_ALL, name) == NULL)
58       return 77;
59
60     /* Clobber the codepage and MB_CUR_MAX, both set by setlocale().  */
61     __lc_codepage = codepage;
62     switch (codepage)
63       {
64       case 1252:
65       case 1256:
66         MB_CUR_MAX = 1;
67         break;
68       case 932:
69       case 950:
70       case 936:
71         MB_CUR_MAX = 2;
72         break;
73       case 54936:
74       case 65001:
75         MB_CUR_MAX = 4;
76         break;
77       }
78
79     /* Test whether the codepage is really available.  */
80     memset (&state, '\0', sizeof (mbstate_t));
81     if (mbrtowc (&wc, " ", 1, &state) == (size_t)(-1))
82       return 77;
83   }
84 # endif
85
86   /* Test zero-length input.  */
87   {
88     memset (&state, '\0', sizeof (mbstate_t));
89     wc = (wchar_t) 0xBADFACE;
90     ret = mbrtowc (&wc, "x", 0, &state);
91     /* gnulib's implementation returns (size_t)(-2).
92        The AIX 5.1 implementation returns (size_t)(-1).
93        glibc's implementation returns 0.  */
94     ASSERT (ret == (size_t)(-2) || ret == (size_t)(-1) || ret == 0);
95     ASSERT (mbsinit (&state));
96   }
97
98   /* Test NUL byte input.  */
99   {
100     memset (&state, '\0', sizeof (mbstate_t));
101     wc = (wchar_t) 0xBADFACE;
102     ret = mbrtowc (&wc, "", 1, &state);
103     ASSERT (ret == 0);
104     ASSERT (wc == 0);
105     ASSERT (mbsinit (&state));
106     ret = mbrtowc (NULL, "", 1, &state);
107     ASSERT (ret == 0);
108     ASSERT (mbsinit (&state));
109   }
110
111   /* Test single-byte input.  */
112   {
113     int c;
114     char buf[1];
115
116     memset (&state, '\0', sizeof (mbstate_t));
117     for (c = 0; c < 0x100; c++)
118       switch (c)
119         {
120         case '\t': case '\v': case '\f':
121         case ' ': case '!': case '"': case '#': case '%':
122         case '&': case '\'': case '(': case ')': case '*':
123         case '+': case ',': case '-': case '.': case '/':
124         case '0': case '1': case '2': case '3': case '4':
125         case '5': case '6': case '7': case '8': case '9':
126         case ':': case ';': case '<': case '=': case '>':
127         case '?':
128         case 'A': case 'B': case 'C': case 'D': case 'E':
129         case 'F': case 'G': case 'H': case 'I': case 'J':
130         case 'K': case 'L': case 'M': case 'N': case 'O':
131         case 'P': case 'Q': case 'R': case 'S': case 'T':
132         case 'U': case 'V': case 'W': case 'X': case 'Y':
133         case 'Z':
134         case '[': case '\\': case ']': case '^': case '_':
135         case 'a': case 'b': case 'c': case 'd': case 'e':
136         case 'f': case 'g': case 'h': case 'i': case 'j':
137         case 'k': case 'l': case 'm': case 'n': case 'o':
138         case 'p': case 'q': case 'r': case 's': case 't':
139         case 'u': case 'v': case 'w': case 'x': case 'y':
140         case 'z': case '{': case '|': case '}': case '~':
141           /* c is in the ISO C "basic character set".  */
142           buf[0] = c;
143           wc = (wchar_t) 0xBADFACE;
144           ret = mbrtowc (&wc, buf, 1, &state);
145           ASSERT (ret == 1);
146           ASSERT (wc == c);
147           ASSERT (mbsinit (&state));
148           ret = mbrtowc (NULL, buf, 1, &state);
149           ASSERT (ret == 1);
150           ASSERT (mbsinit (&state));
151           break;
152         }
153   }
154
155   /* Test special calling convention, passing a NULL pointer.  */
156   {
157     memset (&state, '\0', sizeof (mbstate_t));
158     wc = (wchar_t) 0xBADFACE;
159     ret = mbrtowc (&wc, NULL, 5, &state);
160     ASSERT (ret == 0);
161     ASSERT (wc == (wchar_t) 0xBADFACE);
162     ASSERT (mbsinit (&state));
163   }
164
165   switch (codepage)
166     {
167     case 1252:
168       /* Locale encoding is CP1252, an extension of ISO-8859-1.  */
169       {
170         char input[] = "B\374\337er"; /* "Büßer" */
171         memset (&state, '\0', sizeof (mbstate_t));
172
173         wc = (wchar_t) 0xBADFACE;
174         ret = mbrtowc (&wc, input, 1, &state);
175         ASSERT (ret == 1);
176         ASSERT (wc == 'B');
177         ASSERT (mbsinit (&state));
178         input[0] = '\0';
179
180         wc = (wchar_t) 0xBADFACE;
181         ret = mbrtowc (&wc, input + 1, 1, &state);
182         ASSERT (ret == 1);
183         ASSERT (wctob (wc) == (unsigned char) '\374');
184         ASSERT (wc == 0x00FC);
185         ASSERT (mbsinit (&state));
186         input[1] = '\0';
187
188         /* Test support of NULL first argument.  */
189         ret = mbrtowc (NULL, input + 2, 3, &state);
190         ASSERT (ret == 1);
191         ASSERT (mbsinit (&state));
192
193         wc = (wchar_t) 0xBADFACE;
194         ret = mbrtowc (&wc, input + 2, 3, &state);
195         ASSERT (ret == 1);
196         ASSERT (wctob (wc) == (unsigned char) '\337');
197         ASSERT (wc == 0x00DF);
198         ASSERT (mbsinit (&state));
199         input[2] = '\0';
200
201         wc = (wchar_t) 0xBADFACE;
202         ret = mbrtowc (&wc, input + 3, 2, &state);
203         ASSERT (ret == 1);
204         ASSERT (wc == 'e');
205         ASSERT (mbsinit (&state));
206         input[3] = '\0';
207
208         wc = (wchar_t) 0xBADFACE;
209         ret = mbrtowc (&wc, input + 4, 1, &state);
210         ASSERT (ret == 1);
211         ASSERT (wc == 'r');
212         ASSERT (mbsinit (&state));
213       }
214       return 0;
215
216     case 1256:
217       /* Locale encoding is CP1256, not the same as ISO-8859-6.  */
218       {
219         char input[] = "x\302\341\346y"; /* "xآلوy" */
220         memset (&state, '\0', sizeof (mbstate_t));
221
222         wc = (wchar_t) 0xBADFACE;
223         ret = mbrtowc (&wc, input, 1, &state);
224         ASSERT (ret == 1);
225         ASSERT (wc == 'x');
226         ASSERT (mbsinit (&state));
227         input[0] = '\0';
228
229         wc = (wchar_t) 0xBADFACE;
230         ret = mbrtowc (&wc, input + 1, 1, &state);
231         ASSERT (ret == 1);
232         ASSERT (wctob (wc) == (unsigned char) '\302');
233         ASSERT (wc == 0x0622);
234         ASSERT (mbsinit (&state));
235         input[1] = '\0';
236
237         /* Test support of NULL first argument.  */
238         ret = mbrtowc (NULL, input + 2, 3, &state);
239         ASSERT (ret == 1);
240         ASSERT (mbsinit (&state));
241
242         wc = (wchar_t) 0xBADFACE;
243         ret = mbrtowc (&wc, input + 2, 3, &state);
244         ASSERT (ret == 1);
245         ASSERT (wctob (wc) == (unsigned char) '\341');
246         ASSERT (wc == 0x0644);
247         ASSERT (mbsinit (&state));
248         input[2] = '\0';
249
250         wc = (wchar_t) 0xBADFACE;
251         ret = mbrtowc (&wc, input + 3, 2, &state);
252         ASSERT (ret == 1);
253         ASSERT (wctob (wc) == (unsigned char) '\346');
254         ASSERT (wc == 0x0648);
255         ASSERT (mbsinit (&state));
256         input[3] = '\0';
257
258         wc = (wchar_t) 0xBADFACE;
259         ret = mbrtowc (&wc, input + 4, 1, &state);
260         ASSERT (ret == 1);
261         ASSERT (wc == 'y');
262         ASSERT (mbsinit (&state));
263       }
264       return 0;
265
266     case 932:
267       /* Locale encoding is CP932, similar to Shift_JIS.  */
268       {
269         char input[] = "<\223\372\226\173\214\352>"; /* "<日本語>" */
270         memset (&state, '\0', sizeof (mbstate_t));
271
272         wc = (wchar_t) 0xBADFACE;
273         ret = mbrtowc (&wc, input, 1, &state);
274         ASSERT (ret == 1);
275         ASSERT (wc == '<');
276         ASSERT (mbsinit (&state));
277         input[0] = '\0';
278
279         wc = (wchar_t) 0xBADFACE;
280         ret = mbrtowc (&wc, input + 1, 2, &state);
281         ASSERT (ret == 2);
282         ASSERT (wctob (wc) == EOF);
283         ASSERT (wc == 0x65E5);
284         ASSERT (mbsinit (&state));
285         input[1] = '\0';
286         input[2] = '\0';
287
288         wc = (wchar_t) 0xBADFACE;
289         ret = mbrtowc (&wc, input + 3, 1, &state);
290         ASSERT (ret == (size_t)(-2));
291         ASSERT (wc == (wchar_t) 0xBADFACE);
292         ASSERT (!mbsinit (&state));
293         input[3] = '\0';
294
295         wc = (wchar_t) 0xBADFACE;
296         ret = mbrtowc (&wc, input + 4, 4, &state);
297         ASSERT (ret == 1);
298         ASSERT (wctob (wc) == EOF);
299         ASSERT (wc == 0x672C);
300         ASSERT (mbsinit (&state));
301         input[4] = '\0';
302
303         /* Test support of NULL first argument.  */
304         ret = mbrtowc (NULL, input + 5, 3, &state);
305         ASSERT (ret == 2);
306         ASSERT (mbsinit (&state));
307
308         wc = (wchar_t) 0xBADFACE;
309         ret = mbrtowc (&wc, input + 5, 3, &state);
310         ASSERT (ret == 2);
311         ASSERT (wctob (wc) == EOF);
312         ASSERT (wc == 0x8A9E);
313         ASSERT (mbsinit (&state));
314         input[5] = '\0';
315         input[6] = '\0';
316
317         wc = (wchar_t) 0xBADFACE;
318         ret = mbrtowc (&wc, input + 7, 1, &state);
319         ASSERT (ret == 1);
320         ASSERT (wc == '>');
321         ASSERT (mbsinit (&state));
322       }
323       return 0;
324
325     case 950:
326       /* Locale encoding is CP950, similar to Big5.  */
327       {
328         char input[] = "<\244\351\245\273\273\171>"; /* "<日本語>" */
329         memset (&state, '\0', sizeof (mbstate_t));
330
331         wc = (wchar_t) 0xBADFACE;
332         ret = mbrtowc (&wc, input, 1, &state);
333         ASSERT (ret == 1);
334         ASSERT (wc == '<');
335         ASSERT (mbsinit (&state));
336         input[0] = '\0';
337
338         wc = (wchar_t) 0xBADFACE;
339         ret = mbrtowc (&wc, input + 1, 2, &state);
340         ASSERT (ret == 2);
341         ASSERT (wctob (wc) == EOF);
342         ASSERT (wc == 0x65E5);
343         ASSERT (mbsinit (&state));
344         input[1] = '\0';
345         input[2] = '\0';
346
347         wc = (wchar_t) 0xBADFACE;
348         ret = mbrtowc (&wc, input + 3, 1, &state);
349         ASSERT (ret == (size_t)(-2));
350         ASSERT (wc == (wchar_t) 0xBADFACE);
351         ASSERT (!mbsinit (&state));
352         input[3] = '\0';
353
354         wc = (wchar_t) 0xBADFACE;
355         ret = mbrtowc (&wc, input + 4, 4, &state);
356         ASSERT (ret == 1);
357         ASSERT (wctob (wc) == EOF);
358         ASSERT (wc == 0x672C);
359         ASSERT (mbsinit (&state));
360         input[4] = '\0';
361
362         /* Test support of NULL first argument.  */
363         ret = mbrtowc (NULL, input + 5, 3, &state);
364         ASSERT (ret == 2);
365         ASSERT (mbsinit (&state));
366
367         wc = (wchar_t) 0xBADFACE;
368         ret = mbrtowc (&wc, input + 5, 3, &state);
369         ASSERT (ret == 2);
370         ASSERT (wctob (wc) == EOF);
371         ASSERT (wc == 0x8A9E);
372         ASSERT (mbsinit (&state));
373         input[5] = '\0';
374         input[6] = '\0';
375
376         wc = (wchar_t) 0xBADFACE;
377         ret = mbrtowc (&wc, input + 7, 1, &state);
378         ASSERT (ret == 1);
379         ASSERT (wc == '>');
380         ASSERT (mbsinit (&state));
381       }
382       return 0;
383
384     case 936:
385       /* Locale encoding is CP936 = GBK, an extension of GB2312.  */
386       {
387         char input[] = "<\310\325\261\276\325\132>"; /* "<日本語>" */
388         memset (&state, '\0', sizeof (mbstate_t));
389
390         wc = (wchar_t) 0xBADFACE;
391         ret = mbrtowc (&wc, input, 1, &state);
392         ASSERT (ret == 1);
393         ASSERT (wc == '<');
394         ASSERT (mbsinit (&state));
395         input[0] = '\0';
396
397         wc = (wchar_t) 0xBADFACE;
398         ret = mbrtowc (&wc, input + 1, 2, &state);
399         ASSERT (ret == 2);
400         ASSERT (wctob (wc) == EOF);
401         ASSERT (wc == 0x65E5);
402         ASSERT (mbsinit (&state));
403         input[1] = '\0';
404         input[2] = '\0';
405
406         wc = (wchar_t) 0xBADFACE;
407         ret = mbrtowc (&wc, input + 3, 1, &state);
408         ASSERT (ret == (size_t)(-2));
409         ASSERT (wc == (wchar_t) 0xBADFACE);
410         ASSERT (!mbsinit (&state));
411         input[3] = '\0';
412
413         wc = (wchar_t) 0xBADFACE;
414         ret = mbrtowc (&wc, input + 4, 4, &state);
415         ASSERT (ret == 1);
416         ASSERT (wctob (wc) == EOF);
417         ASSERT (wc == 0x672C);
418         ASSERT (mbsinit (&state));
419         input[4] = '\0';
420
421         /* Test support of NULL first argument.  */
422         ret = mbrtowc (NULL, input + 5, 3, &state);
423         ASSERT (ret == 2);
424         ASSERT (mbsinit (&state));
425
426         wc = (wchar_t) 0xBADFACE;
427         ret = mbrtowc (&wc, input + 5, 3, &state);
428         ASSERT (ret == 2);
429         ASSERT (wctob (wc) == EOF);
430         ASSERT (wc == 0x8A9E);
431         ASSERT (mbsinit (&state));
432         input[5] = '\0';
433         input[6] = '\0';
434
435         wc = (wchar_t) 0xBADFACE;
436         ret = mbrtowc (&wc, input + 7, 1, &state);
437         ASSERT (ret == 1);
438         ASSERT (wc == '>');
439         ASSERT (mbsinit (&state));
440       }
441       return 0;
442
443     case 54936:
444       /* Locale encoding is CP54936 = GB18030.  */
445       {
446         char input[] = "B\250\271\201\060\211\070er"; /* "Büßer" */
447         memset (&state, '\0', sizeof (mbstate_t));
448
449         wc = (wchar_t) 0xBADFACE;
450         ret = mbrtowc (&wc, input, 1, &state);
451         ASSERT (ret == 1);
452         ASSERT (wc == 'B');
453         ASSERT (mbsinit (&state));
454         input[0] = '\0';
455
456         wc = (wchar_t) 0xBADFACE;
457         ret = mbrtowc (&wc, input + 1, 1, &state);
458         ASSERT (ret == (size_t)(-2));
459         ASSERT (wc == (wchar_t) 0xBADFACE);
460         ASSERT (!mbsinit (&state));
461         input[1] = '\0';
462
463         wc = (wchar_t) 0xBADFACE;
464         ret = mbrtowc (&wc, input + 2, 7, &state);
465         ASSERT (ret == 1);
466         ASSERT (wctob (wc) == EOF);
467         ASSERT (wc == 0x00FC);
468         ASSERT (mbsinit (&state));
469         input[2] = '\0';
470
471         /* Test support of NULL first argument.  */
472         ret = mbrtowc (NULL, input + 3, 6, &state);
473         ASSERT (ret == 4);
474         ASSERT (mbsinit (&state));
475
476         wc = (wchar_t) 0xBADFACE;
477         ret = mbrtowc (&wc, input + 3, 6, &state);
478         ASSERT (ret == 4);
479         ASSERT (wctob (wc) == EOF);
480         ASSERT (wc == 0x00DF);
481         ASSERT (mbsinit (&state));
482         input[3] = '\0';
483         input[4] = '\0';
484         input[5] = '\0';
485         input[6] = '\0';
486
487         wc = (wchar_t) 0xBADFACE;
488         ret = mbrtowc (&wc, input + 7, 2, &state);
489         ASSERT (ret == 1);
490         ASSERT (wc == 'e');
491         ASSERT (mbsinit (&state));
492         input[5] = '\0';
493
494         wc = (wchar_t) 0xBADFACE;
495         ret = mbrtowc (&wc, input + 8, 1, &state);
496         ASSERT (ret == 1);
497         ASSERT (wc == 'r');
498         ASSERT (mbsinit (&state));
499       }
500       return 0;
501
502     case 65001:
503       /* Locale encoding is CP65001 = UTF-8.  */
504       {
505         char input[] = "B\303\274\303\237er"; /* "Büßer" */
506         memset (&state, '\0', sizeof (mbstate_t));
507
508         wc = (wchar_t) 0xBADFACE;
509         ret = mbrtowc (&wc, input, 1, &state);
510         ASSERT (ret == 1);
511         ASSERT (wc == 'B');
512         ASSERT (mbsinit (&state));
513         input[0] = '\0';
514
515         wc = (wchar_t) 0xBADFACE;
516         ret = mbrtowc (&wc, input + 1, 1, &state);
517         ASSERT (ret == (size_t)(-2));
518         ASSERT (wc == (wchar_t) 0xBADFACE);
519         ASSERT (!mbsinit (&state));
520         input[1] = '\0';
521
522         wc = (wchar_t) 0xBADFACE;
523         ret = mbrtowc (&wc, input + 2, 5, &state);
524         ASSERT (ret == 1);
525         ASSERT (wctob (wc) == EOF);
526         ASSERT (wc == 0x00FC);
527         ASSERT (mbsinit (&state));
528         input[2] = '\0';
529
530         /* Test support of NULL first argument.  */
531         ret = mbrtowc (NULL, input + 3, 4, &state);
532         ASSERT (ret == 2);
533         ASSERT (mbsinit (&state));
534
535         wc = (wchar_t) 0xBADFACE;
536         ret = mbrtowc (&wc, input + 3, 4, &state);
537         ASSERT (ret == 2);
538         ASSERT (wctob (wc) == EOF);
539         ASSERT (wc == 0x00DF);
540         ASSERT (mbsinit (&state));
541         input[3] = '\0';
542         input[4] = '\0';
543
544         wc = (wchar_t) 0xBADFACE;
545         ret = mbrtowc (&wc, input + 5, 2, &state);
546         ASSERT (ret == 1);
547         ASSERT (wc == 'e');
548         ASSERT (mbsinit (&state));
549         input[5] = '\0';
550
551         wc = (wchar_t) 0xBADFACE;
552         ret = mbrtowc (&wc, input + 6, 1, &state);
553         ASSERT (ret == 1);
554         ASSERT (wc == 'r');
555         ASSERT (mbsinit (&state));
556       }
557       return 0;
558
559     default:
560       return 1;
561     }
562 }
563
564 int
565 main (int argc, char *argv[])
566 {
567   int codepage = atoi (argv[argc - 1]);
568   int result;
569   int i;
570
571   result = 77;
572   for (i = 1; i < argc - 1; i++)
573     {
574       int ret = test_one_locale (argv[i], codepage);
575
576       if (ret != 77)
577         result = ret;
578     }
579
580   if (result == 77)
581     {
582       fprintf (stderr, "Skipping test: found no locale with codepage %d\n",
583                codepage);
584     }
585   return result;
586 }
587
588 #else
589
590 int
591 main (int argc, char *argv[])
592 {
593   fputs ("Skipping test: not a native Windows system\n", stderr);
594   return 77;
595 }
596
597 #endif