1/* GNU gettext - internationalization aids 2 Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc. 3 4 This file was written by Peter Miller <millerp@canb.auug.org.au> 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23/* Specification. */ 24#include "message.h" 25 26#include <stdlib.h> 27#include <string.h> 28 29#include "fstrcmp.h" 30#include "hash.h" 31#include "xalloc.h" 32#include "xmalloca.h" 33 34 35const char *const format_language[NFORMATS] = 36{ 37 /* format_c */ "c", 38 /* format_objc */ "objc", 39 /* format_sh */ "sh", 40 /* format_python */ "python", 41 /* format_lisp */ "lisp", 42 /* format_elisp */ "elisp", 43 /* format_librep */ "librep", 44 /* format_scheme */ "scheme", 45 /* format_smalltalk */ "smalltalk", 46 /* format_java */ "java", 47 /* format_csharp */ "csharp", 48 /* format_awk */ "awk", 49 /* format_pascal */ "object-pascal", 50 /* format_ycp */ "ycp", 51 /* format_tcl */ "tcl", 52 /* format_perl */ "perl", 53 /* format_perl_brace */ "perl-brace", 54 /* format_php */ "php", 55 /* format_gcc_internal */ "gcc-internal", 56 /* format_qt */ "qt", 57 /* format_kde */ "kde", 58 /* format_boost */ "boost" 59}; 60 61const char *const format_language_pretty[NFORMATS] = 62{ 63 /* format_c */ "C", 64 /* format_objc */ "Objective C", 65 /* format_sh */ "Shell", 66 /* format_python */ "Python", 67 /* format_lisp */ "Lisp", 68 /* format_elisp */ "Emacs Lisp", 69 /* format_librep */ "librep", 70 /* format_scheme */ "Scheme", 71 /* format_smalltalk */ "Smalltalk", 72 /* format_java */ "Java", 73 /* format_csharp */ "C#", 74 /* format_awk */ "awk", 75 /* format_pascal */ "Object Pascal", 76 /* format_ycp */ "YCP", 77 /* format_tcl */ "Tcl", 78 /* format_perl */ "Perl", 79 /* format_perl_brace */ "Perl brace", 80 /* format_php */ "PHP", 81 /* format_gcc_internal */ "GCC internal", 82 /* format_qt */ "Qt", 83 /* format_kde */ "KDE", 84 /* format_boost */ "Boost" 85}; 86 87 88bool 89possible_format_p (enum is_format is_format) 90{ 91 return is_format == possible 92 || is_format == yes_according_to_context 93 || is_format == yes; 94} 95 96 97message_ty * 98message_alloc (const char *msgctxt, 99 const char *msgid, const char *msgid_plural, 100 const char *msgstr, size_t msgstr_len, 101 const lex_pos_ty *pp) 102{ 103 message_ty *mp; 104 size_t i; 105 106 mp = XMALLOC (message_ty); 107 mp->msgctxt = msgctxt; 108 mp->msgid = msgid; 109 mp->msgid_plural = (msgid_plural != NULL ? xstrdup (msgid_plural) : NULL); 110 mp->msgstr = msgstr; 111 mp->msgstr_len = msgstr_len; 112 mp->pos = *pp; 113 mp->comment = NULL; 114 mp->comment_dot = NULL; 115 mp->filepos_count = 0; 116 mp->filepos = NULL; 117 mp->is_fuzzy = false; 118 for (i = 0; i < NFORMATS; i++) 119 mp->is_format[i] = undecided; 120 mp->do_wrap = undecided; 121 mp->prev_msgctxt = NULL; 122 mp->prev_msgid = NULL; 123 mp->prev_msgid_plural = NULL; 124 mp->used = 0; 125 mp->obsolete = false; 126 return mp; 127} 128 129 130void 131message_free (message_ty *mp) 132{ 133 size_t j; 134 135 free ((char *) mp->msgid); 136 if (mp->msgid_plural != NULL) 137 free ((char *) mp->msgid_plural); 138 free ((char *) mp->msgstr); 139 if (mp->comment != NULL) 140 string_list_free (mp->comment); 141 if (mp->comment_dot != NULL) 142 string_list_free (mp->comment_dot); 143 for (j = 0; j < mp->filepos_count; ++j) 144 free ((char *) mp->filepos[j].file_name); 145 if (mp->filepos != NULL) 146 free (mp->filepos); 147 if (mp->prev_msgctxt != NULL) 148 free ((char *) mp->prev_msgctxt); 149 if (mp->prev_msgid != NULL) 150 free ((char *) mp->prev_msgid); 151 if (mp->prev_msgid_plural != NULL) 152 free ((char *) mp->prev_msgid_plural); 153 free (mp); 154} 155 156 157void 158message_comment_append (message_ty *mp, const char *s) 159{ 160 if (mp->comment == NULL) 161 mp->comment = string_list_alloc (); 162 string_list_append (mp->comment, s); 163} 164 165 166void 167message_comment_dot_append (message_ty *mp, const char *s) 168{ 169 if (mp->comment_dot == NULL) 170 mp->comment_dot = string_list_alloc (); 171 string_list_append (mp->comment_dot, s); 172} 173 174 175void 176message_comment_filepos (message_ty *mp, const char *name, size_t line) 177{ 178 size_t j; 179 size_t nbytes; 180 lex_pos_ty *pp; 181 182 /* See if we have this position already. */ 183 for (j = 0; j < mp->filepos_count; j++) 184 { 185 pp = &mp->filepos[j]; 186 if (strcmp (pp->file_name, name) == 0 && pp->line_number == line) 187 return; 188 } 189 190 /* Extend the list so that we can add a position to it. */ 191 nbytes = (mp->filepos_count + 1) * sizeof (mp->filepos[0]); 192 mp->filepos = xrealloc (mp->filepos, nbytes); 193 194 /* Insert the position at the end. Don't sort the file positions here. */ 195 pp = &mp->filepos[mp->filepos_count++]; 196 pp->file_name = xstrdup (name); 197 pp->line_number = line; 198} 199 200 201message_ty * 202message_copy (message_ty *mp) 203{ 204 message_ty *result; 205 size_t j, i; 206 207 result = message_alloc (mp->msgctxt != NULL ? xstrdup (mp->msgctxt) : NULL, 208 xstrdup (mp->msgid), mp->msgid_plural, 209 mp->msgstr, mp->msgstr_len, &mp->pos); 210 211 if (mp->comment) 212 { 213 for (j = 0; j < mp->comment->nitems; ++j) 214 message_comment_append (result, mp->comment->item[j]); 215 } 216 if (mp->comment_dot) 217 { 218 for (j = 0; j < mp->comment_dot->nitems; ++j) 219 message_comment_dot_append (result, mp->comment_dot->item[j]); 220 } 221 result->is_fuzzy = mp->is_fuzzy; 222 for (i = 0; i < NFORMATS; i++) 223 result->is_format[i] = mp->is_format[i]; 224 result->do_wrap = mp->do_wrap; 225 for (j = 0; j < mp->filepos_count; ++j) 226 { 227 lex_pos_ty *pp = &mp->filepos[j]; 228 message_comment_filepos (result, pp->file_name, pp->line_number); 229 } 230 result->prev_msgctxt = 231 (mp->prev_msgctxt != NULL ? xstrdup (mp->prev_msgctxt) : NULL); 232 result->prev_msgid = 233 (mp->prev_msgid != NULL ? xstrdup (mp->prev_msgid) : NULL); 234 result->prev_msgid_plural = 235 (mp->prev_msgid_plural != NULL ? xstrdup (mp->prev_msgid_plural) : NULL); 236 return result; 237} 238 239 240message_list_ty * 241message_list_alloc (bool use_hashtable) 242{ 243 message_list_ty *mlp; 244 245 mlp = XMALLOC (message_list_ty); 246 mlp->nitems = 0; 247 mlp->nitems_max = 0; 248 mlp->item = NULL; 249 if ((mlp->use_hashtable = use_hashtable)) 250 hash_init (&mlp->htable, 10); 251 return mlp; 252} 253 254 255void 256message_list_free (message_list_ty *mlp, int keep_messages) 257{ 258 size_t j; 259 260 if (keep_messages == 0) 261 for (j = 0; j < mlp->nitems; ++j) 262 message_free (mlp->item[j]); 263 if (mlp->item) 264 free (mlp->item); 265 if (mlp->use_hashtable) 266 hash_destroy (&mlp->htable); 267 free (mlp); 268} 269 270 271static int 272message_list_hash_insert_entry (hash_table *htable, message_ty *mp) 273{ 274 char *alloced_key; 275 const char *key; 276 size_t keylen; 277 int found; 278 279 if (mp->msgctxt != NULL) 280 { 281 /* Concatenate mp->msgctxt and mp->msgid, to form the hash table key. */ 282 size_t msgctxt_len = strlen (mp->msgctxt); 283 size_t msgid_len = strlen (mp->msgid); 284 keylen = msgctxt_len + 1 + msgid_len + 1; 285 alloced_key = (char *) xmalloca (keylen); 286 memcpy (alloced_key, mp->msgctxt, msgctxt_len); 287 alloced_key[msgctxt_len] = MSGCTXT_SEPARATOR; 288 memcpy (alloced_key + msgctxt_len + 1, mp->msgid, msgid_len + 1); 289 key = alloced_key; 290 } 291 else 292 { 293 alloced_key = NULL; 294 key = mp->msgid; 295 keylen = strlen (mp->msgid) + 1; 296 } 297 298 found = (hash_insert_entry (htable, key, keylen, mp) == NULL); 299 300 if (mp->msgctxt != NULL) 301 freea (alloced_key); 302 303 return found; 304} 305 306 307void 308message_list_append (message_list_ty *mlp, message_ty *mp) 309{ 310 if (mlp->nitems >= mlp->nitems_max) 311 { 312 size_t nbytes; 313 314 mlp->nitems_max = mlp->nitems_max * 2 + 4; 315 nbytes = mlp->nitems_max * sizeof (message_ty *); 316 mlp->item = xrealloc (mlp->item, nbytes); 317 } 318 mlp->item[mlp->nitems++] = mp; 319 320 if (mlp->use_hashtable) 321 if (message_list_hash_insert_entry (&mlp->htable, mp)) 322 /* A message list has duplicates, although it was allocated with the 323 assertion that it wouldn't have duplicates. It is a bug. */ 324 abort (); 325} 326 327 328void 329message_list_prepend (message_list_ty *mlp, message_ty *mp) 330{ 331 size_t j; 332 333 if (mlp->nitems >= mlp->nitems_max) 334 { 335 size_t nbytes; 336 337 mlp->nitems_max = mlp->nitems_max * 2 + 4; 338 nbytes = mlp->nitems_max * sizeof (message_ty *); 339 mlp->item = xrealloc (mlp->item, nbytes); 340 } 341 for (j = mlp->nitems; j > 0; j--) 342 mlp->item[j] = mlp->item[j - 1]; 343 mlp->item[0] = mp; 344 mlp->nitems++; 345 346 if (mlp->use_hashtable) 347 if (message_list_hash_insert_entry (&mlp->htable, mp)) 348 /* A message list has duplicates, although it was allocated with the 349 assertion that it wouldn't have duplicates. It is a bug. */ 350 abort (); 351} 352 353 354void 355message_list_insert_at (message_list_ty *mlp, size_t n, message_ty *mp) 356{ 357 size_t j; 358 359 if (mlp->nitems >= mlp->nitems_max) 360 { 361 size_t nbytes; 362 363 mlp->nitems_max = mlp->nitems_max * 2 + 4; 364 nbytes = mlp->nitems_max * sizeof (message_ty *); 365 mlp->item = xrealloc (mlp->item, nbytes); 366 } 367 for (j = mlp->nitems; j > n; j--) 368 mlp->item[j] = mlp->item[j - 1]; 369 mlp->item[j] = mp; 370 mlp->nitems++; 371 372 if (mlp->use_hashtable) 373 if (message_list_hash_insert_entry (&mlp->htable, mp)) 374 /* A message list has duplicates, although it was allocated with the 375 assertion that it wouldn't have duplicates. It is a bug. */ 376 abort (); 377} 378 379 380#if 0 /* unused */ 381void 382message_list_delete_nth (message_list_ty *mlp, size_t n) 383{ 384 size_t j; 385 386 if (n >= mlp->nitems) 387 return; 388 message_free (mlp->item[n]); 389 for (j = n + 1; j < mlp->nitems; ++j) 390 mlp->item[j - 1] = mlp->item[j]; 391 mlp->nitems--; 392 393 if (mlp->use_hashtable) 394 { 395 /* Our simple-minded hash tables don't support removal. */ 396 hash_destroy (&mlp->htable); 397 mlp->use_hashtable = false; 398 } 399} 400#endif 401 402 403void 404message_list_remove_if_not (message_list_ty *mlp, 405 message_predicate_ty *predicate) 406{ 407 size_t i, j; 408 409 for (j = 0, i = 0; j < mlp->nitems; j++) 410 if (predicate (mlp->item[j])) 411 mlp->item[i++] = mlp->item[j]; 412 if (mlp->use_hashtable && i < mlp->nitems) 413 { 414 /* Our simple-minded hash tables don't support removal. */ 415 hash_destroy (&mlp->htable); 416 mlp->use_hashtable = false; 417 } 418 mlp->nitems = i; 419} 420 421 422bool 423message_list_msgids_changed (message_list_ty *mlp) 424{ 425 if (mlp->use_hashtable) 426 { 427 unsigned long int size = mlp->htable.size; 428 size_t j; 429 430 hash_destroy (&mlp->htable); 431 hash_init (&mlp->htable, size); 432 433 for (j = 0; j < mlp->nitems; j++) 434 { 435 message_ty *mp = mlp->item[j]; 436 437 if (message_list_hash_insert_entry (&mlp->htable, mp)) 438 /* A message list has duplicates, although it was allocated with 439 the assertion that it wouldn't have duplicates, and before the 440 msgids changed it indeed didn't have duplicates. */ 441 { 442 hash_destroy (&mlp->htable); 443 mlp->use_hashtable = false; 444 return true; 445 } 446 } 447 } 448 return false; 449} 450 451 452message_list_ty * 453message_list_copy (message_list_ty *mlp, int copy_level) 454{ 455 message_list_ty *result; 456 size_t j; 457 458 result = message_list_alloc (mlp->use_hashtable); 459 for (j = 0; j < mlp->nitems; j++) 460 { 461 message_ty *mp = mlp->item[j]; 462 463 message_list_append (result, copy_level ? mp : message_copy (mp)); 464 } 465 466 return result; 467} 468 469 470message_ty * 471message_list_search (message_list_ty *mlp, 472 const char *msgctxt, const char *msgid) 473{ 474 if (mlp->use_hashtable) 475 { 476 char *alloced_key; 477 const char *key; 478 size_t keylen; 479 480 if (msgctxt != NULL) 481 { 482 /* Concatenate the msgctxt and msgid, to form the hash table key. */ 483 size_t msgctxt_len = strlen (msgctxt); 484 size_t msgid_len = strlen (msgid); 485 keylen = msgctxt_len + 1 + msgid_len + 1; 486 alloced_key = (char *) xmalloca (keylen); 487 memcpy (alloced_key, msgctxt, msgctxt_len); 488 alloced_key[msgctxt_len] = MSGCTXT_SEPARATOR; 489 memcpy (alloced_key + msgctxt_len + 1, msgid, msgid_len + 1); 490 key = alloced_key; 491 } 492 else 493 { 494 alloced_key = NULL; 495 key = msgid; 496 keylen = strlen (msgid) + 1; 497 } 498 499 { 500 void *htable_value; 501 int found = !hash_find_entry (&mlp->htable, key, keylen, &htable_value); 502 503 if (msgctxt != NULL) 504 freea (alloced_key); 505 506 if (found) 507 return (message_ty *) htable_value; 508 else 509 return NULL; 510 } 511 } 512 else 513 { 514 size_t j; 515 516 for (j = 0; j < mlp->nitems; ++j) 517 { 518 message_ty *mp; 519 520 mp = mlp->item[j]; 521 if ((msgctxt != NULL 522 ? mp->msgctxt != NULL && strcmp (msgctxt, mp->msgctxt) == 0 523 : mp->msgctxt == NULL) 524 && strcmp (msgid, mp->msgid) == 0) 525 return mp; 526 } 527 return NULL; 528 } 529} 530 531 532double 533fuzzy_search_goal_function (const message_ty *mp, 534 const char *msgctxt, const char *msgid) 535{ 536 /* The use of 'volatile' guarantees that excess precision bits are dropped 537 before the addition and before the following comparison at the caller's 538 site. It is necessary on x86 systems where double-floats are not IEEE 539 compliant by default, to avoid that msgmerge results become platform and 540 compiler option dependent. 'volatile' is a portable alternative to gcc's 541 -ffloat-store option. */ 542 volatile double weight = fstrcmp (msgid, mp->msgid); 543 /* A translation for a context is a good proposal also for another. But 544 give mp a small advantage if mp is valid regardless of any context or 545 has the same context as the one being looked up. */ 546 if (mp->msgctxt == NULL 547 || (msgctxt != NULL && strcmp (msgctxt, mp->msgctxt) == 0)) 548 weight += 0.00001; 549 return weight; 550} 551 552 553static message_ty * 554message_list_search_fuzzy_inner (message_list_ty *mlp, 555 const char *msgctxt, const char *msgid, 556 double *best_weight_p) 557{ 558 size_t j; 559 message_ty *best_mp; 560 561 best_mp = NULL; 562 for (j = 0; j < mlp->nitems; ++j) 563 { 564 message_ty *mp; 565 566 mp = mlp->item[j]; 567 568 if (mp->msgstr != NULL && mp->msgstr[0] != '\0') 569 { 570 double weight = fuzzy_search_goal_function (mp, msgctxt, msgid); 571 if (weight > *best_weight_p) 572 { 573 *best_weight_p = weight; 574 best_mp = mp; 575 } 576 } 577 } 578 return best_mp; 579} 580 581 582message_ty * 583message_list_search_fuzzy (message_list_ty *mlp, 584 const char *msgctxt, const char *msgid) 585{ 586 double best_weight; 587 588 best_weight = FUZZY_THRESHOLD; 589 return message_list_search_fuzzy_inner (mlp, msgctxt, msgid, &best_weight); 590} 591 592 593message_list_list_ty * 594message_list_list_alloc () 595{ 596 message_list_list_ty *mllp; 597 598 mllp = XMALLOC (message_list_list_ty); 599 mllp->nitems = 0; 600 mllp->nitems_max = 0; 601 mllp->item = NULL; 602 return mllp; 603} 604 605 606void 607message_list_list_free (message_list_list_ty *mllp, int keep_level) 608{ 609 size_t j; 610 611 if (keep_level < 2) 612 for (j = 0; j < mllp->nitems; ++j) 613 message_list_free (mllp->item[j], keep_level); 614 if (mllp->item) 615 free (mllp->item); 616 free (mllp); 617} 618 619 620void 621message_list_list_append (message_list_list_ty *mllp, message_list_ty *mlp) 622{ 623 if (mllp->nitems >= mllp->nitems_max) 624 { 625 size_t nbytes; 626 627 mllp->nitems_max = mllp->nitems_max * 2 + 4; 628 nbytes = mllp->nitems_max * sizeof (message_list_ty *); 629 mllp->item = xrealloc (mllp->item, nbytes); 630 } 631 mllp->item[mllp->nitems++] = mlp; 632} 633 634 635void 636message_list_list_append_list (message_list_list_ty *mllp, 637 message_list_list_ty *mllp2) 638{ 639 size_t j; 640 641 for (j = 0; j < mllp2->nitems; ++j) 642 message_list_list_append (mllp, mllp2->item[j]); 643} 644 645 646message_ty * 647message_list_list_search (message_list_list_ty *mllp, 648 const char *msgctxt, const char *msgid) 649{ 650 message_ty *best_mp; 651 int best_weight; /* 0: not found, 1: found without msgstr, 2: translated */ 652 size_t j; 653 654 best_mp = NULL; 655 best_weight = 0; 656 for (j = 0; j < mllp->nitems; ++j) 657 { 658 message_list_ty *mlp; 659 message_ty *mp; 660 661 mlp = mllp->item[j]; 662 mp = message_list_search (mlp, msgctxt, msgid); 663 if (mp) 664 { 665 int weight = (mp->msgstr_len == 1 && mp->msgstr[0] == '\0' ? 1 : 2); 666 if (weight > best_weight) 667 { 668 best_mp = mp; 669 best_weight = weight; 670 } 671 } 672 } 673 return best_mp; 674} 675 676 677#if 0 /* unused */ 678message_ty * 679message_list_list_search_fuzzy (message_list_list_ty *mllp, 680 const char *msgctxt, const char *msgid) 681{ 682 size_t j; 683 double best_weight; 684 message_ty *best_mp; 685 686 best_weight = FUZZY_THRESHOLD; 687 best_mp = NULL; 688 for (j = 0; j < mllp->nitems; ++j) 689 { 690 message_list_ty *mlp; 691 message_ty *mp; 692 693 mlp = mllp->item[j]; 694 mp = message_list_search_fuzzy_inner (mlp, msgctxt, msgid, &best_weight); 695 if (mp) 696 best_mp = mp; 697 } 698 return best_mp; 699} 700#endif 701 702 703msgdomain_ty* 704msgdomain_alloc (const char *domain, bool use_hashtable) 705{ 706 msgdomain_ty *mdp; 707 708 mdp = XMALLOC (msgdomain_ty); 709 mdp->domain = domain; 710 mdp->messages = message_list_alloc (use_hashtable); 711 return mdp; 712} 713 714 715void 716msgdomain_free (msgdomain_ty *mdp) 717{ 718 message_list_free (mdp->messages, 0); 719 free (mdp); 720} 721 722 723msgdomain_list_ty * 724msgdomain_list_alloc (bool use_hashtable) 725{ 726 msgdomain_list_ty *mdlp; 727 728 mdlp = XMALLOC (msgdomain_list_ty); 729 /* Put the default domain first, so that when we output it, 730 we can omit the 'domain' directive. */ 731 mdlp->nitems = 1; 732 mdlp->nitems_max = 1; 733 mdlp->item = XNMALLOC (mdlp->nitems_max, msgdomain_ty *); 734 mdlp->item[0] = msgdomain_alloc (MESSAGE_DOMAIN_DEFAULT, use_hashtable); 735 mdlp->use_hashtable = use_hashtable; 736 mdlp->encoding = NULL; 737 return mdlp; 738} 739 740 741void 742msgdomain_list_free (msgdomain_list_ty *mdlp) 743{ 744 size_t j; 745 746 for (j = 0; j < mdlp->nitems; ++j) 747 msgdomain_free (mdlp->item[j]); 748 if (mdlp->item) 749 free (mdlp->item); 750 free (mdlp); 751} 752 753 754void 755msgdomain_list_append (msgdomain_list_ty *mdlp, msgdomain_ty *mdp) 756{ 757 if (mdlp->nitems >= mdlp->nitems_max) 758 { 759 size_t nbytes; 760 761 mdlp->nitems_max = mdlp->nitems_max * 2 + 4; 762 nbytes = mdlp->nitems_max * sizeof (msgdomain_ty *); 763 mdlp->item = xrealloc (mdlp->item, nbytes); 764 } 765 mdlp->item[mdlp->nitems++] = mdp; 766} 767 768 769#if 0 /* unused */ 770void 771msgdomain_list_append_list (msgdomain_list_ty *mdlp, msgdomain_list_ty *mdlp2) 772{ 773 size_t j; 774 775 for (j = 0; j < mdlp2->nitems; ++j) 776 msgdomain_list_append (mdlp, mdlp2->item[j]); 777} 778#endif 779 780 781message_list_ty * 782msgdomain_list_sublist (msgdomain_list_ty *mdlp, const char *domain, 783 bool create) 784{ 785 size_t j; 786 787 for (j = 0; j < mdlp->nitems; j++) 788 if (strcmp (mdlp->item[j]->domain, domain) == 0) 789 return mdlp->item[j]->messages; 790 791 if (create) 792 { 793 msgdomain_ty *mdp = msgdomain_alloc (domain, mdlp->use_hashtable); 794 msgdomain_list_append (mdlp, mdp); 795 return mdp->messages; 796 } 797 else 798 return NULL; 799} 800 801 802/* Copy a message domain list. 803 If copy_level = 0, also copy the messages. If copy_level = 1, share the 804 messages but copy the domains. If copy_level = 2, share the domains. */ 805msgdomain_list_ty * 806msgdomain_list_copy (msgdomain_list_ty *mdlp, int copy_level) 807{ 808 msgdomain_list_ty *result; 809 size_t j; 810 811 result = XMALLOC (msgdomain_list_ty); 812 result->nitems = 0; 813 result->nitems_max = 0; 814 result->item = NULL; 815 result->use_hashtable = mdlp->use_hashtable; 816 result->encoding = mdlp->encoding; 817 818 for (j = 0; j < mdlp->nitems; j++) 819 { 820 msgdomain_ty *mdp = mdlp->item[j]; 821 822 if (copy_level < 2) 823 { 824 msgdomain_ty *result_mdp = XMALLOC (msgdomain_ty); 825 826 result_mdp->domain = mdp->domain; 827 result_mdp->messages = message_list_copy (mdp->messages, copy_level); 828 829 msgdomain_list_append (result, result_mdp); 830 } 831 else 832 msgdomain_list_append (result, mdp); 833 } 834 835 return result; 836} 837 838 839#if 0 /* unused */ 840message_ty * 841msgdomain_list_search (msgdomain_list_ty *mdlp, 842 const char *msgctxt, const char *msgid) 843{ 844 size_t j; 845 846 for (j = 0; j < mdlp->nitems; ++j) 847 { 848 msgdomain_ty *mdp; 849 message_ty *mp; 850 851 mdp = mdlp->item[j]; 852 mp = message_list_search (mdp->messages, msgctxt, msgid); 853 if (mp) 854 return mp; 855 } 856 return NULL; 857} 858#endif 859 860 861#if 0 /* unused */ 862message_ty * 863msgdomain_list_search_fuzzy (msgdomain_list_ty *mdlp, 864 const char *msgctxt, const char *msgid) 865{ 866 size_t j; 867 double best_weight; 868 message_ty *best_mp; 869 870 best_weight = FUZZY_THRESHOLD; 871 best_mp = NULL; 872 for (j = 0; j < mdlp->nitems; ++j) 873 { 874 msgdomain_ty *mdp; 875 message_ty *mp; 876 877 mdp = mdlp->item[j]; 878 mp = message_list_search_fuzzy_inner (mdp->messages, msgctxt, msgid, 879 &best_weight); 880 if (mp) 881 best_mp = mp; 882 } 883 return best_mp; 884} 885#endif 886