From: Bruno Haible Date: Wed, 22 Oct 2003 10:49:08 +0000 (+0000) Subject: Support for GNUstep .strings format. X-Git-Tag: v0.13~193 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=71369e271602bb1fa9ce0d706202eaff8ff8867a;p=thirdparty%2Fgettext.git Support for GNUstep .strings format. --- diff --git a/gettext-tools/doc/ChangeLog b/gettext-tools/doc/ChangeLog index d8271c184..5f869c3ce 100644 --- a/gettext-tools/doc/ChangeLog +++ b/gettext-tools/doc/ChangeLog @@ -1,3 +1,22 @@ +2003-10-12 Bruno Haible + + * msgattrib.texi: Document --stringtable-input and --stringtable-output + options. + * msgcat.texi: Likewise. + * msgcomm.texi: Likewise. + * msgconv.text: Likewise. + * msgen.texi: Likewise. + * msgfilter.texi: Likewise. + * msgrep.texi: Likewise. + * msginit.texi: Likewise. + * msgmerge.texi: Likewise. + * msguniq.texi: Likewise. + * msgcmp.texi: Document --stringtable-input option. + * msgexec.texi: Likewise. + * msgfmt.texi: Likewise. + * msgunfmt.texi: Document --stringtable-output option. + * xgettext.texi: Likewise. Document --language=NXStringTable. + 2003-10-11 Bruno Haible * gettext.texi (PHP): Drop phplib from list of RPMs. diff --git a/gettext-tools/doc/msgattrib.texi b/gettext-tools/doc/msgattrib.texi index f4c31702b..d27912a9e 100644 --- a/gettext-tools/doc/msgattrib.texi +++ b/gettext-tools/doc/msgattrib.texi @@ -128,6 +128,11 @@ obsolete messages and makes them non-obsolete. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgattrib} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -169,6 +174,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgattrib} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgattrib} option} diff --git a/gettext-tools/doc/msgcat.texi b/gettext-tools/doc/msgcat.texi index 0e61e18ba..c53d883cd 100644 --- a/gettext-tools/doc/msgcat.texi +++ b/gettext-tools/doc/msgcat.texi @@ -92,6 +92,11 @@ printed. Assume the input files are Java ResourceBundles in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgcat} option} +Assume the input files are NeXTstep/GNUstep localized resource files in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -144,6 +149,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgcat} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgcat} option} diff --git a/gettext-tools/doc/msgcmp.texi b/gettext-tools/doc/msgcmp.texi index 80b7eee15..b7f5a2a8b 100644 --- a/gettext-tools/doc/msgcmp.texi +++ b/gettext-tools/doc/msgcmp.texi @@ -52,6 +52,11 @@ Apply @var{ref}.pot to each of the domains in @var{def}.po. Assume the input files are Java ResourceBundles in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgcmp} option} +Assume the input files are NeXTstep/GNUstep localized resource files in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Informative output diff --git a/gettext-tools/doc/msgcomm.texi b/gettext-tools/doc/msgcomm.texi index 0ad42036a..86fc711f4 100644 --- a/gettext-tools/doc/msgcomm.texi +++ b/gettext-tools/doc/msgcomm.texi @@ -90,6 +90,11 @@ printed. Assume the input files are Java ResourceBundles in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgcomm} option} +Assume the input files are NeXTstep/GNUstep localized resource files in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -131,6 +136,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgcomm} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgcomm} option} diff --git a/gettext-tools/doc/msgconv.texi b/gettext-tools/doc/msgconv.texi index 814824413..c5f53f6ee 100644 --- a/gettext-tools/doc/msgconv.texi +++ b/gettext-tools/doc/msgconv.texi @@ -63,6 +63,11 @@ The default encoding is the current locale's encoding. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgonv} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -102,6 +107,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgconv} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgconv} option} diff --git a/gettext-tools/doc/msgen.texi b/gettext-tools/doc/msgen.texi index b3a7e5245..7923cd7ba 100644 --- a/gettext-tools/doc/msgen.texi +++ b/gettext-tools/doc/msgen.texi @@ -56,6 +56,11 @@ or if it is @samp{-}. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgen} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -95,6 +100,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgen} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgen} option} diff --git a/gettext-tools/doc/msgexec.texi b/gettext-tools/doc/msgexec.texi index 7163fa40f..461183270 100644 --- a/gettext-tools/doc/msgexec.texi +++ b/gettext-tools/doc/msgexec.texi @@ -66,6 +66,11 @@ If no @var{inputfile} is given or if it is @samp{-}, standard input is read. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgexec} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Informative output diff --git a/gettext-tools/doc/msgfilter.texi b/gettext-tools/doc/msgfilter.texi index 7c78dc875..4e978cdb5 100644 --- a/gettext-tools/doc/msgfilter.texi +++ b/gettext-tools/doc/msgfilter.texi @@ -104,6 +104,11 @@ Suppress automatic printing of pattern space. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgfilter} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -147,6 +152,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgfilter} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgfilter} option} diff --git a/gettext-tools/doc/msgfmt.texi b/gettext-tools/doc/msgfmt.texi index 144436856..821ca8855 100644 --- a/gettext-tools/doc/msgfmt.texi +++ b/gettext-tools/doc/msgfmt.texi @@ -126,6 +126,11 @@ written in the specified directory. Assume the input files are Java ResourceBundles in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgfmt} option} +Assume the input files are NeXTstep/GNUstep localized resource files in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Input file interpretation diff --git a/gettext-tools/doc/msggrep.texi b/gettext-tools/doc/msggrep.texi index b8dfe5ff5..d3b4eb8a9 100644 --- a/gettext-tools/doc/msggrep.texi +++ b/gettext-tools/doc/msggrep.texi @@ -143,6 +143,11 @@ Ignore case distinctions. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msggrep} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -180,6 +185,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msggrep} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msggrep} option} diff --git a/gettext-tools/doc/msginit.texi b/gettext-tools/doc/msginit.texi index e2f539174..5b0f52535 100644 --- a/gettext-tools/doc/msginit.texi +++ b/gettext-tools/doc/msginit.texi @@ -48,6 +48,11 @@ standard output. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msginit} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -74,6 +79,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msginit} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msginit} option} diff --git a/gettext-tools/doc/msgmerge.texi b/gettext-tools/doc/msgmerge.texi index d2830d073..90dccd5b9 100644 --- a/gettext-tools/doc/msgmerge.texi +++ b/gettext-tools/doc/msgmerge.texi @@ -138,6 +138,11 @@ up the operation considerably. Assume the input files are Java ResourceBundles in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msgmerge} option} +Assume the input files are NeXTstep/GNUstep localized resource files in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -177,6 +182,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgmerge} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgmerge} option} diff --git a/gettext-tools/doc/msgunfmt.texi b/gettext-tools/doc/msgunfmt.texi index afd4f19bc..150bcd9f1 100644 --- a/gettext-tools/doc/msgunfmt.texi +++ b/gettext-tools/doc/msgunfmt.texi @@ -118,6 +118,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msgunfmt} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msgunfmt} option} diff --git a/gettext-tools/doc/msguniq.texi b/gettext-tools/doc/msguniq.texi index 42c897ebb..43bb48236 100644 --- a/gettext-tools/doc/msguniq.texi +++ b/gettext-tools/doc/msguniq.texi @@ -76,6 +76,11 @@ Print only unique messages, discard duplicates. Assume the input file is a Java ResourceBundle in Java @code{.properties} syntax, not in PO file syntax. +@item --stringtable-input +@opindex --stringtable-input@r{, @code{msguniq} option} +Assume the input file is a NeXTstep/GNUstep localized resource file in +@code{.strings} syntax, not in PO file syntax. + @end table @subsection Output details @@ -128,6 +133,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{msguniq} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{msguniq} option} diff --git a/gettext-tools/doc/xgettext.texi b/gettext-tools/doc/xgettext.texi index a29cbc76f..2c84ee6e3 100644 --- a/gettext-tools/doc/xgettext.texi +++ b/gettext-tools/doc/xgettext.texi @@ -72,7 +72,7 @@ Specifies the language of the input files. The supported languages are @code{C}, @code{C++}, @code{ObjectiveC}, @code{PO}, @code{Python}, @code{Lisp}, @code{EmacsLisp}, @code{librep}, @code{Smalltalk}, @code{Java}, @code{JavaProperties}, @code{awk}, @code{YCP}, @code{Tcl}, @code{Perl}, -@code{PHP}, @code{GCC-source}, @code{RST}, @code{Glade}. +@code{PHP}, @code{GCC-source}, @code{NXStringTable}, @code{RST}, @code{Glade}. @item -C @itemx --c++ @@ -269,6 +269,11 @@ Write out a Java ResourceBundle in Java @code{.properties} syntax. Note that this file format doesn't support plural forms and silently drops obsolete messages. +@item --stringtable-output +@opindex --stringtable-output@r{, @code{xgettext} option} +Write out a NeXTstep/GNUstep localized resource file in @code{.strings} syntax. +Note that this file format doesn't support plural forms. + @item -w @var{number} @itemx --width=@var{number} @opindex -w@r{, @code{xgettext} option} diff --git a/gettext-tools/po/ChangeLog b/gettext-tools/po/ChangeLog index 94b614078..8ccd55389 100644 --- a/gettext-tools/po/ChangeLog +++ b/gettext-tools/po/ChangeLog @@ -1,3 +1,7 @@ +2003-10-14 Bruno Haible + + * POTFILES.in: Add src/read-stringtable.c. + 2003-10-09 Bruno Haible * POTFILES.in: Add src/java.c. diff --git a/gettext-tools/po/POTFILES.in b/gettext-tools/po/POTFILES.in index 74046b099..c35255253 100644 --- a/gettext-tools/po/POTFILES.in +++ b/gettext-tools/po/POTFILES.in @@ -68,6 +68,7 @@ src/read-java.c src/read-mo.c src/read-po.c src/read-properties.c +src/read-stringtable.c src/read-tcl.c src/urlget.c src/write-java.c diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog index 7e023b414..2a104ea60 100644 --- a/gettext-tools/src/ChangeLog +++ b/gettext-tools/src/ChangeLog @@ -1,3 +1,100 @@ +2003-10-18 Bruno Haible + + Support for GNUstep .strings format. + * read-stringtable.h: New file. + * read-stringtable.c: New file. + * read-po-abstract.h (enum input_syntax_ty): New item + syntax_stringtable. + (po_callback_comment_dispatcher): Renamed from po_callback_comment. + (po_callback_comment, po_callback_comment_special): New declarations. + * read-po-abstract.c: Include read-stringtable.h. + (po_scan): Add support for syntax_stringtable. + (po_callback_comment_dispatcher): Renamed from po_callback_comment. + (po_callback_comment, po_callback_comment_dot): New functions. + (po_callback_comment_special): New function. + * read-po.c (read_po): Set mdlp->encoding for syntax_stringtable too. + * po-gram-gen.y: Update po_callback_comment_dispatcher call. + * read-properties.c (properties_parse): Likewise. + * write-stringtable.h: New file. + * write-stringtable.c: New file. + * write-po.h (make_format_description_string, significant_format_p): + New declarations. + (message_print_syntax_stringtable): New declaration. + * write-po.c: Include write-stringtable.h. + (make_format_description_string, significant_format_p): Make + non-static. + (use_syntax_stringtable): New variable. + (message_print_syntax_stringtable): New function. + (msgdomain_list_print): Add check for plural forms for + syntax_stringtable too. Add support for writing the .strings format. + * msgattrib.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * msgcat.c (long_options): Add --stringtable-input/output. + (main): Handle them. If option --stringtable-output is used, convert to + UTF-8 and ignore the to_code. + (usage): Document options --stringtable-input/output. + * msgcmp.c (long_options): Add --stringtable-input. + (main): Handle it. + (usage): Document option --stringtable-input. + * msgcomm.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * msgconv.c (long_options): Add --stringtable-input/output. + (main): Handle them. If option --stringtable-output is used, ignore the + to_code. + (usage): Document options --stringtable-input/output. + * msgen.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * msgexec.c: Include limits.h. + (long_options): Add --stringtable-input. + (main): Handle it. + (usage): Document option --stringtable-input. + * msgfilter.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * msgfmt.c (long_options): Add --stringtable-input. + (main): Handle it. + (usage): Document option --stringtable-input. + * msggrep.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * msginit.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * msgmerge.c (long_options): Add --stringtable-input/output. + (main): Handle them. In update mode, --stringtable-input implies + --stringtable-output. + (usage): Document options --stringtable-input/output. + * msgunfmt.c (long_options): Add --stringtable-output. + (main): Handle it. + (usage): Document option --stringtable-output. + * msguniq.c (long_options): Add --stringtable-input/output. + (main): Handle them. + (usage): Document options --stringtable-input/output. + * x-stringtable.h: New file. + * x-po.c: Include x-stringtable.h. + (extract_stringtable): New function. + * xgettext.c: Include x-stringtable.h. + (long_options): Add --stringtable-output. + (main): Handle it. + (usage): Document options -L NXStringTable and --stringtable-output. + (finalize_header): If --stringtable-output was given, set the charset. + (language_to_extractor): Add support for .strings format. + (extension_to_language): Likewise. + * Makefile.am (noinst_HEADERS): Add read-stringtable.h, + write-stringtable.h, x-stringtable.h. + (COMMON_SOURCE): Add read-stringtable.c. + (libgettextsrc_la_SOURCES): Add write-stringtable.c. + * Makefile.msvc (OBJECTS): Add read-stringtable.obj, + write-stringtable.obj. + (read-stringtable.obj, write-stringtable.obj): New rules. + * Makefile.vms (OBJECTS): Add read-stringtable.obj, + write-stringtable.obj. + (read-stringtable.obj, write-stringtable.obj): New rules. + * FILES: Update. + 2003-10-21 Bruno Haible * hostname.c (xgethostname): Add support for native Woe32 API. diff --git a/gettext-tools/src/FILES b/gettext-tools/src/FILES index 9f4ad08ee..e67a6a746 100644 --- a/gettext-tools/src/FILES +++ b/gettext-tools/src/FILES @@ -38,6 +38,10 @@ write-po.c write-properties.h write-properties.c Output of a list-of-messages to a Java .properties file. +write-stringtable.h +write-stringtable.c + Output of a list-of-messages to a NeXTstep/GNUstep .strings + file. +-------------- Reading PO files | open-po.h @@ -59,8 +63,11 @@ write-properties.c | po-gram-gen.y | read-properties.h | read-properties.c +| read-stringtable.h +| read-stringtable.c | read-po-abstract.c -| Parsing of PO files and Java .properties files. +| Parsing of PO files and Java .properties and NeXTstep/GNUstep +| .strings files. | read-po-abstract.h | General parser structure. | po-hash.h @@ -73,6 +80,9 @@ write-properties.c | read-properties.h | read-properties.c | Parsing of Java .properties files. +| read-stringtable.h +| read-stringtable.c +| Parsing of NeXTstep/GNUstep .strings files. | read-po-abstract.c | Top-level parser functions and callbacks. | @@ -217,8 +227,10 @@ format.c Table of the language dependent format string handlers. | String extractor for C. | x-po.h | x-properties.h +| x-stringtable.h | x-po.c -| String extractor from PO files and Java .properties files. +| String extractor from PO files and Java .properties and +| NeXTstep/GNUstep .strings files. | x-sh.h | x-sh.c | String extractor for Shell. diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am index 29c45c310..fc8cae11c 100644 --- a/gettext-tools/src/Makefile.am +++ b/gettext-tools/src/Makefile.am @@ -35,14 +35,15 @@ 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 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 plural-count.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-sh.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-perl.h x-php.h x-rst.h x-glade.h +open-po.h read-po-abstract.h read-po.h read-properties.h read-stringtable.h \ +str-list.h write-po.h write-properties.h write-stringtable.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 plural-count.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-sh.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-perl.h x-php.h x-stringtable.h \ +x-rst.h x-glade.h EXTRA_DIST += FILES project-id ChangeLog.0 @@ -87,7 +88,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 \ -read-properties.c open-po.c dir-list.c str-list.c +read-properties.c read-stringtable.c open-po.c dir-list.c str-list.c # xgettext and msgfmt deal with format strings. FORMAT_SOURCE = format.c format-invalid.h \ @@ -98,8 +99,8 @@ format-gcc-internal.c # libgettextsrc contains all code that is needed by at least two programs. libgettextsrc_la_SOURCES = \ -$(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 \ +$(COMMON_SOURCE) read-po.c write-properties.c write-stringtable.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. diff --git a/gettext-tools/src/Makefile.msvc b/gettext-tools/src/Makefile.msvc index 46ae9630c..d9c2f922e 100644 --- a/gettext-tools/src/Makefile.msvc +++ b/gettext-tools/src/Makefile.msvc @@ -112,11 +112,13 @@ OBJECTS = \ po-hash-gen.obj \ po-charset.obj \ read-properties.obj \ + read-stringtable.obj \ open-po.obj \ dir-list.obj \ str-list.obj \ read-po.obj \ write-properties.obj \ + write-stringtable.obj \ write-po.obj \ msgl-ascii.obj \ msgl-iconv.obj \ @@ -189,6 +191,9 @@ po-charset.obj : po-charset.c read-properties.obj : read-properties.c $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-properties.c +read-stringtable.obj : read-stringtable.c + $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c read-stringtable.c + open-po.obj : open-po.c $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c open-po.c @@ -204,6 +209,9 @@ read-po.obj : read-po.c write-properties.obj : write-properties.c $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-properties.c +write-stringtable.obj : write-stringtable.c + $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c write-stringtable.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 0e46986af..2282c7fbc 100644 --- a/gettext-tools/src/Makefile.vms +++ b/gettext-tools/src/Makefile.vms @@ -58,11 +58,13 @@ OBJECTS = \ po-hash-gen.obj, \ po-charset.obj, \ read-properties.obj, \ + read-stringtable.obj, \ open-po.obj, \ dir-list.obj, \ str-list.obj, \ read-po.obj, \ write-properties.obj, \ + write-stringtable.obj, \ write-po.obj, \ msgl-ascii.obj, \ msgl-iconv.obj, \ @@ -133,6 +135,9 @@ po-charset.obj : po-charset.c read-properties.obj : read-properties.c $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-properties.c +read-stringtable.obj : read-stringtable.c + $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) read-stringtable.c + open-po.obj : open-po.c $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) open-po.c @@ -148,6 +153,9 @@ read-po.obj : read-po.c write-properties.obj : write-properties.c $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-properties.c +write-stringtable.obj : write-stringtable.c + $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-stringtable.c + write-po.obj : write-po.c $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) write-po.c diff --git a/gettext-tools/src/msgattrib.c b/gettext-tools/src/msgattrib.c index 0e78d9fa4..fede0840d 100644 --- a/gettext-tools/src/msgattrib.c +++ b/gettext-tools/src/msgattrib.c @@ -97,6 +97,8 @@ static const struct option long_options[] = { "set-obsolete", no_argument, NULL, CHAR_MAX + 9 }, { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 16 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 17 }, { "strict", no_argument, NULL, 'S' }, { "translated", no_argument, NULL, CHAR_MAX + 1 }, { "untranslated", no_argument, NULL, CHAR_MAX + 2 }, @@ -288,6 +290,14 @@ main (int argc, char **argv) ignore_file = optarg; break; + case CHAR_MAX + 16: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 17: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -430,6 +440,8 @@ Attribute manipulation:\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -450,6 +462,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 f78ee2b53..5c90f87be 100644 --- a/gettext-tools/src/msgcat.c +++ b/gettext-tools/src/msgcat.c @@ -71,6 +71,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 }, { "to-code", required_argument, NULL, 't' }, { "unique", no_argument, NULL, 'u' }, { "use-first", no_argument, NULL, CHAR_MAX + 1 }, @@ -240,6 +242,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 3: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 4: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -290,6 +300,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ /* Read input files, then filter, convert and merge messages. */ result = catenate_msgdomain_list (file_list, output_syntax != syntax_properties + && output_syntax != syntax_stringtable ? to_code : "UTF-8"); @@ -372,6 +383,9 @@ Message selection:\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input files are in NeXTstep/GNUstep .strings\n\ + syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -397,6 +411,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 0ec830996..00c1692ad 100644 --- a/gettext-tools/src/msgcmp.c +++ b/gettext-tools/src/msgcmp.c @@ -55,6 +55,7 @@ static const struct option long_options[] = { "help", no_argument, NULL, 'h' }, { "multi-domain", no_argument, NULL, 'm' }, { "properties-input", no_argument, NULL, 'P' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 1 }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; @@ -122,6 +123,10 @@ main (int argc, char *argv[]) do_version = true; break; + case CHAR_MAX + 1: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + default: usage (EXIT_FAILURE); break; @@ -207,6 +212,9 @@ Operation modifiers:\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input files are in NeXTstep/GNUstep .strings\n\ + syntax\n")); printf ("\n"); printf (_("\ Informative output:\n")); diff --git a/gettext-tools/src/msgcomm.c b/gettext-tools/src/msgcomm.c index 6a6c41ba1..bff1c82a9 100644 --- a/gettext-tools/src/msgcomm.c +++ b/gettext-tools/src/msgcomm.c @@ -75,6 +75,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 }, { "to-code", required_argument, NULL, 't' }, { "unique", no_argument, NULL, 'u' }, { "version", no_argument, NULL, 'V' }, @@ -237,6 +239,14 @@ main (int argc, char *argv[]) message_page_width_ignore (); break; + case CHAR_MAX + 3: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 4: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -378,6 +388,9 @@ Message selection:\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input files are in NeXTstep/GNUstep .strings\n\ + syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -398,6 +411,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 448bbffa6..adea84a67 100644 --- a/gettext-tools/src/msgconv.c +++ b/gettext-tools/src/msgconv.c @@ -69,6 +69,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 }, { "to-code", required_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w', }, @@ -194,6 +196,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 2: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 3: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -245,7 +255,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ result = read_po_file (input_file); /* Convert if and only if the output syntax supports different encodings. */ - if (output_syntax != syntax_properties) + if (output_syntax != syntax_properties + && output_syntax != syntax_stringtable) result = iconv_msgdomain_list (result, to_code, input_file); /* Sort the results. */ @@ -309,6 +320,8 @@ The default encoding is the current locale's encoding.\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -329,6 +342,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 f90a37c47..cabe80bcd 100644 --- a/gettext-tools/src/msgen.c +++ b/gettext-tools/src/msgen.c @@ -65,6 +65,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 2 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w', }, { NULL, 0, NULL, 0 } @@ -180,6 +182,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 2: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 3: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -285,6 +295,8 @@ or if it is -.\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -305,6 +317,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 66e6331d7..4b3f4221f 100644 --- a/gettext-tools/src/msgexec.c +++ b/gettext-tools/src/msgexec.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -79,6 +80,7 @@ static const struct option long_options[] = { "help", no_argument, NULL, 'h' }, { "input", required_argument, NULL, 'i' }, { "properties-input", no_argument, NULL, 'P' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 1 }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; @@ -158,6 +160,10 @@ main (int argc, char **argv) do_version = true; break; + case CHAR_MAX + 1: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + default: usage (EXIT_FAILURE); break; @@ -264,6 +270,8 @@ If no input file is given or if it is -, standard input is read.\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Informative output:\n")); diff --git a/gettext-tools/src/msgfilter.c b/gettext-tools/src/msgfilter.c index b3e4911b8..88b6ed0cd 100644 --- a/gettext-tools/src/msgfilter.c +++ b/gettext-tools/src/msgfilter.c @@ -116,6 +116,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 4 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 5 }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w', }, { NULL, 0, NULL, 0 } @@ -247,6 +249,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 4: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 5: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -405,6 +415,8 @@ Useful FILTER-OPTIONs when the FILTER is 'sed':\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -427,6 +439,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 5d2460811..a30b98a05 100644 --- a/gettext-tools/src/msgfmt.c +++ b/gettext-tools/src/msgfmt.c @@ -167,6 +167,7 @@ static const struct option long_options[] = { "resource", required_argument, NULL, 'r' }, { "statistics", no_argument, &do_statistics, 1 }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 8 }, { "tcl", no_argument, NULL, CHAR_MAX + 7 }, { "use-fuzzy", no_argument, NULL, 'f' }, { "verbose", no_argument, NULL, 'v' }, @@ -281,7 +282,7 @@ main (int argc, char *argv[]) case 'V': do_version = true; break; - case CHAR_MAX + 1: + case CHAR_MAX + 1: /* --check-accelerators */ check_accelerators = true; if (optarg != NULL) { @@ -294,25 +295,28 @@ main (int argc, char *argv[]) "--check-accelerators"); } break; - case CHAR_MAX + 2: + case CHAR_MAX + 2: /* --check-domain */ check_domain = true; break; - case CHAR_MAX + 3: + case CHAR_MAX + 3: /* --check-format */ check_format_strings = true; break; - case CHAR_MAX + 4: + case CHAR_MAX + 4: /* --check-header */ check_header = true; break; - case CHAR_MAX + 5: + case CHAR_MAX + 5: /* --java2 */ java_mode = true; assume_java2 = true; break; - case CHAR_MAX + 6: + case CHAR_MAX + 6: /* --no-hash */ no_hash_table = true; break; - case CHAR_MAX + 7: + case CHAR_MAX + 7: /* --tcl */ tcl_mode = true; break; + case CHAR_MAX + 8: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; default: usage (EXIT_FAILURE); break; @@ -428,8 +432,12 @@ 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); + /* We know a priori that properties_parse() and stringtable_parse() convert + strings to UTF-8. */ + canon_encoding = + (input_syntax == syntax_properties || input_syntax == syntax_stringtable + ? po_charset_utf8 + : NULL); /* Remove obsolete messages. They were only needed for duplicate checking. */ @@ -571,6 +579,9 @@ specified directory.\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input files are in NeXTstep/GNUstep .strings\n\ + syntax\n")); printf ("\n"); printf (_("\ Input file interpretation:\n")); diff --git a/gettext-tools/src/msggrep.c b/gettext-tools/src/msggrep.c index 1fc10a961..0b5c29b94 100644 --- a/gettext-tools/src/msggrep.c +++ b/gettext-tools/src/msggrep.c @@ -107,6 +107,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, CHAR_MAX + 4 }, { "sort-output", no_argument, NULL, CHAR_MAX + 5 }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 7 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 8 }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w' }, { NULL, 0, NULL, 0 } @@ -290,6 +292,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 7: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 8: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -488,6 +498,8 @@ expressions if -E is given, or fixed strings if -F is given.\n\ Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -508,6 +520,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 fb63147f2..459286fdd 100644 --- a/gettext-tools/src/msginit.c +++ b/gettext-tools/src/msginit.c @@ -133,6 +133,8 @@ static const struct option long_options[] = { "output-file", required_argument, NULL, 'o' }, { "properties-input", no_argument, NULL, 'P' }, { "properties-output", no_argument, NULL, 'p' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w' }, { NULL, 0, NULL, 0 } @@ -242,6 +244,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 3: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 4: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -379,6 +389,8 @@ locale setting. If it is -, the results are written to standard output.\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -389,6 +401,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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/msgmerge.c b/gettext-tools/src/msgmerge.c index 658cfd6f0..14aa79e77 100644 --- a/gettext-tools/src/msgmerge.c +++ b/gettext-tools/src/msgmerge.c @@ -103,6 +103,8 @@ static const struct option long_options[] = { "sort-output", no_argument, NULL, 's' }, { "silent", no_argument, NULL, 'q' }, { "strict", no_argument, NULL, CHAR_MAX + 2 }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 5 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 6 }, { "suffix", required_argument, NULL, CHAR_MAX + 3 }, { "update", no_argument, NULL, 'U' }, { "verbose", no_argument, NULL, 'v' }, @@ -270,6 +272,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 5: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 6: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -341,6 +351,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ /* In update mode, --properties-input implies --properties-output. */ if (update_mode && input_syntax == syntax_properties) message_print_syntax_properties (); + /* In update mode, --stringtable-input implies --stringtable-output. */ + if (update_mode && input_syntax == syntax_stringtable) + message_print_syntax_stringtable (); /* Merge the two files. */ result = merge (argv[optind], argv[optind + 1], &def); @@ -482,6 +495,9 @@ Operation modifiers:\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input files are in NeXTstep/GNUstep .strings\n\ + syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -502,6 +518,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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/msgunfmt.c b/gettext-tools/src/msgunfmt.c index e6ce82468..61ff5cbf5 100644 --- a/gettext-tools/src/msgunfmt.c +++ b/gettext-tools/src/msgunfmt.c @@ -77,6 +77,7 @@ static const struct option long_options[] = { "resource", required_argument, NULL, 'r' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 3 }, { "tcl", no_argument, NULL, CHAR_MAX + 1 }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, @@ -203,6 +204,10 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 3: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); break; @@ -395,6 +400,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 6e7ff9ec6..26d82f383 100644 --- a/gettext-tools/src/msguniq.c +++ b/gettext-tools/src/msguniq.c @@ -70,6 +70,8 @@ static const struct option long_options[] = { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, + { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 }, { "to-code", required_argument, NULL, 't' }, { "unique", no_argument, NULL, 'u' }, { "use-first", no_argument, NULL, CHAR_MAX + 1 }, @@ -216,6 +218,14 @@ main (int argc, char **argv) message_page_width_ignore (); break; + case CHAR_MAX + 3: /* --stringtable-input */ + input_syntax = syntax_stringtable; + break; + + case CHAR_MAX + 4: /* --stringtable-output */ + message_print_syntax_stringtable (); + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -338,6 +348,8 @@ Message selection:\n")); Input file syntax:\n")); printf (_("\ -P, --properties-input input file is in Java .properties syntax\n")); + printf (_("\ + --stringtable-input input file is in NeXTstep/GNUstep .strings syntax\n")); printf ("\n"); printf (_("\ Output details:\n")); @@ -363,6 +375,8 @@ Output details:\n")); printf (_("\ -p, --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings 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 29624223f..cca925760 100644 --- a/gettext-tools/src/po-gram-gen.y +++ b/gettext-tools/src/po-gram-gen.y @@ -288,6 +288,6 @@ string_list comment : COMMENT { - po_callback_comment ($1.string); + po_callback_comment_dispatcher ($1.string); } ; diff --git a/gettext-tools/src/read-po-abstract.c b/gettext-tools/src/read-po-abstract.c index 1b02a1cb4..0aa1300f5 100644 --- a/gettext-tools/src/read-po-abstract.c +++ b/gettext-tools/src/read-po-abstract.c @@ -31,6 +31,7 @@ #include "po-gram.h" #include "po-hash.h" #include "read-properties.h" +#include "read-stringtable.h" #include "xalloc.h" #include "gettext.h" @@ -177,6 +178,11 @@ po_scan (abstract_po_reader_ty *pop, FILE *fp, properties_parse (pop, fp, real_filename, logical_filename); po_scan_end (pop); break; + case syntax_stringtable: + po_scan_start (pop); + stringtable_parse (pop, fp, real_filename, logical_filename); + po_scan_end (pop); + break; default: abort (); } @@ -219,6 +225,22 @@ po_callback_message (char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural, } +void +po_callback_comment (const char *s) +{ + /* assert(callback_arg); */ + call_comment (callback_arg, s); +} + + +void +po_callback_comment_dot (const char *s) +{ + /* assert(callback_arg); */ + call_comment_dot (callback_arg, s); +} + + /* This function is called by po_parse_comment_filepos(), once for each filename. */ void @@ -229,6 +251,14 @@ po_callback_comment_filepos (const char *name, size_t line) } +void +po_callback_comment_special (const char *s) +{ + /* assert(callback_arg); */ + call_comment_special (callback_arg, s); +} + + /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp. */ void po_parse_comment_special (const char *s, @@ -332,11 +362,10 @@ po_parse_comment_special (const char *s, call_comment_filepos (via po_parse_comment_filepos), or call_comment_special. */ void -po_callback_comment (const char *s) +po_callback_comment_dispatcher (const char *s) { - /* assert(callback_arg); */ if (*s == '.') - call_comment_dot (callback_arg, s + 1); + po_callback_comment_dot (s + 1); else if (*s == ':') { /* Parse the file location string. If the parse succeeds, the @@ -346,12 +375,12 @@ po_callback_comment (const char *s) if (po_parse_comment_filepos (s + 1) == 0) /* Do nothing, it is a GNU-style file pos line. */ ; else - call_comment (callback_arg, s + 1); + po_callback_comment (s + 1); } else if (*s == ',' || *s == '!') { /* Get all entries in the special comment line. */ - call_comment_special (callback_arg, s + 1); + po_callback_comment_special (s + 1); } else { @@ -365,6 +394,6 @@ po_callback_comment (const char *s) && po_parse_comment_filepos (s) == 0) /* Do nothing, it is a Sun-style file pos line. */ ; else - call_comment (callback_arg, s); + po_callback_comment (s); } } diff --git a/gettext-tools/src/read-po-abstract.h b/gettext-tools/src/read-po-abstract.h index 85b960f97..0c076f026 100644 --- a/gettext-tools/src/read-po-abstract.h +++ b/gettext-tools/src/read-po-abstract.h @@ -133,7 +133,8 @@ extern abstract_po_reader_ty * enum input_syntax_ty { syntax_po, - syntax_properties + syntax_properties, + syntax_stringtable }; typedef enum input_syntax_ty input_syntax_ty; @@ -161,6 +162,8 @@ extern void po_callback_message (char *msgid, lex_pos_ty *msgid_pos, 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); +extern void po_callback_comment_special (const char *s); +extern void po_callback_comment_dispatcher (const char *s); /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp. */ extern void po_parse_comment_special (const char *s, bool *fuzzyp, diff --git a/gettext-tools/src/read-po.c b/gettext-tools/src/read-po.c index e80635d6e..f8735aae6 100644 --- a/gettext-tools/src/read-po.c +++ b/gettext-tools/src/read-po.c @@ -450,8 +450,9 @@ 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. */ + if (input_syntax == syntax_properties || input_syntax == syntax_stringtable) + /* We know a priori that properties_parse() and stringtable_parse() + convert 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, diff --git a/gettext-tools/src/read-properties.c b/gettext-tools/src/read-properties.c index e95b787e6..eac198fb2 100644 --- a/gettext-tools/src/read-properties.c +++ b/gettext-tools/src/read-properties.c @@ -502,7 +502,7 @@ properties_parse (abstract_po_reader_ty *this, FILE *file, } buffer[buflen] = '\0'; - po_callback_comment (conv_from_java (conv_from_iso_8859_1 (buffer))); + po_callback_comment_dispatcher (conv_from_java (conv_from_iso_8859_1 (buffer))); } else { diff --git a/gettext-tools/src/read-stringtable.c b/gettext-tools/src/read-stringtable.c new file mode 100644 index 000000000..e938a727a --- /dev/null +++ b/gettext-tools/src/read-stringtable.c @@ -0,0 +1,967 @@ +/* Reading NeXTstep/GNUstep .strings files. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#endif + +/* Specification. */ +#include "read-stringtable.h" + +#include +#include +#include +#include +#include +#include + +#include "error.h" +#include "error-progname.h" +#include "read-po-abstract.h" +#include "po-hash.h" +#include "xalloc.h" +#include "exit.h" +#include "utf8-ucs4.h" +#include "ucs4-utf8.h" +#include "gettext.h" + +#define _(str) gettext (str) + +/* The format of NeXTstep/GNUstep .strings files is documented in + gnustep-base-1.8.0/Tools/make_strings/Using.txt + and in the comments of method propertyListFromStringsFileFormat in + gnustep-base-1.8.0/Source/NSString.m + In summary, it's a Objective-C like file with pseudo-assignments of the form + "key" = "value"; + where the key is the msgid and the value is the msgstr. + + The implementation of the parser of .strings files is in + gnustep-base-1.8.0/Source/NSString.m + function GSPropertyListFromStringsFormat + (indirectly called from NSBundle's method localizedStringForKey). + + A test case is in + gnustep-base-1.8.0/Testing/English.lproj/NXStringTable.example + */ + +/* Handling of comments: We copy all comments from the .strings 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 .strings 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 a byte. + Max. 4 pushback characters. */ + +static unsigned char phase1_pushback[4]; +static int phase1_pushback_length; + +static int +phase1_getc () +{ + int c; + + if (phase1_pushback_length) + return phase1_pushback[--phase1_pushback_length]; + + 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 void +phase1_ungetc (int c) +{ + if (c != EOF) + phase1_pushback[phase1_pushback_length++] = c; +} + + +/* Phase 2: Read an UCS-4 character. + Max. 2 pushback characters. */ + +/* End-of-file indicator for functions returning an UCS-4 character. */ +#define UEOF -1 + +static int phase2_pushback[4]; +static int phase2_pushback_length; + +/* The input file can be in Unicode encoding (UCS-2BE, UCS-2LE, UTF-8, each + with a BOM!), or otherwise the locale-dependent default encoding is used. + Since we don't want to depend on the locale here, we use ISO-8859-1 + instead. */ +enum enc +{ + enc_undetermined, + enc_ucs2be, + enc_ucs2le, + enc_utf8, + enc_iso8859_1 +}; +static enum enc encoding; + +static int +phase2_getc () +{ + if (phase2_pushback_length) + return phase2_pushback[--phase2_pushback_length]; + + if (encoding == enc_undetermined) + { + /* Determine the input file's encoding. */ + int c0, c1; + + c0 = phase1_getc (); + if (c0 == EOF) + return UEOF; + c1 = phase1_getc (); + if (c1 == EOF) + { + phase1_ungetc (c0); + encoding = enc_iso8859_1; + } + else if (c0 == 0xfe && c1 == 0xff) + encoding = enc_ucs2be; + else if (c0 == 0xff && c1 == 0xfe) + encoding = enc_ucs2le; + else + { + int c2; + + c2 = phase1_getc (); + if (c2 == EOF) + { + phase1_ungetc (c1); + phase1_ungetc (c0); + encoding = enc_iso8859_1; + } + else if (c0 == 0xef && c1 == 0xbb && c2 == 0xbf) + encoding = enc_utf8; + else + { + phase1_ungetc (c2); + phase1_ungetc (c1); + phase1_ungetc (c0); + encoding = enc_iso8859_1; + } + } + } + + switch (encoding) + { + case enc_ucs2be: + /* Read an UCS-2BE encoded character. */ + { + int c0, c1; + + c0 = phase1_getc (); + if (c0 == EOF) + return UEOF; + c1 = phase1_getc (); + if (c1 == EOF) + return UEOF; + return (c0 << 8) + c1; + } + + case enc_ucs2le: + /* Read an UCS-2LE encoded character. */ + { + int c0, c1; + + c0 = phase1_getc (); + if (c0 == EOF) + return UEOF; + c1 = phase1_getc (); + if (c1 == EOF) + return UEOF; + return c0 + (c1 << 8); + } + + case enc_utf8: + /* Read an UTF-8 encoded character. */ + { + unsigned char buf[6]; + unsigned int count; + int c; + unsigned int uc; + + c = phase1_getc (); + if (c == EOF) + return UEOF; + buf[0] = c; + count = 1; + + if (buf[0] >= 0xc0) + { + c = phase1_getc (); + if (c == EOF) + return UEOF; + buf[1] = c; + count = 2; + } + + if (buf[0] >= 0xe0 + && ((buf[1] ^ 0x80) < 0x40)) + { + c = phase1_getc (); + if (c == EOF) + return UEOF; + buf[2] = c; + count = 3; + } + + if (buf[0] >= 0xf0 + && ((buf[1] ^ 0x80) < 0x40) + && ((buf[2] ^ 0x80) < 0x40)) + { + c = phase1_getc (); + if (c == EOF) + return UEOF; + buf[3] = c; + count = 4; + } + + if (buf[0] >= 0xf8 + && ((buf[1] ^ 0x80) < 0x40) + && ((buf[2] ^ 0x80) < 0x40) + && ((buf[3] ^ 0x80) < 0x40)) + { + c = phase1_getc (); + if (c == EOF) + return UEOF; + buf[4] = c; + count = 5; + } + + if (buf[0] >= 0xfc + && ((buf[1] ^ 0x80) < 0x40) + && ((buf[2] ^ 0x80) < 0x40) + && ((buf[3] ^ 0x80) < 0x40) + && ((buf[4] ^ 0x80) < 0x40)) + { + c = phase1_getc (); + if (c == EOF) + return UEOF; + buf[5] = c; + count = 6; + } + + u8_mbtouc (&uc, buf, count); + return uc; + } + + case enc_iso8859_1: + /* Read an ISO-8859-1 encoded character. */ + { + int c = phase1_getc (); + + if (c == EOF) + return UEOF; + return c; + } + + default: + abort (); + } +} + +static void +phase2_ungetc (int c) +{ + if (c != UEOF) + phase2_pushback[phase2_pushback_length++] = c; +} + + +/* Phase 3: Read an UCS-4 character, with line number handling. */ + +static int +phase3_getc () +{ + int c = phase2_getc (); + + if (c == '\n') + gram_pos.line_number++; + + return c; +} + +static void +phase3_ungetc (int c) +{ + if (c == '\n') + --gram_pos.line_number; + phase2_ungetc (c); +} + + +/* Convert from UCS-4 to UTF-8. */ +static char * +conv_from_ucs4 (const int *buffer, size_t buflen) +{ + unsigned char *utf8_string; + size_t pos; + unsigned char *q; + + /* Each UCS-4 word needs 6 bytes at worst. */ + utf8_string = (unsigned char *) xmalloc (6 * buflen + 1); + + for (pos = 0, q = utf8_string; pos < buflen; ) + { + unsigned int uc; + int n; + + uc = buffer[pos++]; + n = u8_uctomb (q, uc, 6); + assert (n > 0); + q += n; + } + *q = '\0'; + assert (q - utf8_string <= 6 * buflen); + + return (char *) utf8_string; +} + + +/* Parse a string enclosed in double-quotes. Input is UCS-4 encoded. + Return the string in UTF-8 encoding, or NULL if the input doesn't represent + a valid string enclosed in double-quotes. */ +static char * +parse_escaped_string (const int *string, size_t length) +{ + static int *buffer; + static size_t bufmax; + static size_t buflen; + const int *string_limit = string + length; + int c; + + if (string == string_limit) + return NULL; + c = *string++; + if (c != '"') + return NULL; + buflen = 0; + for (;;) + { + if (string == string_limit) + return NULL; + c = *string++; + if (c == '"') + break; + if (c == '\\') + { + if (string == string_limit) + return NULL; + c = *string++; + if (c >= '0' && c <= '7') + { + unsigned int n = 0; + int j = 0; + for (;;) + { + n = n * 8 + (c - '0'); + if (++j == 3) + break; + if (string == string_limit) + break; + c = *string; + if (!(c >= '0' && c <= '7')) + break; + string++; + } + c = n; + } + else if (c == 'u' || c == 'U') + { + unsigned int n = 0; + int j; + for (j = 0; j < 4; j++) + { + if (string == string_limit) + break; + c = *string; + if (c >= '0' && c <= '9') + n = n * 16 + (c - '0'); + else if (c >= 'A' && c <= 'F') + n = n * 16 + (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + n = n * 16 + (c - 'a' + 10); + else + break; + string++; + } + c = n; + } + else + switch (c) + { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 't': c = '\t'; break; + case 'r': c = '\r'; break; + case 'n': c = '\n'; break; + case 'v': c = '\v'; break; + case 'f': c = '\f'; break; + } + } + if (buflen >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax * sizeof (int)); + } + buffer[buflen++] = c; + } + + return conv_from_ucs4 (buffer, buflen); +} + + +/* Accumulating flag comments. */ + +static char *special_comment; + +static inline void +special_comment_reset () +{ + if (special_comment != NULL) + free (special_comment); + special_comment = NULL; +} + +static void +special_comment_add (const char *flag) +{ + if (special_comment == NULL) + special_comment = xstrdup (flag); + else + { + size_t total_len = strlen (special_comment) + 2 + strlen (flag) + 1; + special_comment = xrealloc (special_comment, total_len); + strcat (special_comment, ", "); + strcat (special_comment, flag); + } +} + +static inline void +special_comment_finish () +{ + if (special_comment != NULL) + { + po_callback_comment_special (special_comment); + free (special_comment); + special_comment = NULL; + } +} + + +/* Accumulating comments. */ + +static int *buffer; +static size_t bufmax; +static size_t buflen; +static bool next_is_obsolete; +static bool next_is_fuzzy; +static char *fuzzy_msgstr; +static bool expect_fuzzy_msgstr_as_c_comment; +static bool expect_fuzzy_msgstr_as_cxx_comment; + +static inline void +comment_start () +{ + buflen = 0; +} + +static inline void +comment_add (int c) +{ + if (buflen >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax * sizeof (int)); + } + buffer[buflen++] = c; +} + +static inline void +comment_line_end (size_t chars_to_remove, bool test_for_fuzzy_msgstr) +{ + char *line; + + buflen -= chars_to_remove; + /* Drop trailing white space, but not EOLs. */ + while (buflen >= 1 + && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t')) + --buflen; + + /* At special positions we interpret a comment of the form + = "escaped string" + with an optional trailing semicolon as being the fuzzy msgstr, not a + regular comment. */ + if (test_for_fuzzy_msgstr + && buflen > 2 && buffer[0] == '=' && buffer[1] == ' ' + && (fuzzy_msgstr = + parse_escaped_string (buffer + 2, + buflen - (buffer[buflen - 1] == ';') - 2))) + return; + + line = conv_from_ucs4 (buffer, buflen); + + if (strcmp (line, "Flag: untranslated") == 0) + { + special_comment_add ("fuzzy"); + next_is_fuzzy = true; + } + else if (strcmp (line, "Flag: unmatched") == 0) + next_is_obsolete = true; + else if (strlen (line) >= 6 && memcmp (line, "Flag: ", 6) == 0) + special_comment_add (line + 6); + else if (strlen (line) >= 9 && memcmp (line, "Comment: ", 9) == 0) + /* A comment extracted from the source. */ + po_callback_comment_dot (line + 9); + else + { + char *last_colon; + unsigned long number; + char *endp; + + if (strlen (line) >= 6 && memcmp (line, "File: ", 6) == 0 + && (last_colon = strrchr (line + 6, ':')) != NULL + && *(last_colon + 1) != '\0' + && (number = strtoul (last_colon + 1, &endp, 10), *endp == '\0')) + { + /* A "File: :" type comment. */ + *last_colon = '\0'; + po_callback_comment_filepos (line + 6, number); + } + else + po_callback_comment (line); + } +} + + +/* Phase 4: Replace each comment that is not inside a string with a space + character. */ + +static int +phase4_getc () +{ + int c; + + c = phase3_getc (); + if (c != '/') + return c; + c = phase3_getc (); + switch (c) + { + default: + phase3_ungetc (c); + return '/'; + + case '*': + /* C style comment. */ + { + bool last_was_star; + size_t trailing_stars; + bool seen_newline; + + comment_start (); + last_was_star = false; + trailing_stars = 0; + seen_newline = false; + /* Drop additional stars at the beginning of the comment. */ + for (;;) + { + c = phase3_getc (); + if (c != '*') + break; + last_was_star = true; + } + phase3_ungetc (c); + for (;;) + { + c = phase3_getc (); + if (c == UEOF) + break; + /* We skip all leading white space, but not EOLs. */ + if (!(buflen == 0 && (c == ' ' || c == '\t'))) + comment_add (c); + switch (c) + { + case '\n': + seen_newline = true; + comment_line_end (1, false); + comment_start (); + last_was_star = false; + trailing_stars = 0; + continue; + + case '*': + last_was_star = true; + trailing_stars++; + continue; + + case '/': + if (last_was_star) + { + /* Drop additional stars at the end of the comment. */ + comment_line_end (trailing_stars + 1, + expect_fuzzy_msgstr_as_c_comment + && !seen_newline); + break; + } + /* FALLTHROUGH */ + + default: + last_was_star = false; + trailing_stars = 0; + continue; + } + break; + } + return ' '; + } + + case '/': + /* C++ style comment. */ + comment_start (); + for (;;) + { + c = phase3_getc (); + if (c == '\n' || c == UEOF) + break; + /* We skip all leading white space, but not EOLs. */ + if (!(buflen == 0 && (c == ' ' || c == '\t'))) + comment_add (c); + } + comment_line_end (0, expect_fuzzy_msgstr_as_cxx_comment); + return '\n'; + } +} + +static inline void +phase4_ungetc (int c) +{ + phase3_ungetc (c); +} + + +/* Return true if a character is considered as whitespace. */ +static bool +is_whitespace (int c) +{ + return (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' + || c == '\b'); +} + +/* Return true if a character needs quoting, i.e. cannot be used in unquoted + tokens. */ +static bool +is_quotable (int c) +{ + if ((c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) + return false; + switch (c) + { + case '!': case '#': case '$': case '%': case '&': case '*': + case '+': case '-': case '.': case '/': case ':': case '?': + case '@': case '|': case '~': case '_': case '^': + return false; + default: + return true; + } +} + + +/* Read a key or value string. + Return the string in UTF-8 encoding, or NULL if no string is seen. + Return the start position of the string in *pos. */ +static char * +read_string (lex_pos_ty *pos) +{ + static int *buffer; + static size_t bufmax; + static size_t buflen; + int c; + + /* Skip whitespace before the string. */ + do + c = phase4_getc (); + while (is_whitespace (c)); + + if (c == UEOF) + /* No more string. */ + return NULL; + + *pos = gram_pos; + buflen = 0; + if (c == '"') + { + /* Read a string enclosed in double-quotes. */ + for (;;) + { + c = phase3_getc (); + if (c == UEOF || c == '"') + break; + if (c == '\\') + { + c = phase3_getc (); + if (c == UEOF) + break; + if (c >= '0' && c <= '7') + { + unsigned int n = 0; + int j = 0; + for (;;) + { + n = n * 8 + (c - '0'); + if (++j == 3) + break; + c = phase3_getc (); + if (!(c >= '0' && c <= '7')) + { + phase3_ungetc (c); + break; + } + } + c = n; + } + else if (c == 'u' || c == 'U') + { + unsigned int n = 0; + int j; + for (j = 0; j < 4; j++) + { + c = phase3_getc (); + if (c >= '0' && c <= '9') + n = n * 16 + (c - '0'); + else if (c >= 'A' && c <= 'F') + n = n * 16 + (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + n = n * 16 + (c - 'a' + 10); + else + { + phase3_ungetc (c); + break; + } + } + c = n; + } + else + switch (c) + { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 't': c = '\t'; break; + case 'r': c = '\r'; break; + case 'n': c = '\n'; break; + case 'v': c = '\v'; break; + case 'f': c = '\f'; break; + } + } + if (buflen >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax * sizeof (int)); + } + buffer[buflen++] = c; + } + if (c == UEOF) + { + error_with_progname = false; + error (0, 0, _("%s:%d: warning: unterminated string"), + real_file_name, gram_pos.line_number); + error_with_progname = true; + } + } + else + { + /* Read a token outside quotes. */ + if (is_quotable (c)) + { + error_with_progname = false; + error (0, 0, _("%s:%d: warning: syntax error"), + real_file_name, gram_pos.line_number); + error_with_progname = true; + } + for (; c != UEOF && !is_quotable (c); c = phase4_getc ()) + { + if (buflen >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax * sizeof (int)); + } + buffer[buflen++] = c; + } + } + + return conv_from_ucs4 (buffer, buflen); +} + + +/* Read a .strings file from a stream, and dispatch to the various + abstract_po_reader_class_ty methods. */ +void +stringtable_parse (abstract_po_reader_ty *pop, 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; + encoding = enc_undetermined; + expect_fuzzy_msgstr_as_c_comment = false; + expect_fuzzy_msgstr_as_cxx_comment = false; + + for (;;) + { + char *msgid; + lex_pos_ty msgid_pos; + char *msgstr; + lex_pos_ty msgstr_pos; + int c; + + /* Prepare for next msgid/msgstr pair. */ + special_comment_reset (); + next_is_obsolete = false; + next_is_fuzzy = false; + fuzzy_msgstr = NULL; + + /* Read the key and all the comments preceding it. */ + msgid = read_string (&msgid_pos); + if (msgid == NULL) + break; + + special_comment_finish (); + + /* Skip whitespace. */ + do + c = phase4_getc (); + while (is_whitespace (c)); + + /* Expect a '=' or ';'. */ + if (c == UEOF) + { + error_with_progname = false; + error (0, 0, _("%s:%d: warning: unterminated key/value pair"), + real_file_name, gram_pos.line_number); + error_with_progname = true; + break; + } + if (c == ';') + { + /* "key"; is an abbreviation for "key"=""; and does not + necessarily designate an untranslated entry. */ + msgstr = ""; + msgstr_pos = msgid_pos; + po_callback_message (msgid, &msgid_pos, NULL, + msgstr, strlen (msgstr) + 1, &msgstr_pos, + false, next_is_obsolete); + } + else if (c == '=') + { + /* Read the value. */ + msgstr = read_string (&msgstr_pos); + if (msgstr == NULL) + { + error_with_progname = false; + error (0, 0, _("%s:%d: warning: unterminated key/value pair"), + real_file_name, gram_pos.line_number); + error_with_progname = true; + break; + } + + /* Skip whitespace. But for fuzzy key/value pairs, look for the + tentative msgstr in the form of a C style comment. */ + expect_fuzzy_msgstr_as_c_comment = next_is_fuzzy; + do + { + c = phase4_getc (); + if (fuzzy_msgstr != NULL) + expect_fuzzy_msgstr_as_c_comment = false; + } + while (is_whitespace (c)); + expect_fuzzy_msgstr_as_c_comment = false; + + /* Expect a ';'. */ + if (c == ';') + { + /* But for fuzzy key/value pairs, look for the tentative msgstr + in the form of a C++ style comment. */ + if (fuzzy_msgstr == NULL && next_is_fuzzy) + { + do + c = phase3_getc (); + while (c == ' '); + phase3_ungetc (c); + + expect_fuzzy_msgstr_as_cxx_comment = true; + c = phase4_getc (); + phase4_ungetc (c); + expect_fuzzy_msgstr_as_cxx_comment = false; + } + if (fuzzy_msgstr != NULL && strcmp (msgstr, msgid) == 0) + msgstr = fuzzy_msgstr; + + /* A key/value pair. */ + po_callback_message (msgid, &msgid_pos, NULL, + msgstr, strlen (msgstr) + 1, &msgstr_pos, + false, next_is_obsolete); + } + else + { + error_with_progname = false; + error (0, 0, _("\ +%s:%d: warning: syntax error, expected ';' after string"), + real_file_name, gram_pos.line_number); + error_with_progname = true; + break; + } + } + else + { + error_with_progname = false; + error (0, 0, _("\ +%s:%d: warning: syntax error, expected '=' or ';' after string"), + real_file_name, gram_pos.line_number); + error_with_progname = true; + break; + } + } + + fp = NULL; + real_file_name = NULL; + gram_pos.line_number = 0; +} diff --git a/gettext-tools/src/read-stringtable.h b/gettext-tools/src/read-stringtable.h new file mode 100644 index 000000000..3f3d9ad2e --- /dev/null +++ b/gettext-tools/src/read-stringtable.h @@ -0,0 +1,30 @@ +/* Reading NeXTstep/GNUstep .strings files. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 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_STRINGTABLE_H +#define _READ_STRINGTABLE_H + +#include "read-po-abstract.h" + +/* Read a .strings file from a stream, and dispatch to the various + abstract_po_reader_class_ty methods. */ +extern void stringtable_parse (abstract_po_reader_ty *pop, FILE *fp, + const char *real_filename, + const char *logical_filename); + +#endif /* _READ_STRINGTABLE_H */ diff --git a/gettext-tools/src/write-po.c b/gettext-tools/src/write-po.c index 90782683a..68c02cd01 100644 --- a/gettext-tools/src/write-po.c +++ b/gettext-tools/src/write-po.c @@ -40,6 +40,7 @@ #include "linebreak.h" #include "msgl-ascii.h" #include "write-properties.h" +#include "write-stringtable.h" #include "xalloc.h" #include "strstr.h" #include "fwriteerror.h" @@ -64,7 +65,7 @@ /* Convert IS_FORMAT in the context of programming language LANG to a flag string for use in #, flags. */ -static const char * +const char * make_format_description_string (enum is_format is_format, const char *lang, bool debug) { @@ -97,7 +98,7 @@ make_format_description_string (enum is_format is_format, const char *lang, /* Return true if IS_FORMAT is worth mentioning in a #, flags list. */ -static bool +bool significant_format_p (enum is_format is_format) { return is_format != undecided && is_format != impossible; @@ -387,6 +388,16 @@ message_print_syntax_properties () } +/* Whether to output a file in NeXTstep/GNUstep .strings syntax. */ +static bool use_syntax_stringtable = false; + +void +message_print_syntax_stringtable () +{ + use_syntax_stringtable = true; +} + + /* ================ msgdomain_list_print() and subroutines. ================ */ @@ -1038,10 +1049,15 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename, } /* Check whether the output format can accomodate all messages. */ - if (use_syntax_properties) + if (use_syntax_properties || use_syntax_stringtable) { 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 (use_syntax_properties) + error (EXIT_FAILURE, 0, _("Cannot output multiple translation domains into a single file with Java .properties syntax. Try using PO file syntax instead.")); + if (use_syntax_stringtable) + error (EXIT_FAILURE, 0, _("Cannot output multiple translation domains into a single file with NeXTstep/GNUstep .strings syntax.")); + } if (mdlp->nitems == 1) { message_list_ty *mlp = mdlp->item[0]->messages; @@ -1063,9 +1079,14 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename, 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.")); + if (use_syntax_properties) + 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.")); + if (use_syntax_stringtable) + 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.")); error_with_progname = true; } } @@ -1089,6 +1110,8 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename, if (use_syntax_properties) msgdomain_list_print_properties (mdlp, fp, page_width, debug); + else if (use_syntax_stringtable) + msgdomain_list_print_stringtable (mdlp, fp, page_width, debug); else msgdomain_list_print_po (mdlp, fp, debug); diff --git a/gettext-tools/src/write-po.h b/gettext-tools/src/write-po.h index 5cbe3199a..3d7ac9052 100644 --- a/gettext-tools/src/write-po.h +++ b/gettext-tools/src/write-po.h @@ -31,6 +31,14 @@ extern "C" { #endif +/* These functions are used to output a #, flags line. */ +extern const char * + make_format_description_string (enum is_format is_format, + const char *lang, bool debug); +extern bool + significant_format_p (enum is_format is_format); + + /* These functions output parts of a message, as comments. */ extern void message_print_comment (const message_ty *mp, FILE *fp); @@ -56,6 +64,8 @@ extern void message_print_style_escape (bool flag); extern void message_print_syntax_properties (void); +extern void + message_print_syntax_stringtable (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-stringtable.c b/gettext-tools/src/write-stringtable.c new file mode 100644 index 000000000..f99d2d1eb --- /dev/null +++ b/gettext-tools/src/write-stringtable.c @@ -0,0 +1,311 @@ +/* Writing NeXTstep/GNUstep .strings files. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 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 +#endif + +/* Specification. */ +#include "write-stringtable.h" + +#include +#include +#include +#include + +#include "message.h" +#include "msgl-ascii.h" +#include "msgl-iconv.h" +#include "po-charset.h" +#include "strstr.h" +#include "write-po.h" + +/* The format of NeXTstep/GNUstep .strings files is documented in + gnustep-base-1.8.0/Tools/make_strings/Using.txt + and in the comments of method propertyListFromStringsFileFormat in + gnustep-base-1.8.0/Source/NSString.m + In summary, it's a Objective-C like file with pseudo-assignments of the form + "key" = "value"; + where the key is the msgid and the value is the msgstr. + */ + +/* Handling of comments: We copy all comments from the PO file to the + .strings file. This is not really needed; it's a service for translators + who don't like PO files and prefer to maintain the .strings file. */ + +/* Since the interpretation of text files in GNUstep depends on the locale's + encoding if they don't have a BOM, we choose one of three encodings with + a BOM: UCS-2BE, UCS-2LE, UTF-8. Since the first two of these don't cope + with all of Unicode and we don't know whether GNUstep will switch to + UTF-16 instead of UCS-2, we use UTF-8 with BOM. BOMs are bad because they + get in the way when concatenating files, but here we have no choice. */ + +/* Writes a key or value to the file, without newline. */ +static void +write_escaped_string (FILE *fp, const char *str) +{ + const char *str_limit = str + strlen (str); + + putc ('"', fp); + while (str < str_limit) + { + unsigned char c = (unsigned char) *str++; + + if (c == '\t') + { + putc ('\\', fp); + putc ('t', fp); + } + else if (c == '\n') + { + putc ('\\', fp); + putc ('n', fp); + } + else if (c == '\r') + { + putc ('\\', fp); + putc ('r', fp); + } + else if (c == '\f') + { + putc ('\\', fp); + putc ('f', fp); + } + else if (c == '\\' || c == '"') + { + putc ('\\', fp); + putc (c, fp); + } + else + putc (c, fp); + } + putc ('"', fp); +} + +/* 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. */ + if (mp->comment != NULL) + { + size_t j; + + for (j = 0; j < mp->comment->nitems; ++j) + { + const char *s = mp->comment->item[j]; + + /* Test whether it is safe to output the comment in C style, or + whether we need C++ style for it. */ + if (strstr (s, "*/") == NULL) + { + fputs ("/*", fp); + if (*s != '\0' && *s != '\n' && *s != ' ') + putc (' ', fp); + fputs (s, fp); + fputs (" */\n", fp); + } + else + do + { + const char *e; + fputs ("//", fp); + if (*s != '\0' && *s != '\n' && *s != ' ') + putc (' ', fp); + e = strchr (s, '\n'); + if (e == NULL) + { + fputs (s, fp); + s = NULL; + } + else + { + fwrite (s, 1, e - s, fp); + s = e + 1; + } + putc ('\n', fp); + } + while (s != NULL); + } + } + + /* Print xgettext extracted comments. */ + if (mp->comment_dot != NULL) + { + size_t j; + + for (j = 0; j < mp->comment_dot->nitems; ++j) + { + const char *s = mp->comment_dot->item[j]; + + /* Test whether it is safe to output the comment in C style, or + whether we need C++ style for it. */ + if (strstr (s, "*/") == NULL) + { + fputs ("/* Comment: ", fp); + fputs (s, fp); + fputs (" */\n", fp); + } + else + { + bool first = true; + do + { + const char *e; + fputs ("//", fp); + if (first || (*s != '\0' && *s != '\n' && *s != ' ')) + putc (' ', fp); + if (first) + fputs ("Comment: ", fp); + e = strchr (s, '\n'); + if (e == NULL) + { + fputs (s, fp); + s = NULL; + } + else + { + fwrite (s, 1, e - s, fp); + s = e + 1; + } + putc ('\n', fp); + first = false; + } + while (s != NULL); + } + } + } + + /* Print the file position comments. */ + if (mp->filepos_count != 0) + { + size_t j; + + for (j = 0; j < mp->filepos_count; ++j) + { + lex_pos_ty *pp = &mp->filepos[j]; + char *cp = pp->file_name; + while (cp[0] == '.' && cp[1] == '/') + cp += 2; + fprintf (fp, "/* File: %s:%ld */\n", cp, (long) pp->line_number); + } + } + + /* Print flag information in special comment. */ + if (mp->is_fuzzy || mp->msgstr[0] == '\0') + fputs ("/* Flag: untranslated */\n", fp); + if (mp->obsolete) + fputs ("/* Flag: unmatched */\n", fp); + { + size_t i; + for (i = 0; i < NFORMATS; i++) + if (significant_format_p (mp->is_format[i])) + { + fputs ("/* Flag:", fp); + fputs (make_format_description_string (mp->is_format[i], + format_language[i], debug), + fp); + fputs (" */\n", fp); + } + } + + /* Now write the untranslated string and the translated string. */ + write_escaped_string (fp, mp->msgid); + fputs (" = ", fp); + if (mp->msgstr[0] != '\0') + { + if (mp->is_fuzzy) + { + /* Output the msgid as value, so that at runtime the untranslated + string is returned. */ + write_escaped_string (fp, mp->msgid); + + /* Output the msgstr as a comment, so that at runtime + propertyListFromStringsFileFormat ignores it. */ + if (strstr (mp->msgstr, "*/") == NULL) + { + fputs (" /* = ", fp); + write_escaped_string (fp, mp->msgstr); + fputs (" */", fp); + } + else + { + fputs ("; // = ", fp); + write_escaped_string (fp, mp->msgstr); + } + } + else + write_escaped_string (fp, mp->msgstr); + } + else + { + /* Output the msgid as value, so that at runtime the untranslated + string is returned. */ + write_escaped_string (fp, mp->msgid); + } + putc (';', fp); + + putc ('\n', fp); +} + +/* Writes an entire message list to the file. */ +static void +write_stringtable (FILE *fp, message_list_ty *mlp, const char *canon_encoding, + size_t page_width, bool debug) +{ + bool blank_line; + size_t j; + + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + + /* Output the BOM. */ + if (!is_ascii_message_list (mlp)) + fputs ("\xef\xbb\xbf", fp); + + /* 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) + { + if (blank_line) + putc ('\n', fp); + + write_message (fp, mp, page_width, debug); + + blank_line = true; + } + } +} + +/* Output the contents of a PO file in .strings syntax. */ +void +msgdomain_list_print_stringtable (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_stringtable (fp, mlp, mdlp->encoding, page_width, debug); +} diff --git a/gettext-tools/src/write-stringtable.h b/gettext-tools/src/write-stringtable.h new file mode 100644 index 000000000..6b2787c30 --- /dev/null +++ b/gettext-tools/src/write-stringtable.h @@ -0,0 +1,33 @@ +/* Writing NeXTstep/GNUstep .strings files. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 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_STRINGTABLE_H +#define _WRITE_STRINGTABLE_H + +#include +#include +#include + +#include "message.h" + +/* Output the contents of a PO file in .strings syntax. */ +extern void + msgdomain_list_print_stringtable (msgdomain_list_ty *mdlp, FILE *fp, + size_t page_width, bool debug); + +#endif /* _WRITE_STRINGTABLE_H */ diff --git a/gettext-tools/src/x-po.c b/gettext-tools/src/x-po.c index 594531550..89580b798 100644 --- a/gettext-tools/src/x-po.c +++ b/gettext-tools/src/x-po.c @@ -30,6 +30,7 @@ #include "xgettext.h" #include "x-po.h" #include "x-properties.h" +#include "x-stringtable.h" #include "xalloc.h" #include "read-po.h" #include "po-lex.h" @@ -139,3 +140,13 @@ extract_properties (FILE *fp, { extract (fp, real_filename, logical_filename, syntax_properties, mdlp); } + + +void +extract_stringtable (FILE *fp, + const char *real_filename, const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp) +{ + extract (fp, real_filename, logical_filename, syntax_stringtable, mdlp); +} diff --git a/gettext-tools/src/x-stringtable.h b/gettext-tools/src/x-stringtable.h new file mode 100644 index 000000000..8e9b81f9b --- /dev/null +++ b/gettext-tools/src/x-stringtable.h @@ -0,0 +1,30 @@ +/* xgettext NXStringTable backend. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 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_STRINGTABLE \ + { "strings", "NXStringTable" }, \ + +#define SCANNERS_STRINGTABLE \ + { "NXStringTable", extract_stringtable, NULL, NULL, NULL }, \ + +/* Scan a JavaProperties file and add its translatable strings to mdlp. */ +extern void extract_stringtable (FILE *fp, const char *real_filename, + const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp); diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c index 0ab44b959..c10b3ead4 100644 --- a/gettext-tools/src/xgettext.c +++ b/gettext-tools/src/xgettext.c @@ -84,6 +84,7 @@ extern "C" { #include "x-tcl.h" #include "x-perl.h" #include "x-php.h" +#include "x-stringtable.h" #include "x-rst.h" #include "x-glade.h" @@ -126,7 +127,7 @@ static const char *msgstr_suffix; /* Directory in which output files are created. */ static char *output_dir; -/* The output syntax: .pot or .properties. */ +/* The output syntax: .pot or .properties or .strings. */ static input_syntax_ty output_syntax = syntax_po; /* If nonzero omit header with information about this run. */ @@ -179,7 +180,7 @@ static const struct option long_options[] = { "exclude-file", required_argument, NULL, 'x' }, { "extract-all", no_argument, NULL, 'a' }, { "files-from", required_argument, NULL, 'f' }, - { "flag", required_argument, NULL, CHAR_MAX + 7 }, + { "flag", required_argument, NULL, CHAR_MAX + 8 }, { "force-po", no_argument, &force_po, 1 }, { "foreign-user", no_argument, NULL, CHAR_MAX + 2 }, { "from-code", required_argument, NULL, CHAR_MAX + 3 }, @@ -202,6 +203,7 @@ static const struct option long_options[] = { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, { "string-limit", required_argument, NULL, 'l' }, + { "stringtable-output", no_argument, NULL, CHAR_MAX + 7 }, { "trigraphs", no_argument, NULL, 'T' }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w', }, @@ -453,7 +455,11 @@ main (int argc, char *argv[]) message_print_syntax_properties (); output_syntax = syntax_properties; break; - case CHAR_MAX + 7: /* --flag */ + case CHAR_MAX + 7: /* --stringtable-output */ + message_print_syntax_stringtable (); + output_syntax = syntax_stringtable; + break; + case CHAR_MAX + 8: /* --flag */ xgettext_record_flag (optarg); break; default: @@ -721,7 +727,7 @@ Choice of input file language:\n")); (C, C++, ObjectiveC, PO, Shell, Python, Lisp,\n\ EmacsLisp, librep, Smalltalk, Java,\n\ JavaProperties, awk, YCP, Tcl, Perl, PHP,\n\ - GCC-source, RST, Glade)\n")); + GCC-source, NXStringTable, RST, Glade)\n")); printf (_("\ -C, --c++ shorthand for --language=C++\n")); printf (_("\ @@ -793,6 +799,8 @@ Output details:\n")); printf (_("\ --properties-output write out a Java .properties file\n")); printf (_("\ + --stringtable-output write out a NeXTstep/GNUstep .strings file\n")); + printf (_("\ -w, --width=NUMBER set output page width\n")); printf (_("\ --no-wrap do not break long message lines, longer than\n\ @@ -1994,7 +2002,9 @@ finalize_header (msgdomain_list_ty *mdlp) has_nonascii = true; } - if (has_nonascii || output_syntax == syntax_properties) + if (has_nonascii + || output_syntax == syntax_properties + || output_syntax == syntax_stringtable) { message_list_ty *mlp = mdlp->item[0]->messages; @@ -2038,6 +2048,7 @@ language_to_extractor (const char *name) SCANNERS_TCL SCANNERS_PERL SCANNERS_PHP + SCANNERS_STRINGTABLE SCANNERS_RST SCANNERS_GLADE /* Here will follow more languages and their scanners: pike, C#, etc... @@ -2095,6 +2106,7 @@ extension_to_language (const char *extension) EXTENSIONS_TCL EXTENSIONS_PERL EXTENSIONS_PHP + EXTENSIONS_STRINGTABLE EXTENSIONS_RST EXTENSIONS_GLADE /* Here will follow more file extensions: cs ... */ diff --git a/gettext-tools/tests/ChangeLog b/gettext-tools/tests/ChangeLog index 2d66349e2..a093c2762 100644 --- a/gettext-tools/tests/ChangeLog +++ b/gettext-tools/tests/ChangeLog @@ -1,3 +1,9 @@ +2003-10-12 Bruno Haible + + * msgcat-13: New file. + * xgettext-33: New file. + * Makefile.am (TESTS): Add them. + 2003-10-12 Bruno Haible * xgettext-32: New file. diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index f960b9a80..0fdb2897c 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -25,7 +25,7 @@ TESTS = gettext-1 gettext-2 \ msgattrib-6 msgattrib-7 msgattrib-8 msgattrib-9 msgattrib-10 \ msgattrib-11 msgattrib-12 msgattrib-13 msgattrib-14 msgattrib-15 \ msgcat-1 msgcat-2 msgcat-3 msgcat-4 msgcat-5 msgcat-6 msgcat-7 \ - msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 \ + msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 msgcat-13 \ msgcmp-1 msgcmp-2 msgcmp-3 \ msgcomm-1 msgcomm-2 msgcomm-3 msgcomm-4 msgcomm-5 msgcomm-6 msgcomm-7 \ msgcomm-8 msgcomm-9 msgcomm-10 msgcomm-11 msgcomm-12 msgcomm-13 \ @@ -51,6 +51,7 @@ TESTS = gettext-1 gettext-2 \ xgettext-18 xgettext-19 xgettext-20 xgettext-21 xgettext-22 \ xgettext-23 xgettext-24 xgettext-25 xgettext-26 xgettext-27 \ xgettext-28 xgettext-29 xgettext-30 xgettext-31 xgettext-32 \ + xgettext-33 \ format-awk-1 format-awk-2 \ format-c-1 format-c-2 format-c-3 format-c-4 \ format-elisp-1 format-elisp-2 \ diff --git a/gettext-tools/tests/msgcat-13 b/gettext-tools/tests/msgcat-13 new file mode 100755 index 000000000..9938540f1 --- /dev/null +++ b/gettext-tools/tests/msgcat-13 @@ -0,0 +1,69 @@ +#! /bin/sh + +# Test reading in NeXTstep/GNUstep .strings syntax. + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="$tmpfiles mcat-test13.in" +cat <<\EOF > mcat-test13.in +/* This is an example of a string table file. Everything inside a comment +is completely ignored, even if in "quotes", or \escape characters, etc. +*/ + +"title" = "pattern II target 1"; + +/* This is an example of excape codes in the string table, codes */ +/* that are not one of abfnrtv are stripped of the \ character */ +"escapes" = "This is a tab \t and a return \n or a \a but not a \p"; +"escapes2" = "Well how about a \0? Guess not."; + +/* more parameters, white space between tokens is ignored */ +"actualSize" + = + "0.000250 0.000250"; + +/* a key with no value assumes the value is the same as the key */ +"hoe322070.element"; +EOF + +tmpfiles="$tmpfiles mcat-test13.out" +rm -f mcat-test13.out +: ${MSGCAT=msgcat} +${MSGCAT} --stringtable-input mcat-test13.in -o mcat-test13.out +test $? = 0 || { rm -fr $tmpfiles; exit 1; } + +tmpfiles="$tmpfiles mcat-test13.ok" +cat << \EOF > mcat-test13.ok +# This is an example of a string table file. Everything inside a comment +# is completely ignored, even if in "quotes", or \escape characters, etc. +# +msgid "title" +msgstr "pattern II target 1" + +# This is an example of excape codes in the string table, codes +# that are not one of abfnrtv are stripped of the \ character +msgid "escapes" +msgstr "" +"This is a tab \t and a return \n" +" or a  but not a p" + +msgid "escapes2" +msgstr "Well how about a " + +# more parameters, white space between tokens is ignored +msgid "actualSize" +msgstr "0.000250 0.000250" + +# a key with no value assumes the value is the same as the key +msgid "hoe322070.element" +msgstr "hoe322070.element" +EOF + +: ${DIFF=diff} +${DIFF} mcat-test13.ok mcat-test13.out +result=$? + +rm -fr $tmpfiles + +exit $result diff --git a/gettext-tools/tests/xgettext-33 b/gettext-tools/tests/xgettext-33 new file mode 100755 index 000000000..a4f17f9b4 --- /dev/null +++ b/gettext-tools/tests/xgettext-33 @@ -0,0 +1,72 @@ +#! /bin/sh + +# Test extractor of NeXTstep/GNUstep .strings files. + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="$tmpfiles xg-test33.strings" +cat <<\EOF > xg-test33.strings +/*** +German.lproj/Localizable.strings +updated by make_strings 2003-10-12 15:31:50 +0200 +add comments above this one +***/ + + +/*** Strings from Hello.m ***/ +/* File: Hello.m:57 */ +/* File: Hello.m:56 */ +"Hello, world!" = "Hallo Welt!"; +/* File: Hello.m:67 */ +"This program is running as process number %d." += "Dieses Programm läuft mit der Prozess-Nummer %d."; +EOF + +tmpfiles="$tmpfiles xg-test33.tmp xg-test33.po" +: ${XGETTEXT=xgettext} +${XGETTEXT} xg-test33.strings -o xg-test33.tmp +test $? = 0 || { rm -fr $tmpfiles; exit 1; } +grep -v 'POT-Creation-Date' < xg-test33.tmp > xg-test33.po + +tmpfiles="$tmpfiles xg-test33.ok" +cat <<\EOF > xg-test33.ok +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +# +# German.lproj/Localizable.strings +# updated by make_strings 2003-10-12 15:31:50 +0200 +# add comments above this one +# +# Strings from Hello.m +#: Hello.m:57 Hello.m:56 +msgid "Hello, world!" +msgstr "Hallo Welt!" + +#: Hello.m:67 +msgid "This program is running as process number %d." +msgstr "Dieses Programm läuft mit der Prozess-Nummer %d." +EOF + +: ${DIFF=diff} +${DIFF} xg-test33.ok xg-test33.po +result=$? + +rm -fr $tmpfiles + +exit $result