diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-12-24 07:38:37 +0000 |
---|---|---|
committer | <> | 2015-02-02 12:02:29 +0000 |
commit | 482840e61f86ca321838a91e902c41d40c098bbb (patch) | |
tree | 01ea2e242fd2792d19fe192476601587901db794 /gettext-tools/src/format.c | |
download | gettext-tarball-482840e61f86ca321838a91e902c41d40c098bbb.tar.gz |
Imported from /home/lorry/working-area/delta_gettext-tarball/gettext-0.19.4.tar.xz.gettext-0.19.4
Diffstat (limited to 'gettext-tools/src/format.c')
-rw-r--r-- | gettext-tools/src/format.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/gettext-tools/src/format.c b/gettext-tools/src/format.c new file mode 100644 index 0000000..c73ad7d --- /dev/null +++ b/gettext-tools/src/format.c @@ -0,0 +1,197 @@ +/* Format strings. + Copyright (C) 2001-2009 Free Software Foundation, Inc. + Written by Bruno Haible <haible@clisp.cons.org>, 2001. + + 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "format.h" + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include "message.h" +#include "gettext.h" + +#define _(str) gettext (str) + +/* Table of all format string parsers. */ +struct formatstring_parser *formatstring_parsers[NFORMATS] = +{ + /* format_c */ &formatstring_c, + /* format_objc */ &formatstring_objc, + /* format_sh */ &formatstring_sh, + /* format_python */ &formatstring_python, + /* format_python_brace */ &formatstring_python_brace, + /* format_lisp */ &formatstring_lisp, + /* format_elisp */ &formatstring_elisp, + /* format_librep */ &formatstring_librep, + /* format_scheme */ &formatstring_scheme, + /* format_smalltalk */ &formatstring_smalltalk, + /* format_java */ &formatstring_java, + /* format_csharp */ &formatstring_csharp, + /* format_awk */ &formatstring_awk, + /* format_pascal */ &formatstring_pascal, + /* format_ycp */ &formatstring_ycp, + /* format_tcl */ &formatstring_tcl, + /* format_perl */ &formatstring_perl, + /* format_perl_brace */ &formatstring_perl_brace, + /* format_php */ &formatstring_php, + /* format_gcc_internal */ &formatstring_gcc_internal, + /* format_gfc_internal */ &formatstring_gfc_internal, + /* format_qt */ &formatstring_qt, + /* format_qt_plural */ &formatstring_qt_plural, + /* format_kde */ &formatstring_kde, + /* format_boost */ &formatstring_boost, + /* format_lua */ &formatstring_lua, + /* format_javascript */ &formatstring_javascript +}; + +/* Check whether both formats strings contain compatible format + specifications for format type i (0 <= i < NFORMATS). */ +int +check_msgid_msgstr_format_i (const char *msgid, const char *msgid_plural, + const char *msgstr, size_t msgstr_len, + size_t i, + struct argument_range range, + const struct plural_distribution *distribution, + formatstring_error_logger_t error_logger) +{ + int seen_errors = 0; + + /* At runtime, we can assume the program passes arguments that fit well for + msgid. We must signal an error if msgstr wants more arguments that msgid + accepts. + If msgstr wants fewer arguments than msgid, it wouldn't lead to a crash + at runtime, but we nevertheless give an error because + 1) this situation occurs typically after the programmer has added some + arguments to msgid, so we must make the translator specially aware + of it (more than just "fuzzy"), + 2) it is generally wrong if a translation wants to ignore arguments that + are used by other translations. */ + + struct formatstring_parser *parser = formatstring_parsers[i]; + char *invalid_reason = NULL; + void *msgid_descr = + parser->parse (msgid_plural != NULL ? msgid_plural : msgid, false, NULL, + &invalid_reason); + + if (msgid_descr != NULL) + { + const char *pretty_msgid = + (msgid_plural != NULL ? "msgid_plural" : "msgid"); + char buf[18+1]; + const char *pretty_msgstr = "msgstr"; + bool has_plural_translations = (strlen (msgstr) + 1 < msgstr_len); + const char *p_end = msgstr + msgstr_len; + const char *p; + unsigned int j; + + for (p = msgstr, j = 0; p < p_end; p += strlen (p) + 1, j++) + { + void *msgstr_descr; + + if (msgid_plural != NULL) + { + sprintf (buf, "msgstr[%u]", j); + pretty_msgstr = buf; + } + + msgstr_descr = parser->parse (p, true, NULL, &invalid_reason); + + if (msgstr_descr != NULL) + { + /* Use strict checking (require same number of format + directives on both sides) if the message has no plurals, + or if msgid_plural exists but on the msgstr[] side + there is only msgstr[0], or if distribution->often[j] + indicates that the variant applies to infinitely many + values of N and the N range is not restricted in a way + that the variant applies to only one N. + Use relaxed checking when there are at least two + msgstr[] forms and the distribution does not give more + precise information. */ + bool strict_checking = + (msgid_plural == NULL + || !has_plural_translations + || (distribution != NULL + && distribution->often != NULL + && j < distribution->often_length + && distribution->often[j] + && !(has_range_p (range) + && distribution->histogram (distribution, + range.min, range.max, j) + <= 1))); + + if (parser->check (msgid_descr, msgstr_descr, + strict_checking, + error_logger, pretty_msgid, pretty_msgstr)) + seen_errors++; + + parser->free (msgstr_descr); + } + else + { + error_logger (_("\ +'%s' is not a valid %s format string, unlike '%s'. Reason: %s"), + pretty_msgstr, format_language_pretty[i], + pretty_msgid, invalid_reason); + seen_errors++; + free (invalid_reason); + } + } + + parser->free (msgid_descr); + } + else + free (invalid_reason); + + return seen_errors; +} + +/* Check whether both formats strings contain compatible format + specifications. + Return the number of errors that were seen. */ +int +check_msgid_msgstr_format (const char *msgid, const char *msgid_plural, + const char *msgstr, size_t msgstr_len, + const enum is_format is_format[NFORMATS], + struct argument_range range, + const struct plural_distribution *distribution, + formatstring_error_logger_t error_logger) +{ + int seen_errors = 0; + size_t i; + + /* We check only those messages for which the msgid's is_format flag + is one of 'yes' or 'possible'. We don't check msgids with is_format + 'no' or 'impossible', to obey the programmer's order. We don't check + msgids with is_format 'undecided' because that would introduce too + many checks, thus forcing the programmer to add "xgettext: no-c-format" + anywhere where a translator wishes to use a percent sign. */ + for (i = 0; i < NFORMATS; i++) + if (possible_format_p (is_format[i])) + seen_errors += check_msgid_msgstr_format_i (msgid, msgid_plural, + msgstr, msgstr_len, i, + range, + distribution, + error_logger); + + return seen_errors; +} |