+2001-12-15 Bruno Haible <bruno@clisp.org>
+
+ * 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 <bruno@clisp.org>
* x-java.l (strip_ending_spaces): Fix isspace call.
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
}
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;
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;
#include "format.h"
#include "c-ctype.h"
#include "xmalloc.h"
-#include "system.h"
#include "error.h"
#include "progname.h"
#include "libgettext.h"
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:
}
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;
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)
{
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;
}
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;
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 ======================= */
}
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;
#include "format.h"
#include "c-ctype.h"
#include "xmalloc.h"
-#include "system.h"
#include "error.h"
#include "progname.h"
#include "libgettext.h"
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
}
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;
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)
{
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;
}
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;
#include "format.h"
#include "xmalloc.h"
-#include "system.h"
#include "error.h"
#include "progname.h"
#include "libgettext.h"
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
}
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;
{
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;
{
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;
{
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)
{
{
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;
}
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)
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;
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 *
}
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 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;
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. */
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));
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;
}
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;
}
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
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);
+2001-12-15 Bruno Haible <bruno@clisp.org>
+
+ * msgfmt-10: New file.
+ * Makefile.am (TESTS): Add it.
+
2001-12-11 Bruno Haible <bruno@clisp.org>
* lang-c++: Don't use ostream::form, it's a g++ 2.x extension not
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 \
--- /dev/null
+#! /bin/sh
+
+# Test format string checking in plural entries.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="mf-test10.po1"
+cat <<EOF > mf-test10.po1
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: GNU bison\n"
+"PO-Revision-Date: 2001-04-05 19:47+0200\n"
+"Last-Translator: ABC DEF <abc@gnu.uucp>\n"
+"Language-Team: test <test@li.org>\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 <<EOF > mf-test10.po2
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: GNU bison\n"
+"PO-Revision-Date: 2001-04-05 19:47+0200\n"
+"Last-Translator: ABC DEF <abc@gnu.uucp>\n"
+"Language-Team: test <test@li.org>\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