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
possible_format_p(enum is_format is_format)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 *
message_alloc(const char * msgctxt,const char * msgid,const char * msgid_plural,const char * msgstr,size_t msgstr_len,const lex_pos_ty * pp)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
message_free(message_ty * mp)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
message_comment_append(message_ty * mp,const char * s)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
message_comment_dot_append(message_ty * mp,const char * s)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
message_comment_filepos(message_ty * mp,const char * name,size_t line)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 *
message_copy(message_ty * mp)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 *
message_list_alloc(bool use_hashtable)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
message_list_free(message_list_ty * mlp,int keep_messages)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
message_list_hash_insert_entry(hash_table * htable,message_ty * mp)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
message_list_append(message_list_ty * mlp,message_ty * mp)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
message_list_prepend(message_list_ty * mlp,message_ty * mp)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
message_list_insert_at(message_list_ty * mlp,size_t n,message_ty * mp)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
message_list_remove_if_not(message_list_ty * mlp,message_predicate_ty * predicate)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
message_list_msgids_changed(message_list_ty * mlp)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 *
message_list_search(message_list_ty * mlp,const char * msgctxt,const char * msgid)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
fuzzy_search_goal_function(const message_ty * mp,const char * msgctxt,const char * msgid)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 *
message_list_search_fuzzy_inner(message_list_ty * mlp,const char * msgctxt,const char * msgid,double * best_weight_p)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 *
message_list_search_fuzzy(message_list_ty * mlp,const char * msgctxt,const char * msgid)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 *
message_list_list_alloc()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
message_list_list_free(message_list_list_ty * mllp,int keep_level)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
message_list_list_append(message_list_list_ty * mllp,message_list_ty * mlp)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
message_list_list_append_list(message_list_list_ty * mllp,message_list_list_ty * mllp2)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 *
message_list_list_search(message_list_list_ty * mllp,const char * msgctxt,const char * msgid)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*
msgdomain_alloc(const char * domain,bool use_hashtable)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
msgdomain_free(msgdomain_ty * mdp)697 msgdomain_free (msgdomain_ty *mdp)
698 {
699 message_list_free (mdp->messages, 0);
700 free (mdp);
701 }
702
703
704 msgdomain_list_ty *
msgdomain_list_alloc(bool use_hashtable)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
msgdomain_list_free(msgdomain_list_ty * mdlp)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
msgdomain_list_append(msgdomain_list_ty * mdlp,msgdomain_ty * mdp)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 *
msgdomain_list_sublist(msgdomain_list_ty * mdlp,const char * domain,bool create)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