No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / src / message.c
blob27de7bf848e477e8614167961b8b8fa545245845
1 /* GNU gettext - internationalization aids
2 Copyright (C) 1995-1998, 2000-2004 Free Software Foundation, Inc.
4 This file was written by Peter Miller <millerp@canb.auug.org.au>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 /* Specification. */
25 #include "message.h"
27 #include <stdlib.h>
28 #include <string.h>
30 #include "fstrcmp.h"
31 #include "hash.h"
32 #include "xalloc.h"
35 const char *const format_language[NFORMATS] =
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"
59 const char *const format_language_pretty[NFORMATS] =
61 /* format_c */ "C",
62 /* format_objc */ "Objective C",
63 /* format_sh */ "Shell",
64 /* format_python */ "Python",
65 /* format_lisp */ "Lisp",
66 /* format_elisp */ "Emacs Lisp",
67 /* format_librep */ "librep",
68 /* format_scheme */ "Scheme",
69 /* format_smalltalk */ "Smalltalk",
70 /* format_java */ "Java",
71 /* format_csharp */ "C#",
72 /* format_awk */ "awk",
73 /* format_pascal */ "Object Pascal",
74 /* format_ycp */ "YCP",
75 /* format_tcl */ "Tcl",
76 /* format_perl */ "Perl",
77 /* format_perl_brace */ "Perl brace",
78 /* format_php */ "PHP",
79 /* format_gcc_internal */ "GCC internal",
80 /* format_qt */ "Qt"
84 bool
85 possible_format_p (enum is_format is_format)
87 return is_format == possible
88 || is_format == yes_according_to_context
89 || is_format == yes;
93 message_ty *
94 message_alloc (const char *msgid, const char *msgid_plural,
95 const char *msgstr, size_t msgstr_len,
96 const lex_pos_ty *pp)
98 message_ty *mp;
99 size_t i;
101 mp = (message_ty *) xmalloc (sizeof (message_ty));
102 mp->msgid = msgid;
103 mp->msgid_plural = (msgid_plural != NULL ? xstrdup (msgid_plural) : NULL);
104 mp->msgstr = msgstr;
105 mp->msgstr_len = msgstr_len;
106 mp->pos = *pp;
107 mp->comment = NULL;
108 mp->comment_dot = NULL;
109 mp->filepos_count = 0;
110 mp->filepos = NULL;
111 mp->is_fuzzy = false;
112 for (i = 0; i < NFORMATS; i++)
113 mp->is_format[i] = undecided;
114 mp->do_wrap = undecided;
115 mp->used = 0;
116 mp->obsolete = false;
117 return mp;
121 void
122 message_free (message_ty *mp)
124 size_t j;
126 free ((char *) mp->msgid);
127 if (mp->msgid_plural != NULL)
128 free ((char *) mp->msgid_plural);
129 free ((char *) mp->msgstr);
130 if (mp->comment != NULL)
131 string_list_free (mp->comment);
132 if (mp->comment_dot != NULL)
133 string_list_free (mp->comment_dot);
134 for (j = 0; j < mp->filepos_count; ++j)
135 free ((char *) mp->filepos[j].file_name);
136 if (mp->filepos != NULL)
137 free (mp->filepos);
138 free (mp);
142 void
143 message_comment_append (message_ty *mp, const char *s)
145 if (mp->comment == NULL)
146 mp->comment = string_list_alloc ();
147 string_list_append (mp->comment, s);
151 void
152 message_comment_dot_append (message_ty *mp, const char *s)
154 if (mp->comment_dot == NULL)
155 mp->comment_dot = string_list_alloc ();
156 string_list_append (mp->comment_dot, s);
160 void
161 message_comment_filepos (message_ty *mp, const char *name, size_t line)
163 size_t j;
164 size_t nbytes;
165 lex_pos_ty *pp;
167 /* See if we have this position already. */
168 for (j = 0; j < mp->filepos_count; j++)
170 pp = &mp->filepos[j];
171 if (strcmp (pp->file_name, name) == 0 && pp->line_number == line)
172 return;
175 /* Extend the list so that we can add a position to it. */
176 nbytes = (mp->filepos_count + 1) * sizeof (mp->filepos[0]);
177 mp->filepos = xrealloc (mp->filepos, nbytes);
179 /* Insert the position at the end. Don't sort the file positions here. */
180 pp = &mp->filepos[mp->filepos_count++];
181 pp->file_name = xstrdup (name);
182 pp->line_number = line;
186 message_ty *
187 message_copy (message_ty *mp)
189 message_ty *result;
190 size_t j, i;
192 result = message_alloc (xstrdup (mp->msgid), mp->msgid_plural,
193 mp->msgstr, mp->msgstr_len, &mp->pos);
195 if (mp->comment)
197 for (j = 0; j < mp->comment->nitems; ++j)
198 message_comment_append (result, mp->comment->item[j]);
200 if (mp->comment_dot)
202 for (j = 0; j < mp->comment_dot->nitems; ++j)
203 message_comment_dot_append (result, mp->comment_dot->item[j]);
205 result->is_fuzzy = mp->is_fuzzy;
206 for (i = 0; i < NFORMATS; i++)
207 result->is_format[i] = mp->is_format[i];
208 result->do_wrap = mp->do_wrap;
209 for (j = 0; j < mp->filepos_count; ++j)
211 lex_pos_ty *pp = &mp->filepos[j];
212 message_comment_filepos (result, pp->file_name, pp->line_number);
214 return result;
218 message_list_ty *
219 message_list_alloc (bool use_hashtable)
221 message_list_ty *mlp;
223 mlp = (message_list_ty *) xmalloc (sizeof (message_list_ty));
224 mlp->nitems = 0;
225 mlp->nitems_max = 0;
226 mlp->item = NULL;
227 if ((mlp->use_hashtable = use_hashtable))
228 init_hash (&mlp->htable, 10);
229 return mlp;
233 void
234 message_list_free (message_list_ty *mlp)
236 size_t j;
238 for (j = 0; j < mlp->nitems; ++j)
239 message_free (mlp->item[j]);
240 if (mlp->item)
241 free (mlp->item);
242 if (mlp->use_hashtable)
243 delete_hash (&mlp->htable);
244 free (mlp);
248 void
249 message_list_append (message_list_ty *mlp, message_ty *mp)
251 if (mlp->nitems >= mlp->nitems_max)
253 size_t nbytes;
255 mlp->nitems_max = mlp->nitems_max * 2 + 4;
256 nbytes = mlp->nitems_max * sizeof (message_ty *);
257 mlp->item = xrealloc (mlp->item, nbytes);
259 mlp->item[mlp->nitems++] = mp;
261 if (mlp->use_hashtable)
262 if (insert_entry (&mlp->htable, mp->msgid, strlen (mp->msgid) + 1, mp))
263 /* A message list has duplicates, although it was allocated with the
264 assertion that it wouldn't have duplicates. It is a bug. */
265 abort ();
269 void
270 message_list_prepend (message_list_ty *mlp, message_ty *mp)
272 size_t j;
274 if (mlp->nitems >= mlp->nitems_max)
276 size_t nbytes;
278 mlp->nitems_max = mlp->nitems_max * 2 + 4;
279 nbytes = mlp->nitems_max * sizeof (message_ty *);
280 mlp->item = xrealloc (mlp->item, nbytes);
282 for (j = mlp->nitems; j > 0; j--)
283 mlp->item[j] = mlp->item[j - 1];
284 mlp->item[0] = mp;
285 mlp->nitems++;
287 if (mlp->use_hashtable)
288 if (insert_entry (&mlp->htable, mp->msgid, strlen (mp->msgid) + 1, mp))
289 /* A message list has duplicates, although it was allocated with the
290 assertion that it wouldn't have duplicates. It is a bug. */
291 abort ();
295 void
296 message_list_insert_at (message_list_ty *mlp, size_t n, message_ty *mp)
298 size_t j;
300 if (mlp->nitems >= mlp->nitems_max)
302 size_t nbytes;
304 mlp->nitems_max = mlp->nitems_max * 2 + 4;
305 nbytes = mlp->nitems_max * sizeof (message_ty *);
306 mlp->item = xrealloc (mlp->item, nbytes);
308 for (j = mlp->nitems; j > n; j--)
309 mlp->item[j] = mlp->item[j - 1];
310 mlp->item[j] = mp;
311 mlp->nitems++;
313 if (mlp->use_hashtable)
314 if (insert_entry (&mlp->htable, mp->msgid, strlen (mp->msgid) + 1, mp))
315 /* A message list has duplicates, although it was allocated with the
316 assertion that it wouldn't have duplicates. It is a bug. */
317 abort ();
321 #if 0 /* unused */
322 void
323 message_list_delete_nth (message_list_ty *mlp, size_t n)
325 size_t j;
327 if (n >= mlp->nitems)
328 return;
329 message_free (mlp->item[n]);
330 for (j = n + 1; j < mlp->nitems; ++j)
331 mlp->item[j - 1] = mlp->item[j];
332 mlp->nitems--;
334 if (mlp->use_hashtable)
336 /* Our simple-minded hash tables don't support removal. */
337 delete_hash (&mlp->htable);
338 mlp->use_hashtable = false;
341 #endif
344 void
345 message_list_remove_if_not (message_list_ty *mlp,
346 message_predicate_ty *predicate)
348 size_t i, j;
350 for (j = 0, i = 0; j < mlp->nitems; j++)
351 if (predicate (mlp->item[j]))
352 mlp->item[i++] = mlp->item[j];
353 if (mlp->use_hashtable && i < mlp->nitems)
355 /* Our simple-minded hash tables don't support removal. */
356 delete_hash (&mlp->htable);
357 mlp->use_hashtable = false;
359 mlp->nitems = i;
363 bool
364 message_list_msgids_changed (message_list_ty *mlp)
366 if (mlp->use_hashtable)
368 unsigned long int size = mlp->htable.size;
369 size_t j;
371 delete_hash (&mlp->htable);
372 init_hash (&mlp->htable, size);
374 for (j = 0; j < mlp->nitems; j++)
376 message_ty *mp = mlp->item[j];
378 if (insert_entry (&mlp->htable, mp->msgid, strlen (mp->msgid) + 1,
379 mp))
380 /* A message list has duplicates, although it was allocated with
381 the assertion that it wouldn't have duplicates, and before the
382 msgids changed it indeed didn't have duplicates. */
384 delete_hash (&mlp->htable);
385 mlp->use_hashtable = false;
386 return true;
390 return false;
394 message_ty *
395 message_list_search (message_list_ty *mlp, const char *msgid)
397 if (mlp->use_hashtable)
399 void *htable_value;
401 if (find_entry (&mlp->htable, msgid, strlen (msgid) + 1, &htable_value))
402 return NULL;
403 else
404 return (message_ty *) htable_value;
406 else
408 size_t j;
410 for (j = 0; j < mlp->nitems; ++j)
412 message_ty *mp;
414 mp = mlp->item[j];
415 if (strcmp (msgid, mp->msgid) == 0)
416 return mp;
418 return NULL;
423 static message_ty *
424 message_list_search_fuzzy_inner (message_list_ty *mlp, const char *msgid,
425 double *best_weight_p)
427 size_t j;
428 message_ty *best_mp;
430 best_mp = NULL;
431 for (j = 0; j < mlp->nitems; ++j)
433 message_ty *mp;
435 mp = mlp->item[j];
437 if (mp->msgstr != NULL && mp->msgstr[0] != '\0')
439 double weight = fstrcmp (msgid, mp->msgid);
440 if (weight > *best_weight_p)
442 *best_weight_p = weight;
443 best_mp = mp;
447 return best_mp;
451 message_ty *
452 message_list_search_fuzzy (message_list_ty *mlp, const char *msgid)
454 double best_weight;
456 best_weight = 0.6;
457 return message_list_search_fuzzy_inner (mlp, msgid, &best_weight);
461 message_list_list_ty *
462 message_list_list_alloc ()
464 message_list_list_ty *mllp;
466 mllp = (message_list_list_ty *) xmalloc (sizeof (message_list_list_ty));
467 mllp->nitems = 0;
468 mllp->nitems_max = 0;
469 mllp->item = NULL;
470 return mllp;
474 #if 0 /* unused */
475 void
476 message_list_list_free (message_list_list_ty *mllp)
478 size_t j;
480 for (j = 0; j < mllp->nitems; ++j)
481 message_list_free (mllp->item[j]);
482 if (mllp->item)
483 free (mllp->item);
484 free (mllp);
486 #endif
489 void
490 message_list_list_append (message_list_list_ty *mllp, message_list_ty *mlp)
492 if (mllp->nitems >= mllp->nitems_max)
494 size_t nbytes;
496 mllp->nitems_max = mllp->nitems_max * 2 + 4;
497 nbytes = mllp->nitems_max * sizeof (message_list_ty *);
498 mllp->item = xrealloc (mllp->item, nbytes);
500 mllp->item[mllp->nitems++] = mlp;
504 void
505 message_list_list_append_list (message_list_list_ty *mllp,
506 message_list_list_ty *mllp2)
508 size_t j;
510 for (j = 0; j < mllp2->nitems; ++j)
511 message_list_list_append (mllp, mllp2->item[j]);
515 message_ty *
516 message_list_list_search (message_list_list_ty *mllp, const char *msgid)
518 message_ty *best_mp;
519 int best_weight; /* 0: not found, 1: found without msgstr, 2: translated */
520 size_t j;
522 best_mp = NULL;
523 best_weight = 0;
524 for (j = 0; j < mllp->nitems; ++j)
526 message_list_ty *mlp;
527 message_ty *mp;
529 mlp = mllp->item[j];
530 mp = message_list_search (mlp, msgid);
531 if (mp)
533 int weight = (mp->msgstr_len == 1 && mp->msgstr[0] == '\0' ? 1 : 2);
534 if (weight > best_weight)
536 best_mp = mp;
537 best_weight = weight;
541 return best_mp;
545 message_ty *
546 message_list_list_search_fuzzy (message_list_list_ty *mllp, const char *msgid)
548 size_t j;
549 double best_weight;
550 message_ty *best_mp;
552 best_weight = 0.6;
553 best_mp = NULL;
554 for (j = 0; j < mllp->nitems; ++j)
556 message_list_ty *mlp;
557 message_ty *mp;
559 mlp = mllp->item[j];
560 mp = message_list_search_fuzzy_inner (mlp, msgid, &best_weight);
561 if (mp)
562 best_mp = mp;
564 return best_mp;
568 msgdomain_ty*
569 msgdomain_alloc (const char *domain, bool use_hashtable)
571 msgdomain_ty *mdp;
573 mdp = (msgdomain_ty *) xmalloc (sizeof (msgdomain_ty));
574 mdp->domain = domain;
575 mdp->messages = message_list_alloc (use_hashtable);
576 return mdp;
580 void
581 msgdomain_free (msgdomain_ty *mdp)
583 message_list_free (mdp->messages);
584 free (mdp);
588 msgdomain_list_ty *
589 msgdomain_list_alloc (bool use_hashtable)
591 msgdomain_list_ty *mdlp;
593 mdlp = (msgdomain_list_ty *) xmalloc (sizeof (msgdomain_list_ty));
594 /* Put the default domain first, so that when we output it,
595 we can omit the 'domain' directive. */
596 mdlp->nitems = 1;
597 mdlp->nitems_max = 1;
598 mdlp->item =
599 (msgdomain_ty **) xmalloc (mdlp->nitems_max * sizeof (msgdomain_ty *));
600 mdlp->item[0] = msgdomain_alloc (MESSAGE_DOMAIN_DEFAULT, use_hashtable);
601 mdlp->use_hashtable = use_hashtable;
602 mdlp->encoding = NULL;
603 return mdlp;
607 void
608 msgdomain_list_free (msgdomain_list_ty *mdlp)
610 size_t j;
612 for (j = 0; j < mdlp->nitems; ++j)
613 msgdomain_free (mdlp->item[j]);
614 if (mdlp->item)
615 free (mdlp->item);
616 free (mdlp);
620 void
621 msgdomain_list_append (msgdomain_list_ty *mdlp, msgdomain_ty *mdp)
623 if (mdlp->nitems >= mdlp->nitems_max)
625 size_t nbytes;
627 mdlp->nitems_max = mdlp->nitems_max * 2 + 4;
628 nbytes = mdlp->nitems_max * sizeof (msgdomain_ty *);
629 mdlp->item = xrealloc (mdlp->item, nbytes);
631 mdlp->item[mdlp->nitems++] = mdp;
635 #if 0 /* unused */
636 void
637 msgdomain_list_append_list (msgdomain_list_ty *mdlp, msgdomain_list_ty *mdlp2)
639 size_t j;
641 for (j = 0; j < mdlp2->nitems; ++j)
642 msgdomain_list_append (mdlp, mdlp2->item[j]);
644 #endif
647 message_list_ty *
648 msgdomain_list_sublist (msgdomain_list_ty *mdlp, const char *domain,
649 bool create)
651 size_t j;
653 for (j = 0; j < mdlp->nitems; j++)
654 if (strcmp (mdlp->item[j]->domain, domain) == 0)
655 return mdlp->item[j]->messages;
657 if (create)
659 msgdomain_ty *mdp = msgdomain_alloc (domain, mdlp->use_hashtable);
660 msgdomain_list_append (mdlp, mdp);
661 return mdp->messages;
663 else
664 return NULL;
668 #if 0 /* unused */
669 message_ty *
670 msgdomain_list_search (msgdomain_list_ty *mdlp, const char *msgid)
672 size_t j;
674 for (j = 0; j < mdlp->nitems; ++j)
676 msgdomain_ty *mdp;
677 message_ty *mp;
679 mdp = mdlp->item[j];
680 mp = message_list_search (mdp->messages, msgid);
681 if (mp)
682 return mp;
684 return NULL;
686 #endif
689 #if 0 /* unused */
690 message_ty *
691 msgdomain_list_search_fuzzy (msgdomain_list_ty *mdlp, const char *msgid)
693 size_t j;
694 double best_weight;
695 message_ty *best_mp;
697 best_weight = 0.6;
698 best_mp = NULL;
699 for (j = 0; j < mdlp->nitems; ++j)
701 msgdomain_ty *mdp;
702 message_ty *mp;
704 mdp = mdlp->item[j];
705 mp = message_list_search_fuzzy_inner (mdp->messages, msgid, &best_weight);
706 if (mp)
707 best_mp = mp;
709 return best_mp;
711 #endif