facf0c92e0
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
936 lines
23 KiB
C
936 lines
23 KiB
C
/* GNU gettext - internationalization aids
|
|
Copyright (C) 1995-1998, 2000-2010, 2012-2013, 2015-2016, 2019-2020, 2023 Free Software Foundation, Inc.
|
|
|
|
This file was written by Peter Miller <millerp@canb.auug.org.au>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
/* Specification. */
|
|
#include "message.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "fstrcmp.h"
|
|
#include "mem-hash-map.h"
|
|
#include "xalloc.h"
|
|
#include "xmalloca.h"
|
|
|
|
|
|
const char *const format_language[NFORMATS] =
|
|
{
|
|
/* format_c */ "c",
|
|
/* format_objc */ "objc",
|
|
/* format_cplusplus_brace */ "c++",
|
|
/* format_python */ "python",
|
|
/* format_python_brace */ "python-brace",
|
|
/* format_java */ "java",
|
|
/* format_java_printf */ "java-printf",
|
|
/* format_csharp */ "csharp",
|
|
/* format_javascript */ "javascript",
|
|
/* format_scheme */ "scheme",
|
|
/* format_lisp */ "lisp",
|
|
/* format_elisp */ "elisp",
|
|
/* format_librep */ "librep",
|
|
/* format_ruby */ "ruby",
|
|
/* format_sh */ "sh",
|
|
/* format_awk */ "awk",
|
|
/* format_lua */ "lua",
|
|
/* format_pascal */ "object-pascal",
|
|
/* format_smalltalk */ "smalltalk",
|
|
/* format_qt */ "qt",
|
|
/* format_qt_plursl */ "qt-plural",
|
|
/* format_kde */ "kde",
|
|
/* format_kde_kuit */ "kde-kuit",
|
|
/* format_boost */ "boost",
|
|
/* format_tcl */ "tcl",
|
|
/* format_perl */ "perl",
|
|
/* format_perl_brace */ "perl-brace",
|
|
/* format_php */ "php",
|
|
/* format_gcc_internal */ "gcc-internal",
|
|
/* format_gfc_internal */ "gfc-internal",
|
|
/* format_ycp */ "ycp"
|
|
};
|
|
|
|
const char *const format_language_pretty[NFORMATS] =
|
|
{
|
|
/* format_c */ "C",
|
|
/* format_objc */ "Objective C",
|
|
/* format_cplusplus_brace */ "C++",
|
|
/* format_python */ "Python",
|
|
/* format_python_brace */ "Python brace",
|
|
/* format_java */ "Java MessageFormat",
|
|
/* format_java_printf */ "Java printf",
|
|
/* format_csharp */ "C#",
|
|
/* format_javascript */ "JavaScript",
|
|
/* format_scheme */ "Scheme",
|
|
/* format_lisp */ "Lisp",
|
|
/* format_elisp */ "Emacs Lisp",
|
|
/* format_librep */ "librep",
|
|
/* format_ruby */ "Ruby",
|
|
/* format_sh */ "Shell",
|
|
/* format_awk */ "awk",
|
|
/* format_lua */ "Lua",
|
|
/* format_pascal */ "Object Pascal",
|
|
/* format_smalltalk */ "Smalltalk",
|
|
/* format_qt */ "Qt",
|
|
/* format_qt_plural */ "Qt plural",
|
|
/* format_kde */ "KDE",
|
|
/* format_kde_kuit */ "KDE KUIT",
|
|
/* format_boost */ "Boost",
|
|
/* format_tcl */ "Tcl",
|
|
/* format_perl */ "Perl",
|
|
/* format_perl_brace */ "Perl brace",
|
|
/* format_php */ "PHP",
|
|
/* format_gcc_internal */ "GCC internal",
|
|
/* format_gfc_internal */ "GFC internal",
|
|
/* format_ycp */ "YCP"
|
|
};
|
|
|
|
|
|
bool
|
|
possible_format_p (enum is_format is_format)
|
|
{
|
|
return is_format == possible
|
|
|| is_format == yes_according_to_context
|
|
|| is_format == yes;
|
|
}
|
|
|
|
|
|
const char *const syntax_check_name[NSYNTAXCHECKS] =
|
|
{
|
|
/* sc_ellipsis_unicode */ "ellipsis-unicode",
|
|
/* sc_space_ellipsis */ "space-ellipsis",
|
|
/* sc_quote_unicode */ "quote-unicode",
|
|
/* sc_bullet_unicode */ "bullet-unicode"
|
|
};
|
|
|
|
|
|
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)
|
|
{
|
|
message_ty *mp;
|
|
size_t i;
|
|
|
|
mp = XMALLOC (message_ty);
|
|
mp->msgctxt = msgctxt;
|
|
mp->msgid = msgid;
|
|
mp->msgid_plural = (msgid_plural != NULL ? xstrdup (msgid_plural) : NULL);
|
|
mp->msgstr = msgstr;
|
|
mp->msgstr_len = msgstr_len;
|
|
mp->pos = *pp;
|
|
mp->comment = NULL;
|
|
mp->comment_dot = NULL;
|
|
mp->filepos_count = 0;
|
|
mp->filepos = NULL;
|
|
mp->is_fuzzy = false;
|
|
for (i = 0; i < NFORMATS; i++)
|
|
mp->is_format[i] = undecided;
|
|
mp->range.min = -1;
|
|
mp->range.max = -1;
|
|
mp->do_wrap = undecided;
|
|
for (i = 0; i < NSYNTAXCHECKS; i++)
|
|
mp->do_syntax_check[i] = undecided;
|
|
mp->prev_msgctxt = NULL;
|
|
mp->prev_msgid = NULL;
|
|
mp->prev_msgid_plural = NULL;
|
|
mp->used = 0;
|
|
mp->obsolete = false;
|
|
return mp;
|
|
}
|
|
|
|
|
|
void
|
|
message_free (message_ty *mp)
|
|
{
|
|
size_t j;
|
|
|
|
free ((char *) mp->msgid);
|
|
if (mp->msgid_plural != NULL)
|
|
free ((char *) mp->msgid_plural);
|
|
free ((char *) mp->msgstr);
|
|
if (mp->comment != NULL)
|
|
string_list_free (mp->comment);
|
|
if (mp->comment_dot != NULL)
|
|
string_list_free (mp->comment_dot);
|
|
for (j = 0; j < mp->filepos_count; ++j)
|
|
free ((char *) mp->filepos[j].file_name);
|
|
if (mp->filepos != NULL)
|
|
free (mp->filepos);
|
|
if (mp->prev_msgctxt != NULL)
|
|
free ((char *) mp->prev_msgctxt);
|
|
if (mp->prev_msgid != NULL)
|
|
free ((char *) mp->prev_msgid);
|
|
if (mp->prev_msgid_plural != NULL)
|
|
free ((char *) mp->prev_msgid_plural);
|
|
free (mp);
|
|
}
|
|
|
|
|
|
void
|
|
message_comment_append (message_ty *mp, const char *s)
|
|
{
|
|
if (mp->comment == NULL)
|
|
mp->comment = string_list_alloc ();
|
|
string_list_append (mp->comment, s);
|
|
}
|
|
|
|
|
|
void
|
|
message_comment_dot_append (message_ty *mp, const char *s)
|
|
{
|
|
if (mp->comment_dot == NULL)
|
|
mp->comment_dot = string_list_alloc ();
|
|
string_list_append (mp->comment_dot, s);
|
|
}
|
|
|
|
|
|
void
|
|
message_comment_filepos (message_ty *mp, const char *name, size_t line)
|
|
{
|
|
size_t j;
|
|
size_t nbytes;
|
|
lex_pos_ty *pp;
|
|
|
|
/* See if we have this position already. */
|
|
for (j = 0; j < mp->filepos_count; j++)
|
|
{
|
|
pp = &mp->filepos[j];
|
|
if (strcmp (pp->file_name, name) == 0 && pp->line_number == line)
|
|
return;
|
|
}
|
|
|
|
/* Extend the list so that we can add a position to it. */
|
|
nbytes = (mp->filepos_count + 1) * sizeof (mp->filepos[0]);
|
|
mp->filepos = xrealloc (mp->filepos, nbytes);
|
|
|
|
/* Insert the position at the end. Don't sort the file positions here. */
|
|
pp = &mp->filepos[mp->filepos_count++];
|
|
pp->file_name = xstrdup (name);
|
|
pp->line_number = line;
|
|
}
|
|
|
|
|
|
message_ty *
|
|
message_copy (message_ty *mp)
|
|
{
|
|
message_ty *result;
|
|
size_t j, i;
|
|
|
|
result = message_alloc (mp->msgctxt != NULL ? xstrdup (mp->msgctxt) : NULL,
|
|
xstrdup (mp->msgid), mp->msgid_plural,
|
|
mp->msgstr, mp->msgstr_len, &mp->pos);
|
|
|
|
if (mp->comment)
|
|
{
|
|
for (j = 0; j < mp->comment->nitems; ++j)
|
|
message_comment_append (result, mp->comment->item[j]);
|
|
}
|
|
if (mp->comment_dot)
|
|
{
|
|
for (j = 0; j < mp->comment_dot->nitems; ++j)
|
|
message_comment_dot_append (result, mp->comment_dot->item[j]);
|
|
}
|
|
result->is_fuzzy = mp->is_fuzzy;
|
|
for (i = 0; i < NFORMATS; i++)
|
|
result->is_format[i] = mp->is_format[i];
|
|
result->range = mp->range;
|
|
result->do_wrap = mp->do_wrap;
|
|
for (i = 0; i < NSYNTAXCHECKS; i++)
|
|
result->do_syntax_check[i] = mp->do_syntax_check[i];
|
|
for (j = 0; j < mp->filepos_count; ++j)
|
|
{
|
|
lex_pos_ty *pp = &mp->filepos[j];
|
|
message_comment_filepos (result, pp->file_name, pp->line_number);
|
|
}
|
|
result->prev_msgctxt =
|
|
(mp->prev_msgctxt != NULL ? xstrdup (mp->prev_msgctxt) : NULL);
|
|
result->prev_msgid =
|
|
(mp->prev_msgid != NULL ? xstrdup (mp->prev_msgid) : NULL);
|
|
result->prev_msgid_plural =
|
|
(mp->prev_msgid_plural != NULL ? xstrdup (mp->prev_msgid_plural) : NULL);
|
|
return result;
|
|
}
|
|
|
|
|
|
message_list_ty *
|
|
message_list_alloc (bool use_hashtable)
|
|
{
|
|
message_list_ty *mlp;
|
|
|
|
mlp = XMALLOC (message_list_ty);
|
|
mlp->nitems = 0;
|
|
mlp->nitems_max = 0;
|
|
mlp->item = NULL;
|
|
if ((mlp->use_hashtable = use_hashtable))
|
|
hash_init (&mlp->htable, 10);
|
|
return mlp;
|
|
}
|
|
|
|
|
|
void
|
|
message_list_free (message_list_ty *mlp, int keep_messages)
|
|
{
|
|
size_t j;
|
|
|
|
if (keep_messages == 0)
|
|
for (j = 0; j < mlp->nitems; ++j)
|
|
message_free (mlp->item[j]);
|
|
if (mlp->item)
|
|
free (mlp->item);
|
|
if (mlp->use_hashtable)
|
|
hash_destroy (&mlp->htable);
|
|
free (mlp);
|
|
}
|
|
|
|
|
|
static int
|
|
message_list_hash_insert_entry (hash_table *htable, message_ty *mp)
|
|
{
|
|
char *alloced_key;
|
|
const char *key;
|
|
size_t keylen;
|
|
int found;
|
|
|
|
if (mp->msgctxt != NULL)
|
|
{
|
|
/* Concatenate mp->msgctxt and mp->msgid, to form the hash table key. */
|
|
size_t msgctxt_len = strlen (mp->msgctxt);
|
|
size_t msgid_len = strlen (mp->msgid);
|
|
keylen = msgctxt_len + 1 + msgid_len + 1;
|
|
alloced_key = (char *) xmalloca (keylen);
|
|
memcpy (alloced_key, mp->msgctxt, msgctxt_len);
|
|
alloced_key[msgctxt_len] = MSGCTXT_SEPARATOR;
|
|
memcpy (alloced_key + msgctxt_len + 1, mp->msgid, msgid_len + 1);
|
|
key = alloced_key;
|
|
}
|
|
else
|
|
{
|
|
alloced_key = NULL;
|
|
key = mp->msgid;
|
|
keylen = strlen (mp->msgid) + 1;
|
|
}
|
|
|
|
found = (hash_insert_entry (htable, key, keylen, mp) == NULL);
|
|
|
|
if (mp->msgctxt != NULL)
|
|
freea (alloced_key);
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
void
|
|
message_list_append (message_list_ty *mlp, message_ty *mp)
|
|
{
|
|
if (mlp->nitems >= mlp->nitems_max)
|
|
{
|
|
size_t nbytes;
|
|
|
|
mlp->nitems_max = mlp->nitems_max * 2 + 4;
|
|
nbytes = mlp->nitems_max * sizeof (message_ty *);
|
|
mlp->item = xrealloc (mlp->item, nbytes);
|
|
}
|
|
mlp->item[mlp->nitems++] = mp;
|
|
|
|
if (mlp->use_hashtable)
|
|
if (message_list_hash_insert_entry (&mlp->htable, mp))
|
|
/* A message list has duplicates, although it was allocated with the
|
|
assertion that it wouldn't have duplicates. It is a bug. */
|
|
abort ();
|
|
}
|
|
|
|
|
|
void
|
|
message_list_prepend (message_list_ty *mlp, message_ty *mp)
|
|
{
|
|
size_t j;
|
|
|
|
if (mlp->nitems >= mlp->nitems_max)
|
|
{
|
|
size_t nbytes;
|
|
|
|
mlp->nitems_max = mlp->nitems_max * 2 + 4;
|
|
nbytes = mlp->nitems_max * sizeof (message_ty *);
|
|
mlp->item = xrealloc (mlp->item, nbytes);
|
|
}
|
|
for (j = mlp->nitems; j > 0; j--)
|
|
mlp->item[j] = mlp->item[j - 1];
|
|
mlp->item[0] = mp;
|
|
mlp->nitems++;
|
|
|
|
if (mlp->use_hashtable)
|
|
if (message_list_hash_insert_entry (&mlp->htable, mp))
|
|
/* A message list has duplicates, although it was allocated with the
|
|
assertion that it wouldn't have duplicates. It is a bug. */
|
|
abort ();
|
|
}
|
|
|
|
|
|
void
|
|
message_list_insert_at (message_list_ty *mlp, size_t n, message_ty *mp)
|
|
{
|
|
size_t j;
|
|
|
|
if (mlp->nitems >= mlp->nitems_max)
|
|
{
|
|
size_t nbytes;
|
|
|
|
mlp->nitems_max = mlp->nitems_max * 2 + 4;
|
|
nbytes = mlp->nitems_max * sizeof (message_ty *);
|
|
mlp->item = xrealloc (mlp->item, nbytes);
|
|
}
|
|
for (j = mlp->nitems; j > n; j--)
|
|
mlp->item[j] = mlp->item[j - 1];
|
|
mlp->item[j] = mp;
|
|
mlp->nitems++;
|
|
|
|
if (mlp->use_hashtable)
|
|
if (message_list_hash_insert_entry (&mlp->htable, mp))
|
|
/* A message list has duplicates, although it was allocated with the
|
|
assertion that it wouldn't have duplicates. It is a bug. */
|
|
abort ();
|
|
}
|
|
|
|
|
|
#if 0 /* unused */
|
|
void
|
|
message_list_delete_nth (message_list_ty *mlp, size_t n)
|
|
{
|
|
size_t j;
|
|
|
|
if (n >= mlp->nitems)
|
|
return;
|
|
message_free (mlp->item[n]);
|
|
for (j = n + 1; j < mlp->nitems; ++j)
|
|
mlp->item[j - 1] = mlp->item[j];
|
|
mlp->nitems--;
|
|
|
|
if (mlp->use_hashtable)
|
|
{
|
|
/* Our simple-minded hash tables don't support removal. */
|
|
hash_destroy (&mlp->htable);
|
|
mlp->use_hashtable = false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
message_list_remove_if_not (message_list_ty *mlp,
|
|
message_predicate_ty *predicate)
|
|
{
|
|
size_t i, j;
|
|
|
|
for (j = 0, i = 0; j < mlp->nitems; j++)
|
|
if (predicate (mlp->item[j]))
|
|
mlp->item[i++] = mlp->item[j];
|
|
if (mlp->use_hashtable && i < mlp->nitems)
|
|
{
|
|
/* Our simple-minded hash tables don't support removal. */
|
|
hash_destroy (&mlp->htable);
|
|
mlp->use_hashtable = false;
|
|
}
|
|
mlp->nitems = i;
|
|
}
|
|
|
|
|
|
bool
|
|
message_list_msgids_changed (message_list_ty *mlp)
|
|
{
|
|
if (mlp->use_hashtable)
|
|
{
|
|
unsigned long int size = mlp->htable.size;
|
|
size_t j;
|
|
|
|
hash_destroy (&mlp->htable);
|
|
hash_init (&mlp->htable, size);
|
|
|
|
for (j = 0; j < mlp->nitems; j++)
|
|
{
|
|
message_ty *mp = mlp->item[j];
|
|
|
|
if (message_list_hash_insert_entry (&mlp->htable, mp))
|
|
/* A message list has duplicates, although it was allocated with
|
|
the assertion that it wouldn't have duplicates, and before the
|
|
msgids changed it indeed didn't have duplicates. */
|
|
{
|
|
hash_destroy (&mlp->htable);
|
|
mlp->use_hashtable = false;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
message_list_ty *
|
|
message_list_copy (message_list_ty *mlp, int copy_level)
|
|
{
|
|
message_list_ty *result;
|
|
size_t j;
|
|
|
|
result = message_list_alloc (mlp->use_hashtable);
|
|
for (j = 0; j < mlp->nitems; j++)
|
|
{
|
|
message_ty *mp = mlp->item[j];
|
|
|
|
message_list_append (result, copy_level ? mp : message_copy (mp));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
message_ty *
|
|
message_list_search (message_list_ty *mlp,
|
|
const char *msgctxt, const char *msgid)
|
|
{
|
|
if (mlp->use_hashtable)
|
|
{
|
|
char *alloced_key;
|
|
const char *key;
|
|
size_t keylen;
|
|
|
|
if (msgctxt != NULL)
|
|
{
|
|
/* Concatenate the msgctxt and msgid, to form the hash table key. */
|
|
size_t msgctxt_len = strlen (msgctxt);
|
|
size_t msgid_len = strlen (msgid);
|
|
keylen = msgctxt_len + 1 + msgid_len + 1;
|
|
alloced_key = (char *) xmalloca (keylen);
|
|
memcpy (alloced_key, msgctxt, msgctxt_len);
|
|
alloced_key[msgctxt_len] = MSGCTXT_SEPARATOR;
|
|
memcpy (alloced_key + msgctxt_len + 1, msgid, msgid_len + 1);
|
|
key = alloced_key;
|
|
}
|
|
else
|
|
{
|
|
alloced_key = NULL;
|
|
key = msgid;
|
|
keylen = strlen (msgid) + 1;
|
|
}
|
|
|
|
{
|
|
void *htable_value;
|
|
int found = !hash_find_entry (&mlp->htable, key, keylen, &htable_value);
|
|
|
|
if (msgctxt != NULL)
|
|
freea (alloced_key);
|
|
|
|
if (found)
|
|
return (message_ty *) htable_value;
|
|
else
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size_t j;
|
|
|
|
for (j = 0; j < mlp->nitems; ++j)
|
|
{
|
|
message_ty *mp;
|
|
|
|
mp = mlp->item[j];
|
|
if ((msgctxt != NULL
|
|
? mp->msgctxt != NULL && strcmp (msgctxt, mp->msgctxt) == 0
|
|
: mp->msgctxt == NULL)
|
|
&& strcmp (msgid, mp->msgid) == 0)
|
|
return mp;
|
|
}
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
double
|
|
fuzzy_search_goal_function (const message_ty *mp,
|
|
const char *msgctxt, const char *msgid,
|
|
double lower_bound)
|
|
{
|
|
double bonus = 0.0;
|
|
/* A translation for a context is a good proposal also for another. But
|
|
give mp a small advantage if mp is valid regardless of any context or
|
|
has the same context as the one being looked up. */
|
|
if (mp->msgctxt == NULL
|
|
|| (msgctxt != NULL && strcmp (msgctxt, mp->msgctxt) == 0))
|
|
{
|
|
bonus = 0.00001;
|
|
/* Since we will consider (weight + bonus) at the end, we are only
|
|
interested in weights that are >= lower_bound - bonus. Subtract
|
|
a little more than the bonus, in order to avoid trouble due to
|
|
rounding errors. */
|
|
lower_bound -= bonus * 1.01;
|
|
}
|
|
|
|
{
|
|
/* The use of 'volatile' guarantees that excess precision bits are dropped
|
|
before the addition and before the following comparison at the caller's
|
|
site. It is necessary on x86 systems where double-floats are not IEEE
|
|
compliant by default, to avoid that msgmerge results become platform and
|
|
compiler option dependent. 'volatile' is a portable alternative to
|
|
gcc's -ffloat-store option. */
|
|
volatile double weight = fstrcmp_bounded (msgid, mp->msgid, lower_bound);
|
|
|
|
weight += bonus;
|
|
|
|
return weight;
|
|
}
|
|
}
|
|
|
|
|
|
static message_ty *
|
|
message_list_search_fuzzy_inner (message_list_ty *mlp,
|
|
const char *msgctxt, const char *msgid,
|
|
double *best_weight_p)
|
|
{
|
|
size_t j;
|
|
message_ty *best_mp;
|
|
|
|
best_mp = NULL;
|
|
for (j = 0; j < mlp->nitems; ++j)
|
|
{
|
|
message_ty *mp;
|
|
|
|
mp = mlp->item[j];
|
|
|
|
if (mp->msgstr != NULL && mp->msgstr[0] != '\0')
|
|
{
|
|
double weight =
|
|
fuzzy_search_goal_function (mp, msgctxt, msgid, *best_weight_p);
|
|
if (weight > *best_weight_p)
|
|
{
|
|
*best_weight_p = weight;
|
|
best_mp = mp;
|
|
}
|
|
}
|
|
}
|
|
return best_mp;
|
|
}
|
|
|
|
|
|
message_ty *
|
|
message_list_search_fuzzy (message_list_ty *mlp,
|
|
const char *msgctxt, const char *msgid)
|
|
{
|
|
double best_weight;
|
|
|
|
best_weight = FUZZY_THRESHOLD;
|
|
return message_list_search_fuzzy_inner (mlp, msgctxt, msgid, &best_weight);
|
|
}
|
|
|
|
|
|
message_list_list_ty *
|
|
message_list_list_alloc ()
|
|
{
|
|
message_list_list_ty *mllp;
|
|
|
|
mllp = XMALLOC (message_list_list_ty);
|
|
mllp->nitems = 0;
|
|
mllp->nitems_max = 0;
|
|
mllp->item = NULL;
|
|
return mllp;
|
|
}
|
|
|
|
|
|
void
|
|
message_list_list_free (message_list_list_ty *mllp, int keep_level)
|
|
{
|
|
size_t j;
|
|
|
|
if (keep_level < 2)
|
|
for (j = 0; j < mllp->nitems; ++j)
|
|
message_list_free (mllp->item[j], keep_level);
|
|
if (mllp->item)
|
|
free (mllp->item);
|
|
free (mllp);
|
|
}
|
|
|
|
|
|
void
|
|
message_list_list_append (message_list_list_ty *mllp, message_list_ty *mlp)
|
|
{
|
|
if (mllp->nitems >= mllp->nitems_max)
|
|
{
|
|
size_t nbytes;
|
|
|
|
mllp->nitems_max = mllp->nitems_max * 2 + 4;
|
|
nbytes = mllp->nitems_max * sizeof (message_list_ty *);
|
|
mllp->item = xrealloc (mllp->item, nbytes);
|
|
}
|
|
mllp->item[mllp->nitems++] = mlp;
|
|
}
|
|
|
|
|
|
void
|
|
message_list_list_append_list (message_list_list_ty *mllp,
|
|
message_list_list_ty *mllp2)
|
|
{
|
|
size_t j;
|
|
|
|
for (j = 0; j < mllp2->nitems; ++j)
|
|
message_list_list_append (mllp, mllp2->item[j]);
|
|
}
|
|
|
|
|
|
message_ty *
|
|
message_list_list_search (message_list_list_ty *mllp,
|
|
const char *msgctxt, const char *msgid)
|
|
{
|
|
message_ty *best_mp;
|
|
int best_weight; /* 0: not found, 1: found without msgstr, 2: translated */
|
|
size_t j;
|
|
|
|
best_mp = NULL;
|
|
best_weight = 0;
|
|
for (j = 0; j < mllp->nitems; ++j)
|
|
{
|
|
message_list_ty *mlp;
|
|
message_ty *mp;
|
|
|
|
mlp = mllp->item[j];
|
|
mp = message_list_search (mlp, msgctxt, msgid);
|
|
if (mp)
|
|
{
|
|
int weight = (mp->msgstr_len == 1 && mp->msgstr[0] == '\0' ? 1 : 2);
|
|
if (weight > best_weight)
|
|
{
|
|
best_mp = mp;
|
|
best_weight = weight;
|
|
}
|
|
}
|
|
}
|
|
return best_mp;
|
|
}
|
|
|
|
|
|
#if 0 /* unused */
|
|
message_ty *
|
|
message_list_list_search_fuzzy (message_list_list_ty *mllp,
|
|
const char *msgctxt, const char *msgid)
|
|
{
|
|
size_t j;
|
|
double best_weight;
|
|
message_ty *best_mp;
|
|
|
|
best_weight = FUZZY_THRESHOLD;
|
|
best_mp = NULL;
|
|
for (j = 0; j < mllp->nitems; ++j)
|
|
{
|
|
message_list_ty *mlp;
|
|
message_ty *mp;
|
|
|
|
mlp = mllp->item[j];
|
|
mp = message_list_search_fuzzy_inner (mlp, msgctxt, msgid, &best_weight);
|
|
if (mp)
|
|
best_mp = mp;
|
|
}
|
|
return best_mp;
|
|
}
|
|
#endif
|
|
|
|
|
|
msgdomain_ty*
|
|
msgdomain_alloc (const char *domain, bool use_hashtable)
|
|
{
|
|
msgdomain_ty *mdp;
|
|
|
|
mdp = XMALLOC (msgdomain_ty);
|
|
mdp->domain = domain;
|
|
mdp->messages = message_list_alloc (use_hashtable);
|
|
return mdp;
|
|
}
|
|
|
|
|
|
void
|
|
msgdomain_free (msgdomain_ty *mdp)
|
|
{
|
|
message_list_free (mdp->messages, 0);
|
|
free (mdp);
|
|
}
|
|
|
|
|
|
msgdomain_list_ty *
|
|
msgdomain_list_alloc (bool use_hashtable)
|
|
{
|
|
msgdomain_list_ty *mdlp;
|
|
|
|
mdlp = XMALLOC (msgdomain_list_ty);
|
|
/* Put the default domain first, so that when we output it,
|
|
we can omit the 'domain' directive. */
|
|
mdlp->nitems = 1;
|
|
mdlp->nitems_max = 1;
|
|
mdlp->item = XNMALLOC (mdlp->nitems_max, msgdomain_ty *);
|
|
mdlp->item[0] = msgdomain_alloc (MESSAGE_DOMAIN_DEFAULT, use_hashtable);
|
|
mdlp->use_hashtable = use_hashtable;
|
|
mdlp->encoding = NULL;
|
|
return mdlp;
|
|
}
|
|
|
|
|
|
void
|
|
msgdomain_list_free (msgdomain_list_ty *mdlp)
|
|
{
|
|
size_t j;
|
|
|
|
for (j = 0; j < mdlp->nitems; ++j)
|
|
msgdomain_free (mdlp->item[j]);
|
|
if (mdlp->item)
|
|
free (mdlp->item);
|
|
free (mdlp);
|
|
}
|
|
|
|
|
|
void
|
|
msgdomain_list_append (msgdomain_list_ty *mdlp, msgdomain_ty *mdp)
|
|
{
|
|
if (mdlp->nitems >= mdlp->nitems_max)
|
|
{
|
|
size_t nbytes;
|
|
|
|
mdlp->nitems_max = mdlp->nitems_max * 2 + 4;
|
|
nbytes = mdlp->nitems_max * sizeof (msgdomain_ty *);
|
|
mdlp->item = xrealloc (mdlp->item, nbytes);
|
|
}
|
|
mdlp->item[mdlp->nitems++] = mdp;
|
|
}
|
|
|
|
|
|
#if 0 /* unused */
|
|
void
|
|
msgdomain_list_append_list (msgdomain_list_ty *mdlp, msgdomain_list_ty *mdlp2)
|
|
{
|
|
size_t j;
|
|
|
|
for (j = 0; j < mdlp2->nitems; ++j)
|
|
msgdomain_list_append (mdlp, mdlp2->item[j]);
|
|
}
|
|
#endif
|
|
|
|
|
|
message_list_ty *
|
|
msgdomain_list_sublist (msgdomain_list_ty *mdlp, const char *domain,
|
|
bool create)
|
|
{
|
|
size_t j;
|
|
|
|
for (j = 0; j < mdlp->nitems; j++)
|
|
if (strcmp (mdlp->item[j]->domain, domain) == 0)
|
|
return mdlp->item[j]->messages;
|
|
|
|
if (create)
|
|
{
|
|
msgdomain_ty *mdp = msgdomain_alloc (domain, mdlp->use_hashtable);
|
|
msgdomain_list_append (mdlp, mdp);
|
|
return mdp->messages;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Copy a message domain list.
|
|
If copy_level = 0, also copy the messages. If copy_level = 1, share the
|
|
messages but copy the domains. If copy_level = 2, share the domains. */
|
|
msgdomain_list_ty *
|
|
msgdomain_list_copy (msgdomain_list_ty *mdlp, int copy_level)
|
|
{
|
|
msgdomain_list_ty *result;
|
|
size_t j;
|
|
|
|
result = XMALLOC (msgdomain_list_ty);
|
|
result->nitems = 0;
|
|
result->nitems_max = 0;
|
|
result->item = NULL;
|
|
result->use_hashtable = mdlp->use_hashtable;
|
|
result->encoding = mdlp->encoding;
|
|
|
|
for (j = 0; j < mdlp->nitems; j++)
|
|
{
|
|
msgdomain_ty *mdp = mdlp->item[j];
|
|
|
|
if (copy_level < 2)
|
|
{
|
|
msgdomain_ty *result_mdp = XMALLOC (msgdomain_ty);
|
|
|
|
result_mdp->domain = mdp->domain;
|
|
result_mdp->messages = message_list_copy (mdp->messages, copy_level);
|
|
|
|
msgdomain_list_append (result, result_mdp);
|
|
}
|
|
else
|
|
msgdomain_list_append (result, mdp);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
#if 0 /* unused */
|
|
message_ty *
|
|
msgdomain_list_search (msgdomain_list_ty *mdlp,
|
|
const char *msgctxt, const char *msgid)
|
|
{
|
|
size_t j;
|
|
|
|
for (j = 0; j < mdlp->nitems; ++j)
|
|
{
|
|
msgdomain_ty *mdp;
|
|
message_ty *mp;
|
|
|
|
mdp = mdlp->item[j];
|
|
mp = message_list_search (mdp->messages, msgctxt, msgid);
|
|
if (mp)
|
|
return mp;
|
|
}
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if 0 /* unused */
|
|
message_ty *
|
|
msgdomain_list_search_fuzzy (msgdomain_list_ty *mdlp,
|
|
const char *msgctxt, const char *msgid)
|
|
{
|
|
size_t j;
|
|
double best_weight;
|
|
message_ty *best_mp;
|
|
|
|
best_weight = FUZZY_THRESHOLD;
|
|
best_mp = NULL;
|
|
for (j = 0; j < mdlp->nitems; ++j)
|
|
{
|
|
msgdomain_ty *mdp;
|
|
message_ty *mp;
|
|
|
|
mdp = mdlp->item[j];
|
|
mp = message_list_search_fuzzy_inner (mdp->messages, msgctxt, msgid,
|
|
&best_weight);
|
|
if (mp)
|
|
best_mp = mp;
|
|
}
|
|
return best_mp;
|
|
}
|
|
#endif
|