summaryrefslogtreecommitdiffstats
path: root/gettext-tools/src
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2003-04-29 10:12:15 +0000
committerBruno Haible <bruno@clisp.org>2009-06-23 12:10:24 +0200
commitcde7e9fa958cdb60d1762921d4704c6b1c3e2504 (patch)
treed5003e47cbac8839b22dbf9ee20723b141a42472 /gettext-tools/src
parentb6d32da76eb3a2aebea75850c5696c0122cfa385 (diff)
downloadexternal_gettext-cde7e9fa958cdb60d1762921d4704c6b1c3e2504.zip
external_gettext-cde7e9fa958cdb60d1762921d4704c6b1c3e2504.tar.gz
external_gettext-cde7e9fa958cdb60d1762921d4704c6b1c3e2504.tar.bz2
Support Java .properties files as alternative syntax, like PO files.
Diffstat (limited to 'gettext-tools/src')
-rw-r--r--gettext-tools/src/ChangeLog121
-rw-r--r--gettext-tools/src/FILES10
-rw-r--r--gettext-tools/src/Makefile.am23
-rw-r--r--gettext-tools/src/Makefile.msvc8
-rw-r--r--gettext-tools/src/Makefile.vms8
-rw-r--r--gettext-tools/src/message.c1
-rw-r--r--gettext-tools/src/message.h3
-rw-r--r--gettext-tools/src/msgattrib.c19
-rw-r--r--gettext-tools/src/msgcat.c26
-rw-r--r--gettext-tools/src/msgcmp.c12
-rw-r--r--gettext-tools/src/msgcomm.c19
-rw-r--r--gettext-tools/src/msgconv.c31
-rw-r--r--gettext-tools/src/msgen.c19
-rw-r--r--gettext-tools/src/msgexec.c13
-rw-r--r--gettext-tools/src/msgfilter.c20
-rw-r--r--gettext-tools/src/msgfmt.c31
-rw-r--r--gettext-tools/src/msggrep.c19
-rw-r--r--gettext-tools/src/msginit.c19
-rw-r--r--gettext-tools/src/msgl-cat.c20
-rw-r--r--gettext-tools/src/msgl-iconv.c3
-rw-r--r--gettext-tools/src/msgmerge.c29
-rw-r--r--gettext-tools/src/msgunfmt.c9
-rw-r--r--gettext-tools/src/msguniq.c19
-rw-r--r--gettext-tools/src/po-gram-gen.y20
-rw-r--r--gettext-tools/src/po-lex.c7
-rw-r--r--gettext-tools/src/read-po-abstract.c54
-rw-r--r--gettext-tools/src/read-po-abstract.h21
-rw-r--r--gettext-tools/src/read-po.c23
-rw-r--r--gettext-tools/src/read-po.h9
-rw-r--r--gettext-tools/src/read-properties.c543
-rw-r--r--gettext-tools/src/read-properties.h30
-rw-r--r--gettext-tools/src/write-java.c4
-rw-r--r--gettext-tools/src/write-java.h3
-rw-r--r--gettext-tools/src/write-po.c142
-rw-r--r--gettext-tools/src/write-po.h2
-rw-r--r--gettext-tools/src/write-properties.c291
-rw-r--r--gettext-tools/src/write-properties.h33
-rw-r--r--gettext-tools/src/write-tcl.c4
-rw-r--r--gettext-tools/src/write-tcl.h4
-rw-r--r--gettext-tools/src/x-po.c36
-rw-r--r--gettext-tools/src/x-properties.h29
-rw-r--r--gettext-tools/src/xgettext.c17
-rw-r--r--gettext-tools/src/xgettext.h4
43 files changed, 1608 insertions, 150 deletions
diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog
index 7fde60e..6d1948d 100644
--- a/gettext-tools/src/ChangeLog
+++ b/gettext-tools/src/ChangeLog
@@ -1,3 +1,124 @@
+2003-04-26 Bruno Haible <bruno@clisp.org>
+
+ * message.h (msgdomain_list_ty): Add field 'encoding'.
+ * message.c (msgdomain_list_alloc): Initialize it.
+ * read-properties.h: New file.
+ * read-properties.c: New file.
+ * read-po-abstract.h (abstract_po_reader_class_ty): In
+ directive_message field, add force_fuzzy argument.
+ (po_scan_start, po_scan_end): Remove declarations.
+ (input_syntax_ty): New type.
+ (po_callback_message): Add force_fuzzy argument.
+ * read-po-abstract.c (call_directive_message, po_callback_message):
+ Add force_fuzzy argument.
+ (po_scan_start, po_scan_end): Make static.
+ (po_scan): Add support for syntax_properties. Move
+ error_message_count handling to here.
+ (po_callback_message): Move po_lex_charset_set invocation away.
+ * read-po.h (default_po_reader_class_ty): In add_message field, add
+ force_fuzzy argument.
+ (default_directive_message, default_add_message): Add force_fuzzy
+ argument.
+ (inout_syntax): New declaration.
+ * read-po.c (call_add_message): Add force_fuzzy argument.
+ (default_directive_message, default_add_message): Likewise.
+ (input_syntax): New variable.
+ (read_po): Pass input_syntax to po_scan(). Set mdlp->encoding if
+ possible.
+ * po-gram-gen.y: Pass force_fuzzy = false.
+ (do_callback_message): New function. Move po_lex_charset_set
+ invocation to here.
+ * po-lex.c (lex_end): Move error_message_count handling away.
+ * write-properties.h: New file.
+ * write-properties.c: New file.
+ * write-po.h (message_print_syntax_properties): New declaration.
+ * write-po.c (use_syntax_properties): New variable.
+ (message_print_syntax_properties): New function.
+ (msgdomain_list_print_po): New function, extracted from
+ msgdomain_list_print.
+ (msgdomain_list_print): Add check for plural forms. Add support for
+ writing the .properties format.
+ (extract_po): Renamed from extract.
+ * write-java.h (msgdomain_write_java): Add canon_encoding argument.
+ * write-java.c (msgdomain_write_java): Likewise.
+ * write-tcl.h (msgdomain_write_tcl): Likewise.
+ * write-tcl.c (msgdomain_write_tcl): Likewise.
+ * msgl-cat.c (catenate_msgdomain_list): Use mdlp->encoding if there
+ is no header entry. Set total_mdlp->encoding if possible.
+ * msgl-iconv.c (iconv_msgdomain_list): Use mdlp->encoding if there
+ is no header entry. Set mdlp->encoding.
+ * msgattrib.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msgcat.c (long_options): Add --properties-input/output.
+ (main): Handle them. If option -p is used, convert to UTF-8 and
+ ignore the to_code.
+ (usage): Document options -P and -p.
+ * msgcomm.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msgconv.c (long_options): Add --properties-input/output.
+ (main): Handle them. If option -p is used, ignore the to_code.
+ (usage): Document options -P and -p.
+ * msgen.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msgfilter.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msggrep.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msginit.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msgmerge.c (long_options): Add --properties-input/output.
+ (main): Handle them. In update mode, --properties-input implies
+ --properties-output.
+ (usage): Document options -P and -p.
+ (merge): Set result->encoding if possible.
+ * msguniq.c (long_options): Add --properties-input/output.
+ (main): Handle them.
+ (usage): Document options -P and -p.
+ * msgcmp.c (long_options): Add --properties-input.
+ (main): Handle it.
+ (usage): Document option -P.
+ * msgexec.c (long_options): Add --properties-input.
+ (main): Handle it.
+ (usage): Document option -P.
+ * msgfmt.c (long_options): Add --properties-input.
+ (main): Handle it. Pass the known canon_encoding to
+ msgdomain_write_java and msgdomain_write_tcl.
+ (usage): Document option -P.
+ (msgfmt_add_message): Add force_fuzzy argument.
+ (read_po_file_msgfmt): Pass input_syntax to po_scan().
+ * msgunfmt.c (long_options): Add --properties-output.
+ (main): Handle it.
+ (usage): Document option -p.
+ * x-properties.h: New file.
+ * x-po.c (extract_add_message): Add force_fuzzy argument.
+ (extract): Renamed from extract_po. Pass input_syntax to po_scan().
+ (extract_po): New function.
+ (extract_properties): New function.
+ * xgettext.h: Include read-po.h.
+ * xgettext.c (long_options): Add --properties-output.
+ (main): Handle it.
+ (usage): Document options -L JavaProperties and --properties-output.
+ (exclude_directive_message): Add force_fuzzy argument.
+ (read_exclusion_file): Pass input_syntax to po_scan().
+ (table): Add support for .properties format.
+ * Makefile.am (noinst_HEADERS): Add read-properties.h,
+ write-properties.h, x-properties.h.
+ (COMMON_SOURCE): Add read-properties.c.
+ (libgettextsrc_la_SOURCES): Add write-properties.c.
+ * Makefile.msvc (OBJECTS): Add read-properties.obj,
+ write-properties.obj.
+ (read-properties.obj, write-properties.obj): New rules.
+ * Makefile.vms (OBJECTS): Add read-properties.obj,
+ write-properties.obj.
+ (read-properties.obj, write-properties.obj): New rules.
+ * FILES: Update.
+
2003-04-21 Bruno Haible <bruno@clisp.org>
* read-po-abstract.h (po_scan_file): Remove declaration.
diff --git a/gettext-tools/src/FILES b/gettext-tools/src/FILES
index d8b35fa..6f9c17a 100644
--- a/gettext-tools/src/FILES
+++ b/gettext-tools/src/FILES
@@ -35,6 +35,9 @@ msgl-ascii.c
write-po.h
write-po.c
Output of a list-of-messages to a PO file.
+write-properties.h
+write-properties.c
+ Output of a list-of-messages to a Java .properties file.
+-------------- Reading PO files
| open-po.h
@@ -54,8 +57,10 @@ write-po.c
| po-hash-gen.y
| po-gram.h
| po-gram-gen.y
+| read-properties.h
+| read-properties.c
| read-po-abstract.c
-| Parsing of PO files.
+| Parsing of PO files and Java .properties files.
| read-po-abstract.h
| General parser structure.
| po-hash.h
@@ -65,6 +70,9 @@ write-po.c
| po-gram.h
| po-gram-gen.y
| Parsing of PO files, based on po-lex.{h,c}.
+| read-properties.h
+| read-properties.c
+| Parsing of Java .properties files.
| read-po-abstract.c
| Top-level parser functions and callbacks.
|
diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am
index 15103e8..4c1d99b 100644
--- a/gettext-tools/src/Makefile.am
+++ b/gettext-tools/src/Makefile.am
@@ -35,13 +35,14 @@ lib_LTLIBRARIES = libgettextsrc.la libgettextpo.la
include_HEADERS = gettext-po.h
noinst_HEADERS = pos.h message.h po-gram.h po-hash.h po-charset.h po-lex.h \
-open-po.h read-po-abstract.h read-po.h str-list.h write-po.h dir-list.h \
-file-list.h po-gram-gen.h po-gram-gen2.h po-hash-gen.h msgl-charset.h \
-msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-english.h msgfmt.h \
-msgunfmt.h read-mo.h write-mo.h read-java.h write-java.h read-tcl.h \
-write-tcl.h po-time.h plural-table.h format.h xgettext.h x-c.h x-po.h \
-x-python.h x-lisp.h x-elisp.h x-librep.h x-smalltalk.h x-java.h x-awk.h \
-x-ycp.h x-tcl.h x-php.h x-rst.h x-glade.h
+open-po.h read-po-abstract.h read-po.h read-properties.h str-list.h \
+write-po.h write-properties.h dir-list.h file-list.h po-gram-gen.h \
+po-gram-gen2.h po-hash-gen.h msgl-charset.h msgl-equal.h msgl-iconv.h \
+msgl-ascii.h msgl-cat.h msgl-english.h msgfmt.h msgunfmt.h read-mo.h \
+write-mo.h read-java.h write-java.h read-tcl.h write-tcl.h po-time.h \
+plural-table.h format.h xgettext.h x-c.h x-po.h x-python.h x-lisp.h x-elisp.h \
+x-librep.h x-smalltalk.h x-java.h x-properties.h x-awk.h x-ycp.h x-tcl.h \
+x-php.h x-rst.h x-glade.h
EXTRA_DIST += FILES project-id ChangeLog.0
@@ -86,7 +87,7 @@ JAVACOMP = $(SHELL) ../lib/javacomp.sh
# (read-po-abstract.c <--> po-hash-gen.y <--> po-gram-gen.y <--> po-lex.c) -> message.c -> str-list.c.
COMMON_SOURCE = message.c \
read-po-abstract.c po-lex.c po-gram-gen.y po-hash-gen.y po-charset.c \
-open-po.c dir-list.c str-list.c
+read-properties.c open-po.c dir-list.c str-list.c
# xgettext and msgfmt deal with format strings.
FORMAT_SOURCE = format.c format-invalid.h \
@@ -96,9 +97,9 @@ format-php.c
# libgettextsrc contains all code that is needed by at least two programs.
libgettextsrc_la_SOURCES = \
-$(COMMON_SOURCE) read-po.c write-po.c msgl-ascii.c msgl-iconv.c msgl-equal.c \
-msgl-cat.c msgl-english.c file-list.c msgl-charset.c po-time.c plural.c \
-plural-table.c $(FORMAT_SOURCE)
+$(COMMON_SOURCE) read-po.c write-properties.c write-po.c msgl-ascii.c \
+msgl-iconv.c msgl-equal.c msgl-cat.c msgl-english.c file-list.c \
+msgl-charset.c po-time.c plural.c plural-table.c $(FORMAT_SOURCE)
# libgettextpo contains the public API for PO files.
libgettextpo_la_SOURCES = gettext-po.c
diff --git a/gettext-tools/src/Makefile.msvc b/gettext-tools/src/Makefile.msvc
index a824f10..ee93260 100644
--- a/gettext-tools/src/Makefile.msvc
+++ b/gettext-tools/src/Makefile.msvc
@@ -109,10 +109,12 @@ OBJECTS = \
po-gram-gen.obj \
po-hash-gen.obj \
po-charset.obj \
+ read-properties.obj \
open-po.obj \
dir-list.obj \
str-list.obj \
read-po.obj \
+ write-properties.obj \
write-po.obj \
msgl-ascii.obj \
msgl-iconv.obj \
@@ -178,6 +180,9 @@ po-hash-gen.obj : po-hash-gen.c
po-charset.obj : po-charset.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c po-charset.c
+read-properties.obj : read-properties.c
+ $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-properties.c
+
open-po.obj : open-po.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c open-po.c
@@ -190,6 +195,9 @@ str-list.obj : str-list.c
read-po.obj : read-po.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-po.c
+write-properties.obj : write-properties.c
+ $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-properties.c
+
write-po.obj : write-po.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-po.c
diff --git a/gettext-tools/src/Makefile.vms b/gettext-tools/src/Makefile.vms
index 481c3d3..6c297c3 100644
--- a/gettext-tools/src/Makefile.vms
+++ b/gettext-tools/src/Makefile.vms
@@ -57,10 +57,12 @@ OBJECTS = \
po-gram-gen.obj, \
po-hash-gen.obj, \
po-charset.obj, \
+ read-properties.obj, \
open-po.obj, \
dir-list.obj, \
str-list.obj, \
read-po.obj, \
+ write-properties.obj, \
write-po.obj, \
msgl-ascii.obj, \
msgl-iconv.obj, \
@@ -124,6 +126,9 @@ po-hash-gen.obj : po-hash-gen.c
po-charset.obj : po-charset.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) po-charset.c
+read-properties.obj : read-properties.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-properties.c
+
open-po.obj : open-po.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) open-po.c
@@ -136,6 +141,9 @@ str-list.obj : str-list.c
read-po.obj : read-po.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-po.c
+write-properties.obj : write-properties.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-properties.c
+
write-po.obj : write-po.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-po.c
diff --git a/gettext-tools/src/message.c b/gettext-tools/src/message.c
index 2b9bc57..6306bc1 100644
--- a/gettext-tools/src/message.c
+++ b/gettext-tools/src/message.c
@@ -524,6 +524,7 @@ msgdomain_list_alloc (bool use_hashtable)
(msgdomain_ty **) xmalloc (mdlp->nitems_max * sizeof (msgdomain_ty *));
mdlp->item[0] = msgdomain_alloc (MESSAGE_DOMAIN_DEFAULT, use_hashtable);
mdlp->use_hashtable = use_hashtable;
+ mdlp->encoding = NULL;
return mdlp;
}
diff --git a/gettext-tools/src/message.h b/gettext-tools/src/message.h
index fe506d7..393ede2 100644
--- a/gettext-tools/src/message.h
+++ b/gettext-tools/src/message.h
@@ -1,5 +1,5 @@
/* GNU gettext - internationalization aids
- Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
+ Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc.
This file was written by Peter Miller <millerp@canb.auug.org.au>
@@ -235,6 +235,7 @@ struct msgdomain_list_ty
size_t nitems;
size_t nitems_max;
bool use_hashtable;
+ const char *encoding; /* canonicalized encoding or NULL if unknown */
};
extern msgdomain_list_ty *
diff --git a/gettext-tools/src/msgattrib.c b/gettext-tools/src/msgattrib.c
index 9b8dab6..a394d6f 100644
--- a/gettext-tools/src/msgattrib.c
+++ b/gettext-tools/src/msgattrib.c
@@ -89,6 +89,8 @@ static const struct option long_options[] =
{ "only-fuzzy", no_argument, NULL, CHAR_MAX + 4 },
{ "only-obsolete", no_argument, NULL, CHAR_MAX + 6 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "set-fuzzy", no_argument, NULL, CHAR_MAX + 7 },
{ "set-obsolete", no_argument, NULL, CHAR_MAX + 9 },
{ "sort-by-file", no_argument, NULL, 'F' },
@@ -150,7 +152,7 @@ main (int argc, char **argv)
only_file = NULL;
ignore_file = NULL;
- while ((optchar = getopt_long (argc, argv, "D:eEFhino:sVw:", long_options,
+ while ((optchar = getopt_long (argc, argv, "D:eEFhino:pPsVw:", long_options,
NULL)) != EOF)
switch (optchar)
{
@@ -189,6 +191,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -412,6 +422,11 @@ Attribute manipulation:\n"));
--obsolete synonym for --only-obsolete --clear-obsolete\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-e, --no-escape do not use C escapes in output (default)\n"));
@@ -428,6 +443,8 @@ Output details:\n"));
printf (_("\
--strict write out strict Uniforum conforming .po file\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgcat.c b/gettext-tools/src/msgcat.c
index 4a07bf6..a4d3e5b 100644
--- a/gettext-tools/src/msgcat.c
+++ b/gettext-tools/src/msgcat.c
@@ -64,6 +64,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -97,6 +99,7 @@ main (int argc, char **argv)
const char *files_from;
string_list_ty *file_list;
msgdomain_list_ty *result;
+ input_syntax_ty output_syntax = syntax_po;
bool sort_by_msgid = false;
bool sort_by_filepos = false;
@@ -122,7 +125,7 @@ main (int argc, char **argv)
less_than = INT_MAX;
use_first = false;
- while ((optchar = getopt_long (argc, argv, "<:>:D:eEf:Fhino:st:uVw:",
+ while ((optchar = getopt_long (argc, argv, "<:>:D:eEf:Fhino:pPst:uVw:",
long_options, NULL)) != EOF)
switch (optchar)
{
@@ -185,6 +188,15 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ output_syntax = syntax_properties;
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -271,7 +283,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
string_list_append_unique (file_list, argv[cnt]);
/* Read input files, then filter, convert and merge messages. */
- result = catenate_msgdomain_list (file_list, to_code);
+ result = catenate_msgdomain_list (file_list,
+ output_syntax != syntax_properties
+ ? to_code
+ : "UTF-8");
string_list_free (file_list);
@@ -349,6 +364,11 @@ Message selection:\n"));
that only unique messages be printed\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input files are in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-t, --to-code=NAME encoding for output\n"));
@@ -370,6 +390,8 @@ Output details:\n"));
printf (_("\
--strict write out strict Uniforum conforming .po file\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgcmp.c b/gettext-tools/src/msgcmp.c
index 6f627a3..c26f0f7 100644
--- a/gettext-tools/src/msgcmp.c
+++ b/gettext-tools/src/msgcmp.c
@@ -52,6 +52,7 @@ static const struct option long_options[] =
{ "directory", required_argument, NULL, 'D' },
{ "help", no_argument, NULL, 'h' },
{ "multi-domain", no_argument, NULL, 'm' },
+ { "properties-input", no_argument, NULL, 'P' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
@@ -89,7 +90,7 @@ main (int argc, char *argv[])
do_help = false;
do_version = false;
- while ((optchar = getopt_long (argc, argv, "D:hmV", long_options, NULL))
+ while ((optchar = getopt_long (argc, argv, "D:hmPV", long_options, NULL))
!= EOF)
switch (optchar)
{
@@ -108,6 +109,10 @@ main (int argc, char *argv[])
multi_domain_mode = true;
break;
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 'V':
do_version = true;
break;
@@ -194,6 +199,11 @@ Operation modifiers:\n"));
-m, --multi-domain apply ref.pot to each of the domains in def.po\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input files are in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Informative output:\n"));
printf (_("\
-h, --help display this help and exit\n"));
diff --git a/gettext-tools/src/msgcomm.c b/gettext-tools/src/msgcomm.c
index 0b82193..3295409 100644
--- a/gettext-tools/src/msgcomm.c
+++ b/gettext-tools/src/msgcomm.c
@@ -68,6 +68,8 @@ static const struct option long_options[] =
{ "omit-header", no_argument, NULL, CHAR_MAX + 1 },
{ "output", required_argument, NULL, 'o' }, /* for backward compatibility */
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -121,7 +123,7 @@ main (int argc, char *argv[])
less_than = -1;
use_first = false;
- while ((optchar = getopt_long (argc, argv, "<:>:D:eEf:Fhino:st:uVw:",
+ while ((optchar = getopt_long (argc, argv, "<:>:D:eEf:Fhino:pPst:uVw:",
long_options, NULL)) != EOF)
switch (optchar)
{
@@ -184,6 +186,14 @@ main (int argc, char *argv[])
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -360,6 +370,11 @@ Message selection:\n"));
that only unique messages be printed\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input files are in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-e, --no-escape do not use C escapes in output (default)\n"));
@@ -376,6 +391,8 @@ Output details:\n"));
printf (_("\
--strict write out strict Uniforum conforming .po file\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgconv.c b/gettext-tools/src/msgconv.c
index 41a0b8a..1929e8c 100644
--- a/gettext-tools/src/msgconv.c
+++ b/gettext-tools/src/msgconv.c
@@ -62,6 +62,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 1 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -89,6 +91,7 @@ main (int argc, char **argv)
char *output_file;
const char *input_file;
msgdomain_list_ty *result;
+ input_syntax_ty output_syntax = syntax_po;
bool sort_by_filepos = false;
bool sort_by_msgid = false;
@@ -111,7 +114,8 @@ main (int argc, char **argv)
output_file = NULL;
input_file = NULL;
- while ((opt = getopt_long (argc, argv, "D:eEFhio:st:Vw:", long_options, NULL))
+ while ((opt = getopt_long (argc, argv, "D:eEFhio:pPst:Vw:", long_options,
+ NULL))
!= EOF)
switch (opt)
{
@@ -146,6 +150,15 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ output_syntax = syntax_properties;
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -223,9 +236,12 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
if (to_code == NULL)
to_code = locale_charset ();
- /* Read input file and convert. */
- result = iconv_msgdomain_list (read_po_file (input_file), to_code,
- input_file);
+ /* Read input file. */
+ result = read_po_file (input_file);
+
+ /* Convert if and only if the output syntax supports different encodings. */
+ if (output_syntax != syntax_properties)
+ result = iconv_msgdomain_list (result, to_code, input_file);
/* Sort the results. */
if (sort_by_filepos)
@@ -285,6 +301,11 @@ Conversion target:\n"));
The default encoding is the current locale's encoding.\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-e, --no-escape do not use C escapes in output (default)\n"));
@@ -301,6 +322,8 @@ Output details:\n"));
printf (_("\
--strict strict Uniforum output style\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgen.c b/gettext-tools/src/msgen.c
index 8e5a017..960a812 100644
--- a/gettext-tools/src/msgen.c
+++ b/gettext-tools/src/msgen.c
@@ -58,6 +58,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 1 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -104,7 +106,7 @@ main (int argc, char **argv)
do_version = false;
output_file = NULL;
- while ((opt = getopt_long (argc, argv, "D:eEFhio:sVw:", long_options, NULL))
+ while ((opt = getopt_long (argc, argv, "D:eEFhio:pPsVw:", long_options, NULL))
!= EOF)
switch (opt)
{
@@ -139,6 +141,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -267,6 +277,11 @@ The results are written to standard output if no output file is specified\n\
or if it is -.\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-e, --no-escape do not use C escapes in output (default)\n"));
@@ -283,6 +298,8 @@ Output details:\n"));
printf (_("\
--strict strict Uniforum output style\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgexec.c b/gettext-tools/src/msgexec.c
index e6e24c6..8e98aa4 100644
--- a/gettext-tools/src/msgexec.c
+++ b/gettext-tools/src/msgexec.c
@@ -76,6 +76,7 @@ static const struct option long_options[] =
{ "directory", required_argument, NULL, 'D' },
{ "help", no_argument, NULL, 'h' },
{ "input", required_argument, NULL, 'i' },
+ { "properties-input", no_argument, NULL, 'P' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
@@ -120,7 +121,8 @@ main (int argc, char **argv)
/* The '+' in the options string causes option parsing to terminate when
the first non-option, i.e. the subprogram name, is encountered. */
- while ((opt = getopt_long (argc, argv, "+D:hi:V", long_options, NULL)) != EOF)
+ while ((opt = getopt_long (argc, argv, "+D:hi:PV", long_options, NULL))
+ != EOF)
switch (opt)
{
case '\0': /* Long option. */
@@ -143,6 +145,10 @@ main (int argc, char **argv)
input_file = optarg;
break;
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 'V':
do_version = true;
break;
@@ -250,6 +256,11 @@ Input file location:\n"));
If no input file is given or if it is -, standard input is read.\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Informative output:\n"));
printf (_("\
-h, --help display this help and exit\n"));
diff --git a/gettext-tools/src/msgfilter.c b/gettext-tools/src/msgfilter.c
index 9ed4097..aa6f1dc 100644
--- a/gettext-tools/src/msgfilter.c
+++ b/gettext-tools/src/msgfilter.c
@@ -107,6 +107,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 3 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -159,7 +161,8 @@ main (int argc, char **argv)
/* The '+' in the options string causes option parsing to terminate when
the first non-option, i.e. the subprogram name, is encountered. */
- while ((opt = getopt_long (argc, argv, "+D:EFhi:o:sVw:", long_options, NULL))
+ while ((opt = getopt_long (argc, argv, "+D:EFhi:o:pPsVw:", long_options,
+ NULL))
!= EOF)
switch (opt)
{
@@ -195,6 +198,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -384,6 +395,11 @@ Useful FILTER-OPTIONs when the FILTER is 'sed':\n"));
-n, --quiet, --silent suppress automatic printing of pattern space\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
--no-escape do not use C escapes in output (default)\n"));
@@ -402,6 +418,8 @@ Output details:\n"));
printf (_("\
--strict strict Uniforum output style\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgfmt.c b/gettext-tools/src/msgfmt.c
index 7a1fbe2..265331e 100644
--- a/gettext-tools/src/msgfmt.c
+++ b/gettext-tools/src/msgfmt.c
@@ -52,6 +52,7 @@
#include "message.h"
#include "open-po.h"
#include "read-po.h"
+#include "po-charset.h"
#define _(str) gettext (str)
@@ -160,6 +161,7 @@ static const struct option long_options[] =
{ "locale", required_argument, NULL, 'l' },
{ "no-hash", no_argument, NULL, CHAR_MAX + 6 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
{ "resource", required_argument, NULL, 'r' },
{ "statistics", no_argument, &do_statistics, 1 },
{ "strict", no_argument, NULL, 'S' },
@@ -191,6 +193,7 @@ main (int argc, char *argv[])
bool do_help = false;
bool do_version = false;
bool strict_uniforum = false;
+ const char *canon_encoding;
struct msg_domain *domain;
/* Set default value for global variables. */
@@ -211,7 +214,7 @@ main (int argc, char *argv[])
bindtextdomain (PACKAGE, relocate (LOCALEDIR));
textdomain (PACKAGE);
- while ((opt = getopt_long (argc, argv, "a:cCd:D:fhjl:o:r:vV", long_options,
+ while ((opt = getopt_long (argc, argv, "a:cCd:D:fhjl:o:Pr:vV", long_options,
NULL))
!= EOF)
switch (opt)
@@ -258,6 +261,9 @@ main (int argc, char *argv[])
case 'o':
output_file_name = optarg;
break;
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
case 'r':
java_resource_name = optarg;
break;
@@ -417,6 +423,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
++optind;
}
+ /* We know a priori that properties_parse() converts strings to UTF-8. */
+ canon_encoding = (input_syntax == syntax_properties ? po_charset_utf8 : NULL);
+
/* Remove obsolete messages. They were only needed for duplicate
checking. */
for (domain = domain_list; domain != NULL; domain = domain->next)
@@ -432,14 +441,14 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
{
if (java_mode)
{
- if (msgdomain_write_java (domain->mlp, java_resource_name,
- java_locale_name, java_class_directory,
- assume_java2))
+ if (msgdomain_write_java (domain->mlp, canon_encoding,
+ java_resource_name, java_locale_name,
+ java_class_directory, assume_java2))
exit_status = EXIT_FAILURE;
}
else if (tcl_mode)
{
- if (msgdomain_write_tcl (domain->mlp,
+ if (msgdomain_write_tcl (domain->mlp, canon_encoding,
tcl_locale_name, tcl_base_directory))
exit_status = EXIT_FAILURE;
}
@@ -554,6 +563,11 @@ The -l and -d options are mandatory. The .msg file is written in the\n\
specified directory.\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input files are in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Input file interpretation:\n"));
printf (_("\
-c, --check perform all the checks implied by\n\
@@ -1402,7 +1416,7 @@ msgfmt_add_message (default_po_reader_ty *this,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
/* Check whether already a domain is specified. If not, use default
domain. */
@@ -1417,7 +1431,7 @@ msgfmt_add_message (default_po_reader_ty *this,
/* Invoke superclass method. */
default_add_message (this, msgid, msgid_pos, msgid_plural,
- msgstr, msgstr_len, msgstr_pos, obsolete);
+ msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete);
}
@@ -1558,7 +1572,8 @@ read_po_file_msgfmt (char *filename)
pop->mlp = current_domain->mlp;
}
po_lex_pass_obsolete_entries (true);
- po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, filename);
+ po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, filename,
+ input_syntax);
po_reader_free ((abstract_po_reader_ty *) pop);
if (fp != stdin)
diff --git a/gettext-tools/src/msggrep.c b/gettext-tools/src/msggrep.c
index b4181de..fba6e74 100644
--- a/gettext-tools/src/msggrep.c
+++ b/gettext-tools/src/msggrep.c
@@ -97,6 +97,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 6 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "regexp", required_argument, NULL, 'e' },
{ "sort-by-file", no_argument, NULL, CHAR_MAX + 4 },
{ "sort-output", no_argument, NULL, CHAR_MAX + 5 },
@@ -159,7 +161,7 @@ main (int argc, char **argv)
grep_args[1] = string_list_alloc ();
grep_args[2] = string_list_alloc ();
- while ((opt = getopt_long (argc, argv, "CD:e:Ef:FhiKM:N:o:TVw:",
+ while ((opt = getopt_long (argc, argv, "CD:e:Ef:FhiKM:N:o:pPTVw:",
long_options, NULL))
!= EOF)
switch (opt)
@@ -227,6 +229,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 'S':
message_print_style_uniforum ();
break;
@@ -468,6 +478,11 @@ expressions if -E is given, or fixed strings if -F is given.\n\
"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
--no-escape do not use C escapes in output (default)\n"));
@@ -484,6 +499,8 @@ Output details:\n"));
printf (_("\
--strict strict Uniforum output style\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msginit.c b/gettext-tools/src/msginit.c
index 6abb690..2205ddd 100644
--- a/gettext-tools/src/msginit.c
+++ b/gettext-tools/src/msginit.c
@@ -124,6 +124,8 @@ static const struct option long_options[] =
{ "no-translator", no_argument, NULL, CHAR_MAX + 1 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "version", no_argument, NULL, 'V' },
{ "width", required_argument, NULL, 'w' },
{ NULL, 0, NULL, 0 }
@@ -172,7 +174,7 @@ main (int argc, char **argv)
input_file = NULL;
locale = NULL;
- while ((opt = getopt_long (argc, argv, "hi:l:o:Vw:", long_options, NULL))
+ while ((opt = getopt_long (argc, argv, "hi:l:o:pPVw:", long_options, NULL))
!= EOF)
switch (opt)
{
@@ -200,6 +202,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 'V':
do_version = true;
break;
@@ -356,12 +366,19 @@ If no output file is given, it depends on the --locale option or the user's\n\
locale setting. If it is -, the results are written to standard output.\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-l, --locale=LL_CC set target locale\n"));
printf (_("\
--no-translator assume the PO file is automatically generated\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msgl-cat.c b/gettext-tools/src/msgl-cat.c
index 1074479..bfb83a4 100644
--- a/gettext-tools/src/msgl-cat.c
+++ b/gettext-tools/src/msgl-cat.c
@@ -191,6 +191,8 @@ two different charsets \"%s\" and \"%s\" in input file"),
{
if (is_ascii_message_list (mlp))
canon_from_code = po_charset_ascii;
+ else if (mdlp->encoding != NULL)
+ canon_from_code = mdlp->encoding;
else
{
if (k == 0)
@@ -352,6 +354,22 @@ domain \"%s\" in input file `%s' doesn't contain a header entry with a charset s
message_list_remove_if_not (mlp, is_message_selected);
}
+ /* Determine the common known a-priori encoding, if any. */
+ if (nfiles > 0)
+ {
+ bool all_same_encoding = true;
+
+ for (n = 1; n < nfiles; n++)
+ if (mdlps[n]->encoding != mdlps[0]->encoding)
+ {
+ all_same_encoding = false;
+ break;
+ }
+
+ if (all_same_encoding)
+ total_mdlp->encoding = mdlps[0]->encoding;
+ }
+
/* Determine the target encoding for the remaining messages. */
if (to_code != NULL)
{
@@ -421,7 +439,7 @@ Input files contain messages in different encodings, %s and %s among others.\n\
Converting the output to UTF-8.\n\
To select a different output encoding, use the --to-code option.\n\
"), first, second));
- canon_to_code = po_charset_canonicalize ("UTF-8");
+ canon_to_code = po_charset_utf8;
}
else if (first != NULL && with_ASCII && all_ASCII_compatible)
{
diff --git a/gettext-tools/src/msgl-iconv.c b/gettext-tools/src/msgl-iconv.c
index 21faaf4..1bebd61 100644
--- a/gettext-tools/src/msgl-iconv.c
+++ b/gettext-tools/src/msgl-iconv.c
@@ -391,8 +391,9 @@ iconv_msgdomain_list (msgdomain_list_ty *mdlp,
to_code);
for (k = 0; k < mdlp->nitems; k++)
- iconv_message_list (mdlp->item[k]->messages, NULL, canon_to_code,
+ iconv_message_list (mdlp->item[k]->messages, mdlp->encoding, canon_to_code,
from_filename);
+ mdlp->encoding = canon_to_code;
return mdlp;
}
diff --git a/gettext-tools/src/msgmerge.c b/gettext-tools/src/msgmerge.c
index 96a4bd9..009b50a 100644
--- a/gettext-tools/src/msgmerge.c
+++ b/gettext-tools/src/msgmerge.c
@@ -94,6 +94,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 4 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "quiet", no_argument, NULL, 'q' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
@@ -161,8 +163,8 @@ main (int argc, char **argv)
do_version = false;
output_file = NULL;
- while ((opt
- = getopt_long (argc, argv, "C:D:eEFhimo:qsUvVw:", long_options, NULL))
+ while ((opt = getopt_long (argc, argv, "C:D:eEFhimo:pPqsUvVw:", long_options,
+ NULL))
!= EOF)
switch (opt)
{
@@ -209,6 +211,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 'q':
quiet = true;
break;
@@ -323,6 +333,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
"--sort-output", "--sort-by-file");
+ /* In update mode, --properties-input implies --properties-output. */
+ if (update_mode && input_syntax == syntax_properties)
+ message_print_syntax_properties ();
+
/* Merge the two files. */
result = merge (argv[optind], argv[optind + 1], &def);
@@ -460,6 +474,11 @@ Operation modifiers:\n"));
-N, --no-fuzzy-matching do not use fuzzy matching\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input files are in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-e, --no-escape do not use C escapes in output (default)\n"));
@@ -476,6 +495,8 @@ Output details:\n"));
printf (_("\
--strict strict Uniforum output style\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
@@ -1163,6 +1184,10 @@ merge (const char *fn1, const char *fn2, msgdomain_list_ty **defp)
}
}
+ /* Determine the known a-priori encoding, if any. */
+ if (def->encoding == ref->encoding)
+ result->encoding = def->encoding;
+
/* Report some statistics. */
if (verbosity_level > 0)
fprintf (stderr, _("%s\
diff --git a/gettext-tools/src/msgunfmt.c b/gettext-tools/src/msgunfmt.c
index 66176b5..e3126e4 100644
--- a/gettext-tools/src/msgunfmt.c
+++ b/gettext-tools/src/msgunfmt.c
@@ -71,6 +71,7 @@ static const struct option long_options[] =
{ "no-escape", no_argument, NULL, 'e' },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "resource", required_argument, NULL, 'r' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -113,7 +114,7 @@ main (int argc, char **argv)
bindtextdomain (PACKAGE, relocate (LOCALEDIR));
textdomain (PACKAGE);
- while ((optchar = getopt_long (argc, argv, "d:eEhijl:o:r:svVw:",
+ while ((optchar = getopt_long (argc, argv, "d:eEhijl:o:pr:svVw:",
long_options, NULL))
!= EOF)
switch (optchar)
@@ -155,6 +156,10 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
case 'r':
java_resource_name = optarg;
break;
@@ -383,6 +388,8 @@ Output details:\n"));
printf (_("\
--strict write strict uniforum style\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/msguniq.c b/gettext-tools/src/msguniq.c
index 31a2ba4..5222534 100644
--- a/gettext-tools/src/msguniq.c
+++ b/gettext-tools/src/msguniq.c
@@ -62,6 +62,8 @@ static const struct option long_options[] =
{ "no-location", no_argument, &line_comment, 0 },
{ "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
{ "output-file", required_argument, NULL, 'o' },
+ { "properties-input", no_argument, NULL, 'P' },
+ { "properties-output", no_argument, NULL, 'p' },
{ "repeated", no_argument, NULL, 'd' },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
@@ -118,7 +120,7 @@ main (int argc, char **argv)
less_than = INT_MAX;
use_first = false;
- while ((optchar = getopt_long (argc, argv, "dD:eEFhino:st:uVw:",
+ while ((optchar = getopt_long (argc, argv, "dD:eEFhino:pPst:uVw:",
long_options, NULL)) != EOF)
switch (optchar)
{
@@ -162,6 +164,14 @@ main (int argc, char **argv)
output_file = optarg;
break;
+ case 'p':
+ message_print_syntax_properties ();
+ break;
+
+ case 'P':
+ input_syntax = syntax_properties;
+ break;
+
case 's':
sort_by_msgid = true;
break;
@@ -320,6 +330,11 @@ Message selection:\n"));
-u, --unique print only unique messages, discard duplicates\n"));
printf ("\n");
printf (_("\
+Input file syntax:\n"));
+ printf (_("\
+ -P, --properties-input input file is in Java .properties syntax\n"));
+ printf ("\n");
+ printf (_("\
Output details:\n"));
printf (_("\
-t, --to-code=NAME encoding for output\n"));
@@ -341,6 +356,8 @@ Output details:\n"));
printf (_("\
--strict write out strict Uniforum conforming .po file\n"));
printf (_("\
+ -p, --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
diff --git a/gettext-tools/src/po-gram-gen.y b/gettext-tools/src/po-gram-gen.y
index 355ffba..e8386bb 100644
--- a/gettext-tools/src/po-gram-gen.y
+++ b/gettext-tools/src/po-gram-gen.y
@@ -25,12 +25,14 @@
/* Specification. */
#include "po-gram.h"
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "str-list.h"
#include "po-lex.h"
+#include "po-charset.h"
#include "error.h"
#include "xmalloc.h"
#include "gettext.h"
@@ -91,6 +93,20 @@ static long plural_counter;
if ((value1).obsolete != (value2).obsolete) \
po_gram_error_at_line (&(value2).pos, _("inconsistent use of #~"));
+static inline void
+do_callback_message (char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
+ char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+ bool obsolete)
+{
+ /* Test for header entry. Ignore fuzziness of the header entry. */
+ if (msgid[0] == '\0' && !obsolete)
+ po_lex_charset_set (msgstr, gram_pos.file_name);
+
+ po_callback_message (msgid, msgid_pos, msgid_plural,
+ msgstr, msgstr_len, msgstr_pos,
+ false, obsolete);
+}
+
%}
%token COMMENT
@@ -148,7 +164,7 @@ message
check_obsolete ($1, $3);
check_obsolete ($1, $4);
if (!$1.obsolete || pass_obsolete_entries)
- po_callback_message (string2, &$1.pos, NULL,
+ do_callback_message (string2, &$1.pos, NULL,
string4, strlen (string4) + 1, &$3.pos,
$1.obsolete);
else
@@ -165,7 +181,7 @@ message
check_obsolete ($1, $3);
check_obsolete ($1, $4);
if (!$1.obsolete || pass_obsolete_entries)
- po_callback_message (string2, &$1.pos, $3.string,
+ do_callback_message (string2, &$1.pos, $3.string,
$4.rhs.msgstr, $4.rhs.msgstr_len, &$4.pos,
$1.obsolete);
else
diff --git a/gettext-tools/src/po-lex.c b/gettext-tools/src/po-lex.c
index d3aaf32..d5be021 100644
--- a/gettext-tools/src/po-lex.c
+++ b/gettext-tools/src/po-lex.c
@@ -618,18 +618,11 @@ lex_start (FILE *fp, const char *real_filename, const char *logical_filename)
void
lex_end ()
{
- if (error_message_count > 0)
- error (EXIT_FAILURE, 0,
- ngettext ("found %d fatal error", "found %d fatal errors",
- error_message_count),
- error_message_count);
-
mbf->fp = NULL;
gram_pos.file_name = NULL;
gram_pos.line_number = 0;
gram_pos_column = 0;
signal_eilseq = false;
- error_message_count = 0;
po_lex_obsolete = false;
po_lex_charset_close ();
}
diff --git a/gettext-tools/src/read-po-abstract.c b/gettext-tools/src/read-po-abstract.c
index 4805fd7..bc562ea 100644
--- a/gettext-tools/src/read-po-abstract.c
+++ b/gettext-tools/src/read-po-abstract.c
@@ -28,10 +28,11 @@
#include <stdlib.h>
#include <string.h>
-#include "po-charset.h"
#include "po-gram.h"
#include "po-hash.h"
+#include "read-properties.h"
#include "xmalloc.h"
+#include "gettext.h"
/* Local variables. */
static abstract_po_reader_ty *callback_arg;
@@ -95,11 +96,12 @@ call_directive_message (abstract_po_reader_ty *pop,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
if (pop->methods->directive_message)
pop->methods->directive_message (pop, msgid, msgid_pos, msgid_plural,
- msgstr, msgstr_len, msgstr_pos, obsolete);
+ msgstr, msgstr_len, msgstr_pos,
+ force_fuzzy, obsolete);
}
static inline void
@@ -135,7 +137,7 @@ call_comment_special (abstract_po_reader_ty *pop, const char *s)
/* Exported functions. */
-void
+static inline void
po_scan_start (abstract_po_reader_ty *pop)
{
/* The parse will call the po_callback_... functions (see below)
@@ -147,7 +149,7 @@ po_scan_start (abstract_po_reader_ty *pop)
call_parse_brief (pop);
}
-void
+static inline void
po_scan_end (abstract_po_reader_ty *pop)
{
call_parse_debrief (pop);
@@ -157,14 +159,34 @@ po_scan_end (abstract_po_reader_ty *pop)
void
po_scan (abstract_po_reader_ty *pop, FILE *fp,
- const char *real_filename, const char *logical_filename)
+ const char *real_filename, const char *logical_filename,
+ input_syntax_ty syntax)
{
/* Parse the stream's content. */
- lex_start (fp, real_filename, logical_filename);
- po_scan_start (pop);
- po_gram_parse ();
- po_scan_end (pop);
- lex_end ();
+ switch (syntax)
+ {
+ case syntax_po:
+ lex_start (fp, real_filename, logical_filename);
+ po_scan_start (pop);
+ po_gram_parse ();
+ po_scan_end (pop);
+ lex_end ();
+ break;
+ case syntax_properties:
+ po_scan_start (pop);
+ properties_parse (pop, fp, real_filename, logical_filename);
+ po_scan_end (pop);
+ break;
+ default:
+ abort ();
+ }
+
+ if (error_message_count > 0)
+ error (EXIT_FAILURE, 0,
+ ngettext ("found %d fatal error", "found %d fatal errors",
+ error_message_count),
+ error_message_count);
+ error_message_count = 0;
}
@@ -188,16 +210,12 @@ po_callback_domain (char *name)
void
po_callback_message (char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
/* assert(callback_arg); */
-
- /* Test for header entry. Ignore fuzziness of the header entry. */
- if (msgid[0] == '\0' && !obsolete)
- po_lex_charset_set (msgstr, gram_pos.file_name);
-
call_directive_message (callback_arg, msgid, msgid_pos, msgid_plural,
- msgstr, msgstr_len, msgstr_pos, obsolete);
+ msgstr, msgstr_len, msgstr_pos,
+ force_fuzzy, obsolete);
}
diff --git a/gettext-tools/src/read-po-abstract.h b/gettext-tools/src/read-po-abstract.h
index 87590a6..4140fc8 100644
--- a/gettext-tools/src/read-po-abstract.h
+++ b/gettext-tools/src/read-po-abstract.h
@@ -73,7 +73,7 @@ struct abstract_po_reader_class_ty
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete);
+ bool force_fuzzy, bool obsolete);
/* What to do with a plain-vanilla comment - the expectation is that
they will be accumulated, and added to the next message
@@ -123,19 +123,20 @@ struct abstract_po_reader_ty
extern abstract_po_reader_ty *
po_reader_alloc (abstract_po_reader_class_ty *method_table);
-/* Prepare for use of abstract_po_reader_class_ty methods. */
-extern void
- po_scan_start (abstract_po_reader_ty *pop);
-
-/* Terminate the use of abstract_po_reader_class_ty methods. */
-extern void
- po_scan_end (abstract_po_reader_ty *pop);
+/* Kinds of PO file input syntaxes. */
+enum input_syntax_ty
+{
+ syntax_po,
+ syntax_properties
+};
+typedef enum input_syntax_ty input_syntax_ty;
/* Read a PO file from a stream, and dispatch to the various
abstract_po_reader_class_ty methods. */
extern void
po_scan (abstract_po_reader_ty *pop, FILE *fp,
- const char *real_filename, const char *logical_filename);
+ const char *real_filename, const char *logical_filename,
+ input_syntax_ty syntax);
/* Call the destructor and deallocate a abstract_po_reader_ty (or derived
class) instance. */
@@ -150,7 +151,7 @@ extern void po_callback_message (char *msgid, lex_pos_ty *msgid_pos,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete);
+ bool force_fuzzy, bool obsolete);
extern void po_callback_comment (const char *s);
extern void po_callback_comment_dot (const char *s);
extern void po_callback_comment_filepos (const char *s, size_t line);
diff --git a/gettext-tools/src/read-po.c b/gettext-tools/src/read-po.c
index e4aec20..a31c55a 100644
--- a/gettext-tools/src/read-po.c
+++ b/gettext-tools/src/read-po.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "open-po.h"
+#include "po-charset.h"
#include "xmalloc.h"
#include "gettext.h"
@@ -51,14 +52,15 @@ static inline void
call_add_message (struct default_po_reader_ty *this,
char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
default_po_reader_class_ty *methods =
(default_po_reader_class_ty *) this->methods;
if (methods->add_message)
methods->add_message (this, msgid, msgid_pos, msgid_plural,
- msgstr, msgstr_len, msgstr_pos, obsolete);
+ msgstr, msgstr_len, msgstr_pos,
+ force_fuzzy, obsolete);
}
static inline void
@@ -230,12 +232,12 @@ default_directive_message (abstract_po_reader_ty *that,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
default_po_reader_ty *this = (default_po_reader_ty *) that;
call_add_message (this, msgid, msgid_pos, msgid_plural,
- msgstr, msgstr_len, msgstr_pos, obsolete);
+ msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete);
/* Prepare for next message. */
default_reset_comment_state (this);
@@ -327,7 +329,7 @@ default_add_message (default_po_reader_ty *this,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
message_ty *mp;
@@ -373,6 +375,8 @@ default_add_message (default_po_reader_ty *this,
mp = message_alloc (msgid, msgid_plural, msgstr, msgstr_len, msgstr_pos);
mp->obsolete = obsolete;
default_copy_comment_state (this, mp);
+ if (force_fuzzy)
+ mp->is_fuzzy = true;
call_frob_new_message (this, mp, msgid_pos, msgstr_pos);
@@ -428,6 +432,9 @@ int line_comment = 1;
appropriately. Defaults to false. */
bool allow_duplicates = false;
+/* Expected syntax of the input files. */
+input_syntax_ty input_syntax = syntax_po;
+
msgdomain_list_ty *
read_po (FILE *fp, const char *real_filename, const char *logical_filename)
@@ -443,8 +450,12 @@ read_po (FILE *fp, const char *real_filename, const char *logical_filename)
pop->allow_duplicates_if_same_msgstr = false;
pop->mdlp = msgdomain_list_alloc (!pop->allow_duplicates);
pop->mlp = msgdomain_list_sublist (pop->mdlp, pop->domain, true);
+ if (input_syntax == syntax_properties)
+ /* We know a priori that properties_parse() converts strings to UTF-8. */
+ pop->mdlp->encoding = po_charset_utf8;
po_lex_pass_obsolete_entries (true);
- po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename);
+ po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename,
+ input_syntax);
mdlp = pop->mdlp;
po_reader_free ((abstract_po_reader_ty *) pop);
return mdlp;
diff --git a/gettext-tools/src/read-po.h b/gettext-tools/src/read-po.h
index f2f6807..ce5c3e3 100644
--- a/gettext-tools/src/read-po.h
+++ b/gettext-tools/src/read-po.h
@@ -47,7 +47,7 @@ struct default_po_reader_class_ty
void (*add_message) (struct default_po_reader_ty *pop,
char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
- bool obsolete);
+ bool force_fuzzy, bool obsolete);
/* How to modify a new message before adding it to the list. */
void (*frob_new_message) (struct default_po_reader_ty *pop, message_ty *mp,
@@ -116,7 +116,7 @@ extern void default_directive_message (abstract_po_reader_ty *that,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete);
+ bool force_fuzzy, bool obsolete);
extern void default_comment (abstract_po_reader_ty *that, const char *s);
extern void default_comment_dot (abstract_po_reader_ty *that, const char *s);
extern void default_comment_filepos (abstract_po_reader_ty *that,
@@ -130,7 +130,7 @@ extern void default_add_message (default_po_reader_ty *this,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete);
+ bool force_fuzzy, bool obsolete);
/* Allocate a fresh default_po_reader_ty (or derived class) instance and
call its constructor. */
@@ -147,6 +147,9 @@ extern int line_comment;
appropriately. Defaults to false. */
extern bool allow_duplicates;
+/* Expected syntax of the input files. */
+extern input_syntax_ty input_syntax;
+
/* Read the input file from a stream. Returns a list of messages. */
extern msgdomain_list_ty *read_po (FILE *fp, const char *real_filename,
const char *logical_filename);
diff --git a/gettext-tools/src/read-properties.c b/gettext-tools/src/read-properties.c
new file mode 100644
index 0000000..2faa300
--- /dev/null
+++ b/gettext-tools/src/read-properties.c
@@ -0,0 +1,543 @@
+/* Reading Java .properties files.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "read-properties.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "progname.h"
+#include "message.h"
+#include "read-po-abstract.h"
+#include "xmalloc.h"
+#include "exit.h"
+#include "msgl-ascii.h"
+#include "utf16-ucs4.h"
+#include "ucs4-utf8.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+/* The format of the Java .properties files is documented in the JDK
+ documentation for class java.util.Properties. In the case of .properties
+ files for PropertyResourceBundle, each non-comment line contains a
+ key/value pair in the form "key = value" or "key : value" or "key value",
+ where the key is the msgid and the value is the msgstr. Messages with
+ plurals are not supported in this format. */
+
+/* Handling of comments: We copy all comments from the .properties file to
+ the PO file. This is not really needed; it's a service for translators
+ who don't like PO files and prefer to maintain the .properties file. */
+
+/* Real filename, used in error messages about the input file. */
+static const char *real_file_name;
+
+/* File name and line number. */
+extern lex_pos_ty gram_pos;
+
+/* The input file stream. */
+static FILE *fp;
+
+
+/* Phase 1: Read an ISO-8859-1 character.
+ Max. 1 pushback character. */
+
+static int
+phase1_getc ()
+{
+ int c;
+
+ c = getc (fp);
+
+ if (c == EOF)
+ {
+ if (ferror (fp))
+ error (EXIT_FAILURE, errno, _("error while reading \"%s\""),
+ real_file_name);
+ return EOF;
+ }
+
+ return c;
+}
+
+static inline void
+phase1_ungetc (int c)
+{
+ if (c != EOF)
+ ungetc (c, fp);
+}
+
+
+/* Phase 2: Read an ISO-8859-1 character, treating CR/LF like a single LF.
+ Max. 2 pushback characters. */
+
+static unsigned char phase2_pushback[2];
+static int phase2_pushback_length;
+
+static int
+phase2_getc ()
+{
+ int c;
+
+ if (phase2_pushback_length)
+ c = phase2_pushback[--phase2_pushback_length];
+ else
+ {
+ c = phase1_getc ();
+
+ if (c == '\r')
+ {
+ int c2 = phase1_getc ();
+ if (c2 == '\n')
+ c = c2;
+ else
+ phase1_ungetc (c2);
+ }
+ }
+
+ if (c == '\n')
+ gram_pos.line_number++;
+
+ return c;
+}
+
+static void
+phase2_ungetc (int c)
+{
+ if (c == '\n')
+ --gram_pos.line_number;
+ if (c != EOF)
+ phase2_pushback[phase2_pushback_length++] = c;
+}
+
+
+/* Phase 3: Read an ISO-8859-1 character, treating CR/LF like a single LF,
+ with handling of continuation lines.
+ Max. 1 pushback character. */
+
+static int
+phase3_getc ()
+{
+ int c = phase2_getc ();
+
+ for (;;)
+ {
+ if (c != '\\')
+ return c;
+
+ c = phase2_getc ();
+ if (c != '\n')
+ {
+ phase2_ungetc (c);
+ return '\\';
+ }
+
+ /* Skip the backslash-newline and all whitespace that follows it. */
+ do
+ c = phase2_getc ();
+ while (c == ' ' || c == '\t' || c == '\r' || c == '\f');
+ }
+}
+
+static inline void
+phase3_ungetc (int c)
+{
+ phase2_ungetc (c);
+}
+
+
+/* Phase 4: Read an UTF-16 codepoint, treating CR/LF like a single LF,
+ with handling of continuation lines and of \uxxxx sequences. */
+
+static int
+phase4_getuc ()
+{
+ int c = phase3_getc ();
+
+ if (c == EOF)
+ return -1;
+ if (c == '\\')
+ {
+ int c2 = phase3_getc ();
+
+ if (c2 == 't')
+ return '\t';
+ if (c2 == 'n')
+ return '\n';
+ if (c2 == 'r')
+ return '\r';
+ if (c2 == 'f')
+ return '\f';
+ if (c2 == 'u')
+ {
+ unsigned int n = 0;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ int c1 = phase3_getc ();
+
+ if (c1 >= '0' && c1 <= '9')
+ n = (n << 4) + (c1 - '0');
+ else if (c1 >= 'A' && c1 <= 'F')
+ n = (n << 4) + (c1 - 'A' + 10);
+ else if (c1 >= 'a' && c1 <= 'f')
+ n = (n << 4) + (c1 - 'a' + 10);
+ else
+ {
+ phase3_ungetc (c1);
+ error_with_progname = false;
+ error (0, 0, _("%s:%d: warning: invalid \\uxxxx syntax for Unicode character"),
+ real_file_name, gram_pos.line_number);
+ error_with_progname = true;
+ return 'u';
+ }
+ }
+ return n;
+ }
+
+ return c2;
+ }
+ else
+ return c;
+}
+
+
+/* Converts a string from ISO-8859-1 encoding to UTF-8 encoding. */
+static char *
+conv_from_iso_8859_1 (char *string)
+{
+ if (is_ascii_string (string))
+ return string;
+ else
+ {
+ size_t length = strlen (string);
+ /* Each ISO-8859-1 character needs 2 bytes at worst. */
+ unsigned char *utf8_string = (unsigned char *) xmalloc (2 * length + 1);
+ unsigned char *q = utf8_string;
+ const char *str = string;
+ const char *str_limit = str + length;
+
+ while (str < str_limit)
+ {
+ unsigned int uc = (unsigned char) *str++;
+ int n = u8_uctomb (q, uc, 6);
+ assert (n > 0);
+ q += n;
+ }
+ *q = '\0';
+ assert (q - utf8_string <= 2 * length);
+
+ return (char *) utf8_string;
+ }
+}
+
+
+/* Converts a string from JAVA encoding (with \uxxxx sequences) to UTF-8
+ encoding. May destructively modify the argument string. */
+static char *
+conv_from_java (char *string)
+{
+ /* This conversion can only shrink the string, never increase its size.
+ So there is no need to xmalloc the result freshly. */
+ const char *p = string;
+ char *q = string;
+
+ while (*p != '\0')
+ {
+ if (p[0] == '\\' && p[1] == 'u')
+ {
+ unsigned int n = 0;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ int c1 = (unsigned char) p[2 + i];
+
+ if (c1 >= '0' && c1 <= '9')
+ n = (n << 4) + (c1 - '0');
+ else if (c1 >= 'A' && c1 <= 'F')
+ n = (n << 4) + (c1 - 'A' + 10);
+ else if (c1 >= 'a' && c1 <= 'f')
+ n = (n << 4) + (c1 - 'a' + 10);
+ else
+ goto just_one_byte;
+ }
+
+ if (i == 4)
+ {
+ unsigned int uc;
+
+ if (n >= 0xd800 && n < 0xdc00)
+ {
+ if (p[6] == '\\' && p[7] == 'u')
+ {
+ unsigned int m = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ int c1 = (unsigned char) p[8 + i];
+
+ if (c1 >= '0' && c1 <= '9')
+ m = (m << 4) + (c1 - '0');
+ else if (c1 >= 'A' && c1 <= 'F')
+ m = (m << 4) + (c1 - 'A' + 10);
+ else if (c1 >= 'a' && c1 <= 'f')
+ m = (m << 4) + (c1 - 'a' + 10);
+ else
+ goto just_one_byte;
+ }
+
+ if (i == 4 && (m >= 0xdc00 && m < 0xe000))
+ {
+ /* Combine two UTF-16 words to a character. */
+ uc = 0x10000 + ((n - 0xd800) << 10) + (m - 0xdc00);
+ p += 12;
+ }
+ else
+ goto just_one_byte;
+ }
+ else
+ goto just_one_byte;
+ }
+ else
+ {
+ uc = n;
+ p += 6;
+ }
+
+ q += u8_uctomb (q, uc, 6);
+ continue;
+ }
+ }
+ just_one_byte:
+ *q++ = *p++;
+ }
+ *q = '\0';
+ return string;
+}
+
+
+/* Reads a key or value string.
+ Returns the string in UTF-8 encoding, or NULL if the end of the logical
+ line is reached.
+ Parsing ends:
+ - when returning NULL, after the end of the logical line,
+ - otherwise, if in_key is true, after the whitespace and possibly the
+ separator that follows after the string,
+ - otherwise, if in_key is false, after the end of the logical line. */
+
+static char *
+read_escaped_string (bool in_key)
+{
+ static unsigned short *buffer;
+ static size_t bufmax;
+ static size_t buflen;
+ int c;
+
+ /* Skip whitespace before the string. */
+ do
+ c = phase3_getc ();
+ while (c == ' ' || c == '\t' || c == '\r' || c == '\f');
+
+ if (c == EOF || c == '\n')
+ /* Empty string. */
+ return NULL;
+
+ /* Start accumulating the string. We store the string in UTF-16 before
+ converting it to UTF-8. Why not converting every character directly to
+ UTF-8? Because a string can contain surrogates like \uD800\uDF00, and
+ we must combine them to a single UTF-8 character. */
+ buflen = 0;
+ for (;;)
+ {
+ if (in_key && (c == '=' || c == ':'
+ || c == ' ' || c == '\t' || c == '\r' || c == '\f'))
+ {
+ /* Skip whitespace after the string. */
+ while (c == ' ' || c == '\t' || c == '\r' || c == '\f')
+ c = phase3_getc ();
+ /* Skip '=' or ':' separator. */
+ if (!(c == '=' || c == ':'))
+ phase3_ungetc (c);
+ break;
+ }
+
+ phase3_ungetc (c);
+
+ /* Read the next UTF-16 codepoint. */
+ c = phase4_getuc ();
+ if (c < 0)
+ break;
+ /* Append it to the buffer. */
+ if (buflen >= bufmax)
+ {
+ bufmax += 100;
+ buffer = xrealloc (buffer, bufmax * sizeof (unsigned short));
+ }
+ buffer[buflen++] = c;
+
+ c = phase3_getc ();
+ if (c == EOF || c == '\n')
+ {
+ if (in_key)
+ phase3_ungetc (c);
+ break;
+ }
+ }
+
+ /* Now convert from UTF-16 to UTF-8. */
+ {
+ size_t pos;
+ unsigned char *utf8_string;
+ unsigned char *q;
+
+ /* Each UTF-16 word needs 3 bytes at worst. */
+ utf8_string = (unsigned char *) xmalloc (3 * buflen + 1);
+ for (pos = 0, q = utf8_string; pos < buflen; )
+ {
+ unsigned int uc;
+ int n;
+
+ pos += u16_mbtouc (&uc, buffer + pos, buflen - pos);
+ n = u8_uctomb (q, uc, 6);
+ assert (n > 0);
+ q += n;
+ }
+ *q = '\0';
+ assert (q - utf8_string <= 3 * buflen);
+
+ return (char *) utf8_string;
+ }
+}
+
+
+/* Read a .properties file from a stream, and dispatch to the various
+ abstract_po_reader_class_ty methods. */
+void
+properties_parse (abstract_po_reader_ty *this, FILE *file,
+ const char *real_filename, const char *logical_filename)
+{
+ fp = file;
+ real_file_name = real_filename;
+ gram_pos.file_name = xstrdup (real_file_name);
+ gram_pos.line_number = 1;
+
+ for (;;)
+ {
+ int c;
+ bool comment;
+ bool hidden;
+
+ c = phase2_getc ();
+
+ if (c == EOF)
+ break;
+
+ comment = false;
+ hidden = false;
+ if (c == '#')
+ comment = true;
+ else if (c == '!')
+ {
+ /* For compatibility with write-properties.c, we treat '!' not
+ followed by space as a fuzzy or untranslated message. */
+ int c2 = phase2_getc ();
+ if (c2 == ' ' || c2 == '\n' || c2 == EOF)
+ comment = true;
+ else
+ hidden = true;
+ phase2_ungetc (c2);
+ }
+ else
+ phase2_ungetc (c);
+
+ if (comment)
+ {
+ /* A comment line. */
+ static char *buffer;
+ static size_t bufmax;
+ static size_t buflen;
+
+ buflen = 0;
+ for (;;)
+ {
+ c = phase2_getc ();
+
+ if (buflen >= bufmax)
+ {
+ bufmax += 100;
+ buffer = xrealloc (buffer, bufmax);
+ }
+
+ if (c == EOF || c == '\n')
+ break;
+
+ buffer[buflen++] = c;
+ }
+ buffer[buflen] = '\0';
+
+ po_callback_comment (conv_from_java (conv_from_iso_8859_1 (buffer)));
+ }
+ else
+ {
+ /* A key/value pair. */
+ char *msgid;
+ lex_pos_ty msgid_pos;
+
+ msgid_pos = gram_pos;
+ msgid = read_escaped_string (true);
+ if (msgid == NULL)
+ /* Skip blank line. */
+ ;
+ else
+ {
+ char *msgstr;
+ lex_pos_ty msgstr_pos;
+ bool force_fuzzy;
+
+ msgstr_pos = gram_pos;
+ msgstr = read_escaped_string (false);
+ if (msgstr == NULL)
+ msgstr = xstrdup ("");
+
+ /* Be sure to make the message fuzzy if it was commented out
+ and if it is not already header/fuzzy/untranslated. */
+ force_fuzzy = (hidden && msgid[0] != '\0' && msgstr[0] != '\0');
+
+ po_callback_message (msgid, &msgid_pos, NULL,
+ msgstr, strlen (msgstr) + 1, &msgstr_pos,
+ force_fuzzy, false);
+ }
+ }
+ }
+
+ fp = NULL;
+ real_file_name = NULL;
+ gram_pos.line_number = 0;
+}
diff --git a/gettext-tools/src/read-properties.h b/gettext-tools/src/read-properties.h
new file mode 100644
index 0000000..00fa0fb
--- /dev/null
+++ b/gettext-tools/src/read-properties.h
@@ -0,0 +1,30 @@
+/* Reading Java .properties files.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _READ_PROPERTIES_H
+#define _READ_PROPERTIES_H
+
+#include "read-po-abstract.h"
+
+/* Read a .properties file from a stream, and dispatch to the various
+ abstract_po_reader_class_ty methods. */
+extern void properties_parse (abstract_po_reader_ty *pop, FILE *fp,
+ const char *real_filename,
+ const char *logical_filename);
+
+#endif /* _READ_PROPERTIES_H */
diff --git a/gettext-tools/src/write-java.c b/gettext-tools/src/write-java.c
index 0958e90..da8c76d 100644
--- a/gettext-tools/src/write-java.c
+++ b/gettext-tools/src/write-java.c
@@ -1018,7 +1018,7 @@ unblock ()
int
-msgdomain_write_java (message_list_ty *mlp,
+msgdomain_write_java (message_list_ty *mlp, const char *canon_encoding,
const char *resource_name, const char *locale_name,
const char *directory,
bool assume_java2)
@@ -1040,7 +1040,7 @@ msgdomain_write_java (message_list_ty *mlp,
retval = 1;
/* Convert the messages to Unicode. */
- iconv_message_list (mlp, NULL, po_charset_canonicalize ("UTF-8"), NULL);
+ iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL);
cleanup_list.tmpdir = NULL;
cleanup_list.subdir_count = 0;
diff --git a/gettext-tools/src/write-java.h b/gettext-tools/src/write-java.h
index 37e1947..8348956 100644
--- a/gettext-tools/src/write-java.h
+++ b/gettext-tools/src/write-java.h
@@ -1,5 +1,5 @@
/* Writing Java ResourceBundles.
- Copyright (C) 2001-2002 Free Software Foundation, Inc.
+ Copyright (C) 2001-2003 Free Software Foundation, Inc.
Written by Bruno Haible <haible@clisp.cons.org>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -30,6 +30,7 @@
Return 0 if ok, nonzero on error. */
extern int
msgdomain_write_java (message_list_ty *mlp,
+ const char *canon_encoding,
const char *resource_name,
const char *locale_name,
const char *directory,
diff --git a/gettext-tools/src/write-po.c b/gettext-tools/src/write-po.c
index 862bc29..434d190 100644
--- a/gettext-tools/src/write-po.c
+++ b/gettext-tools/src/write-po.c
@@ -39,9 +39,11 @@
#include "po-charset.h"
#include "linebreak.h"
#include "msgl-ascii.h"
+#include "write-properties.h"
#include "xmalloc.h"
#include "strstr.h"
#include "exit.h"
+#include "progname.h"
#include "error.h"
#include "xerror.h"
#include "gettext.h"
@@ -373,6 +375,16 @@ message_print_style_escape (bool flag)
}
+/* Whether to output a file in Java .properties syntax. */
+static bool use_syntax_properties = false;
+
+void
+message_print_syntax_properties ()
+{
+ use_syntax_properties = true;
+}
+
+
/* ================ msgdomain_list_print() and subroutines. ================ */
@@ -917,52 +929,12 @@ different from yours. Consider using a pure ASCII msgid instead.\n\
}
-void
-msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
- bool force, bool debug)
+static void
+msgdomain_list_print_po (msgdomain_list_ty *mdlp, FILE *fp, bool debug)
{
- FILE *fp;
size_t j, k;
bool blank_line;
- /* We will not write anything if, for every domain, we have no message
- or only the header entry. */
- if (!force)
- {
- bool found_nonempty = false;
-
- for (k = 0; k < mdlp->nitems; k++)
- {
- message_list_ty *mlp = mdlp->item[k]->messages;
-
- if (!(mlp->nitems == 0
- || (mlp->nitems == 1 && mlp->item[0]->msgid[0] == '\0')))
- {
- found_nonempty = true;
- break;
- }
- }
-
- if (!found_nonempty)
- return;
- }
-
- /* Open the output file. */
- if (filename != NULL && strcmp (filename, "-") != 0
- && strcmp (filename, "/dev/stdout") != 0)
- {
- fp = fopen (filename, "w");
- if (fp == NULL)
- error (EXIT_FAILURE, errno, _("cannot create output file \"%s\""),
- filename);
- }
- else
- {
- fp = stdout;
- /* xgettext:no-c-format */
- filename = _("standard output");
- }
-
/* Write out the messages for each domain. */
blank_line = false;
for (k = 0; k < mdlp->nitems; k++)
@@ -1031,6 +1003,92 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
blank_line = true;
}
}
+}
+
+
+void
+msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
+ bool force, bool debug)
+{
+ FILE *fp;
+
+ /* We will not write anything if, for every domain, we have no message
+ or only the header entry. */
+ if (!force)
+ {
+ bool found_nonempty = false;
+ size_t k;
+
+ for (k = 0; k < mdlp->nitems; k++)
+ {
+ message_list_ty *mlp = mdlp->item[k]->messages;
+
+ if (!(mlp->nitems == 0
+ || (mlp->nitems == 1 && mlp->item[0]->msgid[0] == '\0')))
+ {
+ found_nonempty = true;
+ break;
+ }
+ }
+
+ if (!found_nonempty)
+ return;
+ }
+
+ /* Check whether the output format can accomodate all messages. */
+ if (use_syntax_properties)
+ {
+ if (mdlp->nitems > 1)
+ error (EXIT_FAILURE, 0, _("Cannot output multiple translation domains into a single file with Java .properties syntax. Try using PO file syntax instead."));
+ if (mdlp->nitems == 1)
+ {
+ message_list_ty *mlp = mdlp->item[0]->messages;
+ const lex_pos_ty *has_plural;
+ size_t j;
+
+ has_plural = NULL;
+ for (j = 0; j < mlp->nitems; j++)
+ {
+ message_ty *mp = mlp->item[j];
+
+ if (mp->msgid_plural != NULL)
+ {
+ has_plural = &mp->pos;
+ break;
+ }
+ }
+
+ if (has_plural != NULL)
+ {
+ error_with_progname = false;
+ error_at_line (EXIT_FAILURE, 0,
+ has_plural->file_name, has_plural->line_number,
+ _("message catalog has plural form translations, but the output format does not support them. Try generating a Java class using \"msgfmt --java\", instead of a properties file."));
+ error_with_progname = true;
+ }
+ }
+ }
+
+ /* Open the output file. */
+ if (filename != NULL && strcmp (filename, "-") != 0
+ && strcmp (filename, "/dev/stdout") != 0)
+ {
+ fp = fopen (filename, "w");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno, _("cannot create output file \"%s\""),
+ filename);
+ }
+ else
+ {
+ fp = stdout;
+ /* xgettext:no-c-format */
+ filename = _("standard output");
+ }
+
+ if (use_syntax_properties)
+ msgdomain_list_print_properties (mdlp, fp, page_width, debug);
+ else
+ msgdomain_list_print_po (mdlp, fp, debug);
/* Make sure nothing went wrong. */
if (fflush (fp) || ferror (fp))
diff --git a/gettext-tools/src/write-po.h b/gettext-tools/src/write-po.h
index 261a784..a1a81ef 100644
--- a/gettext-tools/src/write-po.h
+++ b/gettext-tools/src/write-po.h
@@ -48,6 +48,8 @@ extern void
message_print_style_uniforum (void);
extern void
message_print_style_escape (bool flag);
+extern void
+ message_print_syntax_properties (void);
/* Output MDLP into a PO file with the given FILENAME, according to the
parameters set by the functions above. */
diff --git a/gettext-tools/src/write-properties.c b/gettext-tools/src/write-properties.c
new file mode 100644
index 0000000..791a5c0
--- /dev/null
+++ b/gettext-tools/src/write-properties.c
@@ -0,0 +1,291 @@
+/* Writing Java .properties files.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "write-properties.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "message.h"
+#include "msgl-ascii.h"
+#include "msgl-iconv.h"
+#include "po-charset.h"
+#include "utf8-ucs4.h"
+#include "write-po.h"
+#include "xmalloc.h"
+#include "exit.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+/* The format of the Java .properties files is documented in the JDK
+ documentation for class java.util.Properties. In the case of .properties
+ files for PropertyResourceBundle, for each message, the msgid becomes the
+ key (left-hand side) and the msgstr becomes the value (right-hand side)
+ of a "key=value" line. Messages with plurals are not supported in this
+ format. */
+
+/* Handling of comments: We copy all comments from the PO file to the
+ .properties file. This is not really needed; it's a service for translators
+ who don't like PO files and prefer to maintain the .properties file. */
+
+/* Converts a string to JAVA encoding (with \uxxxx sequences for non-ASCII
+ characters). */
+static const char *
+conv_to_java (const char *string)
+{
+ /* We cannot use iconv to "JAVA" because not all iconv() implementations
+ know about the "JAVA" encoding. */
+ static const char hexdigit[] = "0123456789abcdef";
+ size_t length;
+ char *result;
+
+ if (is_ascii_string (string))
+ return string;
+
+ length = 0;
+ {
+ const char *str = string;
+ const char *str_limit = str + strlen (str);
+
+ while (str < str_limit)
+ {
+ unsigned int uc;
+ str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str);
+ length += (uc <= 0x007f ? 1 : uc < 0x10000 ? 6 : 12);
+ }
+ }
+
+ result = (char *) xmalloc (length + 1);
+
+ {
+ char *newstr = result;
+ const char *str = string;
+ const char *str_limit = str + strlen (str);
+
+ while (str < str_limit)
+ {
+ unsigned int uc;
+ str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str);
+ if (uc <= 0x007f)
+ /* ASCII characters can be output literally.
+ We could treat non-ASCII ISO-8859-1 characters (0x0080..0x00FF)
+ the same way, but there is no point in doing this; Sun's
+ nativetoascii doesn't do it either. */
+ *newstr++ = uc;
+ else if (uc < 0x10000)
+ {
+ /* Single UCS-2 'char' */
+ sprintf (newstr, "\\u%c%c%c%c",
+ hexdigit[(uc >> 12) & 0x0f], hexdigit[(uc >> 8) & 0x0f],
+ hexdigit[(uc >> 4) & 0x0f], hexdigit[uc & 0x0f]);
+ newstr += 6;
+ }
+ else
+ {
+ /* UTF-16 surrogate: two 'char's. */
+ unsigned int uc1 = 0xd800 + ((uc - 0x10000) >> 10);
+ unsigned int uc2 = 0xdc00 + ((uc - 0x10000) & 0x3ff);
+ sprintf (newstr, "\\u%c%c%c%c",
+ hexdigit[(uc1 >> 12) & 0x0f], hexdigit[(uc1 >> 8) & 0x0f],
+ hexdigit[(uc1 >> 4) & 0x0f], hexdigit[uc1 & 0x0f]);
+ newstr += 6;
+ sprintf (newstr, "\\u%c%c%c%c",
+ hexdigit[(uc2 >> 12) & 0x0f], hexdigit[(uc2 >> 8) & 0x0f],
+ hexdigit[(uc2 >> 4) & 0x0f], hexdigit[uc2 & 0x0f]);
+ newstr += 6;
+ }
+ }
+ *newstr = '\0';
+ }
+
+ return result;
+}
+
+/* Writes a key or value to the file, without newline. */
+static void
+write_escaped_string (FILE *fp, const char *str, bool in_key)
+{
+ static const char hexdigit[] = "0123456789abcdef";
+ const char *str_limit = str + strlen (str);
+ bool first = true;
+
+ while (str < str_limit)
+ {
+ unsigned int uc;
+ str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str);
+ /* Whitespace must be escaped. */
+ if (uc == 0x0020 && (first || in_key))
+ {
+ putc ('\\', fp);
+ putc (' ', fp);
+ }
+ else if (uc == 0x0009)
+ {
+ putc ('\\', fp);
+ putc ('t', fp);
+ }
+ else if (uc == 0x000a)
+ {
+ putc ('\\', fp);
+ putc ('n', fp);
+ }
+ else if (uc == 0x000d)
+ {
+ putc ('\\', fp);
+ putc ('r', fp);
+ }
+ else if (uc == 0x000c)
+ {
+ putc ('\\', fp);
+ putc ('f', fp);
+ }
+ else if (/* Backslash must be escaped. */
+ uc == '\\'
+ /* Possible comment introducers must be escaped. */
+ || uc == '#' || uc == '!'
+ /* Key terminators must be escaped. */
+ || uc == '=' || uc == ':')
+ {
+ putc ('\\', fp);
+ putc (uc, fp);
+ }
+ else if (uc >= 0x0020 && uc <= 0x007e)
+ {
+ /* ASCII characters can be output literally.
+ We could treat non-ASCII ISO-8859-1 characters (0x0080..0x00FF)
+ the same way, but there is no point in doing this; Sun's
+ nativetoascii doesn't do it either. */
+ putc (uc, fp);
+ }
+ else if (uc < 0x10000)
+ {
+ /* Single UCS-2 'char' */
+ fprintf (fp, "\\u%c%c%c%c",
+ hexdigit[(uc >> 12) & 0x0f], hexdigit[(uc >> 8) & 0x0f],
+ hexdigit[(uc >> 4) & 0x0f], hexdigit[uc & 0x0f]);
+ }
+ else
+ {
+ /* UTF-16 surrogate: two 'char's. */
+ unsigned int uc1 = 0xd800 + ((uc - 0x10000) >> 10);
+ unsigned int uc2 = 0xdc00 + ((uc - 0x10000) & 0x3ff);
+ fprintf (fp, "\\u%c%c%c%c",
+ hexdigit[(uc1 >> 12) & 0x0f], hexdigit[(uc1 >> 8) & 0x0f],
+ hexdigit[(uc1 >> 4) & 0x0f], hexdigit[uc1 & 0x0f]);
+ fprintf (fp, "\\u%c%c%c%c",
+ hexdigit[(uc2 >> 12) & 0x0f], hexdigit[(uc2 >> 8) & 0x0f],
+ hexdigit[(uc2 >> 4) & 0x0f], hexdigit[uc2 & 0x0f]);
+ }
+ first = false;
+ }
+}
+
+/* Writes a message to the file. */
+static void
+write_message (FILE *fp, const message_ty *mp, size_t page_width, bool debug)
+{
+ /* Print translator comment if available. */
+ message_print_comment (mp, fp);
+
+ /* Print xgettext extracted comments. */
+ message_print_comment_dot (mp, fp);
+
+ /* Print the file position comments. */
+ message_print_comment_filepos (mp, fp, false, page_width);
+
+ /* Print flag information in special comment. */
+ message_print_comment_flags (mp, fp, debug);
+
+ /* Put a comment mark if the message is the header or untranslated or
+ fuzzy. */
+ if (mp->msgid[0] == '\0'
+ || mp->msgstr[0] == '\0'
+ || (mp->is_fuzzy && mp->msgid[0] != '\0'))
+ putc ('!', fp);
+
+ /* Now write the untranslated string and the translated string. */
+ write_escaped_string (fp, mp->msgid, true);
+ putc ('=', fp);
+ write_escaped_string (fp, mp->msgstr, false);
+
+ putc ('\n', fp);
+}
+
+/* Writes an entire message list to the file. */
+static void
+write_properties (FILE *fp, message_list_ty *mlp, const char *canon_encoding,
+ size_t page_width, bool debug)
+{
+ bool blank_line;
+ size_t j, i;
+
+ /* Convert the messages to Unicode. */
+ iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL);
+ for (j = 0; j < mlp->nitems; ++j)
+ {
+ message_ty *mp = mlp->item[j];
+
+ if (mp->comment != NULL)
+ for (i = 0; i < mp->comment->nitems; ++i)
+ mp->comment->item[i] = conv_to_java (mp->comment->item[i]);
+ if (mp->comment_dot != NULL)
+ for (i = 0; i < mp->comment_dot->nitems; ++i)
+ mp->comment_dot->item[i] = conv_to_java (mp->comment_dot->item[i]);
+ }
+
+ /* Loop through the messages. */
+ blank_line = false;
+ for (j = 0; j < mlp->nitems; ++j)
+ {
+ const message_ty *mp = mlp->item[j];
+
+ if (mp->msgid_plural == NULL && !mp->obsolete)
+ {
+ if (blank_line)
+ putc ('\n', fp);
+
+ write_message (fp, mp, page_width, debug);
+
+ blank_line = true;
+ }
+ }
+}
+
+/* Output the contents of a PO file in Java .properties syntax. */
+void
+msgdomain_list_print_properties (msgdomain_list_ty *mdlp, FILE *fp,
+ size_t page_width, bool debug)
+{
+ message_list_ty *mlp;
+
+ if (mdlp->nitems == 1)
+ mlp = mdlp->item[0]->messages;
+ else
+ mlp = message_list_alloc (false);
+ write_properties (fp, mlp, mdlp->encoding, page_width, debug);
+}
diff --git a/gettext-tools/src/write-properties.h b/gettext-tools/src/write-properties.h
new file mode 100644
index 0000000..d25be0d
--- /dev/null
+++ b/gettext-tools/src/write-properties.h
@@ -0,0 +1,33 @@
+/* Writing Java .properties files.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _WRITE_PROPERTIES_H
+#define _WRITE_PROPERTIES_H
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "message.h"
+
+/* Output the contents of a PO file in Java .properties syntax. */
+extern void
+ msgdomain_list_print_properties (msgdomain_list_ty *mdlp, FILE *fp,
+ size_t page_width, bool debug);
+
+#endif /* _WRITE_PROPERTIES_H */
diff --git a/gettext-tools/src/write-tcl.c b/gettext-tools/src/write-tcl.c
index fed43f5..b99a103 100644
--- a/gettext-tools/src/write-tcl.c
+++ b/gettext-tools/src/write-tcl.c
@@ -133,7 +133,7 @@ write_msg (FILE *output_file, message_list_ty *mlp, const char *locale_name)
}
int
-msgdomain_write_tcl (message_list_ty *mlp,
+msgdomain_write_tcl (message_list_ty *mlp, const char *canon_encoding,
const char *locale_name,
const char *directory)
{
@@ -161,7 +161,7 @@ but the Tcl message catalog format doesn't support plural handling\n")));
}
/* Convert the messages to Unicode. */
- iconv_message_list (mlp, NULL, po_charset_canonicalize ("UTF-8"), NULL);
+ iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL);
/* Now create the file. */
{
diff --git a/gettext-tools/src/write-tcl.h b/gettext-tools/src/write-tcl.h
index 2b135db..8ebcafb 100644
--- a/gettext-tools/src/write-tcl.h
+++ b/gettext-tools/src/write-tcl.h
@@ -1,5 +1,5 @@
/* Writing tcl/msgcat .msg files.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002-2003 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2002.
This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
the base directory.
Return 0 if ok, nonzero on error. */
extern int
- msgdomain_write_tcl (message_list_ty *mlp,
+ msgdomain_write_tcl (message_list_ty *mlp, const char *canon_encoding,
const char *locale_name,
const char *directory);
diff --git a/gettext-tools/src/x-po.c b/gettext-tools/src/x-po.c
index f513daa..6cc89c7 100644
--- a/gettext-tools/src/x-po.c
+++ b/gettext-tools/src/x-po.c
@@ -1,4 +1,4 @@
-/* xgettext PO backend.
+/* xgettext PO and JavaProperties backends.
Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc.
This file was written by Peter Miller <millerp@canb.auug.org.au>
@@ -47,7 +47,7 @@ extract_add_message (default_po_reader_ty *this,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
/* See whether we shall exclude this message. */
if (exclude != NULL && message_list_search (exclude, msgid) != NULL)
@@ -67,7 +67,7 @@ extract_add_message (default_po_reader_ty *this,
/* Invoke superclass method. */
default_add_message (this, msgid, msgid_pos, msgid_plural,
- msgstr, msgstr_len, msgstr_pos, obsolete);
+ msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete);
}
@@ -98,10 +98,11 @@ static default_po_reader_class_ty extract_methods =
};
-void
-extract_po (FILE *fp,
- const char *real_filename, const char *logical_filename,
- msgdomain_list_ty *mdlp)
+static void
+extract (FILE *fp,
+ const char *real_filename, const char *logical_filename,
+ input_syntax_ty syntax,
+ msgdomain_list_ty *mdlp)
{
default_po_reader_ty *pop;
@@ -113,6 +114,25 @@ extract_po (FILE *fp,
pop->allow_duplicates_if_same_msgstr = true;
pop->mdlp = NULL;
pop->mlp = mdlp->item[0]->messages;
- po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename);
+ po_scan ((abstract_po_reader_ty *) pop, fp, real_filename, logical_filename,
+ syntax);
po_reader_free ((abstract_po_reader_ty *) pop);
}
+
+
+void
+extract_po (FILE *fp,
+ const char *real_filename, const char *logical_filename,
+ msgdomain_list_ty *mdlp)
+{
+ extract (fp, real_filename, logical_filename, syntax_po, mdlp);
+}
+
+
+void
+extract_properties (FILE *fp,
+ const char *real_filename, const char *logical_filename,
+ msgdomain_list_ty *mdlp)
+{
+ extract (fp, real_filename, logical_filename, syntax_properties, mdlp);
+}
diff --git a/gettext-tools/src/x-properties.h b/gettext-tools/src/x-properties.h
new file mode 100644
index 0000000..e9e5f1e
--- /dev/null
+++ b/gettext-tools/src/x-properties.h
@@ -0,0 +1,29 @@
+/* xgettext JavaProperties backend.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#define EXTENSIONS_PROPERTIES \
+ { "properties", "JavaProperties" }, \
+
+#define SCANNERS_PROPERTIES \
+ { "JavaProperties", extract_properties, NULL }, \
+
+/* Scan a JavaProperties file and add its translatable strings to mdlp. */
+extern void extract_properties (FILE *fp, const char *real_filename,
+ const char *logical_filename,
+ msgdomain_list_ty *mdlp);
diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c
index b89e6a6..ae113e2 100644
--- a/gettext-tools/src/xgettext.c
+++ b/gettext-tools/src/xgettext.c
@@ -70,6 +70,7 @@
#include "x-librep.h"
#include "x-smalltalk.h"
#include "x-java.h"
+#include "x-properties.h"
#include "x-awk.h"
#include "x-ycp.h"
#include "x-tcl.h"
@@ -169,6 +170,7 @@ static const struct option long_options[] =
{ "omit-header", no_argument, &xgettext_omit_header, 1 },
{ "output", required_argument, NULL, 'o' },
{ "output-dir", required_argument, NULL, 'p' },
+ { "properties-output", no_argument, NULL, CHAR_MAX + 6 },
{ "sort-by-file", no_argument, NULL, 'F' },
{ "sort-output", no_argument, NULL, 's' },
{ "strict", no_argument, NULL, 'S' },
@@ -393,6 +395,9 @@ main (int argc, char *argv[])
case CHAR_MAX + 5: /* --msgid-bugs-address */
msgid_bugs_address = optarg;
break;
+ case CHAR_MAX + 6: /* --properties-output */
+ message_print_syntax_properties ();
+ break;
default:
usage (EXIT_FAILURE);
/* NOTREACHED */
@@ -644,8 +649,8 @@ Choice of input file language:\n"));
printf (_("\
-L, --language=NAME recognise the specified language\n\
(C, C++, ObjectiveC, PO, Python, Lisp,\n\
- EmacsLisp, librep, Smalltalk, Java, awk, YCP,\n\
- Tcl, PHP, RST, Glade)\n"));
+ EmacsLisp, librep, Smalltalk, Java,\n\
+ JavaProperties, awk, YCP, Tcl, PHP, RST, Glade)\n"));
printf (_("\
-C, --c++ shorthand for --language=C++\n"));
printf (_("\
@@ -698,6 +703,8 @@ Output details:\n"));
printf (_("\
--strict write out strict Uniforum conforming .po file\n"));
printf (_("\
+ --properties-output write out a Java .properties file\n"));
+ printf (_("\
-w, --width=NUMBER set output page width\n"));
printf (_("\
--no-wrap do not break long message lines, longer than\n\
@@ -749,7 +756,7 @@ exclude_directive_message (abstract_po_reader_ty *pop,
char *msgid_plural,
char *msgstr, size_t msgstr_len,
lex_pos_ty *msgstr_pos,
- bool obsolete)
+ bool force_fuzzy, bool obsolete)
{
message_ty *mp;
@@ -802,7 +809,7 @@ read_exclusion_file (char *filename)
abstract_po_reader_ty *pop;
pop = po_reader_alloc (&exclude_methods);
- po_scan (pop, fp, real_filename, filename);
+ po_scan (pop, fp, real_filename, filename, input_syntax);
po_reader_free (pop);
if (fp != stdin)
@@ -1442,6 +1449,7 @@ language_to_extractor (const char *name)
SCANNERS_LIBREP
SCANNERS_SMALLTALK
SCANNERS_JAVA
+ SCANNERS_PROPERTIES
SCANNERS_AWK
SCANNERS_YCP
SCANNERS_TCL
@@ -1489,6 +1497,7 @@ extension_to_language (const char *extension)
EXTENSIONS_LIBREP
EXTENSIONS_SMALLTALK
EXTENSIONS_JAVA
+ EXTENSIONS_PROPERTIES
EXTENSIONS_AWK
EXTENSIONS_YCP
EXTENSIONS_TCL
diff --git a/gettext-tools/src/xgettext.h b/gettext-tools/src/xgettext.h
index 97408b8..a37c544 100644
--- a/gettext-tools/src/xgettext.h
+++ b/gettext-tools/src/xgettext.h
@@ -29,8 +29,8 @@
#include "message.h"
#include "pos.h"
-/* Borrowed from read-po.h. */
-extern int line_comment;
+/* Declare 'line_comment' and 'input_syntax'. */
+#include "read-po.h"
/* If true, omit the header entry.
If false, keep the header entry present in the input. */