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