1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "synonyms.h" 30 #include "mtlib.h" 31 #include <ctype.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <sys/mman.h> 37 #include <sys/param.h> 38 #include <sys/stat.h> 39 #include <thread.h> 40 #include <synch.h> 41 #include <unistd.h> 42 #include <limits.h> 43 #include <errno.h> 44 #include "libc.h" 45 #include "msgfmt.h" 46 #include "nlspath_checks.h" 47 #include "gettext.h" 48 49 #ifdef DEBUG 50 #include <assert.h> 51 #endif 52 53 static const char *nullstr = ""; 54 55 #define CHARSET_MOD "charset=" 56 #define CHARSET_LEN (sizeof (CHARSET_MOD) - 1) 57 #define NPLURALS_MOD "nplurals=" 58 #define NPLURALS_LEN (sizeof (NPLURALS_MOD) - 1) 59 #define PLURAL_MOD "plural=" 60 #define PLURAL_LEN (sizeof (PLURAL_MOD) - 1) 61 62 /* 63 * free_conv_msgstr 64 * 65 * release the memory allocated for storing code-converted messages 66 */ 67 static void 68 free_conv_msgstr(Msg_g_node *gmnp) 69 { 70 int i; 71 unsigned int num_of_str; 72 73 #ifdef GETTEXT_DEBUG 74 (void) printf("*************** free_conv_msgstr(0x%p)\n", 75 (void *)gmnp); 76 printgnumsg(gmnp, 0); 77 #endif 78 79 num_of_str = SWAP(gmnp, gmnp->msg_file_info->num_of_str); 80 for (i = 0; i < num_of_str; i++) { 81 if (gmnp->conv_msgstr[i]) { 82 free(gmnp->conv_msgstr[i]); 83 } 84 } 85 free(gmnp->conv_msgstr); 86 gmnp->conv_msgstr = NULL; 87 88 } 89 90 /* 91 * dfltmsgstr 92 * 93 * choose an appropriate message by evaluating the plural expression, 94 * and return it. 95 */ 96 static char * 97 dfltmsgstr(Msg_g_node *gmnp, const char *msgstr, size_t msgstr_len, 98 struct msg_pack *mp) 99 { 100 unsigned int pindex; 101 size_t len; 102 const char *p; 103 104 #ifdef GETTEXT_DEBUG 105 (void) printf("*************** dfltmsgstr(0x%p, \"%s\", %d, 0x%p)\n", 106 (void *)gmnp, 107 msgstr ? msgstr : "(null)", msgstr_len, (void *)mp); 108 printgnumsg(gmnp, 0); 109 printmp(mp, 0); 110 #endif 111 112 if (mp->plural) { 113 if (gmnp->plural) { 114 pindex = plural_eval(gmnp->plural, mp->n); 115 } else { 116 /* 117 * This mo does not have plural information. 118 * Using the English form. 119 */ 120 if (mp->n == 1) 121 pindex = 0; 122 else 123 pindex = 1; 124 } 125 #ifdef GETTEXT_DEBUG 126 (void) printf("plural_eval returned: %d\n", pindex); 127 #endif 128 if (pindex >= gmnp->nplurals) { 129 /* should never happen */ 130 pindex = 0; 131 } 132 p = msgstr; 133 for (; pindex != 0; pindex--) { 134 len = msgstr_len - (p - msgstr); 135 p = memchr(p, '\0', len); 136 if (!p) { 137 /* 138 * null byte not found 139 * this should never happen 140 */ 141 char *result; 142 DFLTMSG(result, mp->msgid1, mp->msgid2, 143 mp->n, mp->plural); 144 return (result); 145 } 146 p++; /* skip */ 147 } 148 return ((char *)p); 149 } 150 151 return ((char *)msgstr); 152 } 153 154 /* 155 * parse_header 156 * 157 * parse the header entry of the GNU MO file and 158 * extract the src encoding and the plural information of the MO file 159 */ 160 static int 161 parse_header(const char *header, Msg_g_node *gmnp) 162 { 163 char *charset = NULL; 164 char *charset_str; 165 size_t len; 166 char *nplurals_str, *plural_str; 167 plural_expr_t plural; 168 char *p, *q; 169 unsigned int nplurals; 170 int ret; 171 172 #ifdef GETTEXT_DEBUG 173 (void) printf("*************** parse_header(\"%s\", 0x%p)\n", 174 header ? header : "(null)", (void *)gmnp); 175 printgnumsg(gmnp, 0); 176 #endif 177 178 if (!header) { 179 gmnp->src_encoding = (char *)nullstr; 180 gmnp->nplurals = 2; 181 gmnp->plural = NULL; 182 #ifdef GETTEXT_DEBUG 183 (void) printf("*************** exiting parse_header\n"); 184 (void) printf("no header\n"); 185 #endif 186 187 return (0); 188 } 189 190 charset_str = strstr(header, CHARSET_MOD); 191 if (!charset_str) { 192 gmnp->src_encoding = (char *)nullstr; 193 } else { 194 p = charset_str + CHARSET_LEN; 195 q = p; 196 while ((*q != ' ') && (*q != '\t') && 197 (*q != '\n')) { 198 q++; 199 } 200 len = q - p; 201 if (len > 0) { 202 charset = (char *)malloc(len + 1); 203 if (!charset) { 204 gmnp->src_encoding = (char *)nullstr; 205 gmnp->nplurals = 2; 206 gmnp->plural = NULL; 207 return (-1); 208 } 209 (void) memcpy(charset, p, len); 210 charset[len] = '\0'; 211 gmnp->src_encoding = charset; 212 } else { 213 gmnp->src_encoding = (char *)nullstr; 214 } 215 } 216 217 nplurals_str = strstr(header, NPLURALS_MOD); 218 plural_str = strstr(header, PLURAL_MOD); 219 if (!nplurals_str || !plural_str) { 220 /* no valid plural specification */ 221 gmnp->nplurals = 2; 222 gmnp->plural = NULL; 223 #ifdef GETTEXT_DEBUG 224 (void) printf("*************** exiting parse_header\n"); 225 (void) printf("no plural entry\n"); 226 #endif 227 return (0); 228 } else { 229 p = nplurals_str + NPLURALS_LEN; 230 while (*p && isspace((unsigned char)*p)) { 231 p++; 232 } 233 nplurals = (unsigned int)strtol(p, &q, 10); 234 if (p != q) { 235 gmnp->nplurals = nplurals; 236 } else { 237 gmnp->nplurals = 2; 238 } 239 240 p = plural_str + PLURAL_LEN; 241 #ifdef GETTEXT_DEBUG 242 (void) printf("plural_str: \"%s\"\n", p); 243 #endif 244 245 ret = plural_expr(&plural, (const char *)p); 246 if (ret == 0) { 247 /* parse succeeded */ 248 gmnp->plural = plural; 249 #ifdef GETTEXT_DEBUG 250 (void) printf("*************** exiting parse_header\n"); 251 (void) printf("charset: \"%s\"\n", 252 charset ? charset : "(null)"); 253 printexpr(plural, 0); 254 #endif 255 return (0); 256 } else if (ret == 1) { 257 /* parse error */ 258 gmnp->nplurals = 2; 259 gmnp->plural = NULL; 260 return (0); 261 } else { 262 /* fatal error */ 263 if (charset) 264 free(charset); 265 gmnp->src_encoding = (char *)nullstr; 266 gmnp->nplurals = 2; 267 gmnp->plural = NULL; 268 return (-1); 269 } 270 } 271 /* NOTREACHED */ 272 } 273 274 static char * 275 handle_gnu_mo(struct cache_pack *cp, struct msg_pack *mp, 276 Gettext_t *gt) 277 { 278 char *result; 279 char *codeset = get_codeset(mp->domain); 280 281 result = gnu_key_2_text(cp->mnp->msg.gnumsg, codeset, mp); 282 if (mp->plural) { 283 if (((result == mp->msgid1) && (mp->n == 1)) || 284 ((result == mp->msgid2) && (mp->n != 1))) { 285 return (NULL); 286 } 287 } else { 288 if (result == mp->msgid1) { 289 return (NULL); 290 } 291 } 292 gt->c_m_node = cp->mnp; 293 if (!cp->mnp->trusted) { 294 result = check_format(mp->msgid1, result, 0); 295 if (result == mp->msgid1) { 296 DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, 297 mp->plural); 298 } 299 } 300 return (result); 301 } 302 303 /* 304 * handle_lang 305 * 306 * take care of the LANGUAGE specification 307 */ 308 char * 309 handle_lang(struct cache_pack *cp, struct msg_pack *mp) 310 { 311 Gettext_t *gt = global_gt; 312 struct stat64 statbuf; 313 const char *p, *op, *q; 314 char *locale = NULL, *olocale, *result; 315 unsigned int hash_locale; 316 size_t locale_len, olocale_len = 0; 317 int gnu_mo_found = 0; 318 int fd; 319 int ret; 320 321 #ifdef GETTEXT_DEBUG 322 (void) printf("*************** handle_lang(0x%p, 0x%p)\n", 323 (void *)cp, (void *)mp); 324 printcp(cp, 0); 325 printmp(mp, 0); 326 #endif 327 328 p = mp->language; 329 330 while (*p) { 331 op = p; 332 q = strchr(p, ':'); 333 if (!q) { 334 locale_len = strlen(p); 335 p += locale_len; 336 } else { 337 locale_len = q - p; 338 p += locale_len + 1; 339 } 340 if ((locale_len >= MAXPATHLEN) || 341 (locale_len == 0)) { 342 /* illegal locale name */ 343 continue; 344 } 345 if (olocale_len < locale_len) { 346 olocale = locale; 347 locale = (char *)realloc(locale, locale_len + 1); 348 if (!locale) { 349 if (olocale) 350 free(olocale); 351 DFLTMSG(result, mp->msgid1, mp->msgid2, 352 mp->n, mp->plural); 353 return (result); 354 } 355 olocale_len = locale_len; 356 } 357 (void) memcpy(locale, op, locale_len); 358 locale[locale_len] = '\0'; 359 hash_locale = get_hashid(locale, NULL); 360 mp->locale = locale; 361 mp->hash_locale = hash_locale; 362 mp->locale_len = locale_len; 363 #ifdef GETTEXT_DEBUG 364 *mp->msgfile = '\0'; 365 #endif 366 if (mk_msgfile(mp) == NULL) { 367 /* illegal locale name */ 368 continue; 369 } 370 371 cp->node_hash = NULL; 372 373 ret = check_cache(cp, mp); 374 if (ret) { 375 /* 376 * found in cache 377 */ 378 switch (cp->mnp->type) { 379 case T_ILL_MO: 380 /* invalid MO */ 381 continue; 382 case T_SUN_MO: 383 /* Solaris MO */ 384 goto out_loop; 385 case T_GNU_MO: 386 /* GNU MO */ 387 gnu_mo_found = 1; 388 result = handle_gnu_mo(cp, mp, gt); 389 if (result) { 390 free(locale); 391 return (result); 392 } 393 continue; 394 } 395 /* NOTREACHED */ 396 } 397 /* 398 * not found in cache 399 */ 400 fd = nls_safe_open(mp->msgfile, &statbuf, &mp->trusted, 1); 401 if ((fd == -1) || (statbuf.st_size > LONG_MAX)) { 402 if (connect_invalid_entry(cp, mp) == -1) { 403 DFLTMSG(result, mp->msgid1, mp->msgid2, 404 mp->n, mp->plural); 405 free(locale); 406 return (result); 407 } 408 continue; 409 } 410 mp->fsz = (size_t)statbuf.st_size; 411 mp->addr = mmap(0, mp->fsz, PROT_READ, MAP_SHARED, fd, 0); 412 (void) close(fd); 413 414 if (mp->addr == (caddr_t)-1) { 415 if (connect_invalid_entry(cp, mp) == -1) { 416 DFLTMSG(result, mp->msgid1, mp->msgid2, 417 mp->n, mp->plural); 418 free(locale); 419 return (result); 420 } 421 continue; 422 } 423 424 cp->mnp = create_mnp(mp); 425 if (!cp->mnp) { 426 free(locale); 427 free_mnp_mp(cp->mnp, mp); 428 DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, 429 mp->plural); 430 return (result); 431 } 432 433 if (setmsg(cp->mnp, (char *)mp->addr, mp->fsz) == -1) { 434 free(locale); 435 free_mnp_mp(cp->mnp, mp); 436 DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, 437 mp->plural); 438 return (result); 439 } 440 if (!cp->cacheline) { 441 cp->cnp = create_cnp(cp->mnp, mp); 442 if (!cp->cnp) { 443 free(locale); 444 free_mnp_mp(cp->mnp, mp); 445 DFLTMSG(result, mp->msgid1, mp->msgid2, 446 mp->n, mp->plural); 447 return (result); 448 } 449 } 450 cp->mnp->trusted = mp->trusted; 451 connect_entry(cp); 452 453 switch (cp->mnp->type) { 454 case T_ILL_MO: 455 /* invalid MO */ 456 continue; 457 case T_SUN_MO: 458 /* Solaris MO */ 459 goto out_loop; 460 case T_GNU_MO: 461 /* GNU MO */ 462 gnu_mo_found = 1; 463 464 result = handle_gnu_mo(cp, mp, gt); 465 if (result) { 466 free(locale); 467 return (result); 468 } 469 continue; 470 } 471 /* NOTREACHED */ 472 } 473 474 out_loop: 475 if (gnu_mo_found) { 476 DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); 477 free(locale); 478 return (result); 479 } 480 if (locale) 481 free(locale); 482 return (NULL); 483 } 484 485 486 /* 487 * gnu_msgsearch 488 * 489 * Searchs the translation message for the specified msgid1. 490 * Hash algorithm used in this function is Open Addressing 491 * with Double Hashing: 492 * H(k, i) = (H1(k) + i * H2(k)) mod M 493 * H1(k) = hashvalue % M 494 * H2(k) = 1 + (hashvalue % (M - 2)) 495 * 496 * Ref: The Art of Computer Programming Volume 3 497 * Sorting and Searching, second edition 498 * Donald E Knuth 499 */ 500 static char * 501 gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1, 502 size_t *msgstrlen, unsigned int *midx) 503 { 504 unsigned int *hash_table; 505 struct gnu_msg_ent *msgid_tbl, *msgstr_tbl; 506 char *base; 507 struct gnu_msg_info *header = gmnp->msg_file_info; 508 unsigned int hash_size, hash_val, hash_inc, hash_idx; 509 unsigned int offset, msglen, idx; 510 unsigned int num_of_str; 511 unsigned int off_msgid_tbl, off_msgstr_tbl; 512 size_t msgid1_len; 513 514 base = (char *)header; 515 off_msgid_tbl = SWAP(gmnp, header->off_msgid_tbl); 516 off_msgstr_tbl = SWAP(gmnp, header->off_msgstr_tbl); 517 518 /* LINTED */ 519 msgid_tbl = (struct gnu_msg_ent *)(base + off_msgid_tbl); 520 /* LINTED */ 521 msgstr_tbl = (struct gnu_msg_ent *)(base + off_msgstr_tbl); 522 hash_table = gmnp->hash_table; 523 hash_size = SWAP(gmnp, header->sz_hashtbl); 524 num_of_str = SWAP(gmnp, header->num_of_str); 525 526 #ifdef GETTEXT_DEBUG 527 (void) printf("*************** gnu_msgsearch(" 528 "0x%p, \"%s\", 0x%p, 0x%p)\n", 529 (void *)gmnp, 530 msgid1 ? msgid1 : "(null)", 531 (void *)msgstrlen, (void *)midx); 532 printgnumsg(gmnp, 0); 533 #endif 534 535 if (!hash_table || (hash_size <= 2)) { 536 /* 537 * No hash table exists or 538 * hash size is enough small 539 */ 540 unsigned int top, bottom; 541 char *msg_id_str; 542 int val; 543 544 top = 0; 545 bottom = num_of_str; 546 while (top < bottom) { 547 idx = (top + bottom) / 2; 548 msg_id_str = base + 549 SWAP(gmnp, msgid_tbl[idx].offset); 550 551 val = strcmp(msg_id_str, msgid1); 552 if (val < 0) { 553 top = idx + 1; 554 } else if (val > 0) { 555 bottom = idx; 556 } else { 557 goto found; 558 } 559 } 560 /* not found */ 561 return ((char *)msgid1); 562 } 563 564 /* use hash table */ 565 hash_val = get_hashid(msgid1, &msgid1_len); 566 msglen = (unsigned int)msgid1_len; 567 hash_idx = hash_val % hash_size; 568 hash_inc = 1 + (hash_val % (hash_size - 2)); 569 570 for (;;) { 571 offset = SWAP(gmnp, hash_table[hash_idx]); 572 573 if (offset == 0) { 574 return ((char *)msgid1); 575 } 576 577 idx = offset - 1; 578 if ((msglen <= SWAP(gmnp, msgid_tbl[idx].len)) && 579 strcmp(msgid1, base + 580 SWAP(gmnp, msgid_tbl[idx].offset)) == 0) { 581 /* found */ 582 goto found; 583 } 584 585 hash_idx = (hash_idx + hash_inc) % hash_size; 586 } 587 /* NOTREACHED */ 588 589 found: 590 if (msgstrlen) 591 *msgstrlen = SWAP(gmnp, msgstr_tbl[idx].len) + 1; 592 if (midx) 593 *midx = idx; 594 return (base + SWAP(gmnp, msgstr_tbl[idx].offset)); 595 } 596 597 /* 598 * do_conv 599 * 600 * Converts the specified string from the src encoding 601 * to the dst encoding by calling iconv() 602 */ 603 static size_t 604 do_conv(iconv_t fd, char **dst, const char *src, size_t srclen) 605 { 606 size_t oleft, ileft, bufsize, tolen; 607 char *to, *tptr; 608 609 #ifdef GETTEXT_DEBUG 610 (void) printf("*************** do_conv(" 611 "0x%p, 0x%p, \"%s\", %d)\n", 612 (void *)fd, (void *)dst, src ? src : "(null)", srclen); 613 #endif 614 615 bufsize = srclen * 2; 616 ileft = srclen; 617 oleft = bufsize; 618 to = (char *)malloc(bufsize); 619 if (!to) { 620 return ((size_t)-1); 621 } 622 623 for (; ; ) { 624 tptr = to; 625 errno = 0; 626 #ifdef GETTEXT_DEBUG 627 (void) printf("******* calling iconv()\n"); 628 #endif 629 if (iconv(fd, &src, &ileft, &tptr, &oleft) == 630 (size_t)-1) { 631 if (errno == E2BIG) { 632 char *oto; 633 oleft += bufsize; 634 bufsize *= 2; 635 oto = to; 636 to = (char *)realloc(oto, bufsize); 637 if (!to) { 638 free(oto); 639 return ((size_t)-1); 640 } 641 continue; 642 } else { 643 tolen = bufsize - oleft; 644 break; 645 } 646 } 647 tolen = bufsize - oleft; 648 break; 649 } 650 *dst = to; 651 return (tolen); 652 } 653 654 /* 655 * gnu_key_2_text 656 * 657 * Extracts msgstr from the GNU MO file 658 */ 659 char * 660 gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, 661 struct msg_pack *mp) 662 { 663 char *result, *msgstr; 664 size_t msgstr_len; 665 unsigned int midx; 666 int ret; 667 char *conv_msgstr, *conv_dst; 668 size_t *p; 669 size_t conv_msgstr_len, buflen; 670 iconv_t fd; 671 int conversion, new_encoding; 672 unsigned int num_of_str; 673 674 #ifdef GETTEXT_DEBUG 675 (void) printf("*************** gnu_key_2_text(" 676 "0x%p, \"%s\", 0x%p)\n", 677 (void *)gmnp, codeset ? codeset : "(null)", (void *)mp); 678 printgnumsg(gmnp, 0); 679 printmp(mp, 0); 680 #endif 681 682 /* first checks if header entry has been processed */ 683 if (!(gmnp->flag & ST_CHK)) { 684 char *msg_header; 685 686 msg_header = gnu_msgsearch(gmnp, "", NULL, NULL); 687 ret = parse_header((const char *)msg_header, gmnp); 688 if (ret == -1) { 689 /* fatal error */ 690 DFLTMSG(result, mp->msgid1, mp->msgid2, 691 mp->n, mp->plural); 692 return (result); 693 } 694 gmnp->flag |= ST_CHK; 695 } 696 msgstr = gnu_msgsearch(gmnp, mp->msgid1, &msgstr_len, &midx); 697 if (msgstr == mp->msgid1) { 698 /* not found */ 699 DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); 700 return (result); 701 } 702 703 #ifdef GETTEXT_DEBUG 704 printgnumsg(gmnp, 0); 705 #endif 706 if (!gmnp->dst_encoding) { 707 /* 708 * destination encoding has not been set. 709 */ 710 char *dupcodeset = strdup(codeset); 711 if (!dupcodeset) { 712 /* strdup failed */ 713 result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); 714 return (result); 715 } 716 gmnp->dst_encoding = dupcodeset; 717 718 if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) == 0) { 719 /* 720 * target encoding and src encoding 721 * are the same. 722 * No conversion required. 723 */ 724 conversion = 0; 725 } else { 726 /* 727 * target encoding is different from 728 * src encoding. 729 * New conversion required. 730 */ 731 /* sanity check */ 732 if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) { 733 (void) iconv_close(gmnp->fd); 734 gmnp->fd = (iconv_t)-1; 735 } 736 if (gmnp->conv_msgstr) 737 free_conv_msgstr(gmnp); 738 conversion = 1; 739 new_encoding = 1; 740 } 741 } else { 742 /* 743 * dst encoding has been already set. 744 */ 745 if (strcmp(gmnp->dst_encoding, codeset) == 0) { 746 /* 747 * dst encoding and target encoding are the same. 748 */ 749 if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) 750 == 0) { 751 /* 752 * dst encoding and src encoding are the same. 753 * No conversion required. 754 */ 755 conversion = 0; 756 } else { 757 /* 758 * dst encoding is different from src encoding. 759 * current conversion is valid. 760 */ 761 conversion = 1; 762 new_encoding = 0; 763 /* checks if iconv_open has succeeded before */ 764 if (gmnp->fd == (iconv_t)-1) { 765 /* 766 * iconv_open should have failed before 767 * Assume this conversion is invalid 768 */ 769 conversion = 0; 770 } else { 771 if (!gmnp->conv_msgstr) { 772 /* 773 * memory allocation for 774 * conv_msgstr should 775 * have failed before. 776 */ 777 new_encoding = 1; 778 if (gmnp->fd) 779 (void) iconv_close( 780 gmnp->fd); 781 gmnp->fd = (iconv_t)-1; 782 } 783 } 784 } 785 } else { 786 /* 787 * dst encoding is different from target encoding. 788 * It has changed since before. 789 */ 790 char *dupcodeset = strdup(codeset); 791 if (!dupcodeset) { 792 result = dfltmsgstr(gmnp, msgstr, 793 msgstr_len, mp); 794 return (result); 795 } 796 free(gmnp->dst_encoding); 797 gmnp->dst_encoding = dupcodeset; 798 if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) 799 == 0) { 800 /* 801 * dst encoding and src encoding are the same. 802 * now, no conversion required. 803 */ 804 conversion = 0; 805 } else { 806 /* 807 * dst encoding is different from src encoding. 808 * new conversion required. 809 */ 810 conversion = 1; 811 new_encoding = 1; 812 } 813 814 if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) { 815 (void) iconv_close(gmnp->fd); 816 } 817 if (gmnp->fd != (iconv_t)-1) { 818 gmnp->fd = (iconv_t)-1; 819 } 820 if (gmnp->conv_msgstr) 821 free_conv_msgstr(gmnp); 822 } 823 } 824 825 if (conversion == 0) { 826 /* no conversion */ 827 result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); 828 return (result); 829 } 830 /* conversion required */ 831 832 if (new_encoding == 0) { 833 /* dst codeset hasn't been changed since before */ 834 if (!gmnp->conv_msgstr[midx]) { 835 /* this msgstr hasn't been converted yet */ 836 conv_msgstr_len = do_conv(gmnp->fd, 837 &conv_dst, (const char *)msgstr, msgstr_len); 838 if (conv_msgstr_len == (size_t)-1) { 839 result = dfltmsgstr(gmnp, msgstr, 840 msgstr_len, mp); 841 return (result); 842 } 843 buflen = (conv_msgstr_len + sizeof (size_t)); 844 /* allign to sizeof (size_t) */ 845 if (buflen % sizeof (size_t)) 846 buflen += (sizeof (size_t) - 847 (buflen % sizeof (size_t))); 848 p = (size_t *)malloc(buflen); 849 if (!p) { 850 free(conv_dst); 851 result = dfltmsgstr(gmnp, msgstr, 852 msgstr_len, mp); 853 return (result); 854 } 855 *p = conv_msgstr_len; 856 (void) memcpy(p + 1, conv_dst, conv_msgstr_len); 857 free(conv_dst); 858 gmnp->conv_msgstr[midx] = (char *)p; 859 conv_msgstr = (char *)(p + 1); 860 } else { 861 /* this msgstr is in the conversion cache */ 862 /* LINTED */ 863 size_t *cmsg = (size_t *)gmnp->conv_msgstr[midx]; 864 conv_msgstr_len = *cmsg; 865 conv_msgstr = (char *)(cmsg + 1); 866 } 867 result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); 868 return (result); 869 } 870 /* new conversion */ 871 #ifdef GETTEXT_DEBUG 872 (void) printf("******* calling iconv_open()\n"); 873 (void) printf(" dst: \"%s\", src: \"%s\"\n", 874 gmnp->dst_encoding, gmnp->src_encoding); 875 #endif 876 fd = iconv_open(gmnp->dst_encoding, gmnp->src_encoding); 877 gmnp->fd = fd; 878 if (fd == (iconv_t)-1) { 879 /* 880 * iconv_open() failed. 881 * no conversion 882 */ 883 result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); 884 return (result); 885 } 886 num_of_str = SWAP(gmnp, gmnp->msg_file_info->num_of_str); 887 gmnp->conv_msgstr = (char **)calloc((size_t)num_of_str, 888 sizeof (char *)); 889 if (!gmnp->conv_msgstr) { 890 /* malloc failed */ 891 result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); 892 return (result); 893 } 894 conv_msgstr_len = do_conv(gmnp->fd, &conv_dst, 895 (const char *)msgstr, msgstr_len); 896 if (conv_msgstr_len == (size_t)-1) { 897 free_conv_msgstr(gmnp); 898 result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); 899 return (result); 900 } 901 buflen = (conv_msgstr_len + sizeof (size_t)); 902 /* allign to sizeof (size_t) */ 903 if (buflen % sizeof (size_t)) 904 buflen += (sizeof (size_t) - (buflen % sizeof (size_t))); 905 p = (size_t *)malloc(buflen); 906 if (!p) { 907 free(conv_dst); 908 free_conv_msgstr(gmnp); 909 result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); 910 return (result); 911 } 912 *p = conv_msgstr_len; 913 (void) memcpy(p + 1, conv_dst, conv_msgstr_len); 914 free(conv_dst); 915 gmnp->conv_msgstr[midx] = (char *)p; 916 conv_msgstr = (char *)(p + 1); 917 result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); 918 return (result); 919 } 920