From: Bruno Haible Date: Mon, 17 Dec 2001 11:36:35 +0000 (+0000) Subject: Enable format string checking also for plural messages. X-Git-Tag: v0.11~187 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b9cfd7850827ed5c91015d5acae347451966c917;p=thirdparty%2Fgettext.git Enable format string checking also for plural messages. --- diff --git a/src/ChangeLog b/src/ChangeLog index 627bfc188..5a644eaa0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2001-12-15 Bruno Haible + + * format.h (struct formatstring_parser): Add 'equality' and + 'pretty_msgstr' arguments to 'check' field. + * format-c.c (format_check): Add 'equality' and 'pretty_msgstr' + arguments. + * format-java.c (format_check): Likewise. + * format-lisp.c (format_check): Likewise. + * format-pascal.c (format_check): Likewise. + * format-python.c (format_check): Likewise. + * format-ycp.c (format_check): Likewise. + * msgfmt.c (check_pair): Check messages with plural forms as well. + * message.c (msgfmt_check_pair_fails): Add msgid_plural, msgstr_len + arguments. Check messages with plural forms as well. + (message_merge): Check messages with plural forms as well. + 2001-12-11 Bruno Haible * x-java.l (strip_ending_spaces): Fix isspace call. diff --git a/src/format-c.c b/src/format-c.c index 5abf9a6ac..d8e4da227 100644 --- a/src/format-c.c +++ b/src/format-c.c @@ -142,7 +142,8 @@ static void format_free PARAMS ((void *descr)); static int format_get_number_of_directives PARAMS ((void *descr)); static bool format_check PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, - bool noisy)); + bool equality, + bool noisy, const char *pretty_msgstr)); static int @@ -561,11 +562,13 @@ format_get_number_of_directives (descr) } static bool -format_check (pos, msgid_descr, msgstr_descr, noisy) +format_check (pos, msgid_descr, msgstr_descr, equality, noisy, pretty_msgstr) const lex_pos_ty *pos; void *msgid_descr; void *msgstr_descr; + bool equality; bool noisy; + const char *pretty_msgstr; { struct spec *spec1 = (struct spec *) msgid_descr; struct spec *spec2 = (struct spec *) msgstr_descr; @@ -573,27 +576,30 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) unsigned int i; /* Check the argument types are the same. */ - if (spec1->unnumbered_arg_count != spec2->unnumbered_arg_count) + if (equality + ? spec1->unnumbered_arg_count != spec2->unnumbered_arg_count + : spec1->unnumbered_arg_count < spec2->unnumbered_arg_count) { if (noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("number of format specifications in 'msgid' and 'msgstr' does not match")); + _("number of format specifications in 'msgid' and '%s' does not match"), + pretty_msgstr); error_with_progname = true; } err = true; } else - for (i = 0; i < spec1->unnumbered_arg_count; i++) + for (i = 0; i < spec2->unnumbered_arg_count; i++) if (spec1->unnumbered[i].type != spec2->unnumbered[i].type) { if (noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' and 'msgstr' for argument %u are not the same"), - i + 1); + _("format specifications in 'msgid' and '%s' for argument %u are not the same"), + pretty_msgstr, i + 1); error_with_progname = true; } err = true; diff --git a/src/format-java.c b/src/format-java.c index feaf66ac7..09174c015 100644 --- a/src/format-java.c +++ b/src/format-java.c @@ -27,7 +27,6 @@ #include "format.h" #include "c-ctype.h" #include "xmalloc.h" -#include "system.h" #include "error.h" #include "progname.h" #include "libgettext.h" @@ -140,7 +139,8 @@ static void format_free PARAMS ((void *descr)); static int format_get_number_of_directives PARAMS ((void *descr)); static bool format_check PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, - bool noisy)); + bool equality, + bool noisy, const char *pretty_msgstr)); /* Quote handling: @@ -622,11 +622,13 @@ format_get_number_of_directives (descr) } static bool -format_check (pos, msgid_descr, msgstr_descr, noisy) +format_check (pos, msgid_descr, msgstr_descr, equality, noisy, pretty_msgstr) const lex_pos_ty *pos; void *msgid_descr; void *msgstr_descr; + bool equality; bool noisy; + const char *pretty_msgstr; { struct spec *spec1 = (struct spec *) msgid_descr; struct spec *spec2 = (struct spec *) msgstr_descr; @@ -634,17 +636,18 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) if (spec1->numbered_arg_count + spec2->numbered_arg_count > 0) { - unsigned int i; - unsigned int n = MAX (spec1->numbered_arg_count, spec2->numbered_arg_count); + unsigned int i, j; + unsigned int n1 = spec1->numbered_arg_count; + unsigned int n2 = spec2->numbered_arg_count; /* Check the argument names are the same. Both arrays are sorted. We search for the first difference. */ - for (i = 0; i < n; i++) + for (i = 0, j = 0; i < n1 || j < n2; ) { - int cmp = (i >= spec1->numbered_arg_count ? 1 : - i >= spec2->numbered_arg_count ? -1 : - spec1->numbered[i].number > spec2->numbered[i].number ? 1 : - spec1->numbered[i].number < spec2->numbered[i].number ? -1 : + int cmp = (i >= n1 ? 1 : + j >= n2 ? -1 : + spec1->numbered[i].number > spec2->numbered[j].number ? 1 : + spec1->numbered[i].number < spec2->numbered[j].number ? -1 : 0); if (cmp > 0) @@ -653,8 +656,8 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("a format specification for argument {%u} doesn't exist in 'msgid'"), - spec2->numbered[i].number); + _("a format specification for argument {%u}, as in '%s', doesn't exist in 'msgid'"), + spec2->numbered[j].number, pretty_msgstr); error_with_progname = true; } err = true; @@ -662,34 +665,50 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) } else if (cmp < 0) { - if (noisy) + if (equality) { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("a format specification for argument {%u} doesn't exist in 'msgstr'"), - spec1->numbered[i].number); - error_with_progname = true; + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("a format specification for argument {%u} doesn't exist in '%s'"), + spec1->numbered[i].number, pretty_msgstr); + error_with_progname = true; + } + err = true; + break; } - err = true; - break; + else + i++; } + else + j++, i++; } /* Check the argument types are the same. */ if (!err) - for (i = 0; i < spec2->numbered_arg_count; i++) - if (spec1->numbered[i].type != spec2->numbered[i].type) - { - if (noisy) - { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"), - spec2->numbered[i].number); - error_with_progname = true; - } - err = true; - break; - } + for (i = 0, j = 0; j < n2; ) + { + if (spec1->numbered[i].number == spec2->numbered[j].number) + { + if (spec1->numbered[i].type != spec2->numbered[j].type) + { + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("format specifications in 'msgid' and '%s' for argument {%u} are not the same"), + pretty_msgstr, + spec2->numbered[j].number); + error_with_progname = true; + } + err = true; + break; + } + j++, i++; + } + else + i++; + } } return err; diff --git a/src/format-lisp.c b/src/format-lisp.c index 26d7595b0..35e751033 100644 --- a/src/format-lisp.c +++ b/src/format-lisp.c @@ -230,7 +230,8 @@ static void format_free PARAMS ((void *descr)); static int format_get_number_of_directives PARAMS ((void *descr)); static bool format_check PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, - bool noisy)); + bool equality, + bool noisy, const char *pretty_msgstr)); /* ======================= Verify a format_arg_list ======================= */ @@ -3356,26 +3357,53 @@ format_get_number_of_directives (descr) } static bool -format_check (pos, msgid_descr, msgstr_descr, noisy) +format_check (pos, msgid_descr, msgstr_descr, equality, noisy, pretty_msgstr) const lex_pos_ty *pos; void *msgid_descr; void *msgstr_descr; + bool equality; bool noisy; + const char *pretty_msgstr; { struct spec *spec1 = (struct spec *) msgid_descr; struct spec *spec2 = (struct spec *) msgstr_descr; bool err = false; - if (!equal_list (spec1->list, spec2->list)) + if (equality) { - if (noisy) + if (!equal_list (spec1->list, spec2->list)) { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' and 'msgstr' are not equivalent")); - error_with_progname = true; + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("format specifications in 'msgid' and '%s' are not equivalent"), + pretty_msgstr); + error_with_progname = true; + } + err = true; + } + } + else + { + struct format_arg_list *intersection = + make_intersected_list (copy_list (spec1->list), + copy_list (spec2->list)); + + if (!(intersection != NULL + && (normalize_list (intersection), + equal_list (intersection, spec2->list)))) + { + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("format specifications in '%s' are not a subset of those in 'msgid'"), + pretty_msgstr); + error_with_progname = true; + } + err = true; } - err = true; } return err; diff --git a/src/format-pascal.c b/src/format-pascal.c index de06431c6..a3aa95785 100644 --- a/src/format-pascal.c +++ b/src/format-pascal.c @@ -26,7 +26,6 @@ #include "format.h" #include "c-ctype.h" #include "xmalloc.h" -#include "system.h" #include "error.h" #include "progname.h" #include "libgettext.h" @@ -102,7 +101,8 @@ static void format_free PARAMS ((void *descr)); static int format_get_number_of_directives PARAMS ((void *descr)); static bool format_check PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, - bool noisy)); + bool equality, + bool noisy, const char *pretty_msgstr)); static int @@ -366,11 +366,13 @@ format_get_number_of_directives (descr) } static bool -format_check (pos, msgid_descr, msgstr_descr, noisy) +format_check (pos, msgid_descr, msgstr_descr, equality, noisy, pretty_msgstr) const lex_pos_ty *pos; void *msgid_descr; void *msgstr_descr; + bool equality; bool noisy; + const char *pretty_msgstr; { struct spec *spec1 = (struct spec *) msgid_descr; struct spec *spec2 = (struct spec *) msgstr_descr; @@ -378,17 +380,18 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) if (spec1->numbered_arg_count + spec2->numbered_arg_count > 0) { - unsigned int i; - unsigned int n = MAX (spec1->numbered_arg_count, spec2->numbered_arg_count); + unsigned int i, j; + unsigned int n1 = spec1->numbered_arg_count; + unsigned int n2 = spec2->numbered_arg_count; /* Check the argument names are the same. Both arrays are sorted. We search for the first difference. */ - for (i = 0; i < n; i++) + for (i = 0, j = 0; i < n1 || j < n2; ) { - int cmp = (i >= spec1->numbered_arg_count ? 1 : - i >= spec2->numbered_arg_count ? -1 : - spec1->numbered[i].number > spec2->numbered[i].number ? 1 : - spec1->numbered[i].number < spec2->numbered[i].number ? -1 : + int cmp = (i >= n1 ? 1 : + j >= n2 ? -1 : + spec1->numbered[i].number > spec2->numbered[j].number ? 1 : + spec1->numbered[i].number < spec2->numbered[j].number ? -1 : 0); if (cmp > 0) @@ -397,8 +400,8 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("a format specification for argument {%u} doesn't exist in 'msgid'"), - spec2->numbered[i].number); + _("a format specification for argument {%u}, as in '%s', doesn't exist in 'msgid'"), + spec2->numbered[j].number, pretty_msgstr); error_with_progname = true; } err = true; @@ -406,34 +409,50 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) } else if (cmp < 0) { - if (noisy) + if (equality) { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("a format specification for argument {%u} doesn't exist in 'msgstr'"), - spec1->numbered[i].number); - error_with_progname = true; + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("a format specification for argument {%u} doesn't exist in '%s'"), + spec1->numbered[i].number, pretty_msgstr); + error_with_progname = true; + } + err = true; + break; } - err = true; - break; + else + i++; } + else + j++, i++; } /* Check the argument types are the same. */ if (!err) - for (i = 0; i < spec2->numbered_arg_count; i++) - if (spec1->numbered[i].type != spec2->numbered[i].type) - { - if (noisy) - { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"), - spec2->numbered[i].number); - error_with_progname = true; - } - err = true; - break; - } + for (i = 0, j = 0; j < n2; ) + { + if (spec1->numbered[i].number == spec2->numbered[j].number) + { + if (spec1->numbered[i].type != spec2->numbered[j].type) + { + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("format specifications in 'msgid' and '%s' for argument {%u} are not the same"), + pretty_msgstr, + spec2->numbered[j].number); + error_with_progname = true; + } + err = true; + break; + } + j++, i++; + } + else + i++; + } } return err; diff --git a/src/format-python.c b/src/format-python.c index ab47d10c5..e0648096b 100644 --- a/src/format-python.c +++ b/src/format-python.c @@ -26,7 +26,6 @@ #include "format.h" #include "xmalloc.h" -#include "system.h" #include "error.h" #include "progname.h" #include "libgettext.h" @@ -110,7 +109,8 @@ static void format_free PARAMS ((void *descr)); static int format_get_number_of_directives PARAMS ((void *descr)); static bool format_check PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, - bool noisy)); + bool equality, + bool noisy, const char *pretty_msgstr)); static int @@ -376,11 +376,13 @@ format_get_number_of_directives (descr) } static bool -format_check (pos, msgid_descr, msgstr_descr, noisy) +format_check (pos, msgid_descr, msgstr_descr, equality, noisy, pretty_msgstr) const lex_pos_ty *pos; void *msgid_descr; void *msgstr_descr; + bool equality; bool noisy; + const char *pretty_msgstr; { struct spec *spec1 = (struct spec *) msgid_descr; struct spec *spec2 = (struct spec *) msgstr_descr; @@ -392,7 +394,8 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' expect a mapping, those in 'msgstr' expect a tuple")); + _("format specifications in 'msgid' expect a mapping, those in '%s' expect a tuple"), + pretty_msgstr); error_with_progname = true; } err = true; @@ -403,7 +406,8 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' expect a tuple, those in 'msgstr' expect a mapping")); + _("format specifications in 'msgid' expect a tuple, those in '%s' expect a mapping"), + pretty_msgstr); error_with_progname = true; } err = true; @@ -412,16 +416,17 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) { if (spec1->named_arg_count + spec2->named_arg_count > 0) { - unsigned int i; - unsigned int n = MAX (spec1->named_arg_count, spec2->named_arg_count); + unsigned int i, j; + unsigned int n1 = spec1->named_arg_count; + unsigned int n2 = spec2->named_arg_count; /* Check the argument names are the same. Both arrays are sorted. We search for the first difference. */ - for (i = 0; i < n; i++) + for (i = 0, j = 0; i < n1 || j < n2; ) { - int cmp = (i >= spec1->named_arg_count ? 1 : - i >= spec2->named_arg_count ? -1 : - strcmp (spec1->named[i].name, spec2->named[i].name)); + int cmp = (i >= n1 ? 1 : + j >= n2 ? -1 : + strcmp (spec1->named[i].name, spec2->named[j].name)); if (cmp > 0) { @@ -429,8 +434,8 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("a format specification for argument '%s' doesn't exist in 'msgid'"), - spec2->named[i].name); + _("a format specification for argument '%s', as in '%s', doesn't exist in 'msgid'"), + spec2->named[j].name, pretty_msgstr); error_with_progname = true; } err = true; @@ -438,34 +443,51 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) } else if (cmp < 0) { - if (noisy) + if (equality) { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("a format specification for argument '%s' doesn't exist in 'msgstr'"), - spec1->named[i].name); - error_with_progname = true; + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, pos->line_number, + _("a format specification for argument '%s' doesn't exist in '%s'"), + spec1->named[i].name, pretty_msgstr); + error_with_progname = true; + } + err = true; + break; } - err = true; - break; + else + i++; } + else + j++, i++; } /* Check the argument types are the same. */ if (!err) - for (i = 0; i < spec2->named_arg_count; i++) - if (spec1->named[i].type != spec2->named[i].type) - { - if (noisy) - { - error_with_progname = false; - error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' and 'msgstr' for argument '%s' are not the same"), - spec2->named[i].name); - error_with_progname = true; - } - err = true; - break; - } + for (i = 0, j = 0; j < n2; ) + { + if (strcmp (spec1->named[i].name, spec2->named[j].name) == 0) + { + if (spec1->named[i].type != spec2->named[j].type) + { + if (noisy) + { + error_with_progname = false; + error_at_line (0, 0, pos->file_name, + pos->line_number, + _("format specifications in 'msgid' and '%s' for argument '%s' are not the same"), + pretty_msgstr, + spec2->named[j].name); + error_with_progname = true; + } + err = true; + break; + } + j++, i++; + } + else + i++; + } } if (spec1->unnamed_arg_count + spec2->unnamed_arg_count > 0) @@ -473,27 +495,30 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) unsigned int i; /* Check the argument types are the same. */ - if (spec1->unnamed_arg_count != spec2->unnamed_arg_count) + if (equality + ? spec1->unnamed_arg_count != spec2->unnamed_arg_count + : spec1->unnamed_arg_count < spec2->unnamed_arg_count) { if (noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("number of format specifications in 'msgid' and 'msgstr' does not match")); + _("number of format specifications in 'msgid' and '%s' does not match"), + pretty_msgstr); error_with_progname = true; } err = true; } else - for (i = 0; i < spec1->unnamed_arg_count; i++) + for (i = 0; i < spec2->unnamed_arg_count; i++) if (spec1->unnamed[i].type != spec2->unnamed[i].type) { if (noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, - _("format specifications in 'msgid' and 'msgstr' for argument %u are not the same"), - i + 1); + _("format specifications in 'msgid' and '%s' for argument %u are not the same"), + pretty_msgstr, i + 1); error_with_progname = true; } err = true; diff --git a/src/format-ycp.c b/src/format-ycp.c index dbd9e6a35..494effd09 100644 --- a/src/format-ycp.c +++ b/src/format-ycp.c @@ -53,7 +53,8 @@ static void format_free PARAMS ((void *descr)); static int format_get_number_of_directives PARAMS ((void *descr)); static bool format_check PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, - bool noisy)); + bool equality, + bool noisy, const char *pretty_msgstr)); static void * @@ -115,11 +116,13 @@ format_get_number_of_directives (descr) } static bool -format_check (pos, msgid_descr, msgstr_descr, noisy) +format_check (pos, msgid_descr, msgstr_descr, equality, noisy, pretty_msgstr) const lex_pos_ty *pos; void *msgid_descr; void *msgstr_descr; + bool equality; bool noisy; + const char *pretty_msgstr; { struct spec *spec1 = (struct spec *) msgid_descr; struct spec *spec2 = (struct spec *) msgstr_descr; @@ -131,16 +134,16 @@ format_check (pos, msgid_descr, msgstr_descr, noisy) bool arg_used1 = (i < spec1->arg_count && spec1->args_used[i]); bool arg_used2 = (i < spec2->arg_count && spec2->args_used[i]); - if (arg_used1 != arg_used2) + if (equality ? (arg_used1 != arg_used2) : (!arg_used1 && arg_used2)) { if (noisy) { error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, arg_used1 - ? _("a format specification for argument %u doesn't exist in 'msgstr'") - : _("a format specification for argument %u doesn't exist in 'msgid'"), - i + 1); + ? _("a format specification for argument %u doesn't exist in '%s'") + : _("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"), + i + 1, pretty_msgstr); error_with_progname = true; } err = true; diff --git a/src/format.h b/src/format.h index cb925ff6c..43cbbcd32 100644 --- a/src/format.h +++ b/src/format.h @@ -42,12 +42,15 @@ struct formatstring_parser int (*get_number_of_directives) PARAMS ((void *descr)); /* Verify that the argument types/names in msgid_descr and those in - msgstr_descr are the same. If not, signal an error using + msgstr_descr are the same (if equality=true), or (if equality=false) + that those of msgid_descr extend those of msgstr_descr (i.e. + msgstr_descr may omit some of the arguments of msgid_descr). + If not, signal an error using error_with_progname = false; error_at_line (0, 0, pos->file_name, pos->line_number, ...); error_with_progname = true; (but only if noisy=true) and return true. Otherwise return false. */ - bool (*check) PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, bool noisy)); + bool (*check) PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, bool equality, bool noisy, const char *pretty_msgstr)); }; /* Format string parsers, each defined in its own file. */ diff --git a/src/message.c b/src/message.c index 2b6c39c38..b6d37512d 100644 --- a/src/message.c +++ b/src/message.c @@ -39,7 +39,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ function argument counts despite of K&R C function definition syntax. */ static bool msgfmt_check_pair_fails PARAMS ((const lex_pos_ty *pos, const char *msgid, - const char *msgstr, size_t i)); + const char *msgid_plural, + const char *msgstr, + size_t msgstr_len, size_t fmt)); static message_ty *message_list_search_fuzzy_inner PARAMS (( message_list_ty *mlp, const char *msgid, double *best_weight_p)); @@ -213,32 +215,44 @@ message_copy (mp) static bool -msgfmt_check_pair_fails (pos, msgid, msgstr, i) +msgfmt_check_pair_fails (pos, msgid, msgid_plural, msgstr, msgstr_len, fmt) const lex_pos_ty *pos; const char *msgid; + const char *msgid_plural; const char *msgstr; - size_t i; + size_t msgstr_len; + size_t fmt; { bool failure; - struct formatstring_parser *parser = formatstring_parsers[i]; - void *msgid_descr = parser->parse (msgid); + struct formatstring_parser *parser = formatstring_parsers[fmt]; + void *msgid_descr = + parser->parse (msgid_plural != NULL ? msgid_plural : msgid); + failure = false; if (msgid_descr != NULL) { - void *msgstr_descr = parser->parse (msgstr); + const char *p_end = msgstr + msgstr_len; + const char *p; - if (msgstr_descr != NULL) + for (p = msgstr; p < p_end; p += strlen (p) + 1) { - failure = parser->check (pos, msgid_descr, msgstr_descr, false); - parser->free (msgstr_descr); + void *msgstr_descr = parser->parse (msgstr); + + if (msgstr_descr != NULL) + { + failure = parser->check (pos, msgid_descr, msgstr_descr, + msgid_plural == NULL, false, NULL); + parser->free (msgstr_descr); + } + else + failure = true; + + if (failure) + break; } - else - failure = true; parser->free (msgid_descr); } - else - failure = false; return failure; } @@ -455,10 +469,10 @@ message_merge (def, ref) 2. msgmerge must not transform a PO file which passes "msgfmt -c" into a PO file which doesn't. */ if (!result->is_fuzzy - && ref->msgid_plural == NULL && possible_format_p (ref->is_format[i]) && !possible_format_p (def->is_format[i]) - && msgfmt_check_pair_fails (&def->pos, ref->msgid, msgstr, i)) + && msgfmt_check_pair_fails (&def->pos, ref->msgid, ref->msgid_plural, + msgstr, msgstr_len, i)) result->is_fuzzy = true; } diff --git a/src/msgfmt.c b/src/msgfmt.c index 01794a2b2..e8a40b64d 100644 --- a/src/msgfmt.c +++ b/src/msgfmt.c @@ -1043,7 +1043,7 @@ check_pair (msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, exit_status = EXIT_FAILURE; } - if (check_format_strings && msgid_plural == NULL) + if (check_format_strings) /* Test 3: Check whether both formats strings contain the same number of format specifications. We check only those messages for which the msgid's is_format flag @@ -1067,30 +1067,48 @@ check_pair (msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, arguments that are used by other translations. */ struct formatstring_parser *parser = formatstring_parsers[i]; - void *msgid_descr = parser->parse (msgid); + void *msgid_descr = + parser->parse (msgid_plural != NULL ? msgid_plural : msgid); if (msgid_descr != NULL) { - void *msgstr_descr = parser->parse (msgstr); + char buf[18+1]; + const char *pretty_msgstr = "msgstr"; + const char *p_end = msgstr + msgstr_len; + const char *p; - if (msgstr_descr != NULL) + for (p = msgstr, j = 0; p < p_end; p += strlen (p) + 1, j++) { - if (parser->check (msgid_pos, msgid_descr, msgstr_descr, - true)) - exit_status = EXIT_FAILURE; - - parser->free (msgstr_descr); - } - else - { - error_with_progname = false; - error_at_line (0, 0, msgid_pos->file_name, - msgid_pos->line_number, - _("\ -'msgstr' is not a valid %s format string, unlike 'msgid'"), - format_language_pretty[i]); - error_with_progname = true; - exit_status = EXIT_FAILURE; + void *msgstr_descr; + + if (msgid_plural != NULL) + { + sprintf (buf, "msgstr[%u]", j); + pretty_msgstr = buf; + } + + msgstr_descr = parser->parse (p); + + if (msgstr_descr != NULL) + { + if (parser->check (msgid_pos, msgid_descr, msgstr_descr, + msgid_plural == NULL, + true, pretty_msgstr)) + exit_status = EXIT_FAILURE; + + parser->free (msgstr_descr); + } + else + { + error_with_progname = false; + error_at_line (0, 0, msgid_pos->file_name, + msgid_pos->line_number, + _("\ +'%s' is not a valid %s format string, unlike 'msgid'"), + pretty_msgstr, format_language_pretty[i]); + error_with_progname = true; + exit_status = EXIT_FAILURE; + } } parser->free (msgid_descr); diff --git a/tests/ChangeLog b/tests/ChangeLog index f11dc471e..d4bc1e16d 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,8 @@ +2001-12-15 Bruno Haible + + * msgfmt-10: New file. + * Makefile.am (TESTS): Add it. + 2001-12-11 Bruno Haible * lang-c++: Don't use ostream::form, it's a g++ 2.x extension not diff --git a/tests/Makefile.am b/tests/Makefile.am index a80860e37..23d2bb483 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -34,7 +34,7 @@ TESTS = gettext-1 gettext-2 \ msgexec-1 msgexec-2 \ msgfilter-1 msgfilter-2 \ msgfmt-1 msgfmt-2 msgfmt-3 msgfmt-4 msgfmt-5 msgfmt-6 msgfmt-7 \ - msgfmt-8 msgfmt-9 \ + msgfmt-8 msgfmt-9 msgfmt-10 \ msggrep-1 msggrep-2 msggrep-3 msggrep-4 \ msgmerge-1 msgmerge-2 msgmerge-3 msgmerge-4 msgmerge-5 msgmerge-6 \ msgmerge-7 msgmerge-8 msgmerge-9 msgmerge-10 msgmerge-11 msgmerge-12 \ diff --git a/tests/msgfmt-10 b/tests/msgfmt-10 new file mode 100755 index 000000000..2945273f3 --- /dev/null +++ b/tests/msgfmt-10 @@ -0,0 +1,87 @@ +#! /bin/sh + +# Test format string checking in plural entries. + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="mf-test10.po1" +cat < mf-test10.po1 +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: GNU bison\n" +"PO-Revision-Date: 2001-04-05 19:47+0200\n" +"Last-Translator: ABC DEF \n" +"Language-Team: test \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-9\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/reduce.c:511 +#, c-format +msgid "%d useless nonterminal" +msgid_plural "%d useless nonterminals" +msgstr[0] "1 yararsýz deðiþken simge" +msgstr[1] "%d yararsýz deðiþken simges" + +#: src/reduce.c:520 +#, c-format +msgid "one useless rule" +msgid_plural "%d useless rules" +msgstr[0] "%d yararsýz kural" +msgstr[1] "%d yararsýz kurals" +EOF + +: ${MSGFMT=msgfmt} +${MSGFMT} --check mf-test10.po1 -o /dev/null || \ + { rm -fr $tmpfiles; exit 1; } + +tmpfiles="mf-test10.po2" +cat < mf-test10.po2 +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Free Software Foundation, Inc. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: GNU bison\n" +"PO-Revision-Date: 2001-04-05 19:47+0200\n" +"Last-Translator: ABC DEF \n" +"Language-Team: test \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-9\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/reduce.c:520 +#, c-format +msgid "one useless rule" +msgid_plural "%d useless rules" +msgstr[0] "%d yararsýz kural" +msgstr[1] "%d yararsýz kural%s" +EOF + +tmpfiles="$tmpfiles mf-test10.err" +: ${MSGFMT=msgfmt} +LC_MESSAGES=C LC_ALL= \ +${MSGFMT} --check mf-test10.po2 -o /dev/null \ + 2> mf-test10.err + +tmpfiles="$tmpfiles mf-test10.ok" +cat << EOF > mf-test10.ok +mf-test10.po2:18: number of format specifications in 'msgid' and 'msgstr[1]' does not match +msgfmt: found 1 fatal error +EOF + +: ${DIFF=diff} +${DIFF} mf-test10.ok mf-test10.err +result=$? + +rm -fr $tmpfiles + +exit $result