diff options
author | Bruno Haible <bruno@clisp.org> | 2003-04-29 10:12:15 +0000 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2009-06-23 12:10:24 +0200 |
commit | cde7e9fa958cdb60d1762921d4704c6b1c3e2504 (patch) | |
tree | d5003e47cbac8839b22dbf9ee20723b141a42472 /gettext-tools/src | |
parent | b6d32da76eb3a2aebea75850c5696c0122cfa385 (diff) | |
download | external_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')
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. */ |