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