Flush the standard error stream before aborting.
[pspp] / tests / test-striconveh.c
1 /* Test of character set conversion with error handling.
2    Copyright (C) 2007-2008 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 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
18
19 #include <config.h>
20
21 #include "striconveh.h"
22
23 #if HAVE_ICONV
24 # include <iconv.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #define SIZEOF(array) (sizeof (array) / sizeof (array[0]))
33 #define ASSERT(expr) \
34   do                                                                         \
35     {                                                                        \
36       if (!(expr))                                                           \
37         {                                                                    \
38           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
39           fflush (stderr);                                                   \
40           abort ();                                                          \
41         }                                                                    \
42     }                                                                        \
43   while (0)
44
45 /* Magic number for detecting bounds violations.  */
46 #define MAGIC 0x1983EFF1
47
48 static size_t *
49 new_offsets (size_t n)
50 {
51   size_t *offsets = (size_t *) malloc ((n + 1) * sizeof (size_t));
52   offsets[n] = MAGIC;
53   return offsets;
54 }
55
56 int
57 main ()
58 {
59   static enum iconv_ilseq_handler handlers[] =
60     { iconveh_error, iconveh_question_mark, iconveh_escape_sequence };
61   size_t h;
62   size_t o;
63   size_t i;
64
65 #if HAVE_ICONV
66   /* Assume that iconv() supports at least the encodings ASCII, ISO-8859-1,
67      ISO-8859-2, and UTF-8.  */
68   iconv_t cd_88591_to_88592 = iconv_open ("ISO-8859-2", "ISO-8859-1");
69   iconv_t cd_88592_to_88591 = iconv_open ("ISO-8859-1", "ISO-8859-2");
70   iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1");
71   iconv_t cd_utf8_to_88591 = iconv_open ("ISO-8859-1", "UTF-8");
72   iconv_t cd_88592_to_utf8 = iconv_open ("UTF-8", "ISO-8859-2");
73   iconv_t cd_utf8_to_88592 = iconv_open ("ISO-8859-2", "UTF-8");
74
75   ASSERT (cd_88591_to_utf8 != (iconv_t)(-1));
76   ASSERT (cd_utf8_to_88591 != (iconv_t)(-1));
77   ASSERT (cd_88592_to_utf8 != (iconv_t)(-1));
78   ASSERT (cd_utf8_to_88592 != (iconv_t)(-1));
79
80   /* ------------------------ Test mem_cd_iconveh() ------------------------ */
81
82   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
83   for (h = 0; h < SIZEOF (handlers); h++)
84     {
85       enum iconv_ilseq_handler handler = handlers[h];
86       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
87       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
88       for (o = 0; o < 2; o++)
89         {
90           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
91           char *result = NULL;
92           size_t length = 0;
93           int retval = mem_cd_iconveh (input, strlen (input),
94                                        cd_88592_to_88591,
95                                        cd_88592_to_utf8, cd_utf8_to_88591,
96                                        handler,
97                                        offsets,
98                                        &result, &length);
99           ASSERT (retval == 0);
100           ASSERT (length == strlen (expected));
101           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
102           if (o)
103             {
104               for (i = 0; i < 37; i++)
105                 ASSERT (offsets[i] == i);
106               ASSERT (offsets[37] == MAGIC);
107               free (offsets);
108             }
109           free (result);
110         }
111     }
112
113   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
114   for (h = 0; h < SIZEOF (handlers); h++)
115     {
116       enum iconv_ilseq_handler handler = handlers[h];
117       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
118       for (o = 0; o < 2; o++)
119         {
120           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
121           char *result = NULL;
122           size_t length = 0;
123           int retval = mem_cd_iconveh (input, strlen (input),
124                                        cd_88592_to_88591,
125                                        cd_88592_to_utf8, cd_utf8_to_88591,
126                                        handler,
127                                        offsets,
128                                        &result, &length);
129           switch (handler)
130             {
131             case iconveh_error:
132               ASSERT (retval == -1 && errno == EILSEQ);
133               ASSERT (result == NULL);
134               if (o)
135                 free (offsets);
136               break;
137             case iconveh_question_mark:
138               {
139                 static const char expected[] = "Rafa? Maszkowski";
140                 ASSERT (retval == 0);
141                 ASSERT (length == strlen (expected));
142                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
143                 if (o)
144                   {
145                     for (i = 0; i < 16; i++)
146                       ASSERT (offsets[i] == i);
147                     ASSERT (offsets[16] == MAGIC);
148                     free (offsets);
149                   }
150                 free (result);
151               }
152               break;
153             case iconveh_escape_sequence:
154               {
155                 static const char expected[] = "Rafa\\u0142 Maszkowski";
156                 ASSERT (retval == 0);
157                 ASSERT (length == strlen (expected));
158                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
159                 if (o)
160                   {
161                     for (i = 0; i < 16; i++)
162                       ASSERT (offsets[i] == (i < 5 ? i :
163                                              i + 5));
164                     ASSERT (offsets[16] == MAGIC);
165                     free (offsets);
166                   }
167                 free (result);
168               }
169               break;
170             }
171         }
172     }
173
174   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
175   for (h = 0; h < SIZEOF (handlers); h++)
176     {
177       enum iconv_ilseq_handler handler = handlers[h];
178       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
179       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
180       for (o = 0; o < 2; o++)
181         {
182           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
183           char *result = NULL;
184           size_t length = 0;
185           int retval = mem_cd_iconveh (input, strlen (input),
186                                        cd_88591_to_utf8,
187                                        cd_88591_to_utf8, (iconv_t)(-1),
188                                        handler,
189                                        offsets,
190                                        &result, &length);
191           ASSERT (retval == 0);
192           ASSERT (length == strlen (expected));
193           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
194           if (o)
195             {
196               for (i = 0; i < 37; i++)
197                 ASSERT (offsets[i] == (i < 1 ? i :
198                                        i < 12 ? i + 1 :
199                                        i < 18 ? i + 2 :
200                                        i + 3));
201               ASSERT (offsets[37] == MAGIC);
202               free (offsets);
203             }
204           free (result);
205         }
206     }
207
208   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
209   for (h = 0; h < SIZEOF (handlers); h++)
210     {
211       enum iconv_ilseq_handler handler = handlers[h];
212       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
213       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
214       for (o = 0; o < 2; o++)
215         {
216           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
217           char *result = NULL;
218           size_t length = 0;
219           int retval = mem_cd_iconveh (input, strlen (input),
220                                        cd_utf8_to_88591,
221                                        (iconv_t)(-1), cd_utf8_to_88591,
222                                        handler,
223                                        offsets,
224                                        &result, &length);
225           ASSERT (retval == 0);
226           ASSERT (length == strlen (expected));
227           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
228           if (o)
229             {
230               for (i = 0; i < 41; i++)
231                 ASSERT (offsets[i] == (i < 1 ? i :
232                                        i == 1 ? (size_t)(-1) :
233                                        i < 13 ? i - 1 :
234                                        i == 13 ? (size_t)(-1) :
235                                        i < 20 ? i - 2 :
236                                        i == 20 ? (size_t)(-1) :
237                                        i < 40 ? i - 3 :
238                                        (size_t)(-1)));
239               ASSERT (offsets[41] == MAGIC);
240               free (offsets);
241             }
242           free (result);
243         }
244     }
245
246   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
247   for (h = 0; h < SIZEOF (handlers); h++)
248     {
249       enum iconv_ilseq_handler handler = handlers[h];
250       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
251       for (o = 0; o < 2; o++)
252         {
253           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
254           char *result = NULL;
255           size_t length = 0;
256           int retval = mem_cd_iconveh (input, strlen (input),
257                                        cd_utf8_to_88591,
258                                        (iconv_t)(-1), cd_utf8_to_88591,
259                                        handler,
260                                        offsets,
261                                        &result, &length);
262           switch (handler)
263             {
264             case iconveh_error:
265               ASSERT (retval == -1 && errno == EILSEQ);
266               ASSERT (result == NULL);
267               if (o)
268                 free (offsets);
269               break;
270             case iconveh_question_mark:
271               {
272                 static const char expected[] = "Rafa? Maszkowski";
273                 ASSERT (retval == 0);
274                 ASSERT (length == strlen (expected));
275                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
276                 if (o)
277                   {
278                     for (i = 0; i < 17; i++)
279                       ASSERT (offsets[i] == (i < 5 ? i :
280                                              i == 5 ? (size_t)(-1) :
281                                              i - 1));
282                     ASSERT (offsets[17] == MAGIC);
283                     free (offsets);
284                   }
285                 free (result);
286               }
287               break;
288             case iconveh_escape_sequence:
289               {
290                 static const char expected[] = "Rafa\\u0142 Maszkowski";
291                 ASSERT (retval == 0);
292                 ASSERT (length == strlen (expected));
293                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
294                 if (o)
295                   {
296                     for (i = 0; i < 17; i++)
297                       ASSERT (offsets[i] == (i < 5 ? i :
298                                              i == 5 ? (size_t)(-1) :
299                                              i + 4));
300                     ASSERT (offsets[17] == MAGIC);
301                     free (offsets);
302                   }
303                 free (result);
304               }
305               break;
306             }
307         }
308     }
309
310   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
311   for (h = 0; h < SIZEOF (handlers); h++)
312     {
313       enum iconv_ilseq_handler handler = handlers[h];
314       static const char input[] = "\342";
315       for (o = 0; o < 2; o++)
316         {
317           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
318           char *result = NULL;
319           size_t length = 0;
320           int retval = mem_cd_iconveh (input, strlen (input),
321                                        cd_utf8_to_88591,
322                                        (iconv_t)(-1), cd_utf8_to_88591,
323                                        handler,
324                                        offsets,
325                                        &result, &length);
326           ASSERT (retval == 0);
327           ASSERT (length == 0);
328           if (o)
329             {
330               ASSERT (offsets[0] == 0);
331               ASSERT (offsets[1] == MAGIC);
332               free (offsets);
333             }
334           free (result);
335         }
336     }
337
338   /* ------------------------ Test str_cd_iconveh() ------------------------ */
339
340   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
341   for (h = 0; h < SIZEOF (handlers); h++)
342     {
343       enum iconv_ilseq_handler handler = handlers[h];
344       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
345       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
346       char *result = str_cd_iconveh (input,
347                                      cd_88592_to_88591,
348                                      cd_88592_to_utf8, cd_utf8_to_88591,
349                                      handler);
350       ASSERT (result != NULL);
351       ASSERT (strcmp (result, expected) == 0);
352       free (result);
353     }
354
355   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
356   for (h = 0; h < SIZEOF (handlers); h++)
357     {
358       enum iconv_ilseq_handler handler = handlers[h];
359       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
360       char *result = str_cd_iconveh (input,
361                                      cd_88592_to_88591,
362                                      cd_88592_to_utf8, cd_utf8_to_88591,
363                                      handler);
364       switch (handler)
365         {
366         case iconveh_error:
367           ASSERT (result == NULL && errno == EILSEQ);
368           break;
369         case iconveh_question_mark:
370           {
371             static const char expected[] = "Rafa? Maszkowski";
372             ASSERT (result != NULL);
373             ASSERT (strcmp (result, expected) == 0);
374             free (result);
375           }
376           break;
377         case iconveh_escape_sequence:
378           {
379             static const char expected[] = "Rafa\\u0142 Maszkowski";
380             ASSERT (result != NULL);
381             ASSERT (strcmp (result, expected) == 0);
382             free (result);
383           }
384           break;
385         }
386     }
387
388   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
389   for (h = 0; h < SIZEOF (handlers); h++)
390     {
391       enum iconv_ilseq_handler handler = handlers[h];
392       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
393       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
394       char *result = str_cd_iconveh (input,
395                                      cd_88591_to_utf8,
396                                      cd_88591_to_utf8, (iconv_t)(-1),
397                                      handler);
398       ASSERT (result != NULL);
399       ASSERT (strcmp (result, expected) == 0);
400       free (result);
401     }
402
403   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
404   for (h = 0; h < SIZEOF (handlers); h++)
405     {
406       enum iconv_ilseq_handler handler = handlers[h];
407       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
408       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
409       char *result = str_cd_iconveh (input,
410                                      cd_utf8_to_88591,
411                                      (iconv_t)(-1), cd_utf8_to_88591,
412                                      handler);
413       ASSERT (result != NULL);
414       ASSERT (strcmp (result, expected) == 0);
415       free (result);
416     }
417
418   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
419   for (h = 0; h < SIZEOF (handlers); h++)
420     {
421       enum iconv_ilseq_handler handler = handlers[h];
422       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
423       char *result = str_cd_iconveh (input,
424                                      cd_utf8_to_88591,
425                                      (iconv_t)(-1), cd_utf8_to_88591,
426                                      handler);
427       switch (handler)
428         {
429         case iconveh_error:
430           ASSERT (result == NULL && errno == EILSEQ);
431           break;
432         case iconveh_question_mark:
433           {
434             static const char expected[] = "Costs: 27 ?";
435             ASSERT (result != NULL);
436             ASSERT (strcmp (result, expected) == 0);
437             free (result);
438           }
439           break;
440         case iconveh_escape_sequence:
441           {
442             static const char expected[] = "Costs: 27 \\u20AC";
443             ASSERT (result != NULL);
444             ASSERT (strcmp (result, expected) == 0);
445             free (result);
446           }
447           break;
448         }
449     }
450
451   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
452   for (h = 0; h < SIZEOF (handlers); h++)
453     {
454       enum iconv_ilseq_handler handler = handlers[h];
455       static const char input[] = "\342";
456       char *result = str_cd_iconveh (input,
457                                      cd_utf8_to_88591,
458                                      (iconv_t)(-1), cd_utf8_to_88591,
459                                      handler);
460       ASSERT (result != NULL);
461       ASSERT (strcmp (result, "") == 0);
462       free (result);
463     }
464
465   if (cd_88591_to_88592 != (iconv_t)(-1))
466     iconv_close (cd_88591_to_88592);
467   if (cd_88592_to_88591 != (iconv_t)(-1))
468     iconv_close (cd_88592_to_88591);
469   iconv_close (cd_88591_to_utf8);
470   iconv_close (cd_utf8_to_88591);
471   iconv_close (cd_88592_to_utf8);
472   iconv_close (cd_utf8_to_88592);
473
474   /* ------------------------- Test mem_iconveh() ------------------------- */
475
476   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
477   for (h = 0; h < SIZEOF (handlers); h++)
478     {
479       enum iconv_ilseq_handler handler = handlers[h];
480       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
481       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
482       for (o = 0; o < 2; o++)
483         {
484           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
485           char *result = NULL;
486           size_t length = 0;
487           int retval = mem_iconveh (input, strlen (input),
488                                     "ISO-8859-2", "ISO-8859-1",
489                                     handler,
490                                     offsets,
491                                     &result, &length);
492           ASSERT (retval == 0);
493           ASSERT (length == strlen (expected));
494           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
495           if (o)
496             {
497               for (i = 0; i < 37; i++)
498                 ASSERT (offsets[i] == i);
499               ASSERT (offsets[37] == MAGIC);
500               free (offsets);
501             }
502           free (result);
503         }
504     }
505
506   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
507   for (h = 0; h < SIZEOF (handlers); h++)
508     {
509       enum iconv_ilseq_handler handler = handlers[h];
510       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
511       for (o = 0; o < 2; o++)
512         {
513           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
514           char *result = NULL;
515           size_t length = 0;
516           int retval = mem_iconveh (input, strlen (input),
517                                     "ISO-8859-2", "ISO-8859-1",
518                                     handler,
519                                     offsets,
520                                     &result, &length);
521           switch (handler)
522             {
523             case iconveh_error:
524               ASSERT (retval == -1 && errno == EILSEQ);
525               ASSERT (result == NULL);
526               if (o)
527                 free (offsets);
528               break;
529             case iconveh_question_mark:
530               {
531                 static const char expected[] = "Rafa? Maszkowski";
532                 ASSERT (retval == 0);
533                 ASSERT (length == strlen (expected));
534                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
535                 if (o)
536                   {
537                     for (i = 0; i < 16; i++)
538                       ASSERT (offsets[i] == i);
539                     ASSERT (offsets[16] == MAGIC);
540                     free (offsets);
541                   }
542                 free (result);
543               }
544               break;
545             case iconveh_escape_sequence:
546               {
547                 static const char expected[] = "Rafa\\u0142 Maszkowski";
548                 ASSERT (retval == 0);
549                 ASSERT (length == strlen (expected));
550                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
551                 if (o)
552                   {
553                     for (i = 0; i < 16; i++)
554                       ASSERT (offsets[i] == (i < 5 ? i :
555                                              i + 5));
556                     ASSERT (offsets[16] == MAGIC);
557                     free (offsets);
558                   }
559                 free (result);
560               }
561               break;
562             }
563         }
564     }
565
566   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
567   for (h = 0; h < SIZEOF (handlers); h++)
568     {
569       enum iconv_ilseq_handler handler = handlers[h];
570       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
571       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
572       for (o = 0; o < 2; o++)
573         {
574           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
575           char *result = NULL;
576           size_t length = 0;
577           int retval = mem_iconveh (input, strlen (input),
578                                     "ISO-8859-1", "UTF-8",
579                                     handler,
580                                     offsets,
581                                     &result, &length);
582           ASSERT (retval == 0);
583           ASSERT (length == strlen (expected));
584           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
585           if (o)
586             {
587               for (i = 0; i < 37; i++)
588                 ASSERT (offsets[i] == (i < 1 ? i :
589                                        i < 12 ? i + 1 :
590                                        i < 18 ? i + 2 :
591                                        i + 3));
592               ASSERT (offsets[37] == MAGIC);
593               free (offsets);
594             }
595           free (result);
596         }
597     }
598
599   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
600   for (h = 0; h < SIZEOF (handlers); h++)
601     {
602       enum iconv_ilseq_handler handler = handlers[h];
603       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
604       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
605       for (o = 0; o < 2; o++)
606         {
607           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
608           char *result = NULL;
609           size_t length = 0;
610           int retval = mem_iconveh (input, strlen (input),
611                                     "UTF-8", "ISO-8859-1",
612                                     handler,
613                                     offsets,
614                                     &result, &length);
615           ASSERT (retval == 0);
616           ASSERT (length == strlen (expected));
617           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
618           if (o)
619             {
620               for (i = 0; i < 41; i++)
621                 ASSERT (offsets[i] == (i < 1 ? i :
622                                        i == 1 ? (size_t)(-1) :
623                                        i < 13 ? i - 1 :
624                                        i == 13 ? (size_t)(-1) :
625                                        i < 20 ? i - 2 :
626                                        i == 20 ? (size_t)(-1) :
627                                        i < 40 ? i - 3 :
628                                        (size_t)(-1)));
629               ASSERT (offsets[41] == MAGIC);
630               free (offsets);
631             }
632           free (result);
633         }
634     }
635
636   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
637   for (h = 0; h < SIZEOF (handlers); h++)
638     {
639       enum iconv_ilseq_handler handler = handlers[h];
640       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
641       for (o = 0; o < 2; o++)
642         {
643           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
644           char *result = NULL;
645           size_t length = 0;
646           int retval = mem_iconveh (input, strlen (input),
647                                     "UTF-8", "ISO-8859-1",
648                                     handler,
649                                     offsets,
650                                     &result, &length);
651           switch (handler)
652             {
653             case iconveh_error:
654               ASSERT (retval == -1 && errno == EILSEQ);
655               ASSERT (result == NULL);
656               if (o)
657                 free (offsets);
658               break;
659             case iconveh_question_mark:
660               {
661                 static const char expected[] = "Rafa? Maszkowski";
662                 ASSERT (retval == 0);
663                 ASSERT (length == strlen (expected));
664                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
665                 if (o)
666                   {
667                     for (i = 0; i < 17; i++)
668                       ASSERT (offsets[i] == (i < 5 ? i :
669                                              i == 5 ? (size_t)(-1) :
670                                              i - 1));
671                     ASSERT (offsets[17] == MAGIC);
672                     free (offsets);
673                   }
674                 free (result);
675               }
676               break;
677             case iconveh_escape_sequence:
678               {
679                 static const char expected[] = "Rafa\\u0142 Maszkowski";
680                 ASSERT (retval == 0);
681                 ASSERT (length == strlen (expected));
682                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
683                 if (o)
684                   {
685                     for (i = 0; i < 17; i++)
686                       ASSERT (offsets[i] == (i < 5 ? i :
687                                              i == 5 ? (size_t)(-1) :
688                                              i + 4));
689                     ASSERT (offsets[17] == MAGIC);
690                     free (offsets);
691                   }
692                 free (result);
693               }
694               break;
695             }
696         }
697     }
698
699   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
700   for (h = 0; h < SIZEOF (handlers); h++)
701     {
702       enum iconv_ilseq_handler handler = handlers[h];
703       static const char input[] = "\342";
704       for (o = 0; o < 2; o++)
705         {
706           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
707           char *result = NULL;
708           size_t length = 0;
709           int retval = mem_iconveh (input, strlen (input),
710                                     "UTF-8", "ISO-8859-1",
711                                     handler,
712                                     offsets,
713                                     &result, &length);
714           ASSERT (retval == 0);
715           ASSERT (length == 0);
716           if (o)
717             {
718               ASSERT (offsets[0] == 0);
719               ASSERT (offsets[1] == MAGIC);
720               free (offsets);
721             }
722           free (result);
723         }
724     }
725
726   /* ------------------------- Test str_iconveh() ------------------------- */
727
728   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
729   for (h = 0; h < SIZEOF (handlers); h++)
730     {
731       enum iconv_ilseq_handler handler = handlers[h];
732       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
733       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
734       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
735       ASSERT (result != NULL);
736       ASSERT (strcmp (result, expected) == 0);
737       free (result);
738     }
739
740   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
741   for (h = 0; h < SIZEOF (handlers); h++)
742     {
743       enum iconv_ilseq_handler handler = handlers[h];
744       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
745       char *result = str_iconveh (input, "ISO-8859-2", "ISO-8859-1", handler);
746       switch (handler)
747         {
748         case iconveh_error:
749           ASSERT (result == NULL && errno == EILSEQ);
750           break;
751         case iconveh_question_mark:
752           {
753             static const char expected[] = "Rafa? Maszkowski";
754             ASSERT (result != NULL);
755             ASSERT (strcmp (result, expected) == 0);
756             free (result);
757           }
758           break;
759         case iconveh_escape_sequence:
760           {
761             static const char expected[] = "Rafa\\u0142 Maszkowski";
762             ASSERT (result != NULL);
763             ASSERT (strcmp (result, expected) == 0);
764             free (result);
765           }
766           break;
767         }
768     }
769
770   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
771   for (h = 0; h < SIZEOF (handlers); h++)
772     {
773       enum iconv_ilseq_handler handler = handlers[h];
774       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
775       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
776       char *result = str_iconveh (input, "ISO-8859-1", "UTF-8", handler);
777       ASSERT (result != NULL);
778       ASSERT (strcmp (result, expected) == 0);
779       free (result);
780     }
781
782   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
783   for (h = 0; h < SIZEOF (handlers); h++)
784     {
785       enum iconv_ilseq_handler handler = handlers[h];
786       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
787       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
788       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
789       ASSERT (result != NULL);
790       ASSERT (strcmp (result, expected) == 0);
791       free (result);
792     }
793
794   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
795   for (h = 0; h < SIZEOF (handlers); h++)
796     {
797       enum iconv_ilseq_handler handler = handlers[h];
798       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
799       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
800       switch (handler)
801         {
802         case iconveh_error:
803           ASSERT (result == NULL && errno == EILSEQ);
804           break;
805         case iconveh_question_mark:
806           {
807             static const char expected[] = "Costs: 27 ?";
808             ASSERT (result != NULL);
809             ASSERT (strcmp (result, expected) == 0);
810             free (result);
811           }
812           break;
813         case iconveh_escape_sequence:
814           {
815             static const char expected[] = "Costs: 27 \\u20AC";
816             ASSERT (result != NULL);
817             ASSERT (strcmp (result, expected) == 0);
818             free (result);
819           }
820           break;
821         }
822     }
823
824   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
825   for (h = 0; h < SIZEOF (handlers); h++)
826     {
827       enum iconv_ilseq_handler handler = handlers[h];
828       static const char input[] = "\342";
829       char *result = str_iconveh (input, "UTF-8", "ISO-8859-1", handler);
830       ASSERT (result != NULL);
831       ASSERT (strcmp (result, "") == 0);
832       free (result);
833     }
834
835 #endif
836
837   return 0;
838 }