the parts of the string.
+2003-12-29 Bruno Haible <bruno@clisp.org>
+
+ * xgettext.h: Include stdlib.h, str-list.h.
+ (struct refcounted_string_list_ty): New type.
+ (add_reference, drop_reference): New functions.
+ (savable_comment, savable_comment_add, savable_comment_reset,
+ savable_comment_to_xgettext_comment): New declarations.
+ * xgettext.c (savable_comment): New variable.
+ (savable_comment_add, savable_comment_reset,
+ savable_comment_to_xgettext_comment): New functions.
+ * x-java.c (struct refcounted_string_list_ty, comment, add_reference,
+ drop_reference, x_java_comment_add, x_java_comment_reset,
+ x_java_comment_to_xgettext_comment): Remove. Use replacement from
+ xgettext.{h,c} instead.
+ * x-csharp.c (struct refcounted_string_list_ty, comment, add_reference,
+ drop_reference, x_csharp_comment_add, x_csharp_comment_reset,
+ x_csharp_comment_to_xgettext_comment): Remove. Use replacement from
+ xgettext.{h,c} instead.
+ * x-c.c (comment_line_end): Call savable_comment_add instead of
+ xgettext_comment_add.
+ (struct token_ty): Add 'comment' field.
+ (free_token): Free it.
+ (phase5_get): Initialize token's 'comment' field.
+ (phase6_get): Call savable_comment_reset instead of
+ xgettext_comment_reset.
+ (phase8a_get): Initialize token's 'comment' field.
+ (phase8b_get): Call savable_comment_reset instead of
+ xgettext_comment_reset.
+ (phase8c_get): In @"...", use the comment of the first token, not of
+ the second.
+ (struct xgettext_token_ty): Add 'comment' field.
+ (x_c_lex): Deal with the token's comment.
+ (extract_parenthesized): Call savable_comment_to_xgettext_comment and
+ savable_comment_reset. Free the token's comment field.
+ * x-python.c (comment_line_end): Call savable_comment_add instead of
+ xgettext_comment_add.
+ (struct token_ty): Add 'comment' field.
+ (phase5_get): Call savable_comment_reset instead of
+ xgettext_comment_reset. Initialize token's 'comment' field.
+ (extract_parenthesized): Call savable_comment_to_xgettext_comment and
+ savable_comment_reset. Free the token's comment field.
+
2003-12-28 Bruno Haible <bruno@clisp.org>
* read-mo.h (read_mo_file): Change 'fn' into 'filename'.
buffer = xrealloc (buffer, bufmax);
}
buffer[buflen] = '\0';
- xgettext_comment_add (buffer);
+ savable_comment_add (buffer);
}
{
token_type_ty type;
char *string; /* for token_type_name, token_type_string_literal */
+ refcounted_string_list_ty *comment; /* for token_type_string_literal,
+ token_type_objc_special */
long number;
int line_number;
};
{
if (tp->type == token_type_name || tp->type == token_type_string_literal)
free (tp->string);
+ if (tp->type == token_type_string_literal
+ || tp->type == token_type_objc_special)
+ drop_reference (tp->comment);
}
buffer[bufpos] = 0;
tp->type = token_type_string_literal;
tp->string = xstrdup (buffer);
+ tp->comment = add_reference (savable_comment);
return;
case '(':
if (objc_extensions)
{
tp->type = token_type_objc_special;
+ tp->comment = add_reference (savable_comment);
return;
}
/* FALLTHROUGH */
free_token (&buf[j]);
/* We must reset the selected comments. */
- xgettext_comment_reset ();
+ savable_comment_reset ();
}
}
new_string[len + 2] = '\0';
free (tp->string);
tp->string = new_string;
+ tp->comment = add_reference (savable_comment);
tp->type = token_type_string_literal;
}
}
with non-white space tokens. */
++newline_count;
if (last_non_comment_line > last_comment_line)
- xgettext_comment_reset ();
+ savable_comment_reset ();
continue;
}
break;
return;
}
/* Drop the '@' token and return immediately the following string. */
+ drop_reference (tmp.comment);
+ tmp.comment = tp->comment;
*tp = tmp;
}
xgettext_token_type_keyword, xgettext_token_type_symbol. */
char *string;
+ /* This field is used only for xgettext_token_type_string_literal. */
+ refcounted_string_list_ty *comment;
+
/* These fields are only for
xgettext_token_type_keyword,
xgettext_token_type_string_literal. */
tp->type = xgettext_token_type_string_literal;
tp->string = token.string;
+ tp->comment = token.comment;
tp->pos.file_name = logical_file_name;
tp->pos.line_number = token.line_number;
return;
+ case token_type_objc_special:
+ drop_reference (token.comment);
+ /* FALLTHROUGH */
+
default:
last_non_comment_line = newline_count;
case xgettext_token_type_string_literal:
if (extract_all)
- remember_a_message (mlp, token.string, inner_context, &token.pos);
+ {
+ savable_comment_to_xgettext_comment (token.comment);
+ remember_a_message (mlp, token.string, inner_context, &token.pos);
+ savable_comment_reset ();
+ }
else
{
if (commas_to_skip == 0)
if (plural_mp == NULL)
{
/* Seen an msgid. */
- message_ty *mp =
- remember_a_message (mlp, token.string,
- inner_context, &token.pos);
+ message_ty *mp;
+
+ savable_comment_to_xgettext_comment (token.comment);
+ mp = remember_a_message (mlp, token.string,
+ inner_context, &token.pos);
+ savable_comment_reset ();
if (plural_commas > 0)
plural_mp = mp;
}
else
free (token.string);
}
+ drop_reference (token.comment);
next_context_iter = null_context_list_iterator;
selectorcall_context_iter = null_context_list_iterator;
state = 0;
/* ======================== Accumulating comments. ======================== */
-/* In this backend we cannot use the xgettext_comment* functions directly,
- because in multiline string expressions like
- "string1" +
- "string2"
- the newline between "string1" and "string2" would cause a call to
- xgettext_comment_reset(), thus destroying the accumulated comments
- that we need a little later, when we have concatenated the two strings
- and pass them to remember_a_message().
- Instead, we do the bookkeeping of the accumulated comments directly,
- and save a pointer to the accumulated comments when we read "string1".
- In order to avoid excessive copying of strings, we use reference
- counting. */
-
-typedef struct refcounted_string_list_ty refcounted_string_list_ty;
-struct refcounted_string_list_ty
-{
- unsigned int refcount;
- struct string_list_ty contents;
-};
-
-static refcounted_string_list_ty *comment;
-
-static inline refcounted_string_list_ty *
-add_reference (refcounted_string_list_ty *rslp)
-{
- if (rslp != NULL)
- rslp->refcount++;
- return rslp;
-}
-
-static inline void
-drop_reference (refcounted_string_list_ty *rslp)
-{
- if (rslp != NULL)
- {
- if (rslp->refcount > 1)
- rslp->refcount--;
- else
- {
- string_list_destroy (&rslp->contents);
- free (rslp);
- }
- }
-}
-
-static void
-x_csharp_comment_add (const char *str)
-{
- if (comment == NULL)
- {
- comment = (refcounted_string_list_ty *) xmalloc (sizeof (*comment));
- comment->refcount = 1;
- string_list_init (&comment->contents);
- }
- else if (comment->refcount > 1)
- {
- /* Unshare the list by making copies. */
- struct string_list_ty *oldcontents;
- size_t i;
-
- comment->refcount--;
- oldcontents = &comment->contents;
-
- comment = (refcounted_string_list_ty *) xmalloc (sizeof (*comment));
- comment->refcount = 1;
- string_list_init (&comment->contents);
- for (i = 0; i < oldcontents->nitems; i++)
- string_list_append (&comment->contents, oldcontents->item[i]);
- }
- string_list_append (&comment->contents, str);
-}
-
-static void
-x_csharp_comment_reset ()
-{
- drop_reference (comment);
- comment = NULL;
-}
-
-static void
-x_csharp_comment_to_xgettext_comment (refcounted_string_list_ty *rslp)
-{
- xgettext_comment_reset ();
- if (rslp != NULL)
- {
- size_t i;
-
- for (i = 0; i < rslp->contents.nitems; i++)
- xgettext_comment_add (rslp->contents.item[i]);
- }
-}
-
-
/* Accumulating a single comment line. */
static struct string_buffer comment_buffer;
&& (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
--buflen;
buffer[buflen] = '\0';
- x_csharp_comment_add (buffer);
+ savable_comment_add (buffer);
}
{
case UNL:
if (last_non_comment_line > last_comment_line)
- x_csharp_comment_reset ();
+ savable_comment_reset ();
/* FALLTHROUGH */
case ' ':
case '\t':
accumulate_escaped (&literal, '"');
tp->string = xstrdup (string_buffer_result (&literal));
free_string_buffer (&literal);
- tp->comment = add_reference (comment);
+ tp->comment = add_reference (savable_comment);
tp->type = token_type_string_literal;
return;
}
}
tp->string = xstrdup (string_buffer_result (&literal));
free_string_buffer (&literal);
- tp->comment = add_reference (comment);
+ tp->comment = add_reference (savable_comment);
tp->type = token_type_string_literal;
return;
}
if (extract_all)
{
xgettext_current_source_encoding = po_charset_utf8;
- x_csharp_comment_to_xgettext_comment (token.comment);
+ savable_comment_to_xgettext_comment (token.comment);
remember_a_message (mlp, token.string, inner_context, &pos);
- x_csharp_comment_reset ();
+ savable_comment_reset ();
xgettext_current_source_encoding = xgettext_global_source_encoding;
}
else
message_ty *mp;
xgettext_current_source_encoding = po_charset_utf8;
- x_csharp_comment_to_xgettext_comment (token.comment);
+ savable_comment_to_xgettext_comment (token.comment);
mp = remember_a_message (mlp, token.string,
inner_context, &pos);
- x_csharp_comment_reset ();
+ savable_comment_reset ();
xgettext_current_source_encoding = xgettext_global_source_encoding;
if (plural_commas > 0)
plural_mp = mp;
/* ======================== Accumulating comments. ======================== */
-/* In this backend we cannot use the xgettext_comment* functions directly,
- because in multiline string expressions like
- "string1" +
- "string2"
- the newline between "string1" and "string2" would cause a call to
- xgettext_comment_reset(), thus destroying the accumulated comments
- that we need a little later, when we have concatenated the two strings
- and pass them to remember_a_message().
- Instead, we do the bookkeeping of the accumulated comments directly,
- and save a pointer to the accumulated comments when we read "string1".
- In order to avoid excessive copying of strings, we use reference
- counting. */
-
-typedef struct refcounted_string_list_ty refcounted_string_list_ty;
-struct refcounted_string_list_ty
-{
- unsigned int refcount;
- struct string_list_ty contents;
-};
-
-static refcounted_string_list_ty *comment;
-
-static inline refcounted_string_list_ty *
-add_reference (refcounted_string_list_ty *rslp)
-{
- if (rslp != NULL)
- rslp->refcount++;
- return rslp;
-}
-
-static inline void
-drop_reference (refcounted_string_list_ty *rslp)
-{
- if (rslp != NULL)
- {
- if (rslp->refcount > 1)
- rslp->refcount--;
- else
- {
- string_list_destroy (&rslp->contents);
- free (rslp);
- }
- }
-}
-
-static void
-x_java_comment_add (const char *str)
-{
- if (comment == NULL)
- {
- comment = (refcounted_string_list_ty *) xmalloc (sizeof (*comment));
- comment->refcount = 1;
- string_list_init (&comment->contents);
- }
- else if (comment->refcount > 1)
- {
- /* Unshare the list by making copies. */
- struct string_list_ty *oldcontents;
- size_t i;
-
- comment->refcount--;
- oldcontents = &comment->contents;
-
- comment = (refcounted_string_list_ty *) xmalloc (sizeof (*comment));
- comment->refcount = 1;
- string_list_init (&comment->contents);
- for (i = 0; i < oldcontents->nitems; i++)
- string_list_append (&comment->contents, oldcontents->item[i]);
- }
- string_list_append (&comment->contents, str);
-}
-
-static void
-x_java_comment_reset ()
-{
- drop_reference (comment);
- comment = NULL;
-}
-
-static void
-x_java_comment_to_xgettext_comment (refcounted_string_list_ty *rslp)
-{
- xgettext_comment_reset ();
- if (rslp != NULL)
- {
- size_t i;
-
- for (i = 0; i < rslp->contents.nitems; i++)
- xgettext_comment_add (rslp->contents.item[i]);
- }
-}
-
-
/* Accumulating a single comment line. */
static struct string_buffer comment_buffer;
&& (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
--buflen;
buffer[buflen] = '\0';
- x_java_comment_add (buffer);
+ savable_comment_add (buffer);
}
{
case '\n':
if (last_non_comment_line > last_comment_line)
- x_java_comment_reset ();
+ savable_comment_reset ();
/* FALLTHROUGH */
case ' ':
case '\t':
accumulate_escaped (&literal, '"');
tp->string = xstrdup (string_buffer_result (&literal));
free_string_buffer (&literal);
- tp->comment = add_reference (comment);
+ tp->comment = add_reference (savable_comment);
tp->type = token_type_string_literal;
return;
}
if (extract_all)
{
xgettext_current_source_encoding = po_charset_utf8;
- x_java_comment_to_xgettext_comment (token.comment);
+ savable_comment_to_xgettext_comment (token.comment);
remember_a_message (mlp, token.string, inner_context, &pos);
- x_java_comment_reset ();
+ savable_comment_reset ();
xgettext_current_source_encoding = xgettext_global_source_encoding;
}
else
message_ty *mp;
xgettext_current_source_encoding = po_charset_utf8;
- x_java_comment_to_xgettext_comment (token.comment);
+ savable_comment_to_xgettext_comment (token.comment);
mp = remember_a_message (mlp, token.string,
inner_context, &pos);
- x_java_comment_reset ();
+ savable_comment_reset ();
xgettext_current_source_encoding = xgettext_global_source_encoding;
if (plural_commas > 0)
plural_mp = mp;
buffer = xrealloc (buffer, bufmax);
}
buffer[buflen] = '\0';
- xgettext_comment_add (buffer);
+ savable_comment_add (buffer);
}
/* These are for tracking whether comments count as immediately before
{
token_type_ty type;
char *string; /* for token_type_string, token_type_symbol */
+ refcounted_string_list_ty *comment; /* for token_type_string */
int line_number;
};
case '\n':
if (last_non_comment_line > last_comment_line)
- xgettext_comment_reset ();
+ savable_comment_reset ();
/* Ignore newline if and only if it is used for implicit line
joining. */
if (open_pbb > 0)
assert (q - utf8_string <= 3 * bufpos);
tp->string = (char *) utf8_string;
}
+ tp->comment = add_reference (savable_comment);
tp->type = token_type_string;
return;
}
pos.line_number = token.line_number;
if (extract_all)
- remember_a_message (mlp, token.string, inner_context, &pos);
+ {
+ savable_comment_to_xgettext_comment (token.comment);
+ remember_a_message (mlp, token.string, inner_context, &pos);
+ savable_comment_reset ();
+ }
else
{
if (commas_to_skip == 0)
if (plural_mp == NULL)
{
/* Seen an msgid. */
- message_ty *mp =
- remember_a_message (mlp, token.string,
- inner_context, &pos);
+ message_ty *mp;
+
+ savable_comment_to_xgettext_comment (token.comment);
+ mp = remember_a_message (mlp, token.string,
+ inner_context, &pos);
+ savable_comment_reset ();
if (plural_commas > 0)
plural_mp = mp;
}
free (token.string);
}
}
+ drop_reference (token.comment);
next_context_iter = null_context_list_iterator;
state = 0;
continue;
}
+refcounted_string_list_ty *savable_comment;
+
+void
+savable_comment_add (const char *str)
+{
+ if (savable_comment == NULL)
+ {
+ savable_comment =
+ (refcounted_string_list_ty *) xmalloc (sizeof (*savable_comment));
+ savable_comment->refcount = 1;
+ string_list_init (&savable_comment->contents);
+ }
+ else if (savable_comment->refcount > 1)
+ {
+ /* Unshare the list by making copies. */
+ struct string_list_ty *oldcontents;
+ size_t i;
+
+ savable_comment->refcount--;
+ oldcontents = &savable_comment->contents;
+
+ savable_comment =
+ (refcounted_string_list_ty *) xmalloc (sizeof (*savable_comment));
+ savable_comment->refcount = 1;
+ string_list_init (&savable_comment->contents);
+ for (i = 0; i < oldcontents->nitems; i++)
+ string_list_append (&savable_comment->contents, oldcontents->item[i]);
+ }
+ string_list_append (&savable_comment->contents, str);
+}
+
+void
+savable_comment_reset ()
+{
+ drop_reference (savable_comment);
+ savable_comment = NULL;
+}
+
+void
+savable_comment_to_xgettext_comment (refcounted_string_list_ty *rslp)
+{
+ xgettext_comment_reset ();
+ if (rslp != NULL)
+ {
+ size_t i;
+
+ for (i = 0; i < rslp->contents.nitems; i++)
+ xgettext_comment_add (rslp->contents.item[i]);
+ }
+}
+
+
static FILE *
xgettext_open (const char *fn,
#define _XGETTEXT_H
#include <stddef.h>
+#include <stdlib.h>
#if HAVE_ICONV
#include <iconv.h>
#include "message.h"
#include "pos.h"
+#include "str-list.h"
/* Declare 'line_comment' and 'input_syntax'. */
#include "read-po.h"
extern void xgettext_comment_reset (void);
+/* Comment handling for backends which support combining adjacent strings
+ even across lines.
+ In these backends we cannot use the xgettext_comment* functions directly,
+ because in multiline string expressions like
+ "string1" +
+ "string2"
+ the newline between "string1" and "string2" would cause a call to
+ xgettext_comment_reset(), thus destroying the accumulated comments
+ that we need a little later, when we have concatenated the two strings
+ and pass them to remember_a_message().
+ Instead, we do the bookkeeping of the accumulated comments directly,
+ and save a pointer to the accumulated comments when we read "string1".
+ In order to avoid excessive copying of strings, we use reference
+ counting. */
+
+typedef struct refcounted_string_list_ty refcounted_string_list_ty;
+struct refcounted_string_list_ty
+{
+ unsigned int refcount;
+ struct string_list_ty contents;
+};
+
+static inline refcounted_string_list_ty *
+add_reference (refcounted_string_list_ty *rslp)
+{
+ if (rslp != NULL)
+ rslp->refcount++;
+ return rslp;
+}
+
+static inline void
+drop_reference (refcounted_string_list_ty *rslp)
+{
+ if (rslp != NULL)
+ {
+ if (rslp->refcount > 1)
+ rslp->refcount--;
+ else
+ {
+ string_list_destroy (&rslp->contents);
+ free (rslp);
+ }
+ }
+}
+
+extern refcounted_string_list_ty *savable_comment;
+extern void savable_comment_add (const char *str);
+extern void savable_comment_reset (void);
+extern void savable_comment_to_xgettext_comment (refcounted_string_list_ty *rslp);
+
+
/* Add a message to the list of extracted messages.
string must be malloc()ed string; its ownership is passed to the callee.
pos->file_name must be allocated with indefinite extent. */
+2003-12-29 Bruno Haible <bruno@clisp.org>
+
+ * xgettext-c-9: Add a test with a multi-part string with newlines and
+ comments between the parts.
+ * xgettext-java-5: Likewise.
+ * xgettext-csharp-5: Likewise.
+ * xgettext-python-2: Likewise.
+ * xgettext-objc-2: New file.
+ * Makefile.am (TESTS): Add it.
+
2003-12-26 Bruno Haible <bruno@clisp.org>
Support for C#.
xgettext-java-5 \
xgettext-librep-1 \
xgettext-lisp-1 \
- xgettext-objc-1 \
+ xgettext-objc-1 xgettext-objc-2 \
xgettext-perl-1 xgettext-perl-2 xgettext-perl-3 xgettext-perl-4 \
xgettext-perl-5 \
xgettext-php-1 \
Nickname of the Beatles
*/
print (gettext ("The Fabulous Four"));
+/* TRANSLATORS: The strings get concatenated. */
+print (gettext ("there is not enough"
+" room on a single line for this entire long, " // confusing, eh?
+"verbose string"));
EOF
tmpfiles="$tmpfiles xg-c-9.po"
#.
msgid "The Fabulous Four"
msgstr ""
+
+#. TRANSLATORS: The strings get concatenated.
+msgid ""
+"there is not enough room on a single line for this entire long, verbose "
+"string"
+msgstr ""
EOF
: ${DIFF=diff}
Nickname of the Beatles
*/
Console.WriteLine(GetString("The Fabulous Four"));
+/* TRANSLATORS: The strings get concatenated. */
+Console.WriteLine(GetString("there is not enough" +
+" room on a single line for this entire long, " // confusing, eh?
++ "verbose string"));
EOF
tmpfiles="$tmpfiles xg-cs-5.po"
#.
msgid "The Fabulous Four"
msgstr ""
+
+#. TRANSLATORS: The strings get concatenated.
+msgid ""
+"there is not enough room on a single line for this entire long, verbose "
+"string"
+msgstr ""
EOF
: ${DIFF=diff}
Nickname of the Beatles
*/
System.out.println(gettext("The Fabulous Four"));
+/* TRANSLATORS: The strings get concatenated. */
+System.out.println(gettext("there is not enough" +
+" room on a single line for this entire long, " // confusing, eh?
++ "verbose string"));
EOF
tmpfiles="$tmpfiles xg-j-5.po"
#.
msgid "The Fabulous Four"
msgstr ""
+
+#. TRANSLATORS: The strings get concatenated.
+msgid ""
+"there is not enough room on a single line for this entire long, verbose "
+"string"
+msgstr ""
EOF
: ${DIFF=diff}
# TRANSLATORS:
# Nickname of the Beatles
print gettext.gettext("The Fabulous Four")
+# TRANSLATORS: The strings get concatenated.
+print gettext.gettext("there is not enough"
+" room on a single line for this entire long, " # confusing, eh?
+"verbose string")
EOF
tmpfiles="$tmpfiles xg-py-2.po"
#. Nickname of the Beatles
msgid "The Fabulous Four"
msgstr ""
+
+#. TRANSLATORS: The strings get concatenated.
+msgid ""
+"there is not enough room on a single line for this entire long, verbose "
+"string"
+msgstr ""
EOF
: ${DIFF=diff}