• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/ap/gpl/timemachine/gettext-0.17/gettext-tools/src/
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