+2005-10-18 Bruno Haible <bruno@clisp.org>
+
+ * xgettext.texi (--keyword): Document how to specify the total number
+ of arguments.
+
2005-10-03 Bruno Haible <bruno@clisp.org>
Add support for contexts in xgettext.
@samp{@var{id}:@var{argnum},@var{contextargnum}c}, @code{xgettext} treats
strings in the @var{contextargnum}th argument as a context specifier.
@*
+Furthermore, if @var{keywordspec} is of the form
+@samp{@var{id}:@dots{},@var{totalnumargs}t}, @code{xgettext} recognizes this
+argument specification only if the number of actual arguments is equal to
+@var{totalnumargs}. This is useful for disambiguating overloaded function
+calls in C++.
+@*
The default keyword specifications, which are always looked for if not
explicitly disabled, are @code{gettext}, @code{dgettext:2},
@code{dcgettext:2}, @code{ngettext:1,2}, @code{dngettext:2,3},
+2005-10-18 Bruno Haible <bruno@clisp.org>
+
+ Disambiguate overloaded function calls according to argument count.
+ * xgettext.h (struct callshape): Add field 'argtotal'.
+ (struct partial_call): Likewise.
+ (arglist_parser_done): Add argnum argument.
+ * xgettext.c (split_keywordspec): Recognize NNt syntax and fill
+ argtotal.
+ (insert_keyword_callshape, arglist_parser_alloc, arglist_parser_clone):
+ Update.
+ (arglist_parser_decidedp): Compare also the argtotal if given.
+ (arglist_parser_done): Add argnum argument.
+ * x-awk.c (extract_parenthesized): Pass arg count to
+ arglist_parser_done.
+ * x-c.c (extract_parenthesized): Likewise.
+ * x-csharp.c (extract_parenthesized): Likewise.
+ * x-elisp.c (read_object): Likewise.
+ * x-java.c (extract_parenthesized): Likewise.
+ * x-librep.c (read_object): Likewise.
+ * x-lisp.c (read_object): Likewise.
+ * x-perl.c (extract_variable): Update.
+ (extract_balanced): Pass arg count to arglist_parser_done.
+ * x-php.c (extract_parenthesized): Likewise.
+ * x-python.c (extract_parenthesized): Likewise.
+ * x-scheme.c (read_object): Likewise.
+ * x-sh.c (read_command): Likewise.
+ * x-tcl.c (read_command): Likewise.
+ Stimulated by a patch from
+ Chusslove Illich (Часлав Илић) <caslav.ilic@gmx.net>.
+
2005-10-09 Bruno Haible <bruno@clisp.org>
* msginit.c (catalogname_for_locale, language_of_locale): Drop support
arglist_parser_alloc (mlp,
state ? next_shapes : NULL)))
{
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return true;
}
next_is_argument = false;
continue;
case token_type_rparen:
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return false;
case token_type_comma:
continue;
case token_type_eof:
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return true;
case token_type_other:
arglist_parser_alloc (mlp,
state ? next_shapes : NULL)))
{
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return true;
}
next_context_iter = null_context_list_iterator;
continue;
case xgettext_token_type_rparen:
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return false;
case xgettext_token_type_comma:
continue;
case xgettext_token_type_eof:
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return true;
default:
state ? next_shapes : NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return true;
}
if (terminator == token_type_rparen)
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return false;
}
arglist_parser_alloc (mlp, NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return true;
}
if (terminator == token_type_rbrace)
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return false;
}
case token_type_eof:
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return true;
/* Don't bother converting "()" to "NIL". */
last_non_comment_line = line_number;
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return;
}
}
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
}
op->type = t_other;
last_non_comment_line = line_number;
state ? next_shapes : NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return true;
}
if (terminator == token_type_rparen)
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return false;
}
arglist_parser_alloc (mlp, NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return true;
}
if (terminator == token_type_rbrace)
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return false;
}
case token_type_eof:
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
return true;
/* Don't bother converting "()" to "NIL". */
last_non_comment_line = line_number;
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return;
}
}
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
}
op->type = t_other;
last_non_comment_line = line_number;
/* Don't bother converting "()" to "NIL". */
last_non_comment_line = line_number;
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return;
}
}
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
}
op->type = t_other;
last_non_comment_line = line_number;
shapes.shapes[0].argnum1 = 1;
shapes.shapes[0].argnum2 = 0;
shapes.shapes[0].argnumc = 0;
+ shapes.shapes[0].argtotal = 0;
/* Extract a possible string from the key. Before proceeding
we check whether the open curly is followed by a symbol and
if (delim == tp->type)
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
#if DEBUG_PERL
fprintf (stderr, "%s:%d: extract_balanced finished (%d)\n",
(const struct callshapes *) keyword_value;
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
argparser = arglist_parser_alloc (mlp, shapes);
arg = 1;
arg, arglist_parser_clone (argparser)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
free_token (tp);
return true;
if (my_last_token == token_type_keyword_symbol)
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
argparser = arglist_parser_alloc (mlp, NULL);
}
{
/* We have missed the argument. */
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
argparser = arglist_parser_alloc (mlp, NULL);
arg = 0;
if (arglist_parser_decidedp (argparser, arg))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
argparser = arglist_parser_alloc (mlp, NULL);
state = 0;
logical_file_name, tp->line_number, nesting_level);
#endif
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
free_token (tp);
return true;
1, arglist_parser_alloc (mlp, NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
free_token (tp);
return true;
1, arglist_parser_alloc (mlp, NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
free_token (tp);
return true;
/* The ultimate sign. */
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_global_source_encoding;
argparser = arglist_parser_alloc (mlp, NULL);
arglist_parser_alloc (mlp,
state ? next_shapes : NULL)))
{
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return true;
}
next_context_iter = null_context_list_iterator;
continue;
case token_type_rparen:
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return false;
case token_type_comma:
continue;
case token_type_eof:
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return true;
default:
state ? next_shapes : NULL)))
{
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_current_file_source_encoding;
return true;
}
case token_type_rparen:
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_current_file_source_encoding;
return false;
case token_type_eof:
xgettext_current_source_encoding = po_charset_utf8;
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
xgettext_current_source_encoding = xgettext_current_file_source_encoding;
return true;
op->type = t_other;
last_non_comment_line = line_number;
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return;
}
free_object (&inner);
}
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
}
op->type = t_other;
last_non_comment_line = line_number;
|| inner.type == t_eof)
{
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return inner.type;
}
{
/* Stop looking for arguments of the last function_name. */
/* FIXME: What about context_iter? */
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
shapes = NULL;
argparser = NULL;
}
|| inner.type == t_brace || inner.type == t_eof)
{
if (argparser != NULL)
- arglist_parser_done (argparser);
+ arglist_parser_done (argparser, arg);
return inner.type;
}
int argnum1 = 0;
int argnum2 = 0;
int argnumc = 0;
+ int argtotal = 0;
/* Start parsing from the end. */
p = spec + strlen (spec);
while (p > spec)
{
if (isdigit ((unsigned char) p[-1])
- || (p[-1] == 'c' && p - 1 > spec && isdigit ((unsigned char) p[-2])))
+ || ((p[-1] == 'c' || p[-1] == 't')
+ && p - 1 > spec && isdigit ((unsigned char) p[-2])))
{
bool contextp = (p[-1] == 'c');
+ bool totalp = (p[-1] == 't');
do
p--;
break;
argnumc = arg;
}
+ else if (totalp)
+ {
+ if (argtotal != 0)
+ /* Only one total number of arguments can be given. */
+ break;
+ argtotal = arg;
+ }
else
{
if (argnum2 != 0)
shapep->argnum1 = (argnum1 > 0 ? argnum1 : 1);
shapep->argnum2 = argnum2;
shapep->argnumc = argnumc;
+ shapep->argtotal = argtotal;
return;
}
}
shapep->argnum1 = 1;
shapep->argnum2 = 0;
shapep->argnumc = 0;
+ shapep->argtotal = 0;
}
for (i = 0; i < old_shapes->nshapes; i++)
if (old_shapes->shapes[i].argnum1 == shape->argnum1
&& old_shapes->shapes[i].argnum2 == shape->argnum2
- && old_shapes->shapes[i].argnumc == shape->argnumc)
+ && old_shapes->shapes[i].argnumc == shape->argnumc
+ && old_shapes->shapes[i].argtotal == shape->argtotal)
{
found = true;
break;
ap->alternative[i].argnumc = shapes->shapes[i].argnumc;
ap->alternative[i].argnum1 = shapes->shapes[i].argnum1;
ap->alternative[i].argnum2 = shapes->shapes[i].argnum2;
+ ap->alternative[i].argtotal = shapes->shapes[i].argtotal;
ap->alternative[i].msgctxt = NULL;
ap->alternative[i].msgctxt_pos.file_name = NULL;
ap->alternative[i].msgctxt_pos.line_number = (size_t)(-1);
ccp->argnumc = cp->argnumc;
ccp->argnum1 = cp->argnum1;
ccp->argnum2 = cp->argnum2;
+ ccp->argtotal = cp->argtotal;
ccp->msgctxt = (cp->msgctxt != NULL ? xstrdup (cp->msgctxt) : NULL);
ccp->msgctxt_pos = cp->msgctxt_pos;
ccp->msgid = (cp->msgid != NULL ? xstrdup (cp->msgid) : NULL);
/* Test whether all alternatives are decided.
Note: A decided alternative can be complete
cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
+ && cp->argtotal == 0
or it can be failed if no literal strings were found at the specified
argument positions:
cp->argnumc <= argnum && cp->argnum1 <= argnum && cp->argnum2 <= argnum
+ or it can be failed if the number of arguments is exceeded:
+ cp->argtotal > 0 && cp->argtotal < argnum
*/
for (i = 0; i < ap->nalternatives; i++)
{
struct partial_call *cp = &ap->alternative[i];
- if (!(cp->argnumc <= argnum
- && cp->argnum1 <= argnum
- && cp->argnum2 <= argnum))
+ if (!((cp->argnumc <= argnum
+ && cp->argnum1 <= argnum
+ && cp->argnum2 <= argnum)
+ || (cp->argtotal > 0 && cp->argtotal < argnum)))
/* cp is still undecided. */
return false;
}
void
-arglist_parser_done (struct arglist_parser *ap)
+arglist_parser_done (struct arglist_parser *ap, int argnum)
{
size_t ncomplete;
size_t i;
{
struct partial_call *cp = &ap->alternative[i];
- if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0)
+ if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
+ && (cp->argtotal == 0 || cp->argtotal == argnum))
ncomplete++;
}
struct partial_call *cp = &ap->alternative[i];
if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
+ && (cp->argtotal == 0 || cp->argtotal == argnum)
&& cp->msgctxt != NULL
&& cp->msgid != NULL
&& cp->msgid_plural != NULL)
struct partial_call *cp = &ap->alternative[i];
if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
+ && (cp->argtotal == 0 || cp->argtotal == argnum)
&& cp->msgctxt != NULL
&& cp->msgid != NULL)
{
struct partial_call *cp = &ap->alternative[i];
if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
+ && (cp->argtotal == 0 || cp->argtotal == argnum)
&& cp->msgid != NULL
&& cp->msgid_plural != NULL)
{
struct partial_call *cp = &ap->alternative[i];
if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
+ && (cp->argtotal == 0 || cp->argtotal == argnum)
&& cp->msgid != NULL)
{
if (best_cp != NULL)
int argnum1; /* argument number to use for msgid */
int argnum2; /* argument number to use for msgid_plural */
int argnumc; /* argument number to use for msgctxt */
+ int argtotal; /* total number of arguments */
};
/* Split keyword spec into keyword, argnum1, argnum2, argnumc. */
int argnumc; /* number of context argument, 0 when seen */
int argnum1; /* number of singular argument, 0 when seen */
int argnum2; /* number of plural argument, 0 when seen */
+ int argtotal; /* total number of arguments, 0 if unspecified */
char *msgctxt; /* context - owned string, or NULL */
lex_pos_ty msgctxt_pos;
char *msgid; /* msgid - owned string, or NULL */
/* Tests whether an arglist_parser has is not waiting for more arguments after
argument ARGNUM. */
extern bool arglist_parser_decidedp (struct arglist_parser *ap, int argnum);
-/* Terminates the processing of an arglist_parser and deletes it. */
-extern void arglist_parser_done (struct arglist_parser *ap);
+/* Terminates the processing of an arglist_parser after argument ARGNUM and
+ deletes it. */
+extern void arglist_parser_done (struct arglist_parser *ap, int argnum);
#ifdef __cplusplus
+2005-10-18 Bruno Haible <bruno@clisp.org>
+
+ * xgettext-c-11: New file.
+ * Makefile.am (TESTS): Add it.
+
2005-10-05 Bruno Haible <bruno@clisp.org>
* msgfmt-15: New file.
xgettext-awk-1 \
xgettext-c-1 xgettext-c-2 xgettext-c-3 xgettext-c-4 xgettext-c-5 \
xgettext-c-6 xgettext-c-7 xgettext-c-8 xgettext-c-9 xgettext-c-10 \
+ xgettext-c-11 \
xgettext-csharp-1 xgettext-csharp-2 xgettext-csharp-3 \
xgettext-csharp-4 xgettext-csharp-5 \
xgettext-elisp-1 \
--- /dev/null
+#! /bin/sh
+
+# Test C support: extraction of contexts, disambiguating according to the
+# argument count.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles xg-c-11.c"
+cat <<\EOF > xg-c-11.c
+// (KDE) The 1-argument i18n macro is a simple gettext without context.
+print (i18n ("help"));
+// (KDE) The 2-argument i18n macro has the context first.
+print (i18n ("Help", "about"));
+// (KDE) The 3-argument i18n macro is an ngettext without context.
+print (i18n ("error", "errors", 7));
+EOF
+
+tmpfiles="$tmpfiles xg-c-11.po"
+: ${XGETTEXT=xgettext}
+${XGETTEXT} --omit-header --no-location \
+ --keyword=i18n:1 --keyword=i18n:1c,2,2t --keyword=i18n:1,2,3t \
+ xg-c-11.c -d xg-c-11
+test $? = 0 || { rm -fr $tmpfiles; exit 1; }
+
+tmpfiles="$tmpfiles xg-c-11.ok"
+cat <<EOF > xg-c-11.ok
+msgid "help"
+msgstr ""
+
+msgctxt "Help"
+msgid "about"
+msgstr ""
+
+msgid "error"
+msgid_plural "errors"
+msgstr[0] ""
+msgstr[1] ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-c-11.ok xg-c-11.po
+result=$?
+
+rm -fr $tmpfiles
+
+exit $result