summaryrefslogtreecommitdiff
path: root/gettext-tools/src/format.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-12-24 07:38:37 +0000
committer <>2015-02-02 12:02:29 +0000
commit482840e61f86ca321838a91e902c41d40c098bbb (patch)
tree01ea2e242fd2792d19fe192476601587901db794 /gettext-tools/src/format.c
downloadgettext-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.c197
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;
+}