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