Add optional offsets argument to conversion routines.
[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_88592 != (iconv_t)(-1));
68   ASSERT (cd_88592_to_88591 != (iconv_t)(-1));
69   ASSERT (cd_88591_to_utf8 != (iconv_t)(-1));
70   ASSERT (cd_utf8_to_88591 != (iconv_t)(-1));
71   ASSERT (cd_88592_to_utf8 != (iconv_t)(-1));
72   ASSERT (cd_utf8_to_88592 != (iconv_t)(-1));
73
74   /* ------------------------ Test mem_cd_iconveh() ------------------------ */
75
76   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
77   for (h = 0; h < SIZEOF (handlers); h++)
78     {
79       enum iconv_ilseq_handler handler = handlers[h];
80       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
81       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
82       for (o = 0; o < 2; o++)
83         {
84           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
85           char *result = NULL;
86           size_t length = 0;
87           int retval = mem_cd_iconveh (input, strlen (input),
88                                        cd_88592_to_88591,
89                                        cd_88592_to_utf8, cd_utf8_to_88591,
90                                        handler,
91                                        offsets,
92                                        &result, &length);
93           ASSERT (retval == 0);
94           ASSERT (length == strlen (expected));
95           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
96           if (o)
97             {
98               for (i = 0; i < 37; i++)
99                 ASSERT (offsets[i] == i);
100               ASSERT (offsets[37] == MAGIC);
101               free (offsets);
102             }
103           free (result);
104         }
105     }
106
107   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
108   for (h = 0; h < SIZEOF (handlers); h++)
109     {
110       enum iconv_ilseq_handler handler = handlers[h];
111       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
112       for (o = 0; o < 2; o++)
113         {
114           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
115           char *result = NULL;
116           size_t length = 0;
117           int retval = mem_cd_iconveh (input, strlen (input),
118                                        cd_88592_to_88591,
119                                        cd_88592_to_utf8, cd_utf8_to_88591,
120                                        handler,
121                                        offsets,
122                                        &result, &length);
123           switch (handler)
124             {
125             case iconveh_error:
126               ASSERT (retval == -1 && errno == EILSEQ);
127               ASSERT (result == NULL);
128               if (o)
129                 free (offsets);
130               break;
131             case iconveh_question_mark:
132               {
133                 static const char expected[] = "Rafa? Maszkowski";
134                 ASSERT (retval == 0);
135                 ASSERT (length == strlen (expected));
136                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
137                 if (o)
138                   {
139                     for (i = 0; i < 16; i++)
140                       ASSERT (offsets[i] == i);
141                     ASSERT (offsets[16] == MAGIC);
142                     free (offsets);
143                   }
144                 free (result);
145               }
146               break;
147             case iconveh_escape_sequence:
148               {
149                 static const char expected[] = "Rafa\\u0142 Maszkowski";
150                 ASSERT (retval == 0);
151                 ASSERT (length == strlen (expected));
152                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
153                 if (o)
154                   {
155                     for (i = 0; i < 16; i++)
156                       ASSERT (offsets[i] == (i < 5 ? i :
157                                              i + 5));
158                     ASSERT (offsets[16] == MAGIC);
159                     free (offsets);
160                   }
161                 free (result);
162               }
163               break;
164             }
165         }
166     }
167
168   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
169   for (h = 0; h < SIZEOF (handlers); h++)
170     {
171       enum iconv_ilseq_handler handler = handlers[h];
172       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
173       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
174       for (o = 0; o < 2; o++)
175         {
176           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
177           char *result = NULL;
178           size_t length = 0;
179           int retval = mem_cd_iconveh (input, strlen (input),
180                                        cd_88591_to_utf8,
181                                        cd_88591_to_utf8, (iconv_t)(-1),
182                                        handler,
183                                        offsets,
184                                        &result, &length);
185           ASSERT (retval == 0);
186           ASSERT (length == strlen (expected));
187           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
188           if (o)
189             {
190               for (i = 0; i < 37; i++)
191                 ASSERT (offsets[i] == (i < 1 ? i :
192                                        i < 12 ? i + 1 :
193                                        i < 18 ? i + 2 :
194                                        i + 3));
195               ASSERT (offsets[37] == MAGIC);
196               free (offsets);
197             }
198           free (result);
199         }
200     }
201
202   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
203   for (h = 0; h < SIZEOF (handlers); h++)
204     {
205       enum iconv_ilseq_handler handler = handlers[h];
206       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
207       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
208       for (o = 0; o < 2; o++)
209         {
210           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
211           char *result = NULL;
212           size_t length = 0;
213           int retval = mem_cd_iconveh (input, strlen (input),
214                                        cd_utf8_to_88591,
215                                        (iconv_t)(-1), cd_utf8_to_88591,
216                                        handler,
217                                        offsets,
218                                        &result, &length);
219           ASSERT (retval == 0);
220           ASSERT (length == strlen (expected));
221           ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
222           if (o)
223             {
224               for (i = 0; i < 41; i++)
225                 ASSERT (offsets[i] == (i < 1 ? i :
226                                        i == 1 ? (size_t)(-1) :
227                                        i < 13 ? i - 1 :
228                                        i == 13 ? (size_t)(-1) :
229                                        i < 20 ? i - 2 :
230                                        i == 20 ? (size_t)(-1) :
231                                        i < 40 ? i - 3 :
232                                        (size_t)(-1)));
233               ASSERT (offsets[41] == MAGIC);
234               free (offsets);
235             }
236           free (result);
237         }
238     }
239
240   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
241   for (h = 0; h < SIZEOF (handlers); h++)
242     {
243       enum iconv_ilseq_handler handler = handlers[h];
244       static const char input[] = "Rafa\305\202 Maszkowski"; /* Rafał Maszkowski */
245       for (o = 0; o < 2; o++)
246         {
247           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
248           char *result = NULL;
249           size_t length = 0;
250           int retval = mem_cd_iconveh (input, strlen (input),
251                                        cd_utf8_to_88591,
252                                        (iconv_t)(-1), cd_utf8_to_88591,
253                                        handler,
254                                        offsets,
255                                        &result, &length);
256           switch (handler)
257             {
258             case iconveh_error:
259               ASSERT (retval == -1 && errno == EILSEQ);
260               ASSERT (result == NULL);
261               if (o)
262                 free (offsets);
263               break;
264             case iconveh_question_mark:
265               {
266                 static const char expected[] = "Rafa? Maszkowski";
267                 ASSERT (retval == 0);
268                 ASSERT (length == strlen (expected));
269                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
270                 if (o)
271                   {
272                     for (i = 0; i < 17; i++)
273                       ASSERT (offsets[i] == (i < 5 ? i :
274                                              i == 5 ? (size_t)(-1) :
275                                              i - 1));
276                     ASSERT (offsets[17] == MAGIC);
277                     free (offsets);
278                   }
279                 free (result);
280               }
281               break;
282             case iconveh_escape_sequence:
283               {
284                 static const char expected[] = "Rafa\\u0142 Maszkowski";
285                 ASSERT (retval == 0);
286                 ASSERT (length == strlen (expected));
287                 ASSERT (result != NULL && memcmp (result, expected, strlen (expected)) == 0);
288                 if (o)
289                   {
290                     for (i = 0; i < 17; i++)
291                       ASSERT (offsets[i] == (i < 5 ? i :
292                                              i == 5 ? (size_t)(-1) :
293                                              i + 4));
294                     ASSERT (offsets[17] == MAGIC);
295                     free (offsets);
296                   }
297                 free (result);
298               }
299               break;
300             }
301         }
302     }
303
304   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
305   for (h = 0; h < SIZEOF (handlers); h++)
306     {
307       enum iconv_ilseq_handler handler = handlers[h];
308       static const char input[] = "\342";
309       for (o = 0; o < 2; o++)
310         {
311           size_t *offsets = (o ? new_offsets (strlen (input)) : NULL);
312           char *result = NULL;
313           size_t length = 0;
314           int retval = mem_cd_iconveh (input, strlen (input),
315                                        cd_utf8_to_88591,
316                                        (iconv_t)(-1), cd_utf8_to_88591,
317                                        handler,
318                                        offsets,
319                                        &result, &length);
320           ASSERT (retval == 0);
321           ASSERT (length == 0);
322           if (o)
323             {
324               ASSERT (offsets[0] == 0);
325               ASSERT (offsets[1] == MAGIC);
326               free (offsets);
327             }
328           if (result != NULL)
329             free (result);
330         }
331     }
332
333   /* ------------------------ Test str_cd_iconveh() ------------------------ */
334
335   /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors.  */
336   for (h = 0; h < SIZEOF (handlers); h++)
337     {
338       enum iconv_ilseq_handler handler = handlers[h];
339       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
340       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
341       char *result = str_cd_iconveh (input,
342                                      cd_88592_to_88591,
343                                      cd_88592_to_utf8, cd_utf8_to_88591,
344                                      handler);
345       ASSERT (result != NULL);
346       ASSERT (strcmp (result, expected) == 0);
347       free (result);
348     }
349
350   /* Test conversion from ISO-8859-2 to ISO-8859-1 with EILSEQ.  */
351   for (h = 0; h < SIZEOF (handlers); h++)
352     {
353       enum iconv_ilseq_handler handler = handlers[h];
354       static const char input[] = "Rafa\263 Maszkowski"; /* Rafał Maszkowski */
355       char *result = str_cd_iconveh (input,
356                                      cd_88592_to_88591,
357                                      cd_88592_to_utf8, cd_utf8_to_88591,
358                                      handler);
359       switch (handler)
360         {
361         case iconveh_error:
362           ASSERT (result == NULL && errno == EILSEQ);
363           break;
364         case iconveh_question_mark:
365           {
366             static const char expected[] = "Rafa? Maszkowski";
367             ASSERT (result != NULL);
368             ASSERT (strcmp (result, expected) == 0);
369             free (result);
370           }
371           break;
372         case iconveh_escape_sequence:
373           {
374             static const char expected[] = "Rafa\\u0142 Maszkowski";
375             ASSERT (result != NULL);
376             ASSERT (strcmp (result, expected) == 0);
377             free (result);
378           }
379           break;
380         }
381     }
382
383   /* Test conversion from ISO-8859-1 to UTF-8 with no errors.  */
384   for (h = 0; h < SIZEOF (handlers); h++)
385     {
386       enum iconv_ilseq_handler handler = handlers[h];
387       static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
388       static const char expected[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
389       char *result = str_cd_iconveh (input,
390                                      cd_88591_to_utf8,
391                                      cd_88591_to_utf8, (iconv_t)(-1),
392                                      handler);
393       ASSERT (result != NULL);
394       ASSERT (strcmp (result, expected) == 0);
395       free (result);
396     }
397
398   /* Test conversion from UTF-8 to ISO-8859-1 with no errors.  */
399   for (h = 0; h < SIZEOF (handlers); h++)
400     {
401       enum iconv_ilseq_handler handler = handlers[h];
402       static const char input[] = "\303\204rger mit b\303\266sen B\303\274bchen ohne Augenma\303\237";
403       static const char expected[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
404       char *result = str_cd_iconveh (input,
405                                      cd_utf8_to_88591,
406                                      (iconv_t)(-1), cd_utf8_to_88591,
407                                      handler);
408       ASSERT (result != NULL);
409       ASSERT (strcmp (result, expected) == 0);
410       free (result);
411     }
412
413   /* Test conversion from UTF-8 to ISO-8859-1 with EILSEQ.  */
414   for (h = 0; h < SIZEOF (handlers); h++)
415     {
416       enum iconv_ilseq_handler handler = handlers[h];
417       static const char input[] = "Costs: 27 \342\202\254"; /* EURO SIGN */
418       char *result = str_cd_iconveh (input,
419                                      cd_utf8_to_88591,
420                                      (iconv_t)(-1), cd_utf8_to_88591,
421                                      handler);
422       switch (handler)
423         {
424         case iconveh_error:
425           ASSERT (result == NULL && errno == EILSEQ);
426           break;
427         case iconveh_question_mark:
428           {
429             static const char expected[] = "Costs: 27 ?";
430             ASSERT (result != NULL);
431             ASSERT (strcmp (result, expected) == 0);
432             free (result);
433           }
434           break;
435         case iconveh_escape_sequence:
436           {
437             static const char expected[] = "Costs: 27 \\u20AC";
438             ASSERT (result != NULL);
439             ASSERT (strcmp (result, expected) == 0);
440             free (result);
441           }
442           break;
443         }
444     }
445
446   /* Test conversion from UTF-8 to ISO-8859-1 with EINVAL.  */
447   for (h = 0; h < SIZEOF (handlers); h++)
448     {
449       enum iconv_ilseq_handler handler = handlers[h];
450       static const char input[] = "\342";
451       char *result = str_cd_iconveh (input,
452                                      cd_utf8_to_88591,
453                                      (iconv_t)(-1), cd_utf8_to_88591,
454                                      handler);
455       ASSERT (result != NULL);
456       ASSERT (strcmp (result, "") == 0);
457       free (result);
458     }
459
460   iconv_close (cd_88591_to_88592);
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 }