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