1/*
2 * Copyright (C) 1999-2007 Free Software Foundation, Inc.
3 * This file is part of the GNU LIBICONV Library.
4 *
5 * The GNU LIBICONV Library is free software; you can redistribute it
6 * and/or modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * The GNU LIBICONV Library is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
17 * If not, write to the Free Software Foundation, Inc., 51 Franklin Street,
18 * Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include "iconv.h"
22
23#include <stdlib.h>
24#include <string.h>
25#include "config.h"
26#include "localcharset.h"
27
28#if ENABLE_EXTRA
29/*
30 * Consider all system dependent encodings, for any system,
31 * and the extra encodings.
32 */
33#define USE_AIX
34#define USE_OSF1
35#define USE_DOS
36#define USE_EXTRA
37#else
38/*
39 * Consider those system dependent encodings that are needed for the
40 * current system.
41 */
42#ifdef _AIX
43#define USE_AIX
44#endif
45#if defined(__osf__) || defined(VMS)
46#define USE_OSF1
47#endif
48#if defined(__DJGPP__) || (defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)))
49#define USE_DOS
50#endif
51#endif
52
53/*
54 * Data type for general conversion loop.
55 */
56struct loop_funcs {
57  size_t (*loop_convert) (iconv_t icd,
58                          const char* * inbuf, size_t *inbytesleft,
59                          char* * outbuf, size_t *outbytesleft);
60  size_t (*loop_reset) (iconv_t icd,
61                        char* * outbuf, size_t *outbytesleft);
62};
63
64/*
65 * Converters.
66 */
67#include "converters.h"
68
69/*
70 * Transliteration tables.
71 */
72#include "cjk_variants.h"
73#include "translit.h"
74
75/*
76 * Table of all supported encodings.
77 */
78struct encoding {
79  struct mbtowc_funcs ifuncs; /* conversion multibyte -> unicode */
80  struct wctomb_funcs ofuncs; /* conversion unicode -> multibyte */
81  int oflags;                 /* flags for unicode -> multibyte conversion */
82};
83enum {
84#define DEFENCODING(xxx_names,xxx,xxx_ifuncs1,xxx_ifuncs2,xxx_ofuncs1,xxx_ofuncs2) \
85  ei_##xxx ,
86#include "encodings.def"
87#ifdef USE_AIX
88#include "encodings_aix.def"
89#endif
90#ifdef USE_OSF1
91#include "encodings_osf1.def"
92#endif
93#ifdef USE_DOS
94#include "encodings_dos.def"
95#endif
96#ifdef USE_EXTRA
97#include "encodings_extra.def"
98#endif
99#include "encodings_local.def"
100#undef DEFENCODING
101ei_for_broken_compilers_that_dont_like_trailing_commas
102};
103#include "flags.h"
104static struct encoding const all_encodings[] = {
105#define DEFENCODING(xxx_names,xxx,xxx_ifuncs1,xxx_ifuncs2,xxx_ofuncs1,xxx_ofuncs2) \
106  { xxx_ifuncs1,xxx_ifuncs2, xxx_ofuncs1,xxx_ofuncs2, ei_##xxx##_oflags },
107#include "encodings.def"
108#ifdef USE_AIX
109#include "encodings_aix.def"
110#endif
111#ifdef USE_OSF1
112#include "encodings_osf1.def"
113#endif
114#ifdef USE_DOS
115#include "encodings_dos.def"
116#endif
117#ifdef USE_EXTRA
118#include "encodings_extra.def"
119#endif
120#undef DEFENCODING
121#define DEFENCODING(xxx_names,xxx,xxx_ifuncs1,xxx_ifuncs2,xxx_ofuncs1,xxx_ofuncs2) \
122  { xxx_ifuncs1,xxx_ifuncs2, xxx_ofuncs1,xxx_ofuncs2, 0 },
123#include "encodings_local.def"
124#undef DEFENCODING
125};
126
127/*
128 * Conversion loops.
129 */
130#include "loops.h"
131
132/*
133 * Alias lookup function.
134 * Defines
135 *   struct alias { int name; unsigned int encoding_index; };
136 *   const struct alias * aliases_lookup (const char *str, unsigned int len);
137 *   #define MAX_WORD_LENGTH ...
138 */
139#include "aliases.h"
140
141/*
142 * System dependent alias lookup function.
143 * Defines
144 *   const struct alias * aliases2_lookup (const char *str);
145 */
146#if defined(USE_AIX) || defined(USE_OSF1) || defined(USE_DOS) || defined(USE_EXTRA) /* || ... */
147struct stringpool2_t {
148#define S(tag,name,encoding_index) char stringpool_##tag[sizeof(name)];
149#include "aliases2.h"
150#undef S
151};
152static const struct stringpool2_t stringpool2_contents = {
153#define S(tag,name,encoding_index) name,
154#include "aliases2.h"
155#undef S
156};
157#define stringpool2 ((const char *) &stringpool2_contents)
158static const struct alias sysdep_aliases[] = {
159#define S(tag,name,encoding_index) { (int)(long)&((struct stringpool2_t *)0)->stringpool_##tag, encoding_index },
160#include "aliases2.h"
161#undef S
162};
163#if defined(__GNUC__) && !defined(DEBUG)
164__inline
165#else
166#ifdef __cplusplus
167inline
168#endif
169#endif
170static const struct alias *
171aliases2_lookup (register const char *str)
172{
173  const struct alias * ptr;
174  unsigned int count;
175  for (ptr = sysdep_aliases, count = sizeof(sysdep_aliases)/sizeof(sysdep_aliases[0]); count > 0; ptr++, count--)
176    if (!strcmp(str, stringpool2 + ptr->name))
177      return ptr;
178  return NULL;
179}
180#else
181#define aliases2_lookup(str)  NULL
182#define stringpool2  NULL
183#endif
184
185#if 0
186/* Like !strcasecmp, except that the both strings can be assumed to be ASCII
187   and the first string can be assumed to be in uppercase. */
188static int strequal (const char* str1, const char* str2)
189{
190  unsigned char c1;
191  unsigned char c2;
192  for (;;) {
193    c1 = * (unsigned char *) str1++;
194    c2 = * (unsigned char *) str2++;
195    if (c1 == 0)
196      break;
197    if (c2 >= 'a' && c2 <= 'z')
198      c2 -= 'a'-'A';
199    if (c1 != c2)
200      break;
201  }
202  return (c1 == c2);
203}
204#endif
205
206iconv_t iconv_open (const char* tocode, const char* fromcode)
207{
208  struct conv_struct * cd;
209  char buf[MAX_WORD_LENGTH+10+1];
210  const char* cp;
211  char* bp;
212  const struct alias * ap;
213  unsigned int count;
214  unsigned int from_index;
215  int from_wchar;
216  unsigned int to_index;
217  int to_wchar;
218  int transliterate = 0;
219  int discard_ilseq = 0;
220
221  /* Before calling aliases_lookup, convert the input string to upper case,
222   * and check whether it's entirely ASCII (we call gperf with option "-7"
223   * to achieve a smaller table) and non-empty. If it's not entirely ASCII,
224   * or if it's too long, it is not a valid encoding name.
225   */
226  for (to_wchar = 0;;) {
227    /* Search tocode in the table. */
228    for (cp = tocode, bp = buf, count = MAX_WORD_LENGTH+10+1; ; cp++, bp++) {
229      unsigned char c = * (unsigned char *) cp;
230      if (c >= 0x80)
231        goto invalid;
232      if (c >= 'a' && c <= 'z')
233        c -= 'a'-'A';
234      *bp = c;
235      if (c == '\0')
236        break;
237      if (--count == 0)
238        goto invalid;
239    }
240    for (;;) {
241      if (bp-buf >= 10 && memcmp(bp-10,"//TRANSLIT",10)==0) {
242        bp -= 10;
243        *bp = '\0';
244        transliterate = 1;
245        continue;
246      }
247      if (bp-buf >= 8 && memcmp(bp-8,"//IGNORE",8)==0) {
248        bp -= 8;
249        *bp = '\0';
250        discard_ilseq = 1;
251        continue;
252      }
253      break;
254    }
255    if (buf[0] == '\0') {
256      tocode = locale_charset();
257      /* Avoid an endless loop that could occur when using an older version
258         of localcharset.c. */
259      if (tocode[0] == '\0')
260        goto invalid;
261      continue;
262    }
263    ap = aliases_lookup(buf,bp-buf);
264    if (ap == NULL) {
265      ap = aliases2_lookup(buf);
266      if (ap == NULL)
267        goto invalid;
268    }
269    if (ap->encoding_index == ei_local_char) {
270      tocode = locale_charset();
271      /* Avoid an endless loop that could occur when using an older version
272         of localcharset.c. */
273      if (tocode[0] == '\0')
274        goto invalid;
275      continue;
276    }
277    if (ap->encoding_index == ei_local_wchar_t) {
278      /* On systems which define __STDC_ISO_10646__, wchar_t is Unicode.
279         This is also the case on native Woe32 systems.  */
280#if __STDC_ISO_10646__ || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
281      if (sizeof(wchar_t) == 4) {
282        to_index = ei_ucs4internal;
283        break;
284      }
285      if (sizeof(wchar_t) == 2) {
286        to_index = ei_ucs2internal;
287        break;
288      }
289      if (sizeof(wchar_t) == 1) {
290        to_index = ei_iso8859_1;
291        break;
292      }
293#endif
294#if HAVE_MBRTOWC
295      to_wchar = 1;
296      tocode = locale_charset();
297      continue;
298#endif
299      goto invalid;
300    }
301    to_index = ap->encoding_index;
302    break;
303  }
304  for (from_wchar = 0;;) {
305    /* Search fromcode in the table. */
306    for (cp = fromcode, bp = buf, count = MAX_WORD_LENGTH+10+1; ; cp++, bp++) {
307      unsigned char c = * (unsigned char *) cp;
308      if (c >= 0x80)
309        goto invalid;
310      if (c >= 'a' && c <= 'z')
311        c -= 'a'-'A';
312      *bp = c;
313      if (c == '\0')
314        break;
315      if (--count == 0)
316        goto invalid;
317    }
318    for (;;) {
319      if (bp-buf >= 10 && memcmp(bp-10,"//TRANSLIT",10)==0) {
320        bp -= 10;
321        *bp = '\0';
322        continue;
323      }
324      if (bp-buf >= 8 && memcmp(bp-8,"//IGNORE",8)==0) {
325        bp -= 8;
326        *bp = '\0';
327        continue;
328      }
329      break;
330    }
331    if (buf[0] == '\0') {
332      fromcode = locale_charset();
333      /* Avoid an endless loop that could occur when using an older version
334         of localcharset.c. */
335      if (fromcode[0] == '\0')
336        goto invalid;
337      continue;
338    }
339    ap = aliases_lookup(buf,bp-buf);
340    if (ap == NULL) {
341      ap = aliases2_lookup(buf);
342      if (ap == NULL)
343        goto invalid;
344    }
345    if (ap->encoding_index == ei_local_char) {
346      fromcode = locale_charset();
347      /* Avoid an endless loop that could occur when using an older version
348         of localcharset.c. */
349      if (fromcode[0] == '\0')
350        goto invalid;
351      continue;
352    }
353    if (ap->encoding_index == ei_local_wchar_t) {
354      /* On systems which define __STDC_ISO_10646__, wchar_t is Unicode.
355         This is also the case on native Woe32 systems.  */
356#if __STDC_ISO_10646__ || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
357      if (sizeof(wchar_t) == 4) {
358        from_index = ei_ucs4internal;
359        break;
360      }
361      if (sizeof(wchar_t) == 2) {
362        from_index = ei_ucs2internal;
363        break;
364      }
365      if (sizeof(wchar_t) == 1) {
366        from_index = ei_iso8859_1;
367        break;
368      }
369#endif
370#if HAVE_WCRTOMB
371      from_wchar = 1;
372      fromcode = locale_charset();
373      continue;
374#endif
375      goto invalid;
376    }
377    from_index = ap->encoding_index;
378    break;
379  }
380  cd = (struct conv_struct *) malloc(from_wchar != to_wchar
381                                     ? sizeof(struct wchar_conv_struct)
382                                     : sizeof(struct conv_struct));
383  if (cd == NULL) {
384    errno = ENOMEM;
385    return (iconv_t)(-1);
386  }
387  cd->iindex = from_index;
388  cd->ifuncs = all_encodings[from_index].ifuncs;
389  cd->oindex = to_index;
390  cd->ofuncs = all_encodings[to_index].ofuncs;
391  cd->oflags = all_encodings[to_index].oflags;
392  /* Initialize the loop functions. */
393#if HAVE_MBRTOWC
394  if (to_wchar) {
395#if HAVE_WCRTOMB
396    if (from_wchar) {
397      cd->lfuncs.loop_convert = wchar_id_loop_convert;
398      cd->lfuncs.loop_reset = wchar_id_loop_reset;
399    } else
400#endif
401    {
402      cd->lfuncs.loop_convert = wchar_to_loop_convert;
403      cd->lfuncs.loop_reset = wchar_to_loop_reset;
404    }
405  } else
406#endif
407  {
408#if HAVE_WCRTOMB
409    if (from_wchar) {
410      cd->lfuncs.loop_convert = wchar_from_loop_convert;
411      cd->lfuncs.loop_reset = wchar_from_loop_reset;
412    } else
413#endif
414    {
415      cd->lfuncs.loop_convert = unicode_loop_convert;
416      cd->lfuncs.loop_reset = unicode_loop_reset;
417    }
418  }
419  /* Initialize the states. */
420  memset(&cd->istate,'\0',sizeof(state_t));
421  memset(&cd->ostate,'\0',sizeof(state_t));
422  /* Initialize the operation flags. */
423  cd->transliterate = transliterate;
424  cd->discard_ilseq = discard_ilseq;
425  #ifndef LIBICONV_PLUG
426  cd->fallbacks.mb_to_uc_fallback = NULL;
427  cd->fallbacks.uc_to_mb_fallback = NULL;
428  cd->fallbacks.mb_to_wc_fallback = NULL;
429  cd->fallbacks.wc_to_mb_fallback = NULL;
430  cd->fallbacks.data = NULL;
431  cd->hooks.uc_hook = NULL;
432  cd->hooks.wc_hook = NULL;
433  cd->hooks.data = NULL;
434  #endif
435  /* Initialize additional fields. */
436  if (from_wchar != to_wchar) {
437    struct wchar_conv_struct * wcd = (struct wchar_conv_struct *) cd;
438    memset(&wcd->state,'\0',sizeof(mbstate_t));
439  }
440  /* Done. */
441  return (iconv_t)cd;
442invalid:
443  errno = EINVAL;
444  return (iconv_t)(-1);
445}
446
447size_t iconv (iconv_t icd,
448              ICONV_CONST char* * inbuf, size_t *inbytesleft,
449              char* * outbuf, size_t *outbytesleft)
450{
451  conv_t cd = (conv_t) icd;
452  if (inbuf == NULL || *inbuf == NULL)
453    return cd->lfuncs.loop_reset(icd,outbuf,outbytesleft);
454  else
455    return cd->lfuncs.loop_convert(icd,
456                                   (const char* *)inbuf,inbytesleft,
457                                   outbuf,outbytesleft);
458}
459
460int iconv_close (iconv_t icd)
461{
462  conv_t cd = (conv_t) icd;
463  free(cd);
464  return 0;
465}
466
467#ifndef LIBICONV_PLUG
468
469int iconvctl (iconv_t icd, int request, void* argument)
470{
471  conv_t cd = (conv_t) icd;
472  switch (request) {
473    case ICONV_TRIVIALP:
474      *(int *)argument =
475        ((cd->lfuncs.loop_convert == unicode_loop_convert
476          && cd->iindex == cd->oindex)
477         || cd->lfuncs.loop_convert == wchar_id_loop_convert
478         ? 1 : 0);
479      return 0;
480    case ICONV_GET_TRANSLITERATE:
481      *(int *)argument = cd->transliterate;
482      return 0;
483    case ICONV_SET_TRANSLITERATE:
484      cd->transliterate = (*(const int *)argument ? 1 : 0);
485      return 0;
486    case ICONV_GET_DISCARD_ILSEQ:
487      *(int *)argument = cd->discard_ilseq;
488      return 0;
489    case ICONV_SET_DISCARD_ILSEQ:
490      cd->discard_ilseq = (*(const int *)argument ? 1 : 0);
491      return 0;
492    case ICONV_SET_HOOKS:
493      if (argument != NULL) {
494        cd->hooks = *(const struct iconv_hooks *)argument;
495      } else {
496        cd->hooks.uc_hook = NULL;
497        cd->hooks.wc_hook = NULL;
498        cd->hooks.data = NULL;
499      }
500      return 0;
501    case ICONV_SET_FALLBACKS:
502      if (argument != NULL) {
503        cd->fallbacks = *(const struct iconv_fallbacks *)argument;
504      } else {
505        cd->fallbacks.mb_to_uc_fallback = NULL;
506        cd->fallbacks.uc_to_mb_fallback = NULL;
507        cd->fallbacks.mb_to_wc_fallback = NULL;
508        cd->fallbacks.wc_to_mb_fallback = NULL;
509        cd->fallbacks.data = NULL;
510      }
511      return 0;
512    default:
513      errno = EINVAL;
514      return -1;
515  }
516}
517
518/* An alias after its name has been converted from 'int' to 'const char*'. */
519struct nalias { const char* name; unsigned int encoding_index; };
520
521static int compare_by_index (const void * arg1, const void * arg2)
522{
523  const struct nalias * alias1 = (const struct nalias *) arg1;
524  const struct nalias * alias2 = (const struct nalias *) arg2;
525  return (int)alias1->encoding_index - (int)alias2->encoding_index;
526}
527
528static int compare_by_name (const void * arg1, const void * arg2)
529{
530  const char * name1 = *(const char **)arg1;
531  const char * name2 = *(const char **)arg2;
532  /* Compare alphabetically, but put "CS" names at the end. */
533  int sign = strcmp(name1,name2);
534  if (sign != 0) {
535    sign = ((name1[0]=='C' && name1[1]=='S') - (name2[0]=='C' && name2[1]=='S'))
536           * 4 + (sign >= 0 ? 1 : -1);
537  }
538  return sign;
539}
540
541void iconvlist (int (*do_one) (unsigned int namescount,
542                               const char * const * names,
543                               void* data),
544                void* data)
545{
546#define aliascount1  sizeof(aliases)/sizeof(aliases[0])
547#ifndef aliases2_lookup
548#define aliascount2  sizeof(sysdep_aliases)/sizeof(sysdep_aliases[0])
549#else
550#define aliascount2  0
551#endif
552#define aliascount  (aliascount1+aliascount2)
553  struct nalias aliasbuf[aliascount];
554  const char * namesbuf[aliascount];
555  size_t num_aliases;
556  {
557    /* Put all existing aliases into a buffer. */
558    size_t i;
559    size_t j;
560    j = 0;
561    for (i = 0; i < aliascount1; i++) {
562      const struct alias * p = &aliases[i];
563      if (p->name >= 0
564          && p->encoding_index != ei_local_char
565          && p->encoding_index != ei_local_wchar_t) {
566        aliasbuf[j].name = stringpool + p->name;
567        aliasbuf[j].encoding_index = p->encoding_index;
568        j++;
569      }
570    }
571#ifndef aliases2_lookup
572    for (i = 0; i < aliascount2; i++) {
573      aliasbuf[j].name = stringpool2 + sysdep_aliases[i].name;
574      aliasbuf[j].encoding_index = sysdep_aliases[i].encoding_index;
575      j++;
576    }
577#endif
578    num_aliases = j;
579  }
580  /* Sort by encoding_index. */
581  if (num_aliases > 1)
582    qsort(aliasbuf, num_aliases, sizeof(struct nalias), compare_by_index);
583  {
584    /* Process all aliases with the same encoding_index together. */
585    size_t j;
586    j = 0;
587    while (j < num_aliases) {
588      unsigned int ei = aliasbuf[j].encoding_index;
589      size_t i = 0;
590      do
591        namesbuf[i++] = aliasbuf[j++].name;
592      while (j < num_aliases && aliasbuf[j].encoding_index == ei);
593      if (i > 1)
594        qsort(namesbuf, i, sizeof(const char *), compare_by_name);
595      /* Call the callback. */
596      if (do_one(i,namesbuf,data))
597        break;
598    }
599  }
600#undef aliascount
601#undef aliascount2
602#undef aliascount1
603}
604
605/*
606 * Table of canonical names of encodings.
607 * Instead of strings, it contains offsets into stringpool and stringpool2.
608 */
609static const unsigned short all_canonical[] = {
610#include "canonical.h"
611#ifdef USE_AIX
612#include "canonical_aix.h"
613#endif
614#ifdef USE_OSF1
615#include "canonical_osf1.h"
616#endif
617#ifdef USE_DOS
618#include "canonical_dos.h"
619#endif
620#ifdef USE_EXTRA
621#include "canonical_extra.h"
622#endif
623#include "canonical_local.h"
624};
625
626const char * iconv_canonicalize (const char * name)
627{
628  const char* code;
629  char buf[MAX_WORD_LENGTH+10+1];
630  const char* cp;
631  char* bp;
632  const struct alias * ap;
633  unsigned int count;
634  unsigned int index;
635  const char* pool;
636
637  /* Before calling aliases_lookup, convert the input string to upper case,
638   * and check whether it's entirely ASCII (we call gperf with option "-7"
639   * to achieve a smaller table) and non-empty. If it's not entirely ASCII,
640   * or if it's too long, it is not a valid encoding name.
641   */
642  for (code = name;;) {
643    /* Search code in the table. */
644    for (cp = code, bp = buf, count = MAX_WORD_LENGTH+10+1; ; cp++, bp++) {
645      unsigned char c = * (unsigned char *) cp;
646      if (c >= 0x80)
647        goto invalid;
648      if (c >= 'a' && c <= 'z')
649        c -= 'a'-'A';
650      *bp = c;
651      if (c == '\0')
652        break;
653      if (--count == 0)
654        goto invalid;
655    }
656    for (;;) {
657      if (bp-buf >= 10 && memcmp(bp-10,"//TRANSLIT",10)==0) {
658        bp -= 10;
659        *bp = '\0';
660        continue;
661      }
662      if (bp-buf >= 8 && memcmp(bp-8,"//IGNORE",8)==0) {
663        bp -= 8;
664        *bp = '\0';
665        continue;
666      }
667      break;
668    }
669    if (buf[0] == '\0') {
670      code = locale_charset();
671      /* Avoid an endless loop that could occur when using an older version
672         of localcharset.c. */
673      if (code[0] == '\0')
674        goto invalid;
675      continue;
676    }
677    pool = stringpool;
678    ap = aliases_lookup(buf,bp-buf);
679    if (ap == NULL) {
680      pool = stringpool2;
681      ap = aliases2_lookup(buf);
682      if (ap == NULL)
683        goto invalid;
684    }
685    if (ap->encoding_index == ei_local_char) {
686      code = locale_charset();
687      /* Avoid an endless loop that could occur when using an older version
688         of localcharset.c. */
689      if (code[0] == '\0')
690        goto invalid;
691      continue;
692    }
693    if (ap->encoding_index == ei_local_wchar_t) {
694      /* On systems which define __STDC_ISO_10646__, wchar_t is Unicode.
695         This is also the case on native Woe32 systems.  */
696#if __STDC_ISO_10646__ || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
697      if (sizeof(wchar_t) == 4) {
698        index = ei_ucs4internal;
699        break;
700      }
701      if (sizeof(wchar_t) == 2) {
702        index = ei_ucs2internal;
703        break;
704      }
705      if (sizeof(wchar_t) == 1) {
706        index = ei_iso8859_1;
707        break;
708      }
709#endif
710    }
711    index = ap->encoding_index;
712    break;
713  }
714  return all_canonical[index] + pool;
715 invalid:
716  return name;
717}
718
719int _libiconv_version = _LIBICONV_VERSION;
720
721#if defined __FreeBSD__ && !defined __gnu_freebsd__
722/* GNU libiconv is the native FreeBSD iconv implementation since 2002.
723   It wants to define the symbols 'iconv_open', 'iconv', 'iconv_close'.  */
724#define strong_alias(name, aliasname) _strong_alias(name, aliasname)
725#define _strong_alias(name, aliasname) \
726  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
727#undef iconv_open
728#undef iconv
729#undef iconv_close
730strong_alias (libiconv_open, iconv_open)
731strong_alias (libiconv, iconv)
732strong_alias (libiconv_close, iconv_close)
733#endif
734
735#endif
736