diff options
Diffstat (limited to 'gettext-tools/src')
230 files changed, 10026 insertions, 2191 deletions
diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog.1 index fbfa43f..5272c06 100644 --- a/gettext-tools/src/ChangeLog +++ b/gettext-tools/src/ChangeLog.1 @@ -1,3 +1,353 @@ +2015-10-06 Daiki Ueno <ueno@gnu.org> + + * msgfmt.c (msgfmt_desktop_bulk): Distinguish the number of errors + and the exit status. + * write-desktop.c (msgdomain_write_desktop_bulk): Don't + immediately exit when fwriteerror() returns error. + +2015-10-06 Daiki Ueno <ueno@gnu.org> + + msgfmt: Refactor --desktop handling + * msgfmt.c (get_languages): Avoid redundant memory allocation. + (msgfmt_operand_list_init): New function. + (msgfmt_operand_list_destroy): New function. + (msgfmt_operand_list_append): New function. + (msgfmt_operand_list_add_directory): New function. + (msgfmt_desktop_bulk): Rewrite using msgfmt_operand_list_ty. + + * msgfmt.h (msgfmt_operand_ty) + (msgfmt_operand_list_ty): New type. + * write-desktop.c (msgdomain_write_desktop_bulk): + Simplify using msgfmt_operand_list_ty. + (msgdomain_write_desktop): Simplify using msgfmt_operand_list_ty. + * write-desktop.h (msgdomain_write_desktop_bulk): Take OPERANDS as + the first argument, instead of LANGUAGES and MESSAGES. + +2015-10-06 Daiki Ueno <ueno@gnu.org> + + * sentence.c (sentence_end): Assign initial values to local + variables to suppress compiler warnings with + -Wmaybe-uninitialized. This shouldn't address any real bug. + +2015-09-11 Daiki Ueno <ueno@gnu.org> + + * gettext 0.19.6 released. + +2015-08-24 Daiki Ueno <ueno@gnu.org> + + * xgettext.c (construct_header): Replace PACKAGE placeholder in + the header comment. + +2015-06-11 Philip Withnall <philip.withnall@collabora.co.uk> + + xgettext: add support for AppData files + * x-appdata.h: New file. + * x-appdata.c: New file. + * xgettext.c: Include x-appdata.h. + (language_to_extractor): Add AppData rule. + (extension_to_language): Add AppData rule. + * Makefile.am (noinst_HEADERS): Add x-appdata.h. + (xgettext_SOURCES): Add x-appdata.c. + * FILES: Update. + +2015-08-21 Daiki Ueno <ueno@gnu.org> + + xgettext: Allow multiple --copyright-holder + Feature requested by Francesco Poli in: + <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=682580>. + * xgettext.c (default_copyright_holder): New constant, renamed + from copyright_holder. + (copyright_holder): Define as a variable. + (main): Allow multiple --copyright-holder options. + (construct_header): Support multiple --copyright-holder options. + +2015-08-15 Daiki Ueno <ueno@gnu.org> + + * cldr-plurals.c (main): Close FP after use. + Reported by Denis Denisov. + +2015-07-21 Václav Slavík <vaclav@slavik.io> (tiny change) + + cldr-plurals: Fix --enable-relocatable compilation + Compilation of the cldr-plurals tool was broken in the relocatable + case because of missing CPPFLAGS/LDFLAGS. Add the same flags used + by other tools to the makefile. + * Makefile.am (cldr_plurals_CPPFLAGS) + (cldr_plurals_LDFLAGS): Adjust for --enable-relocatable + compilation. + +2015-07-10 Daiki Ueno <ueno@gnu.org> + + * gettext 0.19.5 released. + +2015-06-29 Daiki Ueno <ueno@gnu.org> + + * msginit.c (catalogname_for_locale): Remove sr_YU, which were + removed from ISO 3166-1:1997. Add comment saying that pap_AN, + which were removed from ISO 3166-1:2006, can be removed in the + future. + Reported by Jakub Wilk in: + <https://lists.gnu.org/archive/html/bug-gettext/2015-06/msg00057.html>. + +2015-06-25 Daiki Ueno <ueno@gnu.org> + + * x-c.c (literalstring_parse): Bail out if C == NUL. Also adjust + the loop invariant in Unicode literal handling. + Reported by Hanno Boeck in: + <http://savannah.gnu.org/bugs/?45391>. + +2015-06-25 Daiki Ueno <ueno@gnu.org> + + * x-c.c (literalstring_parse): Add more NUL checks. Change the + loop invariant so that C always points to the character previously + pointed by P. + Reported by Hanno Boeck in: + <http://savannah.gnu.org/bugs/?45391>. + +2015-06-24 Daiki Ueno <ueno@gnu.org> + + * x-c.c (literalstring_parse): Check if the next character of a + backslash is NUL. + Reported by Hanno Boeck in: + <http://savannah.gnu.org/bugs/?45391>. + +2015-06-23 Daiki Ueno <ueno@gnu.org> + + * cldr-plurals.c (main): Fix unmatched braces when + !(DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT). + +2015-06-23 Daiki Ueno <ueno@gnu.org> + + * cldr-plurals.c: Include "basename.h". + (main): Place optind on the right hand side of the expression, to + work around build failure on Solaris. + +2015-06-23 Daiki Ueno <ueno@gnu.org> + + * Makefile.am (uninstall-local): Remove cldr-plurals. + +2015-06-23 Daiki Ueno <ueno@gnu.org> + + * Makefile.am (noinst_HEADERS): Add cldr-plural.h and + cldr-plural-exp.h. + +2015-06-22 Daiki Ueno <ueno@gnu.org> + + msginit: Guess plural rules from Unicode CLDR + * Makefile.am (noinst_PROGRAMS): Add cldr-plurals. + (install-exec-local): Install cldr-plurals. + (BUILT_SOURCES): Add cldr-plural.c and cldr-plural.h. + (cldr_plural_SOURCES): New variable. + (cldr_plural_LDADD): New variable. + * cldr-plural-exp.h: New file. + * cldr-plural-exp.c: New file. + * cldr-plural.y: New file. + * cldr-plurals.c: New file. + * msginit.c (plural_forms): Call cldr-plurals program if the + plural rule is not defined in the code. + +2015-06-01 Daiki Ueno <ueno@gnu.org> + + * x-awk.h (EXTENSIONS_AWK): Register file extensions ".gawk" and + ".twjr". Suggested by Karl Berry in: + <https://lists.gnu.org/archive/html/bug-gettext/2015-05/msg00032.html>. + +2015-05-08 Часлав Илић (Chusslove Illich) <caslav.ilic@gmx.net> (tiny change) + + * x-c.c (init_flag_table_kde): New function. + (additional_keywords_kde): New variable. + (activate_additional_keywords_kde): New function. + (init_keywords): Optional addition of KDE-specific keywords. + * x-c.h (init_flag_table_kde): New function declaration. + (activate_additional_keywords_kde): New function declaration. + * xgettext.c (main): Invoke addition of KDE-specific keywords when + language is C++ with KDE. + +2015-03-20 Daiki Ueno <ueno@gnu.org> + + kde-kuit: Use xmlns to avoid element name conflict + * format-kde-kuit.c (XML_NS): New macro. + (format_parse): Add namespace qualifier to the <kuit> tag. + +2015-03-12 Daiki Ueno <ueno@gnu.org> + + * format-kde-kuit.c (format_parse): Remove dead assignment, + spotted by clang-analyzer. + * x-c.c (phase5_get): Likewise. + +2015-03-11 Daiki Ueno <ueno@gnu.org> + + msgunfmt: Check allocated size for static segment + Reported by Max Lin in: + http://lists.gnu.org/archive/html/bug-gettext/2015-03/msg00005.html + * read-mo.c (get_sysdep_string): Check if the embedded segment + size is valid, before adding it to the string length. + +2015-03-06 Daiki Ueno <ueno@gnu.org> + + format-kde: Recognize KUIT markup + Reported by Chusslove Illich in: + https://lists.gnu.org/archive/html/bug-gettext/2015-01/msg00017.html + * format.h (formatstring_kde_kuit): New variable declaration. + * format.c (formatstring_parsers): Register formatstring_kde_kuit + as a format string parser. + * format-kde-kuit.c: New file. + * message.h (NFORMATS): Increment. + (enum format_type): New enum value format_kde_kuit. + * xgettext.c (xgettext_record_flag): Handle format_kde_kuit. + * Makefile.am (xgettext_SOURCES): Move libexpat-compat.c to... + (libgettextsrc_la_SOURCES): ...here. + (xgettext_LDADD): Move @LTLIBEXPAT@ to... + (libgettextsrc_la_LDFLAGS): ...here. + (FORMAT_SOURCE): Add format-kde-kuit.c. + +2015-03-02 Daiki Ueno <ueno@gnu.org> + + xgettext: Support message syntax checks + With this change, xgettext could report common syntactic problems + in extracted strings. The current built-in checks are + ellipsis-unicode, space-ellipsis, and quote-unicode. Those checks + can be enabled with --check option of xgettext and disabled with + special "xgettext:" comment in source files. + Feature suggested by Philip Withnall in: + https://savannah.gnu.org/bugs/?44098 + * message.h (enum syntax_check_type): New enum. + (NSYNTAXCHECKS): New constant. + (enum is_syntax_check): New enum. + (struct message_ty): New field 'do_syntax_check'. + (syntax_check_name): New variable declaration. + * message.c (syntax_check_name): New variable. + * msgl-cat.c (catenate_msgdomain_list): Propagate + mp->do_syntax_check. + * msgmerge.c (message_merge): Propagate ref->do_syntax_check. + * msgl-check.h (syntax_check_message_list): New declaration. + * msgl-check.c (syntax_check_ellipsis_unicode): New function. + (syntax_check_space_ellipsis): New function. + (syntax_check_quote_unicode): New function. + (syntax_check_message): New function. + (syntax_check_message_list): New function. + * read-catalog-abstract.h (po_parse_comment_special): Adjust + function declaration. + * read-catalog-abstract.c (po_parse_comment_special): Add new + argument SCP for syntax checking; all callers changed. + * read-catalog.h (DEFAULT_CATALOG_READER_TY): New field + 'do_syntax_check'. + * read-catalog.c (default_constructor): Initialize + this->do_syntax_check. + (default_copy_comment_state): Propagate this->do_syntax_check. + * sentence.h: New file. + * sentence.c: New file. + * xgettext.c (long_options): Add options --check and --sentence-end. + (main): Handle options --check and --sentence-end. + (usage): Document options --check and --sentence-end. + (remember_a_message): Propagate do_syntax_check value. + +2015-02-05 Alex Henrie <alexhenrie24@gmail.com> (tiny change) + + xgettext: Wrap location comments to 79 characters + Previously, messages were wrapped to 79 characters, but location + comments were wrapped to 78 characters. + * write-po.c (message_print_comment_filepos): Fix off-by-one in + calculating line-wrapping width of location comment. + +2015-02-03 Daiki Ueno <ueno@gnu.org> + + msgfilter: Factor out quoted string handling + For later use in xgettext, separate out the scanner part in + filter-quote.c into a separate file. See: + <https://savannah.gnu.org/bugs/?44098>. + * quote.h: New file split from filter-quote.c. + * filter-quote.c: Include "quote.h". + (convert_quote_callback): New function. + (convert_ascii_quote_to_unicode): Use scan_quoted from quote.h. + * Makefile.am (libgettextsrc_la_SOURCES): Add quote.h. + +2015-01-29 Daiki Ueno <ueno@gnu.org> + + msgexec: Add --newline option + See the commit 96dde0b for the rationale. + * msgexec.c (newline): New variable. + (long_options): Add --newline option. + (main): Handle --newline option. + (usage): Document --newline option. + (process_string): Handle --newline option. + +2015-01-28 Daiki Ueno <ueno@gnu.org> + + msgfilter: Add --newline option + The filter program was supposed to handle translation without a + newline character at the end of line. This was causing + portability problems with standard text processing programs on + some platforms (BSD sed, for instance) and not friendly towards + POSIX, where a "text file" is required to have an ending newline. + The new --newline option controls the behavior. If it is given, + both filter input and output are assumed to end with a newline + character. + * msgfilter.c (newline): New variable. + (long_options): Add --newline option. + (main): Handle --newline option. + (usage): Document --newline option. + (process_string_with_newline): New function which wraps + process_string. + (process_message): Use process_string_with_newline instead of + process_string if --newline is specified. + +2015-01-24 Daiki Ueno <ueno@gnu.org> + + xgettext, msgmerge: Avoid undefined non-null argument behavior + * xgettext.c (remember_a_message): Building with gcc's + -fsanitize=undefined and running tests triggered: + xgettext.c:2425:17: runtime error: null pointer passed as argument \ + 2, which is declared to never be null + Adjust the argument of strncmp to never be null. + * msgmerge.c (message_merge): Likewise for memcpy. + +2015-01-23 Daiki Ueno <ueno@gnu.org> + + build: Fix parallel build from git checkout + Since po-gram-gen2.h depends on po-gram-gen.h, an explicit + dependency on the YACC rule is needed for parallel compilation. + * Makefile.am (po-gram-gen.h): Depend on po-gram-gen.c. + +2015-01-16 Daiki Ueno <ueno@gnu.org> + + desktop: Avoid useless warning for group header + Reported by Marek Černocký at: + <https://savannah.gnu.org/bugs/?44005> + * read-desktop.c (desktop_lex): Fix "invalid non-blank + character" check after reading a group header. + +2015-01-13 Daiki Ueno <ueno@gnu.org> + + * x-c.c (phase5_get): Reset raw_expected at the beginning of the + function. + +2015-01-13 Daiki Ueno <ueno@gnu.org> + + c++: Make C++11 raw string recognition stricter + Reported by Vaclav Slavik at: + <http://savannah.gnu.org/bugs/?43970>. + * x-c.c (struct token_ty): New field 'escape'. + (struct xgettext_token_ty): New field 'escape'. + (phase5_get): Recognize raw strings more strictly. Set 'escape' + field of token appropriately for string literals. + (extract_parenthesized): Respect 'escape' field of token. + +2015-01-13 Daiki Ueno <ueno@gnu.org> + + c++: Differentiate scanning logic from C + To enable raw string literals only in C++, add a flag indicating + the current source language is C++. + Suggested by Vaclav Slavik at: + <https://savannah.gnu.org/bugs/?43970>. + * x-c.h (extract_cxx): New declaration. + (SCANNERS_C): Use extract_cxx for "C++". + * x-c.c (cxx_extensions): New variable. + (phase5_get): Respect cxx_extensions and recognize raw string + literals only when it is set. + (extract_cxx): New function. + (extract_c, extract_objc): Reset cxx_extensions. + 2014-12-24 Daiki Ueno <ueno@gnu.org> * gettext 0.19.4 released. diff --git a/gettext-tools/src/FILES b/gettext-tools/src/FILES index 5fb474f..b647a84 100644 --- a/gettext-tools/src/FILES +++ b/gettext-tools/src/FILES @@ -357,6 +357,9 @@ msgl-check.c | x-desktop.h | x-desktop.c | String extractor from Desktop Entry file. +| x-appdata.h +| x-appdata.c +| String extractor for AppData files. | xgettext.c | Main source for the 'xgettext' program. | diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am index 9f2325f..7109072 100644 --- a/gettext-tools/src/Makefile.am +++ b/gettext-tools/src/Makefile.am @@ -1,5 +1,6 @@ ## Makefile for the gettext-tools/src subdirectory of GNU gettext -## Copyright (C) 1995-1998, 2000-2011 Free Software Foundation, Inc. +## Copyright (C) 1995-1998, 2000-2011, 2015 Free Software Foundation, +## Inc. ## ## 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 @@ -29,7 +30,7 @@ msgcmp msgfmt msgmerge msgunfmt xgettext \ msgattrib msgcat msgcomm msgconv msgen msgexec msgfilter msggrep msginit msguniq \ recode-sr-latin -noinst_PROGRAMS = hostname urlget +noinst_PROGRAMS = hostname urlget cldr-plurals lib_LTLIBRARIES = libgettextsrc.la @@ -38,7 +39,8 @@ po-lex.h open-catalog.h read-catalog-abstract.h read-catalog.h \ read-po.h read-properties.h read-stringtable.h \ str-list.h \ color.h write-catalog.h write-po.h write-properties.h write-stringtable.h \ -dir-list.h file-list.h po-gram-gen.h po-gram-gen2.h \ +dir-list.h file-list.h po-gram-gen.h po-gram-gen2.h cldr-plural.h \ +cldr-plural-exp.h locating-rule.h its.h \ msgl-charset.h msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-header.h \ msgl-english.h msgl-check.h msgl-fsearch.h msgfmt.h msgunfmt.h \ plural-count.h plural-eval.h plural-distrib.h \ @@ -49,13 +51,14 @@ read-resources.h write-resources.h \ read-tcl.h write-tcl.h \ write-qt.h \ read-desktop.h write-desktop.h \ +write-xml.h \ po-time.h plural-table.h lang-table.h format.h filters.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-scheme.h x-smalltalk.h x-java.h x-properties.h x-csharp.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 x-lua.h \ -x-javascript.h x-vala.h x-gsettings.h x-desktop.h libexpat-compat.h +x-javascript.h x-vala.h x-gsettings.h x-desktop.h x-appdata.h -EXTRA_DIST += FILES project-id ChangeLog.0 +EXTRA_DIST += FILES project-id aliaspath = $(localedir) jardir = $(datadir)/gettext @@ -138,6 +141,7 @@ FORMAT_SOURCE += \ format-qt.c \ format-qt-plural.c \ format-kde.c \ + format-kde-kuit.c \ format-boost.c \ format-lua.c \ format-javascript.c @@ -148,9 +152,9 @@ $(COMMON_SOURCE) read-catalog.c \ color.c write-catalog.c write-properties.c write-stringtable.c write-po.c \ msgl-ascii.c msgl-iconv.c msgl-equal.c msgl-cat.c msgl-header.c msgl-english.c \ msgl-check.c file-list.c msgl-charset.c po-time.c plural-exp.c plural-eval.c \ -plural-table.c \ +plural-table.c quote.h sentence.h sentence.c \ $(FORMAT_SOURCE) \ -read-desktop.c +read-desktop.c locating-rule.c its.c # msggrep needs pattern matching. LIBGREP = ../libgrep/libgrep.a @@ -161,7 +165,8 @@ msgcmp_SOURCES += msgl-fsearch.c msgfmt_SOURCES = msgfmt.c msgfmt_SOURCES += \ write-mo.c write-java.c write-csharp.c write-resources.c write-tcl.c \ - write-qt.c write-desktop.c ../../gettext-runtime/intl/hash-string.c + write-qt.c write-desktop.c write-xml.c \ + ../../gettext-runtime/intl/hash-string.c if !WOE32DLL msgmerge_SOURCES = msgmerge.c else @@ -179,8 +184,7 @@ endif xgettext_SOURCES += \ x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-scheme.c \ x-smalltalk.c x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \ - x-rst.c x-glade.c x-lua.c x-javascript.c x-vala.c x-gsettings.c \ - libexpat-compat.c \ + x-rst.c x-lua.c x-javascript.c x-vala.c \ x-desktop.c if !WOE32DLL msgattrib_SOURCES = msgattrib.c @@ -236,6 +240,9 @@ endif recode_sr_latin_SOURCES = recode-sr-latin.c filter-sr-latin.c hostname_SOURCES = hostname.c urlget_SOURCES = urlget.c +cldr_plurals_SOURCES = cldr-plural.y cldr-plural-exp.c cldr-plurals.c +cldr_plurals_CFLAGS = $(AM_CFLAGS) $(INCXML) +cldr_plurals_LDADD = libgettextsrc.la $(LDADD) # How to build libgettextsrc.la. # Need ../gnulib-lib/libgettextlib.la. @@ -249,7 +256,7 @@ libgettextsrc_la_LDFLAGS = \ -release @VERSION@ \ ../gnulib-lib/libgettextlib.la $(LTLIBUNISTRING) @LTLIBINTL@ @LTLIBICONV@ -lc -no-undefined -libgettextsrc_la_CPPFLAGS = $(AM_CPPFLAGS) +libgettextsrc_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCXML) # Tell the mingw or Cygwin linker which symbols to export. if WOE32DLL @@ -278,7 +285,7 @@ msgcmp_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @MSGMERGE_LIBM@ $(WOE32_LDADD msgfmt_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msgmerge_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @MSGMERGE_LIBM@ $(WOE32_LDADD) $(OPENMP_CFLAGS) msgunfmt_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) -xgettext_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @LTLIBEXPAT@ @LTLIBICONV@ $(WOE32_LDADD) +xgettext_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @LTLIBICONV@ $(WOE32_LDADD) msgattrib_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msgcat_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msgcomm_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) @@ -329,6 +336,7 @@ msguniq_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\" recode_sr_latin_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\" hostname_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" urlget_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" +cldr_plurals_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" if RELOCATABLE_VIA_LD msgcmp_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` msgfmt_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` @@ -348,6 +356,7 @@ msguniq_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` recode_sr_latin_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` hostname_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(pkglibdir)` urlget_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(pkglibdir)` +cldr_plurals_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(pkglibdir)` endif # Linking with C++ libraries is needed _only_ on mingw and Cygwin. @@ -446,7 +455,7 @@ endif # Special rules for bison and flex generated files. BUILT_SOURCES = \ - po-gram-gen.c po-gram-gen.h po-gram-gen2.h + po-gram-gen.c po-gram-gen.h po-gram-gen2.h cldr-plural.c cldr-plural.h po-lex.o po-lex.lo: po-gram-gen2.h po-gram-gen2.h: po-gram-gen.h @@ -455,6 +464,7 @@ po-gram-gen2.h: po-gram-gen.h $(SED) -e 's/yy/po_gram_/g' -e 's/extern /extern DLL_VARIABLE /' \ $${srcdir}po-gram-gen.h > $@-tmp && \ mv $@-tmp $@ +po-gram-gen.h: po-gram-gen.c # Special rules for installation of auxiliary programs. @@ -463,6 +473,7 @@ install-exec-local: $(MKDIR_P) $(DESTDIR)$(pkglibdir) $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) hostname$(EXEEXT) $(DESTDIR)$(pkglibdir)/hostname$(EXEEXT) $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) urlget$(EXEEXT) $(DESTDIR)$(pkglibdir)/urlget$(EXEEXT) + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) cldr-plurals$(EXEEXT) $(DESTDIR)$(pkglibdir)/cldr-plurals$(EXEEXT) $(INSTALL_SCRIPT) user-email $(DESTDIR)$(pkglibdir)/user-email $(INSTALL_SCRIPT) $(srcdir)/project-id $(DESTDIR)$(pkglibdir)/project-id @@ -472,6 +483,7 @@ installdirs-local: uninstall-local: $(RM) $(DESTDIR)$(pkglibdir)/hostname$(EXEEXT) $(RM) $(DESTDIR)$(pkglibdir)/urlget$(EXEEXT) + $(RM) $(DESTDIR)$(pkglibdir)/cldr-plurals$(EXEEXT) $(RM) $(DESTDIR)$(pkglibdir)/user-email $(RM) $(DESTDIR)$(pkglibdir)/project-id diff --git a/gettext-tools/src/Makefile.in b/gettext-tools/src/Makefile.in index 4e29138..00da903 100644 --- a/gettext-tools/src/Makefile.in +++ b/gettext-tools/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -17,7 +17,17 @@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -83,7 +93,8 @@ bin_PROGRAMS = msgcmp$(EXEEXT) msgfmt$(EXEEXT) msgmerge$(EXEEXT) \ msgen$(EXEEXT) msgexec$(EXEEXT) msgfilter$(EXEEXT) \ msggrep$(EXEEXT) msginit$(EXEEXT) msguniq$(EXEEXT) \ recode-sr-latin$(EXEEXT) -noinst_PROGRAMS = hostname$(EXEEXT) urlget$(EXEEXT) +noinst_PROGRAMS = hostname$(EXEEXT) urlget$(EXEEXT) \ + cldr-plurals$(EXEEXT) # Tell the mingw or Cygwin linker which symbols to export. @WOE32DLL_TRUE@am__append_1 = ../woe32dll/gettextsrc-exports.c @@ -91,15 +102,10 @@ noinst_PROGRAMS = hostname$(EXEEXT) urlget$(EXEEXT) @WOE32DLL_TRUE@am__append_3 = $(GETTEXTLIB_EXPORTS_FLAGS) @WOE32_TRUE@am__append_4 = gettext.res subdir = src -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/../build-aux/mkinstalldirs \ - $(srcdir)/user-email.sh.in po-gram-gen.c \ - $(top_srcdir)/../build-aux/ylwrap $(noinst_HEADERS) ChangeLog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = \ $(top_srcdir)/libgettextpo/gnulib-m4/gnulib-comp.m4 \ $(top_srcdir)/libgrep/gnulib-m4/gnulib-comp.m4 \ - $(top_srcdir)/libgrep/gnulib-m4/langinfo_h.m4 \ $(top_srcdir)/libgrep/gnulib-m4/localeconv.m4 \ $(top_srcdir)/libgrep/gnulib-m4/mbrlen.m4 \ $(top_srcdir)/libgrep/gnulib-m4/nl_langinfo.m4 \ @@ -116,6 +122,7 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/btowc.m4 \ $(top_srcdir)/gnulib-m4/byteswap.m4 \ $(top_srcdir)/gnulib-m4/canonicalize.m4 \ + $(top_srcdir)/gnulib-m4/check-math-lib.m4 \ $(top_srcdir)/gnulib-m4/close.m4 \ $(top_srcdir)/gnulib-m4/closedir.m4 \ $(top_srcdir)/gnulib-m4/configmake.m4 \ @@ -123,6 +130,7 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/csharp.m4 \ $(top_srcdir)/gnulib-m4/csharpcomp.m4 \ $(top_srcdir)/gnulib-m4/csharpexec.m4 \ + $(top_srcdir)/gnulib-m4/ctype.m4 \ $(top_srcdir)/gnulib-m4/curses.m4 \ $(top_srcdir)/gnulib-m4/dirent_h.m4 \ $(top_srcdir)/gnulib-m4/double-slash-root.m4 \ @@ -134,7 +142,10 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/error.m4 \ $(top_srcdir)/gnulib-m4/execute.m4 \ $(top_srcdir)/gnulib-m4/exponentd.m4 \ + $(top_srcdir)/gnulib-m4/exponentf.m4 \ + $(top_srcdir)/gnulib-m4/exponentl.m4 \ $(top_srcdir)/gnulib-m4/extensions.m4 \ + $(top_srcdir)/gnulib-m4/fabs.m4 \ $(top_srcdir)/gnulib-m4/fatal-signal.m4 \ $(top_srcdir)/gnulib-m4/fcntl.m4 \ $(top_srcdir)/gnulib-m4/fcntl_h.m4 \ @@ -164,10 +175,16 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/inline.m4 \ $(top_srcdir)/gnulib-m4/intmax_t.m4 \ $(top_srcdir)/gnulib-m4/inttypes.m4 \ + $(top_srcdir)/gnulib-m4/isinf.m4 \ + $(top_srcdir)/gnulib-m4/isnan.m4 \ + $(top_srcdir)/gnulib-m4/isnand.m4 \ + $(top_srcdir)/gnulib-m4/isnanf.m4 \ + $(top_srcdir)/gnulib-m4/isnanl.m4 \ $(top_srcdir)/gnulib-m4/iswblank.m4 \ $(top_srcdir)/gnulib-m4/java.m4 \ $(top_srcdir)/gnulib-m4/javacomp.m4 \ $(top_srcdir)/gnulib-m4/javaexec.m4 \ + $(top_srcdir)/gnulib-m4/langinfo_h.m4 \ $(top_srcdir)/gnulib-m4/largefile.m4 \ $(top_srcdir)/gnulib-m4/lib-ld.m4 \ $(top_srcdir)/gnulib-m4/lib-link.m4 \ @@ -185,10 +202,13 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/locale-zh.m4 \ $(top_srcdir)/gnulib-m4/locale_h.m4 \ $(top_srcdir)/gnulib-m4/localename.m4 \ + $(top_srcdir)/gnulib-m4/log10.m4 \ $(top_srcdir)/gnulib-m4/lseek.m4 \ $(top_srcdir)/gnulib-m4/lstat.m4 \ $(top_srcdir)/gnulib-m4/malloc.m4 \ $(top_srcdir)/gnulib-m4/malloca.m4 \ + $(top_srcdir)/gnulib-m4/math_h.m4 \ + $(top_srcdir)/gnulib-m4/mathfunc.m4 \ $(top_srcdir)/gnulib-m4/mbchar.m4 \ $(top_srcdir)/gnulib-m4/mbiter.m4 \ $(top_srcdir)/gnulib-m4/mbrtowc.m4 \ @@ -218,6 +238,7 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/pathmax.m4 \ $(top_srcdir)/gnulib-m4/pipe2.m4 \ $(top_srcdir)/gnulib-m4/posix_spawn.m4 \ + $(top_srcdir)/gnulib-m4/pow.m4 \ $(top_srcdir)/gnulib-m4/printf.m4 \ $(top_srcdir)/gnulib-m4/putenv.m4 \ $(top_srcdir)/gnulib-m4/quote.m4 \ @@ -242,6 +263,7 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/sigaction.m4 \ $(top_srcdir)/gnulib-m4/signal_h.m4 \ $(top_srcdir)/gnulib-m4/signalblocking.m4 \ + $(top_srcdir)/gnulib-m4/signbit.m4 \ $(top_srcdir)/gnulib-m4/sigpipe.m4 \ $(top_srcdir)/gnulib-m4/sleep.m4 \ $(top_srcdir)/gnulib-m4/snprintf.m4 \ @@ -249,6 +271,7 @@ am__aclocal_m4_deps = \ $(top_srcdir)/gnulib-m4/spawn_h.m4 \ $(top_srcdir)/gnulib-m4/ssize_t.m4 \ $(top_srcdir)/gnulib-m4/stat.m4 \ + $(top_srcdir)/gnulib-m4/stdalign.m4 \ $(top_srcdir)/gnulib-m4/stdarg.m4 \ $(top_srcdir)/gnulib-m4/stdbool.m4 \ $(top_srcdir)/gnulib-m4/stddef_h.m4 \ @@ -340,6 +363,8 @@ am__aclocal_m4_deps = \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) mkinstalldirs = $(SHELL) $(top_srcdir)/../build-aux/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = user-email @@ -381,15 +406,17 @@ am__libgettextsrc_la_SOURCES_DIST = message.c po-error.c po-xerror.c \ write-properties.c write-stringtable.c write-po.c msgl-ascii.c \ msgl-iconv.c msgl-equal.c msgl-cat.c msgl-header.c \ msgl-english.c msgl-check.c file-list.c msgl-charset.c \ - po-time.c plural-exp.c plural-eval.c plural-table.c format.c \ - format-invalid.h format-c.c format-c-parse.h format-sh.c \ - format-python.c format-python-brace.c format-lisp.c \ - format-elisp.c format-librep.c format-scheme.c format-java.c \ - format-csharp.c format-awk.c format-pascal.c format-ycp.c \ - format-tcl.c format-perl.c format-perl-brace.c format-php.c \ + po-time.c plural-exp.c plural-eval.c plural-table.c quote.h \ + sentence.h sentence.c format.c format-invalid.h format-c.c \ + format-c-parse.h format-sh.c format-python.c \ + format-python-brace.c format-lisp.c format-elisp.c \ + format-librep.c format-scheme.c format-java.c format-csharp.c \ + format-awk.c format-pascal.c format-ycp.c format-tcl.c \ + format-perl.c format-perl-brace.c format-php.c \ format-gcc-internal.c format-gfc-internal.c format-qt.c \ - format-qt-plural.c format-kde.c format-boost.c format-lua.c \ - format-javascript.c ../woe32dll/c++format.cc read-desktop.c \ + format-qt-plural.c format-kde.c format-kde-kuit.c \ + format-boost.c format-lua.c format-javascript.c \ + ../woe32dll/c++format.cc read-desktop.c locating-rule.c its.c \ ../woe32dll/gettextsrc-exports.c am__objects_1 = libgettextsrc_la-message.lo \ libgettextsrc_la-po-error.lo libgettextsrc_la-po-xerror.lo \ @@ -424,6 +451,7 @@ am__dirstamp = $(am__leading_dot)dirstamp @WOE32DLL_FALSE@ libgettextsrc_la-format-qt.lo \ @WOE32DLL_FALSE@ libgettextsrc_la-format-qt-plural.lo \ @WOE32DLL_FALSE@ libgettextsrc_la-format-kde.lo \ +@WOE32DLL_FALSE@ libgettextsrc_la-format-kde-kuit.lo \ @WOE32DLL_FALSE@ libgettextsrc_la-format-boost.lo \ @WOE32DLL_FALSE@ libgettextsrc_la-format-lua.lo \ @WOE32DLL_FALSE@ libgettextsrc_la-format-javascript.lo @@ -451,6 +479,7 @@ am__dirstamp = $(am__leading_dot)dirstamp @WOE32DLL_TRUE@ libgettextsrc_la-format-qt.lo \ @WOE32DLL_TRUE@ libgettextsrc_la-format-qt-plural.lo \ @WOE32DLL_TRUE@ libgettextsrc_la-format-kde.lo \ +@WOE32DLL_TRUE@ libgettextsrc_la-format-kde-kuit.lo \ @WOE32DLL_TRUE@ libgettextsrc_la-format-boost.lo \ @WOE32DLL_TRUE@ libgettextsrc_la-format-lua.lo \ @WOE32DLL_TRUE@ libgettextsrc_la-format-javascript.lo @@ -467,19 +496,31 @@ am_libgettextsrc_la_OBJECTS = $(am__objects_1) \ libgettextsrc_la-msgl-check.lo libgettextsrc_la-file-list.lo \ libgettextsrc_la-msgl-charset.lo libgettextsrc_la-po-time.lo \ libgettextsrc_la-plural-exp.lo libgettextsrc_la-plural-eval.lo \ - libgettextsrc_la-plural-table.lo $(am__objects_2) \ - libgettextsrc_la-read-desktop.lo $(am__objects_3) + libgettextsrc_la-plural-table.lo libgettextsrc_la-sentence.lo \ + $(am__objects_2) libgettextsrc_la-read-desktop.lo \ + libgettextsrc_la-locating-rule.lo libgettextsrc_la-its.lo \ + $(am__objects_3) libgettextsrc_la_OBJECTS = $(am_libgettextsrc_la_OBJECTS) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) -am_hostname_OBJECTS = hostname-hostname.$(OBJEXT) -hostname_OBJECTS = $(am_hostname_OBJECTS) -hostname_LDADD = $(LDADD) +am_cldr_plurals_OBJECTS = cldr_plurals-cldr-plural.$(OBJEXT) \ + cldr_plurals-cldr-plural-exp.$(OBJEXT) \ + cldr_plurals-cldr-plurals.$(OBJEXT) +cldr_plurals_OBJECTS = $(am_cldr_plurals_OBJECTS) am__DEPENDENCIES_1 = @WOE32_TRUE@am__DEPENDENCIES_2 = gettext.res +am__DEPENDENCIES_3 = ../gnulib-lib/libgettextlib.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +cldr_plurals_DEPENDENCIES = libgettextsrc.la $(am__DEPENDENCIES_3) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = +cldr_plurals_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(cldr_plurals_CFLAGS) \ + $(CFLAGS) $(cldr_plurals_LDFLAGS) $(LDFLAGS) -o $@ +am_hostname_OBJECTS = hostname-hostname.$(OBJEXT) +hostname_OBJECTS = $(am_hostname_OBJECTS) +hostname_LDADD = $(LDADD) hostname_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hostname_LDFLAGS) $(LDFLAGS) -o $@ @@ -533,6 +574,7 @@ am_msgfmt_OBJECTS = msgfmt-msgfmt.$(OBJEXT) msgfmt-write-mo.$(OBJEXT) \ msgfmt-write-java.$(OBJEXT) msgfmt-write-csharp.$(OBJEXT) \ msgfmt-write-resources.$(OBJEXT) msgfmt-write-tcl.$(OBJEXT) \ msgfmt-write-qt.$(OBJEXT) msgfmt-write-desktop.$(OBJEXT) \ + msgfmt-write-xml.$(OBJEXT) \ ../../gettext-runtime/intl/msgfmt-hash-string.$(OBJEXT) msgfmt_OBJECTS = $(am_msgfmt_OBJECTS) msgfmt_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -594,8 +636,7 @@ urlget_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ am__xgettext_SOURCES_DIST = xgettext.c x-c.c x-po.c x-sh.c x-python.c \ x-lisp.c x-elisp.c x-librep.c x-scheme.c x-smalltalk.c \ x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \ - x-rst.c x-glade.c x-lua.c x-javascript.c x-vala.c \ - x-gsettings.c libexpat-compat.c x-desktop.c \ + x-rst.c x-lua.c x-javascript.c x-vala.c x-desktop.c \ ../woe32dll/c++xgettext.cc @WOE32DLL_FALSE@am_xgettext_OBJECTS = xgettext-xgettext.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-c.$(OBJEXT) xgettext-x-po.$(OBJEXT) \ @@ -614,12 +655,9 @@ am__xgettext_SOURCES_DIST = xgettext.c x-c.c x-po.c x-sh.c x-python.c \ @WOE32DLL_FALSE@ xgettext-x-perl.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-php.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-rst.$(OBJEXT) \ -@WOE32DLL_FALSE@ xgettext-x-glade.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-lua.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-javascript.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-vala.$(OBJEXT) \ -@WOE32DLL_FALSE@ xgettext-x-gsettings.$(OBJEXT) \ -@WOE32DLL_FALSE@ xgettext-libexpat-compat.$(OBJEXT) \ @WOE32DLL_FALSE@ xgettext-x-desktop.$(OBJEXT) @WOE32DLL_TRUE@am_xgettext_OBJECTS = \ @WOE32DLL_TRUE@ ../woe32dll/xgettext-c++xgettext.$(OBJEXT) \ @@ -639,12 +677,9 @@ am__xgettext_SOURCES_DIST = xgettext.c x-c.c x-po.c x-sh.c x-python.c \ @WOE32DLL_TRUE@ xgettext-x-perl.$(OBJEXT) \ @WOE32DLL_TRUE@ xgettext-x-php.$(OBJEXT) \ @WOE32DLL_TRUE@ xgettext-x-rst.$(OBJEXT) \ -@WOE32DLL_TRUE@ xgettext-x-glade.$(OBJEXT) \ @WOE32DLL_TRUE@ xgettext-x-lua.$(OBJEXT) \ @WOE32DLL_TRUE@ xgettext-x-javascript.$(OBJEXT) \ @WOE32DLL_TRUE@ xgettext-x-vala.$(OBJEXT) \ -@WOE32DLL_TRUE@ xgettext-x-gsettings.$(OBJEXT) \ -@WOE32DLL_TRUE@ xgettext-libexpat-compat.$(OBJEXT) \ @WOE32DLL_TRUE@ xgettext-x-desktop.$(OBJEXT) xgettext_OBJECTS = $(am_xgettext_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) @@ -708,24 +743,25 @@ am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/../build-aux/ylwrap -SOURCES = $(libgettextsrc_la_SOURCES) $(hostname_SOURCES) \ - $(msgattrib_SOURCES) $(msgcat_SOURCES) $(msgcmp_SOURCES) \ - $(msgcomm_SOURCES) $(msgconv_SOURCES) $(msgen_SOURCES) \ - $(msgexec_SOURCES) $(msgfilter_SOURCES) $(msgfmt_SOURCES) \ - $(msggrep_SOURCES) $(msginit_SOURCES) $(msgmerge_SOURCES) \ - $(msgunfmt_SOURCES) $(msguniq_SOURCES) \ +SOURCES = $(libgettextsrc_la_SOURCES) $(cldr_plurals_SOURCES) \ + $(hostname_SOURCES) $(msgattrib_SOURCES) $(msgcat_SOURCES) \ + $(msgcmp_SOURCES) $(msgcomm_SOURCES) $(msgconv_SOURCES) \ + $(msgen_SOURCES) $(msgexec_SOURCES) $(msgfilter_SOURCES) \ + $(msgfmt_SOURCES) $(msggrep_SOURCES) $(msginit_SOURCES) \ + $(msgmerge_SOURCES) $(msgunfmt_SOURCES) $(msguniq_SOURCES) \ $(recode_sr_latin_SOURCES) $(urlget_SOURCES) \ $(xgettext_SOURCES) DIST_SOURCES = $(am__libgettextsrc_la_SOURCES_DIST) \ - $(hostname_SOURCES) $(am__msgattrib_SOURCES_DIST) \ - $(am__msgcat_SOURCES_DIST) $(msgcmp_SOURCES) \ - $(am__msgcomm_SOURCES_DIST) $(am__msgconv_SOURCES_DIST) \ - $(am__msgen_SOURCES_DIST) $(msgexec_SOURCES) \ - $(am__msgfilter_SOURCES_DIST) $(msgfmt_SOURCES) \ - $(am__msggrep_SOURCES_DIST) $(msginit_SOURCES) \ - $(am__msgmerge_SOURCES_DIST) $(msgunfmt_SOURCES) \ - $(am__msguniq_SOURCES_DIST) $(recode_sr_latin_SOURCES) \ - $(urlget_SOURCES) $(am__xgettext_SOURCES_DIST) + $(cldr_plurals_SOURCES) $(hostname_SOURCES) \ + $(am__msgattrib_SOURCES_DIST) $(am__msgcat_SOURCES_DIST) \ + $(msgcmp_SOURCES) $(am__msgcomm_SOURCES_DIST) \ + $(am__msgconv_SOURCES_DIST) $(am__msgen_SOURCES_DIST) \ + $(msgexec_SOURCES) $(am__msgfilter_SOURCES_DIST) \ + $(msgfmt_SOURCES) $(am__msggrep_SOURCES_DIST) \ + $(msginit_SOURCES) $(am__msgmerge_SOURCES_DIST) \ + $(msgunfmt_SOURCES) $(am__msguniq_SOURCES_DIST) \ + $(recode_sr_latin_SOURCES) $(urlget_SOURCES) \ + $(am__xgettext_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -751,6 +787,9 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/user-email.sh.in \ + $(top_srcdir)/../build-aux/mkinstalldirs \ + $(top_srcdir)/../build-aux/ylwrap cldr-plural.c po-gram-gen.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkgdatadir = $(datadir)/gettext pkglibdir = $(libdir)/gettext @@ -763,6 +802,7 @@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ AR = @AR@ ARCHIVE_FORMAT = @ARCHIVE_FORMAT@ +ARCHIVE_VERSION = @ARCHIVE_VERSION@ ARFLAGS = @ARFLAGS@ AS = @AS@ ASM_SYMBOL_PREFIX = @ASM_SYMBOL_PREFIX@ @@ -834,6 +874,7 @@ EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ ERRNO_H = @ERRNO_H@ EXEEXT = @EXEEXT@ +FABS_LIBM = @FABS_LIBM@ FGREP = @FGREP@ FLOAT_H = @FLOAT_H@ FNMATCH_H = @FNMATCH_H@ @@ -848,15 +889,34 @@ GLIBC21 = @GLIBC21@ GLOBAL_SYMBOL_PIPE = @GLOBAL_SYMBOL_PIPE@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ +GNULIB_ACOSF = @GNULIB_ACOSF@ +GNULIB_ACOSL = @GNULIB_ACOSL@ GNULIB_ALPHASORT = @GNULIB_ALPHASORT@ +GNULIB_ASINF = @GNULIB_ASINF@ +GNULIB_ASINL = @GNULIB_ASINL@ +GNULIB_ATAN2F = @GNULIB_ATAN2F@ +GNULIB_ATANF = @GNULIB_ATANF@ +GNULIB_ATANL = @GNULIB_ATANL@ GNULIB_ATOLL = @GNULIB_ATOLL@ GNULIB_BTOWC = @GNULIB_BTOWC@ GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ +GNULIB_CBRT = @GNULIB_CBRT@ +GNULIB_CBRTF = @GNULIB_CBRTF@ +GNULIB_CBRTL = @GNULIB_CBRTL@ +GNULIB_CEIL = @GNULIB_CEIL@ +GNULIB_CEILF = @GNULIB_CEILF@ +GNULIB_CEILL = @GNULIB_CEILL@ GNULIB_CHDIR = @GNULIB_CHDIR@ GNULIB_CHOWN = @GNULIB_CHOWN@ GNULIB_CLOSE = @GNULIB_CLOSE@ GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@ +GNULIB_COPYSIGN = @GNULIB_COPYSIGN@ +GNULIB_COPYSIGNF = @GNULIB_COPYSIGNF@ +GNULIB_COPYSIGNL = @GNULIB_COPYSIGNL@ +GNULIB_COSF = @GNULIB_COSF@ +GNULIB_COSHF = @GNULIB_COSHF@ +GNULIB_COSL = @GNULIB_COSL@ GNULIB_DIRFD = @GNULIB_DIRFD@ GNULIB_DPRINTF = @GNULIB_DPRINTF@ GNULIB_DUP = @GNULIB_DUP@ @@ -865,6 +925,16 @@ GNULIB_DUP3 = @GNULIB_DUP3@ GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@ GNULIB_ENVIRON = @GNULIB_ENVIRON@ GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ +GNULIB_EXP2 = @GNULIB_EXP2@ +GNULIB_EXP2F = @GNULIB_EXP2F@ +GNULIB_EXP2L = @GNULIB_EXP2L@ +GNULIB_EXPF = @GNULIB_EXPF@ +GNULIB_EXPL = @GNULIB_EXPL@ +GNULIB_EXPM1 = @GNULIB_EXPM1@ +GNULIB_EXPM1F = @GNULIB_EXPM1F@ +GNULIB_EXPM1L = @GNULIB_EXPM1L@ +GNULIB_FABSF = @GNULIB_FABSF@ +GNULIB_FABSL = @GNULIB_FABSL@ GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ GNULIB_FCHDIR = @GNULIB_FCHDIR@ GNULIB_FCHMODAT = @GNULIB_FCHMODAT@ @@ -879,6 +949,15 @@ GNULIB_FFSL = @GNULIB_FFSL@ GNULIB_FFSLL = @GNULIB_FFSLL@ GNULIB_FGETC = @GNULIB_FGETC@ GNULIB_FGETS = @GNULIB_FGETS@ +GNULIB_FLOOR = @GNULIB_FLOOR@ +GNULIB_FLOORF = @GNULIB_FLOORF@ +GNULIB_FLOORL = @GNULIB_FLOORL@ +GNULIB_FMA = @GNULIB_FMA@ +GNULIB_FMAF = @GNULIB_FMAF@ +GNULIB_FMAL = @GNULIB_FMAL@ +GNULIB_FMOD = @GNULIB_FMOD@ +GNULIB_FMODF = @GNULIB_FMODF@ +GNULIB_FMODL = @GNULIB_FMODL@ GNULIB_FOPEN = @GNULIB_FOPEN@ GNULIB_FPRINTF = @GNULIB_FPRINTF@ GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@ @@ -887,6 +966,9 @@ GNULIB_FPUTC = @GNULIB_FPUTC@ GNULIB_FPUTS = @GNULIB_FPUTS@ GNULIB_FREAD = @GNULIB_FREAD@ GNULIB_FREOPEN = @GNULIB_FREOPEN@ +GNULIB_FREXP = @GNULIB_FREXP@ +GNULIB_FREXPF = @GNULIB_FREXPF@ +GNULIB_FREXPL = @GNULIB_FREXPL@ GNULIB_FSCANF = @GNULIB_FSCANF@ GNULIB_FSEEK = @GNULIB_FSEEK@ GNULIB_FSEEKO = @GNULIB_FSEEKO@ @@ -917,17 +999,47 @@ GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@ GNULIB_GRANTPT = @GNULIB_GRANTPT@ GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@ +GNULIB_HYPOT = @GNULIB_HYPOT@ +GNULIB_HYPOTF = @GNULIB_HYPOTF@ +GNULIB_HYPOTL = @GNULIB_HYPOTL@ GNULIB_ICONV = @GNULIB_ICONV@ +GNULIB_ILOGB = @GNULIB_ILOGB@ +GNULIB_ILOGBF = @GNULIB_ILOGBF@ +GNULIB_ILOGBL = @GNULIB_ILOGBL@ GNULIB_IMAXABS = @GNULIB_IMAXABS@ GNULIB_IMAXDIV = @GNULIB_IMAXDIV@ GNULIB_ISATTY = @GNULIB_ISATTY@ +GNULIB_ISBLANK = @GNULIB_ISBLANK@ +GNULIB_ISFINITE = @GNULIB_ISFINITE@ +GNULIB_ISINF = @GNULIB_ISINF@ +GNULIB_ISNAN = @GNULIB_ISNAN@ +GNULIB_ISNAND = @GNULIB_ISNAND@ +GNULIB_ISNANF = @GNULIB_ISNANF@ +GNULIB_ISNANL = @GNULIB_ISNANL@ GNULIB_ISWBLANK = @GNULIB_ISWBLANK@ GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@ GNULIB_LCHMOD = @GNULIB_LCHMOD@ GNULIB_LCHOWN = @GNULIB_LCHOWN@ +GNULIB_LDEXPF = @GNULIB_LDEXPF@ +GNULIB_LDEXPL = @GNULIB_LDEXPL@ GNULIB_LINK = @GNULIB_LINK@ GNULIB_LINKAT = @GNULIB_LINKAT@ GNULIB_LOCALECONV = @GNULIB_LOCALECONV@ +GNULIB_LOG = @GNULIB_LOG@ +GNULIB_LOG10 = @GNULIB_LOG10@ +GNULIB_LOG10F = @GNULIB_LOG10F@ +GNULIB_LOG10L = @GNULIB_LOG10L@ +GNULIB_LOG1P = @GNULIB_LOG1P@ +GNULIB_LOG1PF = @GNULIB_LOG1PF@ +GNULIB_LOG1PL = @GNULIB_LOG1PL@ +GNULIB_LOG2 = @GNULIB_LOG2@ +GNULIB_LOG2F = @GNULIB_LOG2F@ +GNULIB_LOG2L = @GNULIB_LOG2L@ +GNULIB_LOGB = @GNULIB_LOGB@ +GNULIB_LOGBF = @GNULIB_LOGBF@ +GNULIB_LOGBL = @GNULIB_LOGBL@ +GNULIB_LOGF = @GNULIB_LOGF@ +GNULIB_LOGL = @GNULIB_LOGL@ GNULIB_LSEEK = @GNULIB_LSEEK@ GNULIB_LSTAT = @GNULIB_LSTAT@ GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@ @@ -966,6 +1078,9 @@ GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ GNULIB_MKTIME = @GNULIB_MKTIME@ +GNULIB_MODF = @GNULIB_MODF@ +GNULIB_MODFF = @GNULIB_MODFF@ +GNULIB_MODFL = @GNULIB_MODFL@ GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@ GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@ @@ -1001,6 +1116,7 @@ GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDU GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN@ GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY@ GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT@ +GNULIB_POWF = @GNULIB_POWF@ GNULIB_PREAD = @GNULIB_PREAD@ GNULIB_PRINTF = @GNULIB_PRINTF@ GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ @@ -1024,11 +1140,20 @@ GNULIB_READLINK = @GNULIB_READLINK@ GNULIB_READLINKAT = @GNULIB_READLINKAT@ GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ GNULIB_REALPATH = @GNULIB_REALPATH@ +GNULIB_REMAINDER = @GNULIB_REMAINDER@ +GNULIB_REMAINDERF = @GNULIB_REMAINDERF@ +GNULIB_REMAINDERL = @GNULIB_REMAINDERL@ GNULIB_REMOVE = @GNULIB_REMOVE@ GNULIB_RENAME = @GNULIB_RENAME@ GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ GNULIB_REWINDDIR = @GNULIB_REWINDDIR@ +GNULIB_RINT = @GNULIB_RINT@ +GNULIB_RINTF = @GNULIB_RINTF@ +GNULIB_RINTL = @GNULIB_RINTL@ GNULIB_RMDIR = @GNULIB_RMDIR@ +GNULIB_ROUND = @GNULIB_ROUND@ +GNULIB_ROUNDF = @GNULIB_ROUNDF@ +GNULIB_ROUNDL = @GNULIB_ROUNDL@ GNULIB_RPMATCH = @GNULIB_RPMATCH@ GNULIB_SCANDIR = @GNULIB_SCANDIR@ GNULIB_SCANF = @GNULIB_SCANF@ @@ -1039,10 +1164,16 @@ GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@ GNULIB_SETLOCALE = @GNULIB_SETLOCALE@ GNULIB_SIGACTION = @GNULIB_SIGACTION@ GNULIB_SIGNAL_H_SIGPIPE = @GNULIB_SIGNAL_H_SIGPIPE@ +GNULIB_SIGNBIT = @GNULIB_SIGNBIT@ GNULIB_SIGPROCMASK = @GNULIB_SIGPROCMASK@ +GNULIB_SINF = @GNULIB_SINF@ +GNULIB_SINHF = @GNULIB_SINHF@ +GNULIB_SINL = @GNULIB_SINL@ GNULIB_SLEEP = @GNULIB_SLEEP@ GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ +GNULIB_SQRTF = @GNULIB_SQRTF@ +GNULIB_SQRTL = @GNULIB_SQRTL@ GNULIB_STAT = @GNULIB_STAT@ GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@ GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@ @@ -1071,10 +1202,17 @@ GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@ GNULIB_SYMLINK = @GNULIB_SYMLINK@ GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ +GNULIB_TANF = @GNULIB_TANF@ +GNULIB_TANHF = @GNULIB_TANHF@ +GNULIB_TANL = @GNULIB_TANL@ GNULIB_TIMEGM = @GNULIB_TIMEGM@ GNULIB_TIME_R = @GNULIB_TIME_R@ +GNULIB_TIME_RZ = @GNULIB_TIME_RZ@ GNULIB_TMPFILE = @GNULIB_TMPFILE@ GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@ +GNULIB_TRUNC = @GNULIB_TRUNC@ +GNULIB_TRUNCF = @GNULIB_TRUNCF@ +GNULIB_TRUNCL = @GNULIB_TRUNCL@ GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@ GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@ @@ -1134,25 +1272,57 @@ GNULIB_WMEMSET = @GNULIB_WMEMSET@ GNULIB_WRITE = @GNULIB_WRITE@ GNULIB__EXIT = @GNULIB__EXIT@ GREP = @GREP@ +HAVE_ACOSF = @HAVE_ACOSF@ +HAVE_ACOSL = @HAVE_ACOSL@ HAVE_ALPHASORT = @HAVE_ALPHASORT@ +HAVE_ASINF = @HAVE_ASINF@ +HAVE_ASINL = @HAVE_ASINL@ HAVE_ASPRINTF = @HAVE_ASPRINTF@ +HAVE_ATAN2F = @HAVE_ATAN2F@ +HAVE_ATANF = @HAVE_ATANF@ +HAVE_ATANL = @HAVE_ATANL@ HAVE_ATOLL = @HAVE_ATOLL@ HAVE_BTOWC = @HAVE_BTOWC@ HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ +HAVE_CBRT = @HAVE_CBRT@ +HAVE_CBRTF = @HAVE_CBRTF@ +HAVE_CBRTL = @HAVE_CBRTL@ HAVE_CHOWN = @HAVE_CHOWN@ HAVE_CLIX = @HAVE_CLIX@ HAVE_CLIX_IN_PATH = @HAVE_CLIX_IN_PATH@ HAVE_CLOSEDIR = @HAVE_CLOSEDIR@ +HAVE_COPYSIGN = @HAVE_COPYSIGN@ +HAVE_COPYSIGNL = @HAVE_COPYSIGNL@ +HAVE_COSF = @HAVE_COSF@ +HAVE_COSHF = @HAVE_COSHF@ +HAVE_COSL = @HAVE_COSL@ HAVE_CSC = @HAVE_CSC@ HAVE_CSCC = @HAVE_CSCC@ HAVE_CSCC_IN_PATH = @HAVE_CSCC_IN_PATH@ HAVE_CSC_IN_PATH = @HAVE_CSC_IN_PATH@ +HAVE_DECL_ACOSL = @HAVE_DECL_ACOSL@ +HAVE_DECL_ASINL = @HAVE_DECL_ASINL@ +HAVE_DECL_ATANL = @HAVE_DECL_ATANL@ +HAVE_DECL_CBRTF = @HAVE_DECL_CBRTF@ +HAVE_DECL_CBRTL = @HAVE_DECL_CBRTL@ +HAVE_DECL_CEILF = @HAVE_DECL_CEILF@ +HAVE_DECL_CEILL = @HAVE_DECL_CEILL@ +HAVE_DECL_COPYSIGNF = @HAVE_DECL_COPYSIGNF@ +HAVE_DECL_COSL = @HAVE_DECL_COSL@ HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_EXP2 = @HAVE_DECL_EXP2@ +HAVE_DECL_EXP2F = @HAVE_DECL_EXP2F@ +HAVE_DECL_EXP2L = @HAVE_DECL_EXP2L@ +HAVE_DECL_EXPL = @HAVE_DECL_EXPL@ +HAVE_DECL_EXPM1L = @HAVE_DECL_EXPM1L@ HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@ HAVE_DECL_FDOPENDIR = @HAVE_DECL_FDOPENDIR@ +HAVE_DECL_FLOORF = @HAVE_DECL_FLOORF@ +HAVE_DECL_FLOORL = @HAVE_DECL_FLOORL@ HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ +HAVE_DECL_FREXPL = @HAVE_DECL_FREXPL@ HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@ HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@ HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ @@ -1164,13 +1334,28 @@ HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@ HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@ +HAVE_DECL_LDEXPL = @HAVE_DECL_LDEXPL@ HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@ +HAVE_DECL_LOG10L = @HAVE_DECL_LOG10L@ +HAVE_DECL_LOG2 = @HAVE_DECL_LOG2@ +HAVE_DECL_LOG2F = @HAVE_DECL_LOG2F@ +HAVE_DECL_LOG2L = @HAVE_DECL_LOG2L@ +HAVE_DECL_LOGB = @HAVE_DECL_LOGB@ +HAVE_DECL_LOGL = @HAVE_DECL_LOGL@ HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ +HAVE_DECL_REMAINDER = @HAVE_DECL_REMAINDER@ +HAVE_DECL_REMAINDERL = @HAVE_DECL_REMAINDERL@ +HAVE_DECL_RINTF = @HAVE_DECL_RINTF@ +HAVE_DECL_ROUND = @HAVE_DECL_ROUND@ +HAVE_DECL_ROUNDF = @HAVE_DECL_ROUNDF@ +HAVE_DECL_ROUNDL = @HAVE_DECL_ROUNDL@ HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ +HAVE_DECL_SINL = @HAVE_DECL_SINL@ HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ +HAVE_DECL_SQRTL = @HAVE_DECL_SQRTL@ HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@ HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@ @@ -1179,6 +1364,10 @@ HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@ HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@ HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@ +HAVE_DECL_TANL = @HAVE_DECL_TANL@ +HAVE_DECL_TRUNC = @HAVE_DECL_TRUNC@ +HAVE_DECL_TRUNCF = @HAVE_DECL_TRUNCF@ +HAVE_DECL_TRUNCL = @HAVE_DECL_TRUNCL@ HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@ HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@ HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ @@ -1190,6 +1379,12 @@ HAVE_DUP2 = @HAVE_DUP2@ HAVE_DUP3 = @HAVE_DUP3@ HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_EXPF = @HAVE_EXPF@ +HAVE_EXPL = @HAVE_EXPL@ +HAVE_EXPM1 = @HAVE_EXPM1@ +HAVE_EXPM1F = @HAVE_EXPM1F@ +HAVE_FABSF = @HAVE_FABSF@ +HAVE_FABSL = @HAVE_FABSL@ HAVE_FACCESSAT = @HAVE_FACCESSAT@ HAVE_FCHDIR = @HAVE_FCHDIR@ HAVE_FCHMODAT = @HAVE_FCHMODAT@ @@ -1200,6 +1395,12 @@ HAVE_FDOPENDIR = @HAVE_FDOPENDIR@ HAVE_FEATURES_H = @HAVE_FEATURES_H@ HAVE_FFSL = @HAVE_FFSL@ HAVE_FFSLL = @HAVE_FFSLL@ +HAVE_FMA = @HAVE_FMA@ +HAVE_FMAF = @HAVE_FMAF@ +HAVE_FMAL = @HAVE_FMAL@ +HAVE_FMODF = @HAVE_FMODF@ +HAVE_FMODL = @HAVE_FMODL@ +HAVE_FREXPF = @HAVE_FREXPF@ HAVE_FSEEKO = @HAVE_FSEEKO@ HAVE_FSTATAT = @HAVE_FSTATAT@ HAVE_FSYNC = @HAVE_FSYNC@ @@ -1222,9 +1423,18 @@ HAVE_GIJ_IN_PATH = @HAVE_GIJ_IN_PATH@ HAVE_GLOBAL_SYMBOL_PIPE = @HAVE_GLOBAL_SYMBOL_PIPE@ HAVE_GRANTPT = @HAVE_GRANTPT@ HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@ +HAVE_HYPOTF = @HAVE_HYPOTF@ +HAVE_HYPOTL = @HAVE_HYPOTL@ +HAVE_ILOGB = @HAVE_ILOGB@ +HAVE_ILOGBF = @HAVE_ILOGBF@ +HAVE_ILOGBL = @HAVE_ILOGBL@ HAVE_ILRUN = @HAVE_ILRUN@ HAVE_ILRUN_IN_PATH = @HAVE_ILRUN_IN_PATH@ HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISBLANK = @HAVE_ISBLANK@ +HAVE_ISNAND = @HAVE_ISNAND@ +HAVE_ISNANF = @HAVE_ISNANF@ +HAVE_ISNANL = @HAVE_ISNANL@ HAVE_ISWBLANK = @HAVE_ISWBLANK@ HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ HAVE_JAVA = @HAVE_JAVA@ @@ -1246,12 +1456,22 @@ HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@ HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@ HAVE_LCHMOD = @HAVE_LCHMOD@ HAVE_LCHOWN = @HAVE_LCHOWN@ -HAVE_LIBEXPAT = @HAVE_LIBEXPAT@ +HAVE_LDEXPF = @HAVE_LDEXPF@ HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ HAVE_LINK = @HAVE_LINK@ HAVE_LINKAT = @HAVE_LINKAT@ +HAVE_LOG10F = @HAVE_LOG10F@ +HAVE_LOG10L = @HAVE_LOG10L@ +HAVE_LOG1P = @HAVE_LOG1P@ +HAVE_LOG1PF = @HAVE_LOG1PF@ +HAVE_LOG1PL = @HAVE_LOG1PL@ +HAVE_LOGBF = @HAVE_LOGBF@ +HAVE_LOGBL = @HAVE_LOGBL@ +HAVE_LOGF = @HAVE_LOGF@ +HAVE_LOGL = @HAVE_LOGL@ HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@ HAVE_LSTAT = @HAVE_LSTAT@ +HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ HAVE_MBRLEN = @HAVE_MBRLEN@ HAVE_MBRTOWC = @HAVE_MBRTOWC@ HAVE_MBSINIT = @HAVE_MBSINIT@ @@ -1272,6 +1492,8 @@ HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ HAVE_MKSTEMP = @HAVE_MKSTEMP@ HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ +HAVE_MODFF = @HAVE_MODFF@ +HAVE_MODFL = @HAVE_MODFL@ HAVE_MONO = @HAVE_MONO@ HAVE_MONO_IN_PATH = @HAVE_MONO_IN_PATH@ HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@ @@ -1291,6 +1513,7 @@ HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@ HAVE_POSIX_SPAWN = @HAVE_POSIX_SPAWN@ HAVE_POSIX_SPAWNATTR_T = @HAVE_POSIX_SPAWNATTR_T@ HAVE_POSIX_SPAWN_FILE_ACTIONS_T = @HAVE_POSIX_SPAWN_FILE_ACTIONS_T@ +HAVE_POWF = @HAVE_POWF@ HAVE_PREAD = @HAVE_PREAD@ HAVE_PSELECT = @HAVE_PSELECT@ HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@ @@ -1306,9 +1529,14 @@ HAVE_READDIR = @HAVE_READDIR@ HAVE_READLINK = @HAVE_READLINK@ HAVE_READLINKAT = @HAVE_READLINKAT@ HAVE_REALPATH = @HAVE_REALPATH@ +HAVE_REMAINDER = @HAVE_REMAINDER@ +HAVE_REMAINDERF = @HAVE_REMAINDERF@ HAVE_RENAMEAT = @HAVE_RENAMEAT@ HAVE_REWINDDIR = @HAVE_REWINDDIR@ +HAVE_RINT = @HAVE_RINT@ +HAVE_RINTL = @HAVE_RINTL@ HAVE_RPMATCH = @HAVE_RPMATCH@ +HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = @HAVE_SAME_LONG_DOUBLE_AS_DOUBLE@ HAVE_SCANDIR = @HAVE_SCANDIR@ HAVE_SCHED_H = @HAVE_SCHED_H@ HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@ @@ -1321,9 +1549,14 @@ HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@ HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@ HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ HAVE_SIGSET_T = @HAVE_SIGSET_T@ +HAVE_SINF = @HAVE_SINF@ +HAVE_SINHF = @HAVE_SINHF@ +HAVE_SINL = @HAVE_SINL@ HAVE_SLEEP = @HAVE_SLEEP@ HAVE_SNPRINTF = @HAVE_SNPRINTF@ HAVE_SPAWN_H = @HAVE_SPAWN_H@ +HAVE_SQRTF = @HAVE_SQRTF@ +HAVE_SQRTL = @HAVE_SQRTL@ HAVE_STDINT_H = @HAVE_STDINT_H@ HAVE_STPCPY = @HAVE_STPCPY@ HAVE_STPNCPY = @HAVE_STPNCPY@ @@ -1349,7 +1582,11 @@ HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@ HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@ HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@ HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ +HAVE_TANF = @HAVE_TANF@ +HAVE_TANHF = @HAVE_TANHF@ +HAVE_TANL = @HAVE_TANL@ HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ HAVE_UNISTD_H = @HAVE_UNISTD_H@ HAVE_UNLINKAT = @HAVE_UNLINKAT@ @@ -1425,13 +1662,16 @@ INTLOBJS = @INTLOBJS@ INTL_DEFAULT_VERBOSITY = @INTL_DEFAULT_VERBOSITY@ INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISINF_LIBM = @ISINF_LIBM@ +ISNAND_LIBM = @ISNAND_LIBM@ +ISNANF_LIBM = @ISNANF_LIBM@ +ISNANL_LIBM = @ISNANL_LIBM@ +ISNAN_LIBM = @ISNAN_LIBM@ JAR = @JAR@ JAVA_CHOICE = @JAVA_CHOICE@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCROCO = @LIBCROCO@ -LIBEXPAT = @LIBEXPAT@ -LIBEXPAT_PREFIX = @LIBEXPAT_PREFIX@ LIBGLIB = @LIBGLIB@ LIBGLIB_H = @LIBGLIB_H@ LIBGREP_LIBDEPS = @LIBGREP_LIBDEPS@ @@ -1450,6 +1690,7 @@ LIBTOOL = @LIBTOOL@ LIBUNISTRING = @LIBUNISTRING@ LIBUNISTRING_PREFIX = @LIBUNISTRING_PREFIX@ LIBUNISTRING_UNICONV_H = @LIBUNISTRING_UNICONV_H@ +LIBUNISTRING_UNICTYPE_H = @LIBUNISTRING_UNICTYPE_H@ LIBUNISTRING_UNILBRK_H = @LIBUNISTRING_UNILBRK_H@ LIBUNISTRING_UNINAME_H = @LIBUNISTRING_UNINAME_H@ LIBUNISTRING_UNISTR_H = @LIBUNISTRING_UNISTR_H@ @@ -1458,6 +1699,7 @@ LIBUNISTRING_UNIWIDTH_H = @LIBUNISTRING_UNIWIDTH_H@ LIBXML = @LIBXML@ LIBXML_H = @LIBXML_H@ LIB_ACL = @LIB_ACL@ +LIB_HAS_ACL = @LIB_HAS_ACL@ LIB_POSIX_SPAWN = @LIB_POSIX_SPAWN@ LIPO = @LIPO@ LN_S = @LN_S@ @@ -1467,9 +1709,9 @@ LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ LOCALE_JA = @LOCALE_JA@ LOCALE_TR_UTF8 = @LOCALE_TR_UTF8@ LOCALE_ZH_CN = @LOCALE_ZH_CN@ +LOG10_LIBM = @LOG10_LIBM@ LTLIBC = @LTLIBC@ LTLIBCROCO = @LTLIBCROCO@ -LTLIBEXPAT = @LTLIBEXPAT@ LTLIBGLIB = @LTLIBGLIB@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ @@ -1480,6 +1722,7 @@ LTLIBTERMINFO = @LTLIBTERMINFO@ LTLIBTHREAD = @LTLIBTHREAD@ LTLIBUNISTRING = @LTLIBUNISTRING@ LTLIBXML = @LTLIBXML@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ @@ -1489,6 +1732,7 @@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ MSGMERGE_LIBM = @MSGMERGE_LIBM@ +NEXT_AS_FIRST_DIRECTIVE_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@ NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@ NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ @@ -1498,6 +1742,7 @@ NEXT_AS_FIRST_DIRECTIVE_ICONV_H = @NEXT_AS_FIRST_DIRECTIVE_ICONV_H@ NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@ NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@ NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@ +NEXT_AS_FIRST_DIRECTIVE_MATH_H = @NEXT_AS_FIRST_DIRECTIVE_MATH_H@ NEXT_AS_FIRST_DIRECTIVE_SCHED_H = @NEXT_AS_FIRST_DIRECTIVE_SCHED_H@ NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@ NEXT_AS_FIRST_DIRECTIVE_SPAWN_H = @NEXT_AS_FIRST_DIRECTIVE_SPAWN_H@ @@ -1516,6 +1761,7 @@ NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@ NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ +NEXT_CTYPE_H = @NEXT_CTYPE_H@ NEXT_DIRENT_H = @NEXT_DIRENT_H@ NEXT_ERRNO_H = @NEXT_ERRNO_H@ NEXT_FCNTL_H = @NEXT_FCNTL_H@ @@ -1525,6 +1771,7 @@ NEXT_ICONV_H = @NEXT_ICONV_H@ NEXT_INTTYPES_H = @NEXT_INTTYPES_H@ NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ NEXT_LOCALE_H = @NEXT_LOCALE_H@ +NEXT_MATH_H = @NEXT_MATH_H@ NEXT_SCHED_H = @NEXT_SCHED_H@ NEXT_SIGNAL_H = @NEXT_SIGNAL_H@ NEXT_SPAWN_H = @NEXT_SPAWN_H@ @@ -1555,12 +1802,14 @@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_SUFFIX = @PACKAGE_SUFFIX@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ POSUB = @POSUB@ +POW_LIBM = @POW_LIBM@ PRAGMA_COLUMNS = @PRAGMA_COLUMNS@ PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ PRIPTR_PREFIX = @PRIPTR_PREFIX@ @@ -1581,6 +1830,11 @@ RELOCATABLE_STRIP = : REPLACE_BTOWC = @REPLACE_BTOWC@ REPLACE_CALLOC = @REPLACE_CALLOC@ REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CBRTF = @REPLACE_CBRTF@ +REPLACE_CBRTL = @REPLACE_CBRTL@ +REPLACE_CEIL = @REPLACE_CEIL@ +REPLACE_CEILF = @REPLACE_CEILF@ +REPLACE_CEILL = @REPLACE_CEILL@ REPLACE_CHOWN = @REPLACE_CHOWN@ REPLACE_CLOSE = @REPLACE_CLOSE@ REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@ @@ -1589,16 +1843,33 @@ REPLACE_DPRINTF = @REPLACE_DPRINTF@ REPLACE_DUP = @REPLACE_DUP@ REPLACE_DUP2 = @REPLACE_DUP2@ REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@ +REPLACE_EXP2 = @REPLACE_EXP2@ +REPLACE_EXP2L = @REPLACE_EXP2L@ +REPLACE_EXPM1 = @REPLACE_EXPM1@ +REPLACE_EXPM1F = @REPLACE_EXPM1F@ +REPLACE_FABSL = @REPLACE_FABSL@ REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ REPLACE_FCLOSE = @REPLACE_FCLOSE@ REPLACE_FCNTL = @REPLACE_FCNTL@ REPLACE_FDOPEN = @REPLACE_FDOPEN@ REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@ REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FLOOR = @REPLACE_FLOOR@ +REPLACE_FLOORF = @REPLACE_FLOORF@ +REPLACE_FLOORL = @REPLACE_FLOORL@ +REPLACE_FMA = @REPLACE_FMA@ +REPLACE_FMAF = @REPLACE_FMAF@ +REPLACE_FMAL = @REPLACE_FMAL@ +REPLACE_FMOD = @REPLACE_FMOD@ +REPLACE_FMODF = @REPLACE_FMODF@ +REPLACE_FMODL = @REPLACE_FMODL@ REPLACE_FOPEN = @REPLACE_FOPEN@ REPLACE_FPRINTF = @REPLACE_FPRINTF@ REPLACE_FPURGE = @REPLACE_FPURGE@ REPLACE_FREOPEN = @REPLACE_FREOPEN@ +REPLACE_FREXP = @REPLACE_FREXP@ +REPLACE_FREXPF = @REPLACE_FREXPF@ +REPLACE_FREXPL = @REPLACE_FREXPL@ REPLACE_FSEEK = @REPLACE_FSEEK@ REPLACE_FSEEKO = @REPLACE_FSEEKO@ REPLACE_FSTAT = @REPLACE_FSTAT@ @@ -1617,19 +1888,44 @@ REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@ REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ REPLACE_GMTIME = @REPLACE_GMTIME@ +REPLACE_HUGE_VAL = @REPLACE_HUGE_VAL@ +REPLACE_HYPOT = @REPLACE_HYPOT@ +REPLACE_HYPOTF = @REPLACE_HYPOTF@ +REPLACE_HYPOTL = @REPLACE_HYPOTL@ REPLACE_ICONV = @REPLACE_ICONV@ REPLACE_ICONV_OPEN = @REPLACE_ICONV_OPEN@ REPLACE_ICONV_UTF = @REPLACE_ICONV_UTF@ +REPLACE_ILOGB = @REPLACE_ILOGB@ +REPLACE_ILOGBF = @REPLACE_ILOGBF@ REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISFINITE = @REPLACE_ISFINITE@ +REPLACE_ISINF = @REPLACE_ISINF@ +REPLACE_ISNAN = @REPLACE_ISNAN@ REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ REPLACE_ITOLD = @REPLACE_ITOLD@ REPLACE_LCHOWN = @REPLACE_LCHOWN@ +REPLACE_LDEXPL = @REPLACE_LDEXPL@ REPLACE_LINK = @REPLACE_LINK@ REPLACE_LINKAT = @REPLACE_LINKAT@ REPLACE_LOCALECONV = @REPLACE_LOCALECONV@ REPLACE_LOCALTIME = @REPLACE_LOCALTIME@ REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@ +REPLACE_LOG = @REPLACE_LOG@ +REPLACE_LOG10 = @REPLACE_LOG10@ +REPLACE_LOG10F = @REPLACE_LOG10F@ +REPLACE_LOG10L = @REPLACE_LOG10L@ +REPLACE_LOG1P = @REPLACE_LOG1P@ +REPLACE_LOG1PF = @REPLACE_LOG1PF@ +REPLACE_LOG1PL = @REPLACE_LOG1PL@ +REPLACE_LOG2 = @REPLACE_LOG2@ +REPLACE_LOG2F = @REPLACE_LOG2F@ +REPLACE_LOG2L = @REPLACE_LOG2L@ +REPLACE_LOGB = @REPLACE_LOGB@ +REPLACE_LOGBF = @REPLACE_LOGBF@ +REPLACE_LOGBL = @REPLACE_LOGBL@ +REPLACE_LOGF = @REPLACE_LOGF@ +REPLACE_LOGL = @REPLACE_LOGL@ REPLACE_LSEEK = @REPLACE_LSEEK@ REPLACE_LSTAT = @REPLACE_LSTAT@ REPLACE_MALLOC = @REPLACE_MALLOC@ @@ -1647,6 +1943,10 @@ REPLACE_MKFIFO = @REPLACE_MKFIFO@ REPLACE_MKNOD = @REPLACE_MKNOD@ REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ REPLACE_MKTIME = @REPLACE_MKTIME@ +REPLACE_MODF = @REPLACE_MODF@ +REPLACE_MODFF = @REPLACE_MODFF@ +REPLACE_MODFL = @REPLACE_MODFL@ +REPLACE_NAN = @REPLACE_NAN@ REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ REPLACE_NULL = @REPLACE_NULL@ @@ -1676,16 +1976,25 @@ REPLACE_READLINK = @REPLACE_READLINK@ REPLACE_READLINKAT = @REPLACE_READLINKAT@ REPLACE_REALLOC = @REPLACE_REALLOC@ REPLACE_REALPATH = @REPLACE_REALPATH@ +REPLACE_REMAINDER = @REPLACE_REMAINDER@ +REPLACE_REMAINDERF = @REPLACE_REMAINDERF@ +REPLACE_REMAINDERL = @REPLACE_REMAINDERL@ REPLACE_REMOVE = @REPLACE_REMOVE@ REPLACE_RENAME = @REPLACE_RENAME@ REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ REPLACE_RMDIR = @REPLACE_RMDIR@ +REPLACE_ROUND = @REPLACE_ROUND@ +REPLACE_ROUNDF = @REPLACE_ROUNDF@ +REPLACE_ROUNDL = @REPLACE_ROUNDL@ REPLACE_SELECT = @REPLACE_SELECT@ REPLACE_SETENV = @REPLACE_SETENV@ REPLACE_SETLOCALE = @REPLACE_SETLOCALE@ +REPLACE_SIGNBIT = @REPLACE_SIGNBIT@ +REPLACE_SIGNBIT_USING_GCC = @REPLACE_SIGNBIT_USING_GCC@ REPLACE_SLEEP = @REPLACE_SLEEP@ REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ REPLACE_SPRINTF = @REPLACE_SPRINTF@ +REPLACE_SQRTL = @REPLACE_SQRTL@ REPLACE_STAT = @REPLACE_STAT@ REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@ REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ @@ -1711,6 +2020,9 @@ REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@ REPLACE_TIMEGM = @REPLACE_TIMEGM@ REPLACE_TMPFILE = @REPLACE_TMPFILE@ REPLACE_TOWLOWER = @REPLACE_TOWLOWER@ +REPLACE_TRUNC = @REPLACE_TRUNC@ +REPLACE_TRUNCF = @REPLACE_TRUNCF@ +REPLACE_TRUNCL = @REPLACE_TRUNCL@ REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ REPLACE_UNLINK = @REPLACE_UNLINK@ REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ @@ -1737,6 +2049,7 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ +STDALIGN_H = @STDALIGN_H@ STDARG_H = @STDARG_H@ STDBOOL_H = @STDBOOL_H@ STDDEF_H = @STDDEF_H@ @@ -1751,6 +2064,7 @@ TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@ UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@ UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ USE_ACL = @USE_ACL@ @@ -1847,9 +2161,8 @@ AUTOMAKE_OPTIONS = 1.5 gnits no-dependencies subdir-objects # Special rules for C# auxiliary programs. # Special rules for Tcl auxiliary program. -EXTRA_DIST = FILES project-id ChangeLog.0 \ - gnu/gettext/DumpResource.java gnu/gettext/GetURL.java \ - msgfmt.cs msgunfmt.cs msgunfmt.tcl +EXTRA_DIST = FILES project-id gnu/gettext/DumpResource.java \ + gnu/gettext/GetURL.java msgfmt.cs msgunfmt.cs msgunfmt.tcl MOSTLYCLEANFILES = core *.stackdump $(am__append_4) CLEANFILES = gnu.gettext.DumpResource$(EXEEXT) \ gnu.gettext.GetURL$(EXEEXT) gettext.jar gnu/gettext/*.class \ @@ -1863,7 +2176,8 @@ po-lex.h open-catalog.h read-catalog-abstract.h read-catalog.h \ read-po.h read-properties.h read-stringtable.h \ str-list.h \ color.h write-catalog.h write-po.h write-properties.h write-stringtable.h \ -dir-list.h file-list.h po-gram-gen.h po-gram-gen2.h \ +dir-list.h file-list.h po-gram-gen.h po-gram-gen2.h cldr-plural.h \ +cldr-plural-exp.h locating-rule.h its.h \ msgl-charset.h msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-header.h \ msgl-english.h msgl-check.h msgl-fsearch.h msgfmt.h msgunfmt.h \ plural-count.h plural-eval.h plural-distrib.h \ @@ -1874,11 +2188,12 @@ read-resources.h write-resources.h \ read-tcl.h write-tcl.h \ write-qt.h \ read-desktop.h write-desktop.h \ +write-xml.h \ po-time.h plural-table.h lang-table.h format.h filters.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-scheme.h x-smalltalk.h x-java.h x-properties.h x-csharp.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 x-lua.h \ -x-javascript.h x-vala.h x-gsettings.h x-desktop.h libexpat-compat.h +x-javascript.h x-vala.h x-gsettings.h x-desktop.h x-appdata.h aliaspath = $(localedir) jardir = $(datadir)/gettext @@ -1921,7 +2236,7 @@ dir-list.c str-list.c @WOE32DLL_FALSE@ format-perl.c format-perl-brace.c format-php.c \ @WOE32DLL_FALSE@ format-gcc-internal.c format-gfc-internal.c \ @WOE32DLL_FALSE@ format-qt.c format-qt-plural.c format-kde.c \ -@WOE32DLL_FALSE@ format-boost.c format-lua.c \ +@WOE32DLL_FALSE@ format-kde-kuit.c format-boost.c format-lua.c \ @WOE32DLL_FALSE@ format-javascript.c @WOE32DLL_TRUE@FORMAT_SOURCE = ../woe32dll/c++format.cc \ @WOE32DLL_TRUE@ format-invalid.h format-c.c format-c-parse.h \ @@ -1933,7 +2248,8 @@ dir-list.c str-list.c @WOE32DLL_TRUE@ format-perl.c format-perl-brace.c format-php.c \ @WOE32DLL_TRUE@ format-gcc-internal.c format-gfc-internal.c \ @WOE32DLL_TRUE@ format-qt.c format-qt-plural.c format-kde.c \ -@WOE32DLL_TRUE@ format-boost.c format-lua.c format-javascript.c +@WOE32DLL_TRUE@ format-kde-kuit.c format-boost.c format-lua.c \ +@WOE32DLL_TRUE@ format-javascript.c # libgettextsrc contains all code that is needed by at least two programs. libgettextsrc_la_SOURCES = $(COMMON_SOURCE) read-catalog.c color.c \ @@ -1941,7 +2257,8 @@ libgettextsrc_la_SOURCES = $(COMMON_SOURCE) read-catalog.c color.c \ write-po.c msgl-ascii.c msgl-iconv.c msgl-equal.c msgl-cat.c \ msgl-header.c msgl-english.c msgl-check.c file-list.c \ msgl-charset.c po-time.c plural-exp.c plural-eval.c \ - plural-table.c $(FORMAT_SOURCE) read-desktop.c $(am__append_1) + plural-table.c quote.h sentence.h sentence.c $(FORMAT_SOURCE) \ + read-desktop.c locating-rule.c its.c $(am__append_1) # msggrep needs pattern matching. LIBGREP = ../libgrep/libgrep.a @@ -1950,7 +2267,7 @@ LIBGREP = ../libgrep/libgrep.a msgcmp_SOURCES = msgcmp.c msgl-fsearch.c msgfmt_SOURCES = msgfmt.c write-mo.c write-java.c write-csharp.c \ write-resources.c write-tcl.c write-qt.c write-desktop.c \ - ../../gettext-runtime/intl/hash-string.c + write-xml.c ../../gettext-runtime/intl/hash-string.c @WOE32DLL_FALSE@msgmerge_SOURCES = msgmerge.c msgl-fsearch.c \ @WOE32DLL_FALSE@ lang-table.c plural-count.c @WOE32DLL_TRUE@msgmerge_SOURCES = ../woe32dll/c++msgmerge.cc \ @@ -1961,16 +2278,14 @@ msgunfmt_SOURCES = msgunfmt.c read-mo.c read-java.c read-csharp.c \ @WOE32DLL_FALSE@ x-python.c x-lisp.c x-elisp.c x-librep.c \ @WOE32DLL_FALSE@ x-scheme.c x-smalltalk.c x-java.c x-csharp.c \ @WOE32DLL_FALSE@ x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \ -@WOE32DLL_FALSE@ x-rst.c x-glade.c x-lua.c x-javascript.c \ -@WOE32DLL_FALSE@ x-vala.c x-gsettings.c libexpat-compat.c \ +@WOE32DLL_FALSE@ x-rst.c x-lua.c x-javascript.c x-vala.c \ @WOE32DLL_FALSE@ x-desktop.c @WOE32DLL_TRUE@xgettext_SOURCES = ../woe32dll/c++xgettext.cc x-c.c \ @WOE32DLL_TRUE@ x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c \ @WOE32DLL_TRUE@ x-librep.c x-scheme.c x-smalltalk.c x-java.c \ @WOE32DLL_TRUE@ x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c \ -@WOE32DLL_TRUE@ x-php.c x-rst.c x-glade.c x-lua.c \ -@WOE32DLL_TRUE@ x-javascript.c x-vala.c x-gsettings.c \ -@WOE32DLL_TRUE@ libexpat-compat.c x-desktop.c +@WOE32DLL_TRUE@ x-php.c x-rst.c x-lua.c x-javascript.c x-vala.c \ +@WOE32DLL_TRUE@ x-desktop.c @WOE32DLL_FALSE@msgattrib_SOURCES = msgattrib.c @WOE32DLL_TRUE@msgattrib_SOURCES = ../woe32dll/c++msgattrib.cc @WOE32DLL_FALSE@msgcat_SOURCES = msgcat.c @@ -2000,6 +2315,9 @@ msginit_SOURCES = msginit.c lang-table.c plural-count.c \ recode_sr_latin_SOURCES = recode-sr-latin.c filter-sr-latin.c hostname_SOURCES = hostname.c urlget_SOURCES = urlget.c +cldr_plurals_SOURCES = cldr-plural.y cldr-plural-exp.c cldr-plurals.c +cldr_plurals_CFLAGS = $(AM_CFLAGS) $(INCXML) +cldr_plurals_LDADD = libgettextsrc.la $(LDADD) # How to build libgettextsrc.la. # Need ../gnulib-lib/libgettextlib.la. @@ -2012,7 +2330,7 @@ urlget_SOURCES = urlget.c libgettextsrc_la_LDFLAGS = -release @VERSION@ \ ../gnulib-lib/libgettextlib.la $(LTLIBUNISTRING) @LTLIBINTL@ \ @LTLIBICONV@ -lc -no-undefined $(am__append_2) -libgettextsrc_la_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_3) +libgettextsrc_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCXML) $(am__append_3) # Compile-time flags for particular source files. msgmerge_CFLAGS = $(AM_CFLAGS) $(OPENMP_CFLAGS) @@ -2026,7 +2344,7 @@ msgcmp_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @MSGMERGE_LIBM@ $(WOE32_LDADD msgfmt_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msgmerge_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @MSGMERGE_LIBM@ $(WOE32_LDADD) $(OPENMP_CFLAGS) msgunfmt_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) -xgettext_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @LTLIBEXPAT@ @LTLIBICONV@ $(WOE32_LDADD) +xgettext_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ @LTLIBICONV@ $(WOE32_LDADD) msgattrib_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msgcat_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msgcomm_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) @@ -2077,6 +2395,7 @@ msguniq_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\" recode_sr_latin_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\" hostname_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" urlget_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" +cldr_plurals_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" @RELOCATABLE_VIA_LD_TRUE@msgcmp_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` @RELOCATABLE_VIA_LD_TRUE@msgfmt_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` @RELOCATABLE_VIA_LD_TRUE@msgmerge_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` @@ -2095,6 +2414,7 @@ urlget_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" @RELOCATABLE_VIA_LD_TRUE@recode_sr_latin_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` @RELOCATABLE_VIA_LD_TRUE@hostname_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(pkglibdir)` @RELOCATABLE_VIA_LD_TRUE@urlget_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(pkglibdir)` +@RELOCATABLE_VIA_LD_TRUE@cldr_plurals_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(pkglibdir)` # Linking with C++ libraries is needed _only_ on mingw and Cygwin. @WOE32DLL_FALSE@libgettextsrc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -2210,7 +2530,7 @@ urlget_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(pkglibdir)\" # Special rules for bison and flex generated files. BUILT_SOURCES = \ - po-gram-gen.c po-gram-gen.h po-gram-gen2.h + po-gram-gen.c po-gram-gen.h po-gram-gen2.h cldr-plural.c cldr-plural.h # Special rules for Java compilation. @@ -2243,7 +2563,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnits src/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -2383,6 +2702,10 @@ clean-noinstPROGRAMS: echo " rm -f" $$list; \ rm -f $$list +cldr-plurals$(EXEEXT): $(cldr_plurals_OBJECTS) $(cldr_plurals_DEPENDENCIES) $(EXTRA_cldr_plurals_DEPENDENCIES) + @rm -f cldr-plurals$(EXEEXT) + $(AM_V_CCLD)$(cldr_plurals_LINK) $(cldr_plurals_OBJECTS) $(cldr_plurals_LDADD) $(LIBS) + hostname$(EXEEXT): $(hostname_OBJECTS) $(hostname_DEPENDENCIES) $(EXTRA_hostname_DEPENDENCIES) @rm -f hostname$(EXEEXT) $(AM_V_CCLD)$(hostname_LINK) $(hostname_OBJECTS) $(hostname_LDADD) $(LIBS) @@ -2592,6 +2915,9 @@ libgettextsrc_la-plural-eval.lo: plural-eval.c libgettextsrc_la-plural-table.lo: plural-table.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-plural-table.lo `test -f 'plural-table.c' || echo '$(srcdir)/'`plural-table.c +libgettextsrc_la-sentence.lo: sentence.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-sentence.lo `test -f 'sentence.c' || echo '$(srcdir)/'`sentence.c + libgettextsrc_la-format.lo: format.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-format.lo `test -f 'format.c' || echo '$(srcdir)/'`format.c @@ -2661,6 +2987,9 @@ libgettextsrc_la-format-qt-plural.lo: format-qt-plural.c libgettextsrc_la-format-kde.lo: format-kde.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-format-kde.lo `test -f 'format-kde.c' || echo '$(srcdir)/'`format-kde.c +libgettextsrc_la-format-kde-kuit.lo: format-kde-kuit.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-format-kde-kuit.lo `test -f 'format-kde-kuit.c' || echo '$(srcdir)/'`format-kde-kuit.c + libgettextsrc_la-format-boost.lo: format-boost.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-format-boost.lo `test -f 'format-boost.c' || echo '$(srcdir)/'`format-boost.c @@ -2673,9 +3002,33 @@ libgettextsrc_la-format-javascript.lo: format-javascript.c libgettextsrc_la-read-desktop.lo: read-desktop.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-read-desktop.lo `test -f 'read-desktop.c' || echo '$(srcdir)/'`read-desktop.c +libgettextsrc_la-locating-rule.lo: locating-rule.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-locating-rule.lo `test -f 'locating-rule.c' || echo '$(srcdir)/'`locating-rule.c + +libgettextsrc_la-its.lo: its.c + $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgettextsrc_la-its.lo `test -f 'its.c' || echo '$(srcdir)/'`its.c + ../woe32dll/libgettextsrc_la-gettextsrc-exports.lo: ../woe32dll/gettextsrc-exports.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgettextsrc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../woe32dll/libgettextsrc_la-gettextsrc-exports.lo `test -f '../woe32dll/gettextsrc-exports.c' || echo '$(srcdir)/'`../woe32dll/gettextsrc-exports.c +cldr_plurals-cldr-plural.o: cldr-plural.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cldr_plurals_CPPFLAGS) $(CPPFLAGS) $(cldr_plurals_CFLAGS) $(CFLAGS) -c -o cldr_plurals-cldr-plural.o `test -f 'cldr-plural.c' || echo '$(srcdir)/'`cldr-plural.c + +cldr_plurals-cldr-plural.obj: cldr-plural.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cldr_plurals_CPPFLAGS) $(CPPFLAGS) $(cldr_plurals_CFLAGS) $(CFLAGS) -c -o cldr_plurals-cldr-plural.obj `if test -f 'cldr-plural.c'; then $(CYGPATH_W) 'cldr-plural.c'; else $(CYGPATH_W) '$(srcdir)/cldr-plural.c'; fi` + +cldr_plurals-cldr-plural-exp.o: cldr-plural-exp.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cldr_plurals_CPPFLAGS) $(CPPFLAGS) $(cldr_plurals_CFLAGS) $(CFLAGS) -c -o cldr_plurals-cldr-plural-exp.o `test -f 'cldr-plural-exp.c' || echo '$(srcdir)/'`cldr-plural-exp.c + +cldr_plurals-cldr-plural-exp.obj: cldr-plural-exp.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cldr_plurals_CPPFLAGS) $(CPPFLAGS) $(cldr_plurals_CFLAGS) $(CFLAGS) -c -o cldr_plurals-cldr-plural-exp.obj `if test -f 'cldr-plural-exp.c'; then $(CYGPATH_W) 'cldr-plural-exp.c'; else $(CYGPATH_W) '$(srcdir)/cldr-plural-exp.c'; fi` + +cldr_plurals-cldr-plurals.o: cldr-plurals.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cldr_plurals_CPPFLAGS) $(CPPFLAGS) $(cldr_plurals_CFLAGS) $(CFLAGS) -c -o cldr_plurals-cldr-plurals.o `test -f 'cldr-plurals.c' || echo '$(srcdir)/'`cldr-plurals.c + +cldr_plurals-cldr-plurals.obj: cldr-plurals.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cldr_plurals_CPPFLAGS) $(CPPFLAGS) $(cldr_plurals_CFLAGS) $(CFLAGS) -c -o cldr_plurals-cldr-plurals.obj `if test -f 'cldr-plurals.c'; then $(CYGPATH_W) 'cldr-plurals.c'; else $(CYGPATH_W) '$(srcdir)/cldr-plurals.c'; fi` + hostname-hostname.o: hostname.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(hostname_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hostname-hostname.o `test -f 'hostname.c' || echo '$(srcdir)/'`hostname.c @@ -2796,6 +3149,12 @@ msgfmt-write-desktop.o: write-desktop.c msgfmt-write-desktop.obj: write-desktop.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(msgfmt_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msgfmt-write-desktop.obj `if test -f 'write-desktop.c'; then $(CYGPATH_W) 'write-desktop.c'; else $(CYGPATH_W) '$(srcdir)/write-desktop.c'; fi` +msgfmt-write-xml.o: write-xml.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(msgfmt_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msgfmt-write-xml.o `test -f 'write-xml.c' || echo '$(srcdir)/'`write-xml.c + +msgfmt-write-xml.obj: write-xml.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(msgfmt_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msgfmt-write-xml.obj `if test -f 'write-xml.c'; then $(CYGPATH_W) 'write-xml.c'; else $(CYGPATH_W) '$(srcdir)/write-xml.c'; fi` + ../../gettext-runtime/intl/msgfmt-hash-string.o: ../../gettext-runtime/intl/hash-string.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(msgfmt_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../../gettext-runtime/intl/msgfmt-hash-string.o `test -f '../../gettext-runtime/intl/hash-string.c' || echo '$(srcdir)/'`../../gettext-runtime/intl/hash-string.c @@ -3030,12 +3389,6 @@ xgettext-x-rst.o: x-rst.c xgettext-x-rst.obj: x-rst.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-rst.obj `if test -f 'x-rst.c'; then $(CYGPATH_W) 'x-rst.c'; else $(CYGPATH_W) '$(srcdir)/x-rst.c'; fi` -xgettext-x-glade.o: x-glade.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-glade.o `test -f 'x-glade.c' || echo '$(srcdir)/'`x-glade.c - -xgettext-x-glade.obj: x-glade.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-glade.obj `if test -f 'x-glade.c'; then $(CYGPATH_W) 'x-glade.c'; else $(CYGPATH_W) '$(srcdir)/x-glade.c'; fi` - xgettext-x-lua.o: x-lua.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-lua.o `test -f 'x-lua.c' || echo '$(srcdir)/'`x-lua.c @@ -3054,18 +3407,6 @@ xgettext-x-vala.o: x-vala.c xgettext-x-vala.obj: x-vala.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-vala.obj `if test -f 'x-vala.c'; then $(CYGPATH_W) 'x-vala.c'; else $(CYGPATH_W) '$(srcdir)/x-vala.c'; fi` -xgettext-x-gsettings.o: x-gsettings.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-gsettings.o `test -f 'x-gsettings.c' || echo '$(srcdir)/'`x-gsettings.c - -xgettext-x-gsettings.obj: x-gsettings.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-gsettings.obj `if test -f 'x-gsettings.c'; then $(CYGPATH_W) 'x-gsettings.c'; else $(CYGPATH_W) '$(srcdir)/x-gsettings.c'; fi` - -xgettext-libexpat-compat.o: libexpat-compat.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-libexpat-compat.o `test -f 'libexpat-compat.c' || echo '$(srcdir)/'`libexpat-compat.c - -xgettext-libexpat-compat.obj: libexpat-compat.c - $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-libexpat-compat.obj `if test -f 'libexpat-compat.c'; then $(CYGPATH_W) 'libexpat-compat.c'; else $(CYGPATH_W) '$(srcdir)/libexpat-compat.c'; fi` - xgettext-x-desktop.o: x-desktop.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xgettext_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgettext-x-desktop.o `test -f 'x-desktop.c' || echo '$(srcdir)/'`x-desktop.c @@ -3282,6 +3623,7 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." + -rm -f cldr-plural.c -rm -f po-gram-gen.c -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am @@ -3376,6 +3718,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLTLIBRARIES uninstall-local +.PRECIOUS: Makefile + # No need to install libgettextsrc.a, except on AIX. install-exec-hook: install-exec-clean @@ -3392,6 +3736,7 @@ po-gram-gen2.h: po-gram-gen.h $(SED) -e 's/yy/po_gram_/g' -e 's/extern /extern DLL_VARIABLE /' \ $${srcdir}po-gram-gen.h > $@-tmp && \ mv $@-tmp $@ +po-gram-gen.h: po-gram-gen.c # Special rules for installation of auxiliary programs. @@ -3399,6 +3744,7 @@ install-exec-local: $(MKDIR_P) $(DESTDIR)$(pkglibdir) $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) hostname$(EXEEXT) $(DESTDIR)$(pkglibdir)/hostname$(EXEEXT) $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) urlget$(EXEEXT) $(DESTDIR)$(pkglibdir)/urlget$(EXEEXT) + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) cldr-plurals$(EXEEXT) $(DESTDIR)$(pkglibdir)/cldr-plurals$(EXEEXT) $(INSTALL_SCRIPT) user-email $(DESTDIR)$(pkglibdir)/user-email $(INSTALL_SCRIPT) $(srcdir)/project-id $(DESTDIR)$(pkglibdir)/project-id @@ -3408,6 +3754,7 @@ installdirs-local: uninstall-local: $(RM) $(DESTDIR)$(pkglibdir)/hostname$(EXEEXT) $(RM) $(DESTDIR)$(pkglibdir)/urlget$(EXEEXT) + $(RM) $(DESTDIR)$(pkglibdir)/cldr-plurals$(EXEEXT) $(RM) $(DESTDIR)$(pkglibdir)/user-email $(RM) $(DESTDIR)$(pkglibdir)/project-id diff --git a/gettext-tools/src/cldr-plural-exp.c b/gettext-tools/src/cldr-plural-exp.c new file mode 100644 index 0000000..e55b26d --- /dev/null +++ b/gettext-tools/src/cldr-plural-exp.c @@ -0,0 +1,695 @@ +/* Unicode CLDR plural rule parser and converter + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "unistr.h" +#include "xalloc.h" + +#include "cldr-plural-exp.h" +#include "cldr-plural.h" + +/* The grammar of Unicode CLDR plural rules is defined at: + http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax + + This implementation only supports the "preferred" form, which + doesn't support obsolete keywords "in", "is", "not", and "within". + + Unlike gettext, CLDR allows an unsigned decimal value as an + operand, in addition to unsigned integers. For simplicity, we + treat decimal relations as if it has a constant truth value. + + The implementation is largely based on the idea of Michele Locati's + cldr-to-gettext-plural-rules: + https://github.com/mlocati/cldr-to-gettext-plural-rules */ + +void +cldr_plural_range_free (struct cldr_plural_range_ty *range) +{ + if (range->start != range->end) + free (range->start); + free (range->end); + free (range); +} + +void +cldr_plural_range_list_free (struct cldr_plural_range_list_ty *ranges) +{ + while (ranges->nitems-- > 0) + cldr_plural_range_free (ranges->items[ranges->nitems]); + free (ranges->items); + free (ranges); +} + +void +cldr_plural_condition_free (struct cldr_plural_condition_ty *condition) +{ + if (condition->type == CLDR_PLURAL_CONDITION_AND + || condition->type == CLDR_PLURAL_CONDITION_OR) + { + cldr_plural_condition_free (condition->value.conditions[0]); + cldr_plural_condition_free (condition->value.conditions[1]); + } + else if (condition->type == CLDR_PLURAL_CONDITION_RELATION) + cldr_plural_relation_free (condition->value.relation); + free (condition); +} + +void +cldr_plural_relation_free (struct cldr_plural_relation_ty *relation) +{ + free (relation->expression); + cldr_plural_range_list_free (relation->ranges); + free (relation); +} + +static void +cldr_plural_rule_free (struct cldr_plural_rule_ty *rule) +{ + free (rule->name); + cldr_plural_condition_free (rule->condition); + free (rule); +} + +void +cldr_plural_rule_list_free (struct cldr_plural_rule_list_ty *rules) +{ + while (rules->nitems-- > 0) + cldr_plural_rule_free (rules->items[rules->nitems]); + free (rules->items); + free (rules); +} + +struct cldr_plural_rule_list_ty * +cldr_plural_parse (const char *input) +{ + struct cldr_plural_parse_args arg; + + memset (&arg, 0, sizeof (struct cldr_plural_parse_args)); + arg.cp = input; + arg.cp_end = input + strlen (input); + arg.result = XMALLOC (struct cldr_plural_rule_list_ty); + memset (arg.result, 0, sizeof (struct cldr_plural_rule_list_ty)); + + if (yyparse (&arg) != 0) + return NULL; + + return arg.result; +} + +#define OPERAND_ZERO_P(o) \ + (((o)->type == CLDR_PLURAL_OPERAND_INTEGER \ + && (o)->value.ival == 0) \ + || ((o)->type == CLDR_PLURAL_OPERAND_DECIMAL \ + && (o)->value.dval.d == 0)) + +static enum cldr_plural_condition +eval_relation (struct cldr_plural_relation_ty *relation) +{ + switch (relation->expression->operand) + { + case 'n': case 'i': + { + /* Coerce decimal values in ranges into integers. */ + size_t i; + for (i = 0; i < relation->ranges->nitems; i++) + { + struct cldr_plural_range_ty *range = relation->ranges->items[i]; + if (range->start->type == CLDR_PLURAL_OPERAND_DECIMAL) + { + int truncated = (int) range->start->value.dval.d; + range->start->type = CLDR_PLURAL_OPERAND_INTEGER; + range->start->value.ival + = range->start->value.dval.d == truncated + ? truncated : truncated + 1; + } + if (range->end->type == CLDR_PLURAL_OPERAND_DECIMAL) + { + range->end->type = CLDR_PLURAL_OPERAND_INTEGER; + range->end->value.ival = (int) (range->end->value.dval.d); + } + } + relation->expression->operand = 'i'; + } + break; + case 'f': case 't': + case 'v': case 'w': + { + /* Since plural expression in gettext only supports unsigned + integer, turn relations whose operand is either 'f', 't', + 'v', or 'w' into a constant truth value. */ + /* FIXME: check mod? */ + size_t i; + for (i = 0; i < relation->ranges->nitems; i++) + { + struct cldr_plural_range_ty *range = relation->ranges->items[i]; + if ((relation->type == CLDR_PLURAL_RELATION_EQUAL + && (!OPERAND_ZERO_P (range->start) + || !OPERAND_ZERO_P (range->end))) + || (relation->type == CLDR_PLURAL_RELATION_NOT_EQUAL + && (OPERAND_ZERO_P (range->start) + || OPERAND_ZERO_P (range->end)))) + return CLDR_PLURAL_CONDITION_FALSE; + } + return CLDR_PLURAL_CONDITION_TRUE; + } + break; + } + return CLDR_PLURAL_CONDITION_RELATION; +} + +static void +eval_condition (struct cldr_plural_condition_ty *condition) +{ + if (condition->type == CLDR_PLURAL_CONDITION_AND) + { + eval_condition (condition->value.conditions[0]); + eval_condition (condition->value.conditions[1]); + + if (condition->value.conditions[0]->type + == CLDR_PLURAL_CONDITION_FALSE + || condition->value.conditions[1]->type + == CLDR_PLURAL_CONDITION_FALSE) + { + cldr_plural_condition_free (condition->value.conditions[0]); + cldr_plural_condition_free (condition->value.conditions[1]); + condition->type = CLDR_PLURAL_CONDITION_FALSE; + } + else if (condition->value.conditions[0]->type + == CLDR_PLURAL_CONDITION_TRUE + && condition->value.conditions[1]->type + == CLDR_PLURAL_CONDITION_TRUE) + { + cldr_plural_condition_free (condition->value.conditions[0]); + cldr_plural_condition_free (condition->value.conditions[1]); + condition->type = CLDR_PLURAL_CONDITION_TRUE; + } + else if (condition->value.conditions[0]->type + == CLDR_PLURAL_CONDITION_TRUE) + { + struct cldr_plural_condition_ty *original + = condition->value.conditions[1]; + cldr_plural_condition_free (condition->value.conditions[0]); + condition->type = condition->value.conditions[1]->type; + condition->value = condition->value.conditions[1]->value; + free (original); + } + else if (condition->value.conditions[1]->type + == CLDR_PLURAL_CONDITION_TRUE) + { + struct cldr_plural_condition_ty *original + = condition->value.conditions[0]; + cldr_plural_condition_free (condition->value.conditions[1]); + condition->type = condition->value.conditions[0]->type; + condition->value = condition->value.conditions[0]->value; + free (original); + } + } + else if (condition->type == CLDR_PLURAL_CONDITION_OR) + { + eval_condition (condition->value.conditions[0]); + eval_condition (condition->value.conditions[1]); + + if (condition->value.conditions[0]->type + == CLDR_PLURAL_CONDITION_TRUE + || condition->value.conditions[1]->type + == CLDR_PLURAL_CONDITION_TRUE) + { + cldr_plural_condition_free (condition->value.conditions[0]); + cldr_plural_condition_free (condition->value.conditions[1]); + condition->type = CLDR_PLURAL_CONDITION_TRUE; + } + else if (condition->value.conditions[0]->type + == CLDR_PLURAL_CONDITION_FALSE + && condition->value.conditions[1]->type + == CLDR_PLURAL_CONDITION_FALSE) + { + cldr_plural_condition_free (condition->value.conditions[0]); + cldr_plural_condition_free (condition->value.conditions[1]); + condition->type = CLDR_PLURAL_CONDITION_FALSE; + } + else if (condition->value.conditions[0]->type + == CLDR_PLURAL_CONDITION_FALSE) + { + struct cldr_plural_condition_ty *original + = condition->value.conditions[1]; + cldr_plural_condition_free (condition->value.conditions[0]); + condition->type = condition->value.conditions[1]->type; + condition->value = condition->value.conditions[1]->value; + free (original); + } + else if (condition->value.conditions[1]->type + == CLDR_PLURAL_CONDITION_FALSE) + { + struct cldr_plural_condition_ty *original + = condition->value.conditions[0]; + cldr_plural_condition_free (condition->value.conditions[1]); + condition->type = condition->value.conditions[0]->type; + condition->value = condition->value.conditions[0]->value; + free (original); + } + } + else + { + enum cldr_plural_condition value = + eval_relation (condition->value.relation); + if (value == CLDR_PLURAL_CONDITION_TRUE + || value == CLDR_PLURAL_CONDITION_FALSE) + { + cldr_plural_relation_free (condition->value.relation); + condition->type = value; + } + } +} + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +static int +find_largest_modulus (struct cldr_plural_condition_ty *condition) +{ + if (condition->type == CLDR_PLURAL_CONDITION_AND + || condition->type == CLDR_PLURAL_CONDITION_OR) + { + int modulus0 = + find_largest_modulus (condition->value.conditions[0]); + int modulus1 = + find_largest_modulus (condition->value.conditions[1]); + return MAX (modulus0, modulus1); + } + else if (condition->type == CLDR_PLURAL_CONDITION_RELATION) + return condition->value.relation->expression->mod; + else + return 0; +} + +static int +find_largest_number (struct cldr_plural_condition_ty *condition) +{ + if (condition->type == CLDR_PLURAL_CONDITION_AND + || condition->type == CLDR_PLURAL_CONDITION_OR) + { + int number0 = + find_largest_number (condition->value.conditions[0]); + int number1 = + find_largest_number (condition->value.conditions[1]); + return MAX (number0, number1); + } + else if (condition->type == CLDR_PLURAL_CONDITION_RELATION) + { + int number = 0; + size_t i; + for (i = 0; i < condition->value.relation->ranges->nitems; i++) + { + struct cldr_plural_operand_ty *operand; + + operand = condition->value.relation->ranges->items[i]->end; + if (operand->type == CLDR_PLURAL_OPERAND_INTEGER + && operand->value.ival > number) + number = operand->value.ival; + else if (operand->type == CLDR_PLURAL_OPERAND_DECIMAL + && operand->value.dval.d > number) + number = (int) operand->value.dval.d; + } + return number; + } + else + return 0; +} + +static bool +apply_condition (struct cldr_plural_condition_ty *condition, int value) +{ + if (condition->type == CLDR_PLURAL_CONDITION_AND) + return apply_condition (condition->value.conditions[0], value) + && apply_condition (condition->value.conditions[1], value); + else if (condition->type == CLDR_PLURAL_CONDITION_OR) + return apply_condition (condition->value.conditions[0], value) + || apply_condition (condition->value.conditions[1], value); + else if (condition->type == CLDR_PLURAL_CONDITION_RELATION) + { + struct cldr_plural_relation_ty *relation + = condition->value.relation; + int number = value; + size_t i; + + if (relation->expression->mod > 0) + number %= relation->expression->mod; + for (i = 0; i < relation->ranges->nitems; i++) + { + struct cldr_plural_range_ty *range = relation->ranges->items[i]; + if (range->start->value.ival <= number + && number <= range->end->value.ival) + return relation->type == CLDR_PLURAL_RELATION_EQUAL; + } + return relation->type != CLDR_PLURAL_RELATION_EQUAL; + } + return false; +} + +static void +print_expression (struct cldr_plural_expression_ty *expression, bool space, + FILE *fp) +{ + if (expression->mod == 0) + fprintf (fp, "n"); + else + fprintf (fp, space ? "n %% %d" : "n%%%d", expression->mod); +} + +static void +print_relation (struct cldr_plural_relation_ty *relation, + enum cldr_plural_condition parent, bool space, + FILE *fp) +{ + if (relation->type == CLDR_PLURAL_RELATION_EQUAL) + { + size_t i; + if (parent == CLDR_PLURAL_CONDITION_AND + && relation->ranges->nitems > 1) + fputc ('(', fp); + for (i = 0; i < relation->ranges->nitems; i++) + { + struct cldr_plural_range_ty *range = relation->ranges->items[i]; + if (i > 0) + fprintf (fp, " || "); + if (range->start->value.ival == range->end->value.ival) + { + print_expression (relation->expression, space, fp); + fprintf (fp, + space && relation->ranges->nitems == 1 + ? " == %d" : "==%d", + range->start->value.ival); + } + else if (range->start->value.ival == 0) + { + print_expression (relation->expression, false, fp); + fprintf (fp, "<=%d", range->end->value.ival); + } + else + { + if (parent == CLDR_PLURAL_CONDITION_OR + || relation->ranges->nitems > 1) + fputc ('(', fp); + print_expression (relation->expression, false, fp); + fprintf (fp, ">=%d", range->start->value.ival); + fprintf (fp, " && "); + print_expression (relation->expression, false, fp); + fprintf (fp, "<=%d", range->end->value.ival); + if (parent == CLDR_PLURAL_CONDITION_OR + || relation->ranges->nitems > 1) + fputc (')', fp); + } + } + if (parent == CLDR_PLURAL_CONDITION_AND + && relation->ranges->nitems > 1) + fputc (')', fp); + } + else + { + size_t i; + if (parent == CLDR_PLURAL_CONDITION_OR + && relation->ranges->nitems > 1) + fputc ('(', fp); + for (i = 0; i < relation->ranges->nitems; i++) + { + struct cldr_plural_range_ty *range = relation->ranges->items[i]; + if (i > 0) + fprintf (fp," && "); + if (range->start->value.ival == range->end->value.ival) + { + print_expression (relation->expression, space, fp); + fprintf (fp, space && relation->ranges->nitems == 1 + ? " != %d" : "!=%d", range->start->value.ival); + } + else if (range->start->value.ival == 0) + { + print_expression (relation->expression, false, fp); + fprintf (fp, ">%d", range->end->value.ival); + } + else + { + if (parent == CLDR_PLURAL_CONDITION_AND + || relation->ranges->nitems > 1) + fputc ('(', fp); + print_expression (relation->expression, false, fp); + fprintf (fp, "<%d", range->start->value.ival); + fprintf (fp, " || "); + print_expression (relation->expression, false, fp); + fprintf (fp, ">%d", range->end->value.ival); + if (parent == CLDR_PLURAL_CONDITION_AND + || relation->ranges->nitems > 1) + fputc (')', fp); + } + } + if (parent == CLDR_PLURAL_CONDITION_OR + && relation->ranges->nitems > 1) + fputc (')', fp); + } +} + +static bool +print_condition (struct cldr_plural_condition_ty *condition, + enum cldr_plural_condition parent, bool space, + FILE *fp) +{ + if (condition->type == CLDR_PLURAL_CONDITION_AND) + { + if (parent == CLDR_PLURAL_CONDITION_OR) + fputc ('(', fp); + print_condition (condition->value.conditions[0], + CLDR_PLURAL_CONDITION_AND, false, + fp); + fprintf (fp, " && "); + print_condition (condition->value.conditions[1], + CLDR_PLURAL_CONDITION_AND, false, + fp); + if (parent == CLDR_PLURAL_CONDITION_OR) + fputc (')', fp); + return true; + } + else if (condition->type == CLDR_PLURAL_CONDITION_OR) + { + if (parent == CLDR_PLURAL_CONDITION_AND) + fputc ('(', fp); + print_condition (condition->value.conditions[0], + CLDR_PLURAL_CONDITION_OR, false, + fp); + fprintf (fp, " || "); + print_condition (condition->value.conditions[1], + CLDR_PLURAL_CONDITION_OR, false, + fp); + if (parent == CLDR_PLURAL_CONDITION_AND) + fputc (')', fp); + return true; + } + else if (condition->type == CLDR_PLURAL_CONDITION_RELATION) + { + print_relation (condition->value.relation, parent, space, fp); + return true; + } + return false; +} + +#define RULE_PRINTABLE_P(r) \ + ((r)->condition->type != CLDR_PLURAL_CONDITION_TRUE \ + && (r)->condition->type != CLDR_PLURAL_CONDITION_FALSE) + +/* Convert n == N into n != N. */ +static bool +print_condition_negation (struct cldr_plural_condition_ty *condition, FILE *fp) +{ + if (condition->type == CLDR_PLURAL_CONDITION_RELATION + && condition->value.relation->type == CLDR_PLURAL_RELATION_EQUAL + && condition->value.relation->ranges->nitems == 1 + && condition->value.relation->ranges->items[0]->start + == condition->value.relation->ranges->items[0]->end) + { + fprintf (fp, "nplurals=2; plural=(n != %d);\n", + condition->value.relation->ranges->items[0]->start->value.ival); + return true; + } + return false; +} + +/* Convert n == 0,...,N into n > N. */ +static bool +print_condition_greater (struct cldr_plural_condition_ty *condition, FILE *fp) +{ + if (condition->type == CLDR_PLURAL_CONDITION_RELATION + && condition->value.relation->type == CLDR_PLURAL_RELATION_EQUAL) + { + int last = -1; + size_t i; + for (i = 0; i < condition->value.relation->ranges->nitems; i++) + { + struct cldr_plural_range_ty *range = + condition->value.relation->ranges->items[i]; + if (range->start->type != CLDR_PLURAL_OPERAND_INTEGER + || range->end->type != CLDR_PLURAL_OPERAND_INTEGER + || range->start->value.ival != last + 1) + break; + last = range->end->value.ival; + } + if (i == condition->value.relation->ranges->nitems) + { + struct cldr_plural_range_ty *range = + condition->value.relation->ranges->items[i - 1]; + fprintf (fp, "nplurals=2; plural=(n > %d);\n", + range->end->value.ival); + return true; + } + } + return false; +} + +typedef bool (*print_condition_function_ty) (struct cldr_plural_condition_ty *, + FILE *); +static print_condition_function_ty print_condition_functions[] = + { + print_condition_negation, + print_condition_greater + }; + +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + +void +cldr_plural_rule_list_print (struct cldr_plural_rule_list_ty *rules, FILE *fp) +{ + size_t i; + size_t count; + size_t nplurals; + int modulus_max = 0; + + /* Prune trivial conditions. */ + for (i = 0; i < rules->nitems; i++) + { + struct cldr_plural_rule_ty *rule = rules->items[i]; + eval_condition (rule->condition); + } + + /* Omit trivial rules (e.g., the last rule for "ru") with the + following algorithm: + 1. From all rules, find the largest modulus M + 2. Prepare a bit vector with M elements and initialize it with zeros + 3. Loop over the rules, until all bits are set: + For each value in the range [1, M], apply a rule, and flip the + corresponding bit if it evaluates true */ + + /* Find the largest modulus. */ + for (i = 0; i < rules->nitems; i++) + { + struct cldr_plural_rule_ty *rule = rules->items[i]; + int modulus = find_largest_modulus (rule->condition); + int number = find_largest_number (rule->condition); + /* If the rule contains a range whose end is larger than + MODULUS, we can't use MODULUS as the upper bound. Skip + it. */ + if (modulus >= number && modulus > modulus_max) + modulus_max = modulus; + } + + if (modulus_max > 0) + { + bool *values = XNMALLOC (modulus_max, bool); + + memset (values, 0, sizeof (bool) * modulus_max); + for (i = 0; i < rules->nitems; i++) + { + struct cldr_plural_rule_ty *rule = rules->items[i]; + int j; + + for (j = 0; j < modulus_max; j++) + { + bool result = apply_condition (rule->condition, j + 1); + if (result) + values[j] = true; + } + + /* Check if all bits are set. Then we can omit one more rule. */ + for (j = 0; j < modulus_max; j++) + if (values[j] == false) + break; + if (j == modulus_max) + break; + } + + free (values); + + while (i < rules->nitems) + cldr_plural_rule_free (rules->items[--rules->nitems]); + } + + for (i = 0, nplurals = 1; i < rules->nitems; i++) + if (RULE_PRINTABLE_P (rules->items[i])) + nplurals++; + + /* Special case when rules is empty. */ + if (nplurals == 1) + { + fprintf (fp, "nplurals=1; plural=0;\n"); + return; + } + + /* If we have only one printable rule, apply some heuristics. */ + if (nplurals == 2) + { + struct cldr_plural_condition_ty *condition; + size_t j; + + for (j = 0; j < rules->nitems; j++) + if (RULE_PRINTABLE_P (rules->items[j])) + break; + + condition = rules->items[j]->condition; + for (j = 0; j < SIZEOF (print_condition_functions); j++) + if (print_condition_functions[j] (condition, fp)) + return; + } + + /* If there are more printable rules, build a ternary operator. */ + fprintf (fp, "nplurals=%zu; plural=(", nplurals); + for (i = 0, count = 0; i < rules->nitems; i++) + { + struct cldr_plural_rule_ty *rule = rules->items[i]; + if (print_condition (rule->condition, + CLDR_PLURAL_CONDITION_FALSE, + nplurals == 2, + fp) + && rules->nitems > 1) + { + bool printable_left = false; + size_t j; + + for (j = i + 1; j < rules->nitems; j++) + if (RULE_PRINTABLE_P (rules->items[j])) + printable_left = true; + + if (i < rules->nitems - 1 && printable_left) + fprintf (fp, " ? %zu : ", count++); + } + } + if (rules->nitems > 1) + fprintf (fp, " ? %zu : %zu", count, count + 1); + fprintf (fp, ");\n"); +} diff --git a/gettext-tools/src/cldr-plural-exp.h b/gettext-tools/src/cldr-plural-exp.h new file mode 100644 index 0000000..84c8a73 --- /dev/null +++ b/gettext-tools/src/cldr-plural-exp.h @@ -0,0 +1,141 @@ +/* Unicode CLDR plural rule parser and converter + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _CLDR_PLURAL_EXP_H +#define _CLDR_PLURAL_EXP_H 1 + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum cldr_plural_operand + { + CLDR_PLURAL_OPERAND_INTEGER, + CLDR_PLURAL_OPERAND_DECIMAL + }; + +struct cldr_plural_operand_ty +{ + enum cldr_plural_operand type; + union + { + int ival; + struct + { + double d; + int nfractions; + } dval; + } value; +}; + +enum cldr_plural_relation + { + CLDR_PLURAL_RELATION_EQUAL, + CLDR_PLURAL_RELATION_NOT_EQUAL + }; + +struct cldr_plural_range_ty +{ + struct cldr_plural_operand_ty *start; + struct cldr_plural_operand_ty *end; +}; + +struct cldr_plural_range_list_ty +{ + struct cldr_plural_range_ty **items; + size_t nitems; + size_t nitems_max; +}; + +struct cldr_plural_expression_ty +{ + /* 'n', 'i', 'f', 't', 'v', 'w' */ + int operand; + + /* 0 if not given */ + int mod; +}; + +struct cldr_plural_relation_ty +{ + struct cldr_plural_expression_ty *expression; + enum cldr_plural_relation type; + struct cldr_plural_range_list_ty *ranges; +}; + +enum cldr_plural_condition + { + CLDR_PLURAL_CONDITION_AND, + CLDR_PLURAL_CONDITION_OR, + CLDR_PLURAL_CONDITION_RELATION, + CLDR_PLURAL_CONDITION_TRUE, + CLDR_PLURAL_CONDITION_FALSE + }; + +struct cldr_plural_condition_ty +{ + enum cldr_plural_condition type; + union + { + struct cldr_plural_relation_ty *relation; + struct cldr_plural_condition_ty *conditions[2]; + } value; +}; + +struct cldr_plural_rule_ty +{ + char *name; + struct cldr_plural_condition_ty *condition; +}; + +struct cldr_plural_rule_list_ty +{ + struct cldr_plural_rule_ty **items; + size_t nitems; + size_t nitems_max; +}; + +struct cldr_plural_parse_args +{ + const char *cp; + const char *cp_end; + struct cldr_plural_rule_list_ty *result; +}; + +extern void +cldr_plural_range_free (struct cldr_plural_range_ty *range); +extern void +cldr_plural_range_list_free (struct cldr_plural_range_list_ty *ranges); +extern void +cldr_plural_condition_free (struct cldr_plural_condition_ty *condition); +extern void +cldr_plural_relation_free (struct cldr_plural_relation_ty *relation); + +extern struct cldr_plural_rule_list_ty * +cldr_plural_parse (const char *input); +extern void +cldr_plural_rule_list_free (struct cldr_plural_rule_list_ty *rules); +extern void +cldr_plural_rule_list_print (struct cldr_plural_rule_list_ty *rules, FILE *fp); +#ifdef __cplusplus +} +#endif + +#endif /* _CLDR_PLURAL_EXP_H */ diff --git a/gettext-tools/src/cldr-plural.c b/gettext-tools/src/cldr-plural.c new file mode 100644 index 0000000..d0fc4f8 --- /dev/null +++ b/gettext-tools/src/cldr-plural.c @@ -0,0 +1,2013 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 2 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +#line 19 "cldr-plural.y" /* yacc.c:339 */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "unistr.h" +#include "xalloc.h" + +#include "cldr-plural-exp.h" +#include "cldr-plural.h" + +/* Prototypes for local functions. */ +static int yylex (YYSTYPE *lval, struct cldr_plural_parse_args *arg); +static void yyerror (struct cldr_plural_parse_args *arg, const char *str); + +/* Allocation of expressions. */ + +static struct cldr_plural_rule_ty * +new_rule (char *name, struct cldr_plural_condition_ty *condition) +{ + struct cldr_plural_rule_ty *result = + XMALLOC (struct cldr_plural_rule_ty); + result->name = name; + result->condition = condition; + return result; +} + +static struct cldr_plural_condition_ty * +new_leaf_condition (struct cldr_plural_relation_ty *relation) +{ + struct cldr_plural_condition_ty *result = + XMALLOC (struct cldr_plural_condition_ty); + result->type = CLDR_PLURAL_CONDITION_RELATION; + result->value.relation = relation; + return result; +} + +static struct cldr_plural_condition_ty * +new_branch_condition (enum cldr_plural_condition type, + struct cldr_plural_condition_ty *condition0, + struct cldr_plural_condition_ty *condition1) +{ + struct cldr_plural_condition_ty *result = + XMALLOC (struct cldr_plural_condition_ty); + result->type = type; + result->value.conditions[0] = condition0; + result->value.conditions[1] = condition1; + return result; +} + +static struct cldr_plural_relation_ty * +new_relation (struct cldr_plural_expression_ty *expression, + enum cldr_plural_relation type, + struct cldr_plural_range_list_ty *ranges) +{ + struct cldr_plural_relation_ty *result = + XMALLOC (struct cldr_plural_relation_ty); + result->expression = expression; + result->type = type; + result->ranges = ranges; + return result; +} + +static struct cldr_plural_expression_ty * +new_expression (int operand, int mod) +{ + struct cldr_plural_expression_ty *result = + XMALLOC (struct cldr_plural_expression_ty); + result->operand = operand; + result->mod = mod; + return result; +} + +static struct cldr_plural_range_list_ty * +add_range (struct cldr_plural_range_list_ty *ranges, + struct cldr_plural_range_ty *range) +{ + if (ranges->nitems == ranges->nitems_max) + { + ranges->nitems_max = ranges->nitems_max * 2 + 1; + ranges->items = xrealloc (ranges->items, + sizeof (struct cldr_plural_range_ty *) + * ranges->nitems_max); + } + ranges->items[ranges->nitems++] = range; + return ranges; +} + +static struct cldr_plural_range_ty * +new_range (struct cldr_plural_operand_ty *start, + struct cldr_plural_operand_ty *end) +{ + struct cldr_plural_range_ty *result = + XMALLOC (struct cldr_plural_range_ty); + result->start = start; + result->end = end; + return result; +} + +#line 170 "cldr-plural.c" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_YY_CLDR_PLURAL_H_INCLUDED +# define YY_YY_CLDR_PLURAL_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + AND = 258, + OR = 259, + RANGE = 260, + ELLIPSIS = 261, + OTHER = 262, + AT_INTEGER = 263, + AT_DECIMAL = 264, + KEYWORD = 265, + INTEGER = 266, + DECIMAL = 267, + OPERAND = 268 + }; +#endif +/* Tokens. */ +#define AND 258 +#define OR 259 +#define RANGE 260 +#define ELLIPSIS 261 +#define OTHER 262 +#define AT_INTEGER 263 +#define AT_DECIMAL 264 +#define KEYWORD 265 +#define INTEGER 266 +#define DECIMAL 267 +#define OPERAND 268 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 127 "cldr-plural.y" /* yacc.c:355 */ + + char *sval; + struct cldr_plural_condition_ty *cval; + struct cldr_plural_relation_ty *lval; + struct cldr_plural_expression_ty *eval; + struct cldr_plural_range_ty *gval; + struct cldr_plural_operand_ty *oval; + struct cldr_plural_range_list_ty *rval; + int ival; + +#line 247 "cldr-plural.c" /* yacc.c:355 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int yyparse (struct cldr_plural_parse_args *arg); + +#endif /* !YY_YY_CLDR_PLURAL_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 263 "cldr-plural.c" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 7 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 55 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 21 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 17 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 32 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 52 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 268 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 17, 2, 2, 2, 18, 2, 2, + 2, 2, 2, 2, 19, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 15, 14, + 2, 16, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 20, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 159, 159, 160, 163, 176, 179, 183, 189, 193, + 201, 205, 211, 215, 221, 228, 234, 238, 244, 251, + 254, 255, 258, 259, 262, 264, 265, 267, 268, 271, + 273, 275, 277 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "AND", "OR", "RANGE", "ELLIPSIS", + "OTHER", "AT_INTEGER", "AT_DECIMAL", "KEYWORD", "INTEGER", "DECIMAL", + "OPERAND", "';'", "':'", "'='", "'!'", "'%'", "','", "'~'", "$accept", + "rules", "rule", "condition", "and_condition", "relation", "expression", + "range_list", "range_or_integer", "range", "samples", "at_integer", + "at_decimal", "sample_list", "sample_list1", "sample_ellipsis", + "sample_range", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 59, 58, 61, 33, 37, 44, + 126 +}; +# endif + +#define YYPACT_NINF -20 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-20))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + 3, -11, -7, 0, -20, 4, -2, -20, 3, -9, + -20, 8, 2, 1, 15, -20, -1, -20, 5, 6, + -20, 9, -20, -9, -20, 10, -2, -20, -2, 11, + 11, 12, 7, -5, -20, -20, -20, 15, -20, 19, + 13, -20, -20, 13, -20, -20, -20, -20, 16, 11, + -20, -20 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 0, 0, 2, 20, 0, 1, 0, 0, + 5, 22, 12, 20, 6, 8, 0, 3, 31, 29, + 21, 27, 25, 0, 19, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 24, 23, 13, 7, 9, 17, + 10, 14, 16, 11, 32, 30, 28, 26, 0, 0, + 18, 15 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -20, -20, 21, -20, 14, 17, -20, 18, -19, -20, + 20, -20, -20, 23, -20, -20, 22 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 3, 4, 13, 14, 15, 16, 40, 41, 42, + 10, 11, 24, 20, 21, 34, 22 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 7, 46, 18, 19, 5, 26, 18, 19, 6, 9, + 1, 12, 9, 2, 8, 29, 30, 23, 28, 45, + 25, 36, 39, 44, 48, 31, 32, 50, 33, 17, + 51, 0, 49, 27, 0, 0, 0, 0, 0, 0, + 37, 0, 0, 0, 0, 38, 35, 0, 43, 0, + 0, 0, 0, 0, 0, 47 +}; + +static const yytype_int8 yycheck[] = +{ + 0, 6, 11, 12, 15, 4, 11, 12, 15, 8, + 7, 13, 8, 10, 14, 16, 17, 9, 3, 12, + 18, 11, 11, 11, 5, 20, 20, 11, 19, 8, + 49, -1, 19, 13, -1, -1, -1, -1, -1, -1, + 26, -1, -1, -1, -1, 28, 23, -1, 30, -1, + -1, -1, -1, -1, -1, 33 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 7, 10, 22, 23, 15, 15, 0, 14, 8, + 31, 32, 13, 24, 25, 26, 27, 23, 11, 12, + 34, 35, 37, 9, 33, 18, 4, 31, 3, 16, + 17, 20, 20, 19, 36, 34, 11, 25, 26, 11, + 28, 29, 30, 28, 11, 12, 6, 37, 5, 19, + 11, 29 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 21, 22, 22, 23, 23, 24, 24, 25, 25, + 26, 26, 27, 27, 28, 28, 29, 29, 30, 31, + 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, + 37, 37, 37 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 3, 4, 3, 1, 3, 1, 3, + 3, 3, 1, 3, 1, 3, 1, 1, 3, 2, + 0, 2, 0, 2, 2, 1, 3, 0, 2, 1, + 3, 1, 3 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (arg, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, arg); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct cldr_plural_parse_args *arg) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (arg); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct cldr_plural_parse_args *arg) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, arg); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, struct cldr_plural_parse_args *arg) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , arg); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, arg); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct cldr_plural_parse_args *arg) +{ + YYUSE (yyvaluep); + YYUSE (arg); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + switch (yytype) + { + case 10: /* KEYWORD */ +#line 138 "cldr-plural.y" /* yacc.c:1257 */ + { free (((*yyvaluep).sval)); } +#line 1121 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 11: /* INTEGER */ +#line 143 "cldr-plural.y" /* yacc.c:1257 */ + { free (((*yyvaluep).oval)); } +#line 1127 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 12: /* DECIMAL */ +#line 143 "cldr-plural.y" /* yacc.c:1257 */ + { free (((*yyvaluep).oval)); } +#line 1133 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 13: /* OPERAND */ +#line 145 "cldr-plural.y" /* yacc.c:1257 */ + { } +#line 1139 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 24: /* condition */ +#line 139 "cldr-plural.y" /* yacc.c:1257 */ + { cldr_plural_condition_free (((*yyvaluep).cval)); } +#line 1145 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 25: /* and_condition */ +#line 139 "cldr-plural.y" /* yacc.c:1257 */ + { cldr_plural_condition_free (((*yyvaluep).cval)); } +#line 1151 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 26: /* relation */ +#line 140 "cldr-plural.y" /* yacc.c:1257 */ + { cldr_plural_relation_free (((*yyvaluep).lval)); } +#line 1157 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 27: /* expression */ +#line 141 "cldr-plural.y" /* yacc.c:1257 */ + { free (((*yyvaluep).eval)); } +#line 1163 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 28: /* range_list */ +#line 144 "cldr-plural.y" /* yacc.c:1257 */ + { cldr_plural_range_list_free (((*yyvaluep).rval)); } +#line 1169 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 29: /* range_or_integer */ +#line 142 "cldr-plural.y" /* yacc.c:1257 */ + { cldr_plural_range_free (((*yyvaluep).gval)); } +#line 1175 "cldr-plural.c" /* yacc.c:1257 */ + break; + + case 30: /* range */ +#line 142 "cldr-plural.y" /* yacc.c:1257 */ + { cldr_plural_range_free (((*yyvaluep).gval)); } +#line 1181 "cldr-plural.c" /* yacc.c:1257 */ + break; + + + default: + break; + } + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (struct cldr_plural_parse_args *arg) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, arg); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: +#line 164 "cldr-plural.y" /* yacc.c:1646 */ + { + struct cldr_plural_rule_ty *rule = new_rule ((yyvsp[-3].sval), (yyvsp[-1].cval)); + struct cldr_plural_rule_list_ty *result = arg->result; + if (result->nitems == result->nitems_max) + { + result->nitems_max = result->nitems_max * 2 + 1; + result->items = xrealloc (result->items, + sizeof (struct cldr_plural_rule_ty *) + * result->nitems_max); + } + result->items[result->nitems++] = rule; + } +#line 1460 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 6: +#line 180 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.cval) = (yyvsp[0].cval); + } +#line 1468 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 7: +#line 184 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.cval) = new_branch_condition (CLDR_PLURAL_CONDITION_OR, (yyvsp[-2].cval), (yyvsp[0].cval)); + } +#line 1476 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 8: +#line 190 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.cval) = new_leaf_condition ((yyvsp[0].lval)); + } +#line 1484 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 9: +#line 194 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.cval) = new_branch_condition (CLDR_PLURAL_CONDITION_AND, + (yyvsp[-2].cval), + new_leaf_condition ((yyvsp[0].lval))); + } +#line 1494 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 10: +#line 202 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.lval) = new_relation ((yyvsp[-2].eval), CLDR_PLURAL_RELATION_EQUAL, (yyvsp[0].rval)); + } +#line 1502 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 11: +#line 206 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.lval) = new_relation ((yyvsp[-2].eval), CLDR_PLURAL_RELATION_NOT_EQUAL, (yyvsp[0].rval)); + } +#line 1510 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 12: +#line 212 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.eval) = new_expression ((yyvsp[0].ival), 0); + } +#line 1518 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 13: +#line 216 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.eval) = new_expression ((yyvsp[-2].ival), (yyvsp[0].oval)->value.ival); + } +#line 1526 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 14: +#line 222 "cldr-plural.y" /* yacc.c:1646 */ + { + struct cldr_plural_range_list_ty *ranges = + XMALLOC (struct cldr_plural_range_list_ty); + memset (ranges, 0, sizeof (struct cldr_plural_range_list_ty)); + (yyval.rval) = add_range (ranges, (yyvsp[0].gval)); + } +#line 1537 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 15: +#line 229 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.rval) = add_range ((yyvsp[-2].rval), (yyvsp[0].gval)); + } +#line 1545 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 16: +#line 235 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.gval) = (yyvsp[0].gval); + } +#line 1553 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 17: +#line 239 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.gval) = new_range ((yyvsp[0].oval), (yyvsp[0].oval)); + } +#line 1561 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 18: +#line 245 "cldr-plural.y" /* yacc.c:1646 */ + { + (yyval.gval) = new_range ((yyvsp[-2].oval), (yyvsp[0].oval)); + } +#line 1569 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 29: +#line 272 "cldr-plural.y" /* yacc.c:1646 */ + { free ((yyvsp[0].oval)); } +#line 1575 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 30: +#line 274 "cldr-plural.y" /* yacc.c:1646 */ + { free ((yyvsp[-2].oval)); free ((yyvsp[0].oval)); } +#line 1581 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 31: +#line 276 "cldr-plural.y" /* yacc.c:1646 */ + { free ((yyvsp[0].oval)); } +#line 1587 "cldr-plural.c" /* yacc.c:1646 */ + break; + + case 32: +#line 278 "cldr-plural.y" /* yacc.c:1646 */ + { free ((yyvsp[-2].oval)); free ((yyvsp[0].oval)); } +#line 1593 "cldr-plural.c" /* yacc.c:1646 */ + break; + + +#line 1597 "cldr-plural.c" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (arg, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (arg, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, arg); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, arg); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (arg, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, arg); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, arg); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 281 "cldr-plural.y" /* yacc.c:1906 */ + + +static int +yylex (YYSTYPE *lval, struct cldr_plural_parse_args *arg) +{ + const char *exp = arg->cp; + ucs4_t uc; + int length; + int result; + static char *buffer; + static size_t bufmax; + size_t bufpos; + + while (1) + { + if (exp[0] == '\0') + { + arg->cp = exp; + return YYEOF; + } + + if (exp[0] != ' ' && exp[0] != '\t') + break; + + ++exp; + } + + length = u8_mbtouc (&uc, (const uint8_t *) exp, arg->cp_end - exp); + if (uc == 0x2026) + { + arg->cp = exp + length; + return ELLIPSIS; + } + else if (strncmp ("...", exp, 3) == 0) + { + arg->cp = exp + 3; + return ELLIPSIS; + } + else if (strncmp ("..", exp, 2) == 0) + { + arg->cp = exp + 2; + return RANGE; + } + else if (strncmp ("other", exp, 5) == 0) + { + arg->cp = exp + 5; + return OTHER; + } + else if (strncmp ("@integer", exp, 8) == 0) + { + arg->cp = exp + 8; + return AT_INTEGER; + } + else if (strncmp ("@decimal", exp, 8) == 0) + { + arg->cp = exp + 8; + return AT_DECIMAL; + } + + result = *exp++; + switch (result) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + unsigned long int ival = result - '0'; + + while (exp[0] >= '0' && exp[0] <= '9') + { + ival *= 10; + ival += exp[0] - '0'; + ++exp; + } + + lval->oval = XMALLOC (struct cldr_plural_operand_ty); + if (exp[0] == '.' && exp[1] >= '0' && exp[1] <= '9') + { + double dval = ival; + int denominator = 10, nfractions = 0; + ++exp; + while (exp[0] >= '0' && exp[0] <= '9') + { + dval += (exp[0] - '0') / (double) denominator; + denominator *= 10; + ++nfractions; + ++exp; + } + lval->oval->type = CLDR_PLURAL_OPERAND_DECIMAL; + lval->oval->value.dval.d = dval; + lval->oval->value.dval.nfractions = nfractions; + result = DECIMAL; + } + else + { + lval->oval->type = CLDR_PLURAL_OPERAND_INTEGER; + lval->oval->value.ival = ival; + result = INTEGER; + } + } + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + bufpos = 0; + for (;;) + { + if (bufpos >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax); + } + buffer[bufpos++] = result; + result = *exp; + switch (result) + { + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + ++exp; + continue; + default: + break; + } + break; + } + + if (bufpos >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax); + } + buffer[bufpos] = '\0'; + + /* Operands. */ + if (bufpos == 1) + { + switch (buffer[0]) + { + case 'n': case 'i': case 'f': case 't': case 'v': case 'w': + arg->cp = exp; + lval->ival = buffer[0]; + return OPERAND; + default: + break; + } + } + + /* Keywords. */ + if (strcmp (buffer, "and") == 0) + { + arg->cp = exp; + return AND; + } + else if (strcmp (buffer, "or") == 0) + { + arg->cp = exp; + return OR; + } + + lval->sval = xstrdup (buffer); + result = KEYWORD; + break; + case '!': + if (exp[0] == '=') + { + ++exp; + result = '!'; + } + else + result = YYERRCODE; + break; + default: + break; + } + + arg->cp = exp; + + return result; +} + +static void +yyerror (struct cldr_plural_parse_args *arg, char const *s) +{ + fprintf (stderr, "%s\n", s); +} diff --git a/gettext-tools/src/cldr-plural.h b/gettext-tools/src/cldr-plural.h new file mode 100644 index 0000000..4122af5 --- /dev/null +++ b/gettext-tools/src/cldr-plural.h @@ -0,0 +1,102 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YY_CLDR_PLURAL_H_INCLUDED +# define YY_YY_CLDR_PLURAL_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + AND = 258, + OR = 259, + RANGE = 260, + ELLIPSIS = 261, + OTHER = 262, + AT_INTEGER = 263, + AT_DECIMAL = 264, + KEYWORD = 265, + INTEGER = 266, + DECIMAL = 267, + OPERAND = 268 + }; +#endif +/* Tokens. */ +#define AND 258 +#define OR 259 +#define RANGE 260 +#define ELLIPSIS 261 +#define OTHER 262 +#define AT_INTEGER 263 +#define AT_DECIMAL 264 +#define KEYWORD 265 +#define INTEGER 266 +#define DECIMAL 267 +#define OPERAND 268 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 127 "cldr-plural.y" /* yacc.c:1909 */ + + char *sval; + struct cldr_plural_condition_ty *cval; + struct cldr_plural_relation_ty *lval; + struct cldr_plural_expression_ty *eval; + struct cldr_plural_range_ty *gval; + struct cldr_plural_operand_ty *oval; + struct cldr_plural_range_list_ty *rval; + int ival; + +#line 91 "cldr-plural.h" /* yacc.c:1909 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int yyparse (struct cldr_plural_parse_args *arg); + +#endif /* !YY_YY_CLDR_PLURAL_H_INCLUDED */ diff --git a/gettext-tools/src/cldr-plural.y b/gettext-tools/src/cldr-plural.y new file mode 100644 index 0000000..d3128cd --- /dev/null +++ b/gettext-tools/src/cldr-plural.y @@ -0,0 +1,469 @@ +/* Unicode CLDR plural rule parser and converter + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +%{ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "unistr.h" +#include "xalloc.h" + +#include "cldr-plural-exp.h" +#include "cldr-plural.h" + +/* Prototypes for local functions. */ +static int yylex (YYSTYPE *lval, struct cldr_plural_parse_args *arg); +static void yyerror (struct cldr_plural_parse_args *arg, const char *str); + +/* Allocation of expressions. */ + +static struct cldr_plural_rule_ty * +new_rule (char *name, struct cldr_plural_condition_ty *condition) +{ + struct cldr_plural_rule_ty *result = + XMALLOC (struct cldr_plural_rule_ty); + result->name = name; + result->condition = condition; + return result; +} + +static struct cldr_plural_condition_ty * +new_leaf_condition (struct cldr_plural_relation_ty *relation) +{ + struct cldr_plural_condition_ty *result = + XMALLOC (struct cldr_plural_condition_ty); + result->type = CLDR_PLURAL_CONDITION_RELATION; + result->value.relation = relation; + return result; +} + +static struct cldr_plural_condition_ty * +new_branch_condition (enum cldr_plural_condition type, + struct cldr_plural_condition_ty *condition0, + struct cldr_plural_condition_ty *condition1) +{ + struct cldr_plural_condition_ty *result = + XMALLOC (struct cldr_plural_condition_ty); + result->type = type; + result->value.conditions[0] = condition0; + result->value.conditions[1] = condition1; + return result; +} + +static struct cldr_plural_relation_ty * +new_relation (struct cldr_plural_expression_ty *expression, + enum cldr_plural_relation type, + struct cldr_plural_range_list_ty *ranges) +{ + struct cldr_plural_relation_ty *result = + XMALLOC (struct cldr_plural_relation_ty); + result->expression = expression; + result->type = type; + result->ranges = ranges; + return result; +} + +static struct cldr_plural_expression_ty * +new_expression (int operand, int mod) +{ + struct cldr_plural_expression_ty *result = + XMALLOC (struct cldr_plural_expression_ty); + result->operand = operand; + result->mod = mod; + return result; +} + +static struct cldr_plural_range_list_ty * +add_range (struct cldr_plural_range_list_ty *ranges, + struct cldr_plural_range_ty *range) +{ + if (ranges->nitems == ranges->nitems_max) + { + ranges->nitems_max = ranges->nitems_max * 2 + 1; + ranges->items = xrealloc (ranges->items, + sizeof (struct cldr_plural_range_ty *) + * ranges->nitems_max); + } + ranges->items[ranges->nitems++] = range; + return ranges; +} + +static struct cldr_plural_range_ty * +new_range (struct cldr_plural_operand_ty *start, + struct cldr_plural_operand_ty *end) +{ + struct cldr_plural_range_ty *result = + XMALLOC (struct cldr_plural_range_ty); + result->start = start; + result->end = end; + return result; +} +%} + +%parse-param {struct cldr_plural_parse_args *arg} +%lex-param {struct cldr_plural_parse_args *arg} +%define api.pure full + +%union { + char *sval; + struct cldr_plural_condition_ty *cval; + struct cldr_plural_relation_ty *lval; + struct cldr_plural_expression_ty *eval; + struct cldr_plural_range_ty *gval; + struct cldr_plural_operand_ty *oval; + struct cldr_plural_range_list_ty *rval; + int ival; +} + +%destructor { free ($$); } <sval> +%destructor { cldr_plural_condition_free ($$); } <cval> +%destructor { cldr_plural_relation_free ($$); } <lval> +%destructor { free ($$); } <eval> +%destructor { cldr_plural_range_free ($$); } <gval> +%destructor { free ($$); } <oval> +%destructor { cldr_plural_range_list_free ($$); } <rval> +%destructor { } <ival> + +%token AND OR RANGE ELLIPSIS OTHER AT_INTEGER AT_DECIMAL +%token<sval> KEYWORD +%token<oval> INTEGER DECIMAL +%token<ival> OPERAND +%type<cval> condition and_condition +%type<lval> relation +%type<eval> expression +%type<gval> range range_or_integer +%type<rval> range_list + +%% + +rules: rule + | rules ';' rule + ; + +rule: KEYWORD ':' condition samples + { + struct cldr_plural_rule_ty *rule = new_rule ($1, $3); + struct cldr_plural_rule_list_ty *result = arg->result; + if (result->nitems == result->nitems_max) + { + result->nitems_max = result->nitems_max * 2 + 1; + result->items = xrealloc (result->items, + sizeof (struct cldr_plural_rule_ty *) + * result->nitems_max); + } + result->items[result->nitems++] = rule; + } + | OTHER ':' samples + ; + +condition: and_condition + { + $$ = $1; + } + | condition OR and_condition + { + $$ = new_branch_condition (CLDR_PLURAL_CONDITION_OR, $1, $3); + } + ; + +and_condition: relation + { + $$ = new_leaf_condition ($1); + } + | and_condition AND relation + { + $$ = new_branch_condition (CLDR_PLURAL_CONDITION_AND, + $1, + new_leaf_condition ($3)); + } + ; + +relation: expression '=' range_list + { + $$ = new_relation ($1, CLDR_PLURAL_RELATION_EQUAL, $3); + } + | expression '!' range_list + { + $$ = new_relation ($1, CLDR_PLURAL_RELATION_NOT_EQUAL, $3); + } + ; + +expression: OPERAND + { + $$ = new_expression ($1, 0); + } + | OPERAND '%' INTEGER + { + $$ = new_expression ($1, $3->value.ival); + } + ; + +range_list: range_or_integer + { + struct cldr_plural_range_list_ty *ranges = + XMALLOC (struct cldr_plural_range_list_ty); + memset (ranges, 0, sizeof (struct cldr_plural_range_list_ty)); + $$ = add_range (ranges, $1); + } + | range_list ',' range_or_integer + { + $$ = add_range ($1, $3); + } + ; + +range_or_integer: range + { + $$ = $1; + } + | INTEGER + { + $$ = new_range ($1, $1); + } + ; + +range: INTEGER RANGE INTEGER + { + $$ = new_range ($1, $3); + } + ; + +/* FIXME: collect samples */ +samples: at_integer at_decimal + ; + +at_integer: %empty + | AT_INTEGER sample_list + ; + +at_decimal: %empty + | AT_DECIMAL sample_list + ; + +sample_list: sample_list1 sample_ellipsis + ; +sample_list1: sample_range + | sample_list1 ',' sample_range + ; +sample_ellipsis: %empty + | ',' ELLIPSIS + ; + +sample_range: DECIMAL + { free ($1); } + | DECIMAL '~' DECIMAL + { free ($1); free ($3); } + | INTEGER + { free ($1); } + | INTEGER '~' INTEGER + { free ($1); free ($3); } + ; + +%% + +static int +yylex (YYSTYPE *lval, struct cldr_plural_parse_args *arg) +{ + const char *exp = arg->cp; + ucs4_t uc; + int length; + int result; + static char *buffer; + static size_t bufmax; + size_t bufpos; + + while (1) + { + if (exp[0] == '\0') + { + arg->cp = exp; + return YYEOF; + } + + if (exp[0] != ' ' && exp[0] != '\t') + break; + + ++exp; + } + + length = u8_mbtouc (&uc, (const uint8_t *) exp, arg->cp_end - exp); + if (uc == 0x2026) + { + arg->cp = exp + length; + return ELLIPSIS; + } + else if (strncmp ("...", exp, 3) == 0) + { + arg->cp = exp + 3; + return ELLIPSIS; + } + else if (strncmp ("..", exp, 2) == 0) + { + arg->cp = exp + 2; + return RANGE; + } + else if (strncmp ("other", exp, 5) == 0) + { + arg->cp = exp + 5; + return OTHER; + } + else if (strncmp ("@integer", exp, 8) == 0) + { + arg->cp = exp + 8; + return AT_INTEGER; + } + else if (strncmp ("@decimal", exp, 8) == 0) + { + arg->cp = exp + 8; + return AT_DECIMAL; + } + + result = *exp++; + switch (result) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + unsigned long int ival = result - '0'; + + while (exp[0] >= '0' && exp[0] <= '9') + { + ival *= 10; + ival += exp[0] - '0'; + ++exp; + } + + lval->oval = XMALLOC (struct cldr_plural_operand_ty); + if (exp[0] == '.' && exp[1] >= '0' && exp[1] <= '9') + { + double dval = ival; + int denominator = 10, nfractions = 0; + ++exp; + while (exp[0] >= '0' && exp[0] <= '9') + { + dval += (exp[0] - '0') / (double) denominator; + denominator *= 10; + ++nfractions; + ++exp; + } + lval->oval->type = CLDR_PLURAL_OPERAND_DECIMAL; + lval->oval->value.dval.d = dval; + lval->oval->value.dval.nfractions = nfractions; + result = DECIMAL; + } + else + { + lval->oval->type = CLDR_PLURAL_OPERAND_INTEGER; + lval->oval->value.ival = ival; + result = INTEGER; + } + } + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + bufpos = 0; + for (;;) + { + if (bufpos >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax); + } + buffer[bufpos++] = result; + result = *exp; + switch (result) + { + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + ++exp; + continue; + default: + break; + } + break; + } + + if (bufpos >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax); + } + buffer[bufpos] = '\0'; + + /* Operands. */ + if (bufpos == 1) + { + switch (buffer[0]) + { + case 'n': case 'i': case 'f': case 't': case 'v': case 'w': + arg->cp = exp; + lval->ival = buffer[0]; + return OPERAND; + default: + break; + } + } + + /* Keywords. */ + if (strcmp (buffer, "and") == 0) + { + arg->cp = exp; + return AND; + } + else if (strcmp (buffer, "or") == 0) + { + arg->cp = exp; + return OR; + } + + lval->sval = xstrdup (buffer); + result = KEYWORD; + break; + case '!': + if (exp[0] == '=') + { + ++exp; + result = '!'; + } + else + result = YYERRCODE; + break; + default: + break; + } + + arg->cp = exp; + + return result; +} + +static void +yyerror (struct cldr_plural_parse_args *arg, char const *s) +{ + fprintf (stderr, "%s\n", s); +} diff --git a/gettext-tools/src/cldr-plurals.c b/gettext-tools/src/cldr-plurals.c new file mode 100644 index 0000000..abbd0c2 --- /dev/null +++ b/gettext-tools/src/cldr-plurals.c @@ -0,0 +1,370 @@ +/* Unicode CLDR plural rule parser and converter + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "basename.h" +#include "cldr-plural-exp.h" +#include "c-ctype.h" +#include <errno.h> +#include <error.h> +#include <getopt.h> +#include "gettext.h" +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <locale.h> +#include "progname.h" +#include "propername.h" +#include "relocatable.h" +#include <stdlib.h> +#include <string.h> +#include "xalloc.h" + +#define _(s) gettext(s) + + +static char * +extract_rules (FILE *fp, + const char *real_filename, const char *logical_filename, + const char *locale) +{ + xmlDocPtr doc; + xmlNodePtr node, n; + size_t locale_length; + char *buffer = NULL, *p; + size_t bufmax = 0; + size_t buflen = 0; + + doc = xmlReadFd (fileno (fp), logical_filename, NULL, + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOERROR + | XML_PARSE_NOBLANKS); + if (doc == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + + node = xmlDocGetRootElement (doc); + if (!node || !xmlStrEqual (node->name, BAD_CAST "supplementalData")) + { + error_at_line (0, 0, + logical_filename, + xmlGetLineNo (node), + _("\ +The root element must be <%s>"), + "supplementalData"); + goto out; + } + + for (n = node->children; n; n = n->next) + { + if (n->type == XML_ELEMENT_NODE + && xmlStrEqual (n->name, BAD_CAST "plurals")) + break; + } + if (!n) + { + error (0, 0, _("The element <%s> does not contain a <%s> element"), + "supplementalData", "plurals"); + goto out; + } + + locale_length = strlen (locale); + for (n = n->children; n; n = n->next) + { + xmlChar *locales; + xmlChar *cp; + xmlNodePtr n2; + bool found = false; + + if (n->type != XML_ELEMENT_NODE + || !xmlStrEqual (n->name, BAD_CAST "pluralRules")) + continue; + + if (!xmlHasProp (n, BAD_CAST "locales")) + { + error_at_line (0, 0, + logical_filename, + xmlGetLineNo (n), + _("\ +The element <%s> does not have attribute <%s>"), + "pluralRules", "locales"); + continue; + } + + cp = locales = xmlGetProp (n, BAD_CAST "locales"); + while (*cp != '\0') + { + while (c_isspace (*cp)) + cp++; + if (xmlStrncmp (cp, BAD_CAST locale, locale_length) == 0 + && (*(cp + locale_length) == '\0' + || c_isspace (*(cp + locale_length)))) + { + found = true; + break; + } + while (*cp && !c_isspace (*cp)) + cp++; + } + xmlFree (locales); + + if (!found) + continue; + + for (n2 = n->children; n2; n2 = n2->next) + { + xmlChar *count; + xmlChar *content; + size_t length; + + if (n2->type != XML_ELEMENT_NODE + || !xmlStrEqual (n2->name, BAD_CAST "pluralRule")) + continue; + + if (!xmlHasProp (n2, BAD_CAST "count")) + { + error_at_line (0, 0, + logical_filename, + xmlGetLineNo (n2), + _("\ +The element <%s> does not have attribute <%s>"), + "pluralRule", "count"); + break; + } + + count = xmlGetProp (n2, BAD_CAST "count"); + content = xmlNodeGetContent (n2); + length = xmlStrlen (count) + strlen (": ") + + xmlStrlen (content) + strlen ("; "); + + if (buflen + length + 1 > bufmax) + { + bufmax *= 2; + if (bufmax < buflen + length + 1) + bufmax = buflen + length + 1; + buffer = (char *) xrealloc (buffer, bufmax); + } + + sprintf (buffer + buflen, "%s: %s; ", count, content); + xmlFree (count); + xmlFree (content); + + buflen += length; + } + } + + if (buffer) + { + /* Scrub the last semicolon, if any. */ + p = strrchr (buffer, ';'); + if (p) + *p = '\0'; + } + + out: + xmlFreeDoc (doc); + return buffer; +} + +/* Display usage information and exit. */ +static void +usage (int status) +{ + if (status != EXIT_SUCCESS) + fprintf (stderr, _("Try '%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION...] [LOCALE RULES]...\n\ +"), program_name); + printf ("\n"); + /* xgettext: no-wrap */ + printf (_("\ +Extract or convert Unicode CLDR plural rules.\n\ +\n\ +If both LOCALE and RULES are specified, it reads CLDR plural rules for\n\ +LOCALE from RULES and print them in a form suitable for gettext use.\n\ +If no argument is given, it reads CLDR plural rules from the standard input.\n\ +")); + printf ("\n"); + /* xgettext: no-wrap */ + printf (_("\ +Mandatory arguments to long options are mandatory for short options too.\n\ +Similarly for optional arguments.\n\ +")); + printf ("\n"); + printf (_("\ + -c, --cldr print plural rules in the CLDR format\n")); + printf (_("\ + -h, --help display this help and exit\n")); + printf (_("\ + -V, --version output version information and exit\n")); + printf ("\n"); + /* TRANSLATORS: The placeholder indicates the bug-reporting address + for this package. Please add _another line_ saying + "Report translation bugs to <...>\n" with the address for translation + bugs (typically your translation team's web or email address). */ + fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"), + stdout); + } + exit (status); +} + +/* Long options. */ +static const struct option long_options[] = +{ + { "cldr", no_argument, NULL, 'c' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } +}; + +int +main (int argc, char **argv) +{ + bool opt_cldr_format = false; + bool do_help = false; + bool do_version = false; + int optchar; + + /* Set program name for messages. */ + set_program_name (argv[0]); + +#ifdef HAVE_SETLOCALE + /* Set locale via LC_ALL. */ + setlocale (LC_ALL, ""); +#endif + + /* Set the text message domain. */ + bindtextdomain (PACKAGE, relocate (LOCALEDIR)); + bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR)); + textdomain (PACKAGE); + + while ((optchar = getopt_long (argc, argv, "chV", long_options, NULL)) != EOF) + switch (optchar) + { + case '\0': /* Long option. */ + break; + + case 'c': + opt_cldr_format = true; + break; + + case 'h': + do_help = true; + break; + + case 'V': + do_version = true; + break; + + default: + usage (EXIT_FAILURE); + /* NOTREACHED */ + } + + /* Version information requested. */ + if (do_version) + { + printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION); + /* xgettext: no-wrap */ + printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\ +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\ +This is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n\ +"), + "2015"); + printf (_("Written by %s.\n"), proper_name ("Daiki Ueno")); + exit (EXIT_SUCCESS); + } + + /* Help is requested. */ + if (do_help) + usage (EXIT_SUCCESS); + + if (argc == optind + 2) + { + /* Two arguments: Read CLDR rules from a file. */ + const char *locale = argv[optind]; + const char *logical_filename = argv[optind + 1]; + char *extracted_rules; + FILE *fp; + + LIBXML_TEST_VERSION + + fp = fopen (logical_filename, "r"); + if (fp == NULL) + error (1, 0, _("%s cannot be read"), logical_filename); + + extracted_rules = extract_rules (fp, logical_filename, logical_filename, + locale); + fclose (fp); + if (extracted_rules == NULL) + error (1, 0, _("cannot extract rules for %s"), locale); + + if (opt_cldr_format) + printf ("%s\n", extracted_rules); + else + { + struct cldr_plural_rule_list_ty *result; + + result = cldr_plural_parse (extracted_rules); + if (result == NULL) + error (1, 0, _("cannot parse CLDR rule")); + + cldr_plural_rule_list_print (result, stdout); + cldr_plural_rule_list_free (result); + } + free (extracted_rules); + } + else if (argc == optind) + { + /* No argument: Read CLDR rules from standard input. */ + char *line = NULL; + size_t line_size = 0; + for (;;) + { + int line_len; + struct cldr_plural_rule_list_ty *result; + + line_len = getline (&line, &line_size, stdin); + if (line_len < 0) + break; + if (line_len > 0 && line[line_len - 1] == '\n') + line[--line_len] = '\0'; + + result = cldr_plural_parse (line); + if (result) + { + cldr_plural_rule_list_print (result, stdout); + cldr_plural_rule_list_free (result); + } + } + + free (line); + } + else + { + error (1, 0, _("extra operand %s"), argv[optind]); + } + + return 0; +} diff --git a/gettext-tools/src/color.c b/gettext-tools/src/color.c index 47daf00..b372b2e 100644 --- a/gettext-tools/src/color.c +++ b/gettext-tools/src/color.c @@ -1,5 +1,5 @@ /* Color and styling handling. - Copyright (C) 2006-2008 Free Software Foundation, Inc. + Copyright (C) 2006-2008, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/color.h b/gettext-tools/src/color.h index f47f40f..25211ac 100644 --- a/gettext-tools/src/color.h +++ b/gettext-tools/src/color.h @@ -1,5 +1,5 @@ /* Color and styling handling. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/dir-list.c b/gettext-tools/src/dir-list.c index ee46d05..2ab0fd2 100644 --- a/gettext-tools/src/dir-list.c +++ b/gettext-tools/src/dir-list.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1996, 1998, 2000-2002, 2006 Free Software Foundation, Inc. + Copyright (C) 1996, 1998, 2000-2002, 2006, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/dir-list.h b/gettext-tools/src/dir-list.h index 6ce32bb..954e017 100644 --- a/gettext-tools/src/dir-list.h +++ b/gettext-tools/src/dir-list.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1996, 1998, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1996, 1998, 2000-2003, 2015 Free Software Foundation, + Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/file-list.c b/gettext-tools/src/file-list.c index 2ee983d..c60f6a0 100644 --- a/gettext-tools/src/file-list.c +++ b/gettext-tools/src/file-list.c @@ -1,5 +1,6 @@ /* Reading file lists. - Copyright (C) 1995-1998, 2000-2002, 2007 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2002, 2007, 2015 Free Software + Foundation, Inc. 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 diff --git a/gettext-tools/src/file-list.h b/gettext-tools/src/file-list.h index 9665fbe..a43f6a4 100644 --- a/gettext-tools/src/file-list.h +++ b/gettext-tools/src/file-list.h @@ -1,5 +1,5 @@ /* Reading file lists. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/filter-quote.c b/gettext-tools/src/filter-quote.c index 2e9b7dc..25ac391 100644 --- a/gettext-tools/src/filter-quote.c +++ b/gettext-tools/src/filter-quote.c @@ -1,5 +1,5 @@ /* Convert ASCII quotations to Unicode quotations. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014-2015 Free Software Foundation, Inc. Written by Daiki Ueno <ueno@gnu.org>, 2014. This program is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ /* Specification. */ #include "filters.h" +#include "quote.h" #include <stdbool.h> #include <stdlib.h> #include <string.h> @@ -30,28 +31,83 @@ #define BOLD_START "\x1b[1m" #define BOLD_END "\x1b[0m" +struct result +{ + char *output; + char *offset; + bool bold; +}; + +static void +convert_quote_callback (char quote, const char *quoted, size_t quoted_length, + void *data) +{ + struct result *result = data; + + switch (quote) + { + case '\0': + memcpy (result->offset, quoted, quoted_length); + result->offset += quoted_length; + break; + + case '"': + /* U+201C: LEFT DOUBLE QUOTATION MARK */ + memcpy (result->offset, "\xe2\x80\x9c", 3); + result->offset += 3; + if (result->bold) + { + memcpy (result->offset, BOLD_START, 4); + result->offset += 4; + } + memcpy (result->offset, quoted, quoted_length); + result->offset += quoted_length; + if (result->bold) + { + memcpy (result->offset, BOLD_END, 4); + result->offset += 4; + } + /* U+201D: RIGHT DOUBLE QUOTATION MARK */ + memcpy (result->offset, "\xe2\x80\x9d", 3); + result->offset += 3; + break; + + case '\'': + /* U+2018: LEFT SINGLE QUOTATION MARK */ + memcpy (result->offset, "\xe2\x80\x98", 3); + result->offset += 3; + if (result->bold) + { + memcpy (result->offset, BOLD_START, 4); + result->offset += 4; + } + memcpy (result->offset, quoted, quoted_length); + result->offset += quoted_length; + if (result->bold) + { + memcpy (result->offset, BOLD_END, 4); + result->offset += 4; + } + /* U+2019: RIGHT SINGLE QUOTATION MARK */ + memcpy (result->offset, "\xe2\x80\x99", 3); + result->offset += 3; + break; + } +} + /* This is a direct translation of po/quot.sed and po/boldquot.sed. */ static void convert_ascii_quote_to_unicode (const char *input, size_t input_len, char **output_p, size_t *output_len_p, bool bold) { - const char *start, *end, *p; - char *output, *r; - bool state; + const char *p; size_t quote_count; - - start = input; - end = &input[input_len - 1]; - - /* True if we have seen a character which could be an opening - quotation mark. Note that we can't determine if it is really an - opening quotation mark until we see a closing quotation mark. */ - state = false; + struct result result; /* Count the number of quotation characters. */ quote_count = 0; - for (p = start; p <= end; p++) + for (p = input; p < input + input_len; p++) { size_t len; @@ -65,144 +121,16 @@ convert_ascii_quote_to_unicode (const char *input, size_t input_len, } /* Large enough. */ - r = output = XNMALLOC (input_len - quote_count - + (bold ? 7 : 3) * quote_count + 1, - char); - -#undef COPY_SEEN -#define COPY_SEEN \ - do \ - { \ - memcpy (r, start, p - start); \ - r += p - start; \ - start = p; \ - } \ - while (0) - - for (p = start; p <= end; p++) - { - switch (*p) - { - case '"': - if (state) - { - if (*start == '"') - { - if (p > start + 1) - { - /* U+201C: LEFT DOUBLE QUOTATION MARK */ - memcpy (r, "\xe2\x80\x9c", 3); - r += 3; - if (bold) - { - memcpy (r, BOLD_START, 4); - r += 4; - } - memcpy (r, start + 1, p - start - 1); - r += p - start - 1; - if (bold) - { - memcpy (r, BOLD_END, 4); - r += 4; - } - /* U+201D: RIGHT DOUBLE QUOTATION MARK */ - memcpy (r, "\xe2\x80\x9d", 3); - r += 3; - } - else - { - /* Consider "" as "". */ - memcpy (r, "\"\"", 2); - r += 2; - } - start = p + 1; - state = false; - } - } - else - { - COPY_SEEN; - state = true; - } - break; - - case '`': - if (state) - { - if (*start == '`') - COPY_SEEN; - } - else - { - COPY_SEEN; - state = true; - } - break; - - case '\'': - if (state) - { - if (/* `...' */ - *start == '`' - /* '...', where: - - The left quote is preceded by a space, and the - right quote is followed by a space. - - The left quote is preceded by a space, and the - right quote is at the end of line. - - The left quote is at the beginning of the line, and - the right quote is followed by a space. - */ - || (*start == '\'' - && (((start > input && *(start - 1) == ' ') - && (p == end || *(p + 1) == '\n' || *(p + 1) == ' ')) - || ((start == input || *(start - 1) == '\n') - && p < end && *(p + 1) == ' ')))) - { - /* U+2018: LEFT SINGLE QUOTATION MARK */ - memcpy (r, "\xe2\x80\x98", 3); - r += 3; - if (bold) - { - memcpy (r, BOLD_START, 4); - r += 4; - } - memcpy (r, start + 1, p - start - 1); - r += p - start - 1; - if (bold) - { - memcpy (r, BOLD_END, 4); - r += 4; - } - /* U+2019: RIGHT SINGLE QUOTATION MARK */ - memcpy (r, "\xe2\x80\x99", 3); - r += 3; - start = p + 1; - } - else - COPY_SEEN; - state = false; - } - else if (p == input || *(p - 1) == '\n' || *(p - 1) == ' ') - { - COPY_SEEN; - state = true; - } - break; - } - } + result.output = XNMALLOC (input_len - quote_count + + (bold ? 7 : 3) * quote_count + 1, + char); + result.offset = result.output; + result.bold = bold; -#undef COPY_SEEN - - /* Copy the rest to R. */ - if (p > start) - { - memcpy (r, start, p - start); - r += p - start; - } - *r = '\0'; + scan_quoted (input, input_len, convert_quote_callback, &result); - *output_p = output; - *output_len_p = r - output; + *output_p = result.output; + *output_len_p = result.offset - result.output; } void diff --git a/gettext-tools/src/filter-sr-latin.c b/gettext-tools/src/filter-sr-latin.c index d6dbd95..ea5457f 100644 --- a/gettext-tools/src/filter-sr-latin.c +++ b/gettext-tools/src/filter-sr-latin.c @@ -1,5 +1,5 @@ /* Recode Serbian text from Cyrillic to Latin script. - Copyright (C) 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2006-2007, 2009, 2015 Free Software Foundation, Inc. Written by Danilo Šegan <danilo@gnome.org>, 2006, and Bruno Haible <bruno@clisp.org>, 2006. diff --git a/gettext-tools/src/format-awk.c b/gettext-tools/src/format-awk.c index 91251c4..efaa2d7 100644 --- a/gettext-tools/src/format-awk.c +++ b/gettext-tools/src/format-awk.c @@ -1,5 +1,6 @@ /* awk format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-boost.c b/gettext-tools/src/format-boost.c index 688ba97..a390078 100644 --- a/gettext-tools/src/format-boost.c +++ b/gettext-tools/src/format-boost.c @@ -1,5 +1,6 @@ /* Boost format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-c-parse.h b/gettext-tools/src/format-c-parse.h index bacfcef..4918fd5 100644 --- a/gettext-tools/src/format-c-parse.h +++ b/gettext-tools/src/format-c-parse.h @@ -1,5 +1,6 @@ /* Parsing C format strings. - Copyright (C) 2001-2004, 2006-2007, 2009-2010 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009-2010, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-c.c b/gettext-tools/src/format-c.c index d88f8de..b2dc9dc 100644 --- a/gettext-tools/src/format-c.c +++ b/gettext-tools/src/format-c.c @@ -1,5 +1,6 @@ /* C format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-csharp.c b/gettext-tools/src/format-csharp.c index feb3fcf..1f5e715 100644 --- a/gettext-tools/src/format-csharp.c +++ b/gettext-tools/src/format-csharp.c @@ -1,5 +1,6 @@ /* C# format strings. - Copyright (C) 2003-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-elisp.c b/gettext-tools/src/format-elisp.c index 2e43fde..2eb99ac 100644 --- a/gettext-tools/src/format-elisp.c +++ b/gettext-tools/src/format-elisp.c @@ -1,5 +1,6 @@ /* Emacs Lisp format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-gcc-internal.c b/gettext-tools/src/format-gcc-internal.c index 7057628..f5ca5e8 100644 --- a/gettext-tools/src/format-gcc-internal.c +++ b/gettext-tools/src/format-gcc-internal.c @@ -1,5 +1,5 @@ /* GCC internal format strings. - Copyright (C) 2003-2009 Free Software Foundation, Inc. + Copyright (C) 2003-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-gfc-internal.c b/gettext-tools/src/format-gfc-internal.c index 4fbbc66..1932c17 100644 --- a/gettext-tools/src/format-gfc-internal.c +++ b/gettext-tools/src/format-gfc-internal.c @@ -1,5 +1,5 @@ /* GFC (GNU Fortran Compiler) internal format strings. - Copyright (C) 2003-2009 Free Software Foundation, Inc. + Copyright (C) 2003-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2009. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-invalid.h b/gettext-tools/src/format-invalid.h index 3ad60aa..ed6c501 100644 --- a/gettext-tools/src/format-invalid.h +++ b/gettext-tools/src/format-invalid.h @@ -1,5 +1,5 @@ /* Common reasons that make a format string invalid. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-java.c b/gettext-tools/src/format-java.c index 5196835..a69c84f 100644 --- a/gettext-tools/src/format-java.c +++ b/gettext-tools/src/format-java.c @@ -1,5 +1,6 @@ /* Java format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-javascript.c b/gettext-tools/src/format-javascript.c index d76a8d7..fa39e20 100644 --- a/gettext-tools/src/format-javascript.c +++ b/gettext-tools/src/format-javascript.c @@ -1,5 +1,6 @@ /* JavaScript format strings. - Copyright (C) 2001-2004, 2006-2009, 2013 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2009, 2013, 2015 Free Software + Foundation, Inc. Written by Andreas Stricker <andy@knitter.ch>, 2010. It's based on python format module from Bruno Haible. diff --git a/gettext-tools/src/format-kde-kuit.c b/gettext-tools/src/format-kde-kuit.c new file mode 100644 index 0000000..128d05d --- /dev/null +++ b/gettext-tools/src/format-kde-kuit.c @@ -0,0 +1,411 @@ +/* KUIT (KDE User Interface Text) format strings. + Copyright (C) 2015 Free Software Foundation, Inc. + Written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> + +#include "format.h" +#include "unistr.h" +#include "xalloc.h" +#include "xvasprintf.h" +#include "gettext.h" + +#if IN_LIBGETTEXTPO +/* Use included markup parser to avoid extra dependency from + libgettextpo to libxml2. */ +# ifndef FORMAT_KDE_KUIT_FALLBACK_MARKUP +# define FORMAT_KDE_KUIT_USE_FALLBACK_MARKUP 1 +# endif +#else +# define FORMAT_KDE_KUIT_USE_LIBXML2 1 +#endif + +#if FORMAT_KDE_KUIT_USE_LIBXML2 +# include <libxml/parser.h> +#elif FORMAT_KDE_KUIT_USE_FALLBACK_MARKUP +# include "markup.h" +#endif + + +#define _(str) gettext (str) + +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + + +/* KUIT (KDE User Interface Text) is an XML-like markup which augments + translatable strings with semantic information: + http://api.kde.org/frameworks-api/frameworks5-apidocs/ki18n/html/prg_guide.html#kuit_markup + KUIT can be seen as a fragment of a well-formed XML document, + except that it allows '&' as a Qt accelerator marker and '%' as a + format directive. */ + +struct spec +{ + /* A format string descriptor returned from formatstring_kde.parse. */ + void *base; +}; + +#define XML_NS "https://www.gnu.org/s/gettext/kde" + +struct char_range +{ + ucs4_t start; + ucs4_t end; +}; + +/* Character ranges for NameStartChar defined in: + http://www.w3.org/TR/REC-xml/#NT-NameStartChar */ +static const struct char_range name_chars1[] = + { + { ':', ':' }, + { 'A', 'Z' }, + { '_', '_' }, + { 'a', 'z' }, + { 0xC0, 0xD6 }, + { 0xD8, 0xF6 }, + { 0xF8, 0x2FF }, + { 0x370, 0x37D }, + { 0x37F, 0x1FFF }, + { 0x200C, 0x200D }, + { 0x2070, 0x218F }, + { 0x2C00, 0x2FEF }, + { 0x3001, 0xD7FF }, + { 0xF900, 0xFDCF }, + { 0xFDF0, 0xFFFD }, + { 0x10000, 0xEFFFF } + }; + +/* Character ranges for NameChar, excluding NameStartChar: + http://www.w3.org/TR/REC-xml/#NT-NameChar */ +static const struct char_range name_chars2[] = + { + { '-', '-' }, + { '.', '.' }, + { '0', '9' }, + { 0xB7, 0xB7 }, + { 0x0300, 0x036F }, + { 0x203F, 0x2040 } + }; + +/* Return true if INPUT is an XML reference. */ +static bool +is_reference (const char *input) +{ + const char *str = input; + const char *str_limit = str + strlen (input); + ucs4_t uc; + int i; + + str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str); + assert (uc == '&'); + + str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str); + + /* CharRef */ + if (uc == '#') + { + str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str); + if (uc == 'x') + { + while (str < str_limit) + { + str += u8_mbtouc (&uc, (const unsigned char *) str, + str_limit - str); + if (!(('0' <= uc && uc <= '9') + || ('A' <= uc && uc <= 'F') + || ('a' <= uc && uc <= 'f'))) + break; + } + return uc == ';'; + } + else if ('0' <= uc && uc <= '9') + { + while (str < str_limit) + { + str += u8_mbtouc (&uc, (const unsigned char *) str, + str_limit - str); + if (!('0' <= uc && uc <= '9')) + break; + } + return uc == ';'; + } + } + else + { + /* EntityRef */ + for (i = 0; i < SIZEOF (name_chars1); i++) + if (name_chars1[i].start <= uc && uc <= name_chars1[i].end) + break; + + if (i == SIZEOF (name_chars1)) + return false; + + while (str < str_limit) + { + str += u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str); + for (i = 0; i < SIZEOF (name_chars1); i++) + if (name_chars1[i].start <= uc && uc <= name_chars1[i].end) + break; + if (i == SIZEOF (name_chars1)) + { + for (i = 0; i < SIZEOF (name_chars2); i++) + if (name_chars2[i].start <= uc && uc <= name_chars2[i].end) + break; + if (i == SIZEOF (name_chars2)) + return false; + } + } + return uc == ';'; + } + + return false; +} + + +static void * +format_parse (const char *format, bool translated, char *fdi, + char **invalid_reason) +{ + struct spec spec; + struct spec *result; + const char *str; + const char *str_limit; + size_t amp_count; + char *buffer, *bp; + + spec.base = NULL; + + /* Preprocess the input, putting the content in a <gt:kuit> element. */ + str = format; + str_limit = str + strlen (format); + + for (amp_count = 0; str < str_limit; amp_count++) + { + const char *amp = strchrnul (str, '&'); + if (*amp != '&') + break; + str = amp + 1; + } + + buffer = xmalloc (amp_count * 4 + + strlen (format) + + strlen ("<gt:kuit xmlns:gt=\"" XML_NS "\"></gt:kuit>") + + 1); + *buffer = '\0'; + + bp = buffer; + bp = stpcpy (bp, "<gt:kuit xmlns:gt=\"" XML_NS "\">"); + str = format; + while (str < str_limit) + { + const char *amp = strchrnul (str, '&'); + + bp = stpncpy (bp, str, amp - str); + if (*amp != '&') + break; + + bp = stpcpy (bp, is_reference (amp) ? "&" : "&"); + str = amp + 1; + } + stpcpy (bp, "</gt:kuit>"); + +#if FORMAT_KDE_KUIT_USE_LIBXML2 + { + xmlDocPtr doc; + + doc = xmlReadMemory (buffer, strlen (buffer), "", NULL, + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOERROR + | XML_PARSE_NOBLANKS); + if (doc == NULL) + { + xmlError *err = xmlGetLastError (); + *invalid_reason = + xasprintf (_("error while parsing: %s"), + err->message); + free (buffer); + xmlFreeDoc (doc); + return NULL; + } + + free (buffer); + xmlFreeDoc (doc); + } +#elif FORMAT_KDE_KUIT_FALLBACK_MARKUP + { + markup_parser_ty parser; + markup_parse_context_ty *context; + + memset (&parser, 0, sizeof (markup_parser_ty)); + context = markup_parse_context_new (&parser, 0, NULL); + if (!markup_parse_context_parse (context, buffer, strlen (buffer))) + { + *invalid_reason = + xasprintf (_("error while parsing: %s"), + markup_parse_context_get_error (context)); + free (buffer); + markup_parse_context_free (context); + return NULL; + } + + if (!markup_parse_context_end_parse (context)) + { + *invalid_reason = + xasprintf (_("error while parsing: %s"), + markup_parse_context_get_error (context)); + free (buffer); + markup_parse_context_free (context); + return NULL; + } + + free (buffer); + markup_parse_context_free (context); + } +#else + /* No support for XML. */ +#endif + + spec.base = formatstring_kde.parse (format, translated, fdi, invalid_reason); + if (spec.base == NULL) + return NULL; + + result = XMALLOC (struct spec); + *result = spec; + return result; +} + +static void +format_free (void *descr) +{ + struct spec *spec = descr; + formatstring_kde.free (spec->base); + free (spec); +} + +static int +format_get_number_of_directives (void *descr) +{ + struct spec *spec = descr; + return formatstring_kde.get_number_of_directives (spec->base); +} + +static bool +format_check (void *msgid_descr, void *msgstr_descr, bool equality, + formatstring_error_logger_t error_logger, + const char *pretty_msgid, const char *pretty_msgstr) +{ + struct spec *msgid_spec = msgid_descr; + struct spec *msgstr_spec = msgstr_descr; + + return formatstring_kde.check (msgid_spec->base, msgstr_spec->base, equality, + error_logger, + pretty_msgid, pretty_msgstr); +} + +struct formatstring_parser formatstring_kde_kuit = +{ + format_parse, + format_free, + format_get_number_of_directives, + NULL, + format_check +}; + + +#ifdef TEST + +/* Test program: Print the argument list specification returned by + format_parse for strings read from standard input. */ + +#include <stdio.h> + +static void +format_print (void *descr) +{ + struct spec *spec = (struct spec *) descr; + unsigned int last; + unsigned int i; + + if (spec == NULL) + { + printf ("INVALID"); + return; + } + + printf ("("); + last = 1; + for (i = 0; i < spec->numbered_arg_count; i++) + { + unsigned int number = spec->numbered[i].number; + + if (i > 0) + printf (" "); + if (number < last) + abort (); + for (; last < number; last++) + printf ("_ "); + last = number + 1; + } + printf (")"); +} + +int +main () +{ + for (;;) + { + char *line = NULL; + size_t line_size = 0; + int line_len; + char *invalid_reason; + void *descr; + + line_len = getline (&line, &line_size, stdin); + if (line_len < 0) + break; + if (line_len > 0 && line[line_len - 1] == '\n') + line[--line_len] = '\0'; + + invalid_reason = NULL; + descr = format_parse (line, false, NULL, &invalid_reason); + + format_print (descr); + printf ("\n"); + if (descr == NULL) + printf ("%s\n", invalid_reason); + + free (invalid_reason); + free (line); + } + + return 0; +} + +/* + * For Emacs M-x compile + * Local Variables: + * compile-command: "/bin/sh ../libtool --tag=CC --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../gnulib-lib -I../intl -DHAVE_CONFIG_H -DTEST format-kde-kuit.c ../gnulib-lib/libgettextlib.la" + * End: + */ + +#endif /* TEST */ diff --git a/gettext-tools/src/format-kde.c b/gettext-tools/src/format-kde.c index 90e887d..6848781 100644 --- a/gettext-tools/src/format-kde.c +++ b/gettext-tools/src/format-kde.c @@ -1,5 +1,6 @@ /* KDE format strings. - Copyright (C) 2003-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2007. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-librep.c b/gettext-tools/src/format-librep.c index 05185ad..9c15aea 100644 --- a/gettext-tools/src/format-librep.c +++ b/gettext-tools/src/format-librep.c @@ -1,5 +1,6 @@ /* librep format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-lisp.c b/gettext-tools/src/format-lisp.c index 7d423a5..2f9949e 100644 --- a/gettext-tools/src/format-lisp.c +++ b/gettext-tools/src/format-lisp.c @@ -1,5 +1,6 @@ /* Lisp format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-lua.c b/gettext-tools/src/format-lua.c index 272def4..6a68b82 100644 --- a/gettext-tools/src/format-lua.c +++ b/gettext-tools/src/format-lua.c @@ -1,5 +1,5 @@ /* Lua format strings. - Copyright (C) 2012 Free Software Foundation, Inc. + Copyright (C) 2012, 2015 Free Software Foundation, Inc. Written by Ľubomír Remák <lubomirr@lubomirr.eu>, 2012. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-pascal.c b/gettext-tools/src/format-pascal.c index 7e0c505..b443ba7 100644 --- a/gettext-tools/src/format-pascal.c +++ b/gettext-tools/src/format-pascal.c @@ -1,5 +1,6 @@ /* Object Pascal format strings. - Copyright (C) 2001-2004, 2006-2007, 2009-2010 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009-2010, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-perl-brace.c b/gettext-tools/src/format-perl-brace.c index 3ab05ce..64a0663 100644 --- a/gettext-tools/src/format-perl-brace.c +++ b/gettext-tools/src/format-perl-brace.c @@ -1,5 +1,5 @@ /* Perl brace format strings. - Copyright (C) 2004, 2006-2007 Free Software Foundation, Inc. + Copyright (C) 2004, 2006-2007, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-perl.c b/gettext-tools/src/format-perl.c index 730d190..af741e9 100644 --- a/gettext-tools/src/format-perl.c +++ b/gettext-tools/src/format-perl.c @@ -1,5 +1,6 @@ /* Perl format strings. - Copyright (C) 2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2006-2007, 2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-php.c b/gettext-tools/src/format-php.c index 5dd6d7f..ebaaa33 100644 --- a/gettext-tools/src/format-php.c +++ b/gettext-tools/src/format-php.c @@ -1,5 +1,6 @@ /* PHP format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-python-brace.c b/gettext-tools/src/format-python-brace.c index 141d3df..4323230 100644 --- a/gettext-tools/src/format-python-brace.c +++ b/gettext-tools/src/format-python-brace.c @@ -1,5 +1,6 @@ /* Python brace format strings. - Copyright (C) 2004, 2006-2007, 2013 Free Software Foundation, Inc. + Copyright (C) 2004, 2006-2007, 2013, 2015 Free Software Foundation, + Inc. Written by Daiki Ueno <ueno@gnu.org>, 2013. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-python.c b/gettext-tools/src/format-python.c index d6a1338..8af3c12 100644 --- a/gettext-tools/src/format-python.c +++ b/gettext-tools/src/format-python.c @@ -1,5 +1,6 @@ /* Python format strings. - Copyright (C) 2001-2004, 2006-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-qt-plural.c b/gettext-tools/src/format-qt-plural.c index 5301d42..fafe6ab 100644 --- a/gettext-tools/src/format-qt-plural.c +++ b/gettext-tools/src/format-qt-plural.c @@ -1,5 +1,6 @@ /* Qt plural format strings. - Copyright (C) 2003-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2009. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-qt.c b/gettext-tools/src/format-qt.c index 3f759a2..abdc4da 100644 --- a/gettext-tools/src/format-qt.c +++ b/gettext-tools/src/format-qt.c @@ -1,5 +1,6 @@ /* Qt format strings. - Copyright (C) 2003-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-scheme.c b/gettext-tools/src/format-scheme.c index 02c6182..adc1cc6 100644 --- a/gettext-tools/src/format-scheme.c +++ b/gettext-tools/src/format-scheme.c @@ -1,5 +1,5 @@ /* Scheme format strings. - Copyright (C) 2001-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-sh.c b/gettext-tools/src/format-sh.c index b796fcd..eeeec04 100644 --- a/gettext-tools/src/format-sh.c +++ b/gettext-tools/src/format-sh.c @@ -1,5 +1,6 @@ /* Shell format strings. - Copyright (C) 2003-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-tcl.c b/gettext-tools/src/format-tcl.c index e338c6d..1254b2d 100644 --- a/gettext-tools/src/format-tcl.c +++ b/gettext-tools/src/format-tcl.c @@ -1,5 +1,6 @@ /* Tcl format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format-ycp.c b/gettext-tools/src/format-ycp.c index 762a5d7..398b644 100644 --- a/gettext-tools/src/format-ycp.c +++ b/gettext-tools/src/format-ycp.c @@ -1,5 +1,6 @@ /* YCP and Smalltalk format strings. - Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2004, 2006-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/format.c b/gettext-tools/src/format.c index c73ad7d..69b1f47 100644 --- a/gettext-tools/src/format.c +++ b/gettext-tools/src/format.c @@ -1,5 +1,5 @@ /* Format strings. - Copyright (C) 2001-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -58,6 +58,7 @@ struct formatstring_parser *formatstring_parsers[NFORMATS] = /* format_qt */ &formatstring_qt, /* format_qt_plural */ &formatstring_qt_plural, /* format_kde */ &formatstring_kde, + /* format_kde_kuit */ &formatstring_kde_kuit, /* format_boost */ &formatstring_boost, /* format_lua */ &formatstring_lua, /* format_javascript */ &formatstring_javascript diff --git a/gettext-tools/src/format.h b/gettext-tools/src/format.h index d92532d..b311e48 100644 --- a/gettext-tools/src/format.h +++ b/gettext-tools/src/format.h @@ -1,5 +1,5 @@ /* Format strings. - Copyright (C) 2001-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -119,6 +119,7 @@ extern DLL_VARIABLE struct formatstring_parser formatstring_gfc_internal; extern DLL_VARIABLE struct formatstring_parser formatstring_qt; extern DLL_VARIABLE struct formatstring_parser formatstring_qt_plural; extern DLL_VARIABLE struct formatstring_parser formatstring_kde; +extern DLL_VARIABLE struct formatstring_parser formatstring_kde_kuit; extern DLL_VARIABLE struct formatstring_parser formatstring_boost; extern DLL_VARIABLE struct formatstring_parser formatstring_lua; extern DLL_VARIABLE struct formatstring_parser formatstring_javascript; diff --git a/gettext-tools/src/gnu/gettext/DumpResource.java b/gettext-tools/src/gnu/gettext/DumpResource.java index 77c6e01..40a1d92 100644 --- a/gettext-tools/src/gnu/gettext/DumpResource.java +++ b/gettext-tools/src/gnu/gettext/DumpResource.java @@ -1,5 +1,5 @@ /* GNU gettext for Java - * Copyright (C) 2001-2003, 2007 Free Software Foundation, Inc. + * Copyright (C) 2001-2003, 2007, 2015 Free Software Foundation, Inc. * * 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 diff --git a/gettext-tools/src/gnu/gettext/GetURL.java b/gettext-tools/src/gnu/gettext/GetURL.java index f42ccc4..9faac6d 100644 --- a/gettext-tools/src/gnu/gettext/GetURL.java +++ b/gettext-tools/src/gnu/gettext/GetURL.java @@ -1,5 +1,5 @@ /* Fetch an URL's contents. - * Copyright (C) 2001, 2008 Free Software Foundation, Inc. + * Copyright (C) 2001, 2008, 2015 Free Software Foundation, Inc. * * 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 diff --git a/gettext-tools/src/hostname.c b/gettext-tools/src/hostname.c index a7032b3..684aa4e 100644 --- a/gettext-tools/src/hostname.c +++ b/gettext-tools/src/hostname.c @@ -1,5 +1,6 @@ /* Display hostname in various forms. - Copyright (C) 2001-2003, 2006-2007, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006-2007, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/its.c b/gettext-tools/src/its.c new file mode 100644 index 0000000..ce4880a --- /dev/null +++ b/gettext-tools/src/its.c @@ -0,0 +1,1946 @@ +/* Internationalization Tag Set (ITS) handling + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* Specification. */ +#include "its.h" + +#include <assert.h> +#include <errno.h> +#include "error.h" +#include "gettext.h" +#include "hash.h" +#include <stdint.h> +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xmlwriter.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <stdlib.h> +#include "trim.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#define _(str) gettext (str) + +/* The Internationalization Tag Set (ITS) 2.0 standard is available at: + http://www.w3.org/TR/its20/ + + This implementation supports only a few data categories, useful for + gettext-based projects. Other data categories can be added by + extending the its_rule_class_ty class and registering it in + init_classes(). + + The message extraction is performed in three steps. In the first + step, its_rule_list_apply() assigns values to nodes in an XML + document. In the second step, its_rule_list_extract_nodes() marks + translatable nodes. In the final step, + its_rule_list_extract_text() extracts text contents from the marked + nodes. + + The values assigned to a node are represented as an array of + key-value pairs, where both keys and values are string. The array + is stored in node->_private. To retrieve the values for a node, + use its_rule_list_eval(). */ + +#define ITS_NS "http://www.w3.org/2005/11/its" +#define XML_NS "http://www.w3.org/XML/1998/namespace" +#define GT_NS "https://www.gnu.org/s/gettext/ns/its/extensions/1.0" + +struct its_value_ty +{ + char *name; + char *value; +}; + +struct its_value_list_ty +{ + struct its_value_ty *items; + size_t nitems; + size_t nitems_max; +}; + +static void +its_value_list_append (struct its_value_list_ty *values, + const char *name, + const char *value) +{ + struct its_value_ty _value; + + _value.name = xstrdup (name); + _value.value = xstrdup (value); + + if (values->nitems == values->nitems_max) + { + values->nitems_max = 2 * values->nitems_max + 1; + values->items = + xrealloc (values->items, + sizeof (struct its_value_ty) * values->nitems_max); + } + memcpy (&values->items[values->nitems++], &_value, + sizeof (struct its_value_ty)); +} + +static const char * +its_value_list_get_value (struct its_value_list_ty *values, + const char *name) +{ + size_t i; + + for (i = 0; i < values->nitems; i++) + { + struct its_value_ty *value = &values->items[i]; + if (strcmp (value->name, name) == 0) + return value->value; + } + return NULL; +} + +static void +its_value_list_set_value (struct its_value_list_ty *values, + const char *name, + const char *value) +{ + size_t i; + + for (i = 0; i < values->nitems; i++) + { + struct its_value_ty *_value = &values->items[i]; + if (strcmp (_value->name, name) == 0) + { + free (_value->value); + _value->value = xstrdup (value); + break; + } + } + + if (i == values->nitems) + its_value_list_append (values, name, value); +} + +static void +its_value_list_merge (struct its_value_list_ty *values, + struct its_value_list_ty *other) +{ + size_t i; + + for (i = 0; i < other->nitems; i++) + { + struct its_value_ty *other_value = &other->items[i]; + size_t j; + + for (j = 0; j < values->nitems; j++) + { + struct its_value_ty *value = &values->items[j]; + + if (strcmp (value->name, other_value->name) == 0 + && strcmp (value->value, other_value->value) != 0) + { + free (value->value); + value->value = xstrdup (other_value->value); + break; + } + } + + if (j == values->nitems) + its_value_list_append (values, other_value->name, other_value->value); + } +} + +static void +its_value_list_destroy (struct its_value_list_ty *values) +{ + size_t i; + + for (i = 0; i < values->nitems; i++) + { + free (values->items[i].name); + free (values->items[i].value); + } + free (values->items); +} + +struct its_pool_ty +{ + struct its_value_list_ty *items; + size_t nitems; + size_t nitems_max; +}; + +static struct its_value_list_ty * +its_pool_alloc_value_list (struct its_pool_ty *pool) +{ + struct its_value_list_ty *values; + + if (pool->nitems == pool->nitems_max) + { + pool->nitems_max = 2 * pool->nitems_max + 1; + pool->items = + xrealloc (pool->items, + sizeof (struct its_value_list_ty) * pool->nitems_max); + } + + values = &pool->items[pool->nitems++]; + memset (values, 0, sizeof (struct its_value_list_ty)); + return values; +} + +static const char * +its_pool_get_value_for_node (struct its_pool_ty *pool, xmlNode *node, + const char *name) +{ + intptr_t index = (intptr_t) node->_private; + if (index > 0) + { + struct its_value_list_ty *values; + + assert (index <= pool->nitems); + values = &pool->items[index - 1]; + + return its_value_list_get_value (values, name); + } + return NULL; +} + +static void +its_pool_destroy (struct its_pool_ty *pool) +{ + size_t i; + + for (i = 0; i < pool->nitems; i++) + its_value_list_destroy (&pool->items[i]); + free (pool->items); +} + +struct its_rule_list_ty +{ + struct its_rule_ty **items; + size_t nitems; + size_t nitems_max; + + struct its_pool_ty pool; +}; + +struct its_node_list_ty +{ + xmlNode **items; + size_t nitems; + size_t nitems_max; +}; + +static void +its_node_list_append (struct its_node_list_ty *nodes, + xmlNode *node) +{ + if (nodes->nitems == nodes->nitems_max) + { + nodes->nitems_max = 2 * nodes->nitems_max + 1; + nodes->items = + xrealloc (nodes->items, sizeof (xmlNode *) * nodes->nitems_max); + } + nodes->items[nodes->nitems++] = node; +} + +/* Base class representing an ITS rule in global definition. */ +struct its_rule_class_ty +{ + /* How many bytes to malloc for an instance of this class. */ + size_t size; + + /* What to do immediately after the instance is malloc()ed. */ + void (*constructor) (struct its_rule_ty *pop, xmlNode *node); + + /* What to do immediately before the instance is free()ed. */ + void (*destructor) (struct its_rule_ty *pop); + + /* How to apply the rule to all elements in DOC. */ + void (* apply) (struct its_rule_ty *pop, struct its_pool_ty *pool, + xmlDoc *doc); + + /* How to evaluate the value of NODE according to the rule. */ + struct its_value_list_ty *(* eval) (struct its_rule_ty *pop, + struct its_pool_ty *pool, xmlNode *node); +}; + +#define ITS_RULE_TY \ + struct its_rule_class_ty *methods; \ + char *selector; \ + struct its_value_list_ty values; \ + xmlNs **namespaces; + +struct its_rule_ty +{ + ITS_RULE_TY +}; + +static hash_table classes; + +static void +its_rule_destructor (struct its_rule_ty *pop) +{ + free (pop->selector); + its_value_list_destroy (&pop->values); + if (pop->namespaces) + { + size_t i; + for (i = 0; pop->namespaces[i] != NULL; i++) + xmlFreeNs (pop->namespaces[i]); + free (pop->namespaces); + } +} + +static void +its_rule_apply (struct its_rule_ty *rule, struct its_pool_ty *pool, xmlDoc *doc) +{ + xmlXPathContext *context; + xmlXPathObject *object; + size_t i; + + if (!rule->selector) + { + error (0, 0, _("selector is not specified")); + return; + } + + context = xmlXPathNewContext (doc); + if (!context) + { + error (0, 0, _("cannot create XPath context")); + return; + } + + if (rule->namespaces) + { + size_t i; + for (i = 0; rule->namespaces[i] != NULL; i++) + { + xmlNs *ns = rule->namespaces[i]; + xmlXPathRegisterNs (context, ns->prefix, ns->href); + } + } + + object = xmlXPathEval (BAD_CAST rule->selector, context); + if (!object) + { + xmlXPathFreeContext (context); + error (0, 0, _("cannot evaluate XPath expression: %s"), rule->selector); + return; + } + + if (object->nodesetval) + { + xmlNodeSet *nodes = object->nodesetval; + for (i = 0; i < nodes->nodeNr; i++) + { + xmlNode *node = nodes->nodeTab[i]; + struct its_value_list_ty *values; + + /* We can't store VALUES in NODE, since the address can + change when realloc()ed. */ + intptr_t index = (intptr_t) node->_private; + + assert (index <= pool->nitems); + if (index > 0) + values = &pool->items[index - 1]; + else + { + values = its_pool_alloc_value_list (pool); + node->_private = (void *) pool->nitems; + } + + its_value_list_merge (values, &rule->values); + } + } + + xmlXPathFreeObject (object); + xmlXPathFreeContext (context); +} + +static char * +_its_get_attribute (xmlNode *node, const char *attr, const char *namespace) +{ + xmlChar *value; + char *result; + + value = xmlGetNsProp (node, BAD_CAST attr, BAD_CAST namespace); + + result = xstrdup ((const char *) value); + xmlFree (value); + + return result; +} + +static char * +normalize_whitespace (const char *text, enum its_whitespace_type_ty whitespace) +{ + switch (whitespace) + { + case ITS_WHITESPACE_PRESERVE: + return xstrdup (text); + + case ITS_WHITESPACE_TRIM: + return trim (text); + + default: + /* Normalize whitespaces within the text, but not at the beginning + nor the end of the text. */ + { + char *result, *p, *end; + + result = xstrdup (text); + end = result + strlen (result); + for (p = result; *p != '\0';) + { + size_t len = strspn (p, " \t\n"); + if (len > 0) + { + *p = ' '; + memmove (p + 1, p + len, end - (p + len)); + end -= len - 1; + *end = '\0'; + p++; + } + p += strcspn (p, " \t\n"); + } + return result; + } + } +} + +static char * +_its_encode_special_chars (const char *content, bool is_attribute) +{ + const char *str; + size_t amount = 0; + char *result, *p; + + for (str = content; *str != '\0'; str++) + { + switch (*str) + { + case '&': + amount += sizeof ("&"); + break; + case '<': + amount += sizeof ("<"); + break; + case '>': + amount += sizeof (">"); + break; + case '"': + if (is_attribute) + amount += sizeof ("""); + else + amount += 1; + break; + default: + amount += 1; + break; + } + } + + result = XNMALLOC (amount + 1, char); + *result = '\0'; + p = result; + for (str = content; *str != '\0'; str++) + { + switch (*str) + { + case '&': + p = stpcpy (p, "&"); + break; + case '<': + p = stpcpy (p, "<"); + break; + case '>': + p = stpcpy (p, ">"); + break; + case '"': + if (is_attribute) + p = stpcpy (p, """); + else + *p++ = '"'; + break; + default: + *p++ = *str; + break; + } + } + *p = '\0'; + return result; +} + +static char * +_its_collect_text_content (xmlNode *node, + enum its_whitespace_type_ty whitespace, + bool no_escape) +{ + char *buffer = NULL; + size_t bufmax = 0; + size_t bufpos = 0; + xmlNode *n; + + for (n = node->children; n; n = n->next) + { + char *content = NULL; + + switch (n->type) + { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + { + xmlChar *xcontent = xmlNodeGetContent (n); + char *econtent; + const char *ccontent; + + /* We can't expect xmlTextWriterWriteString() encode + special characters as we write text outside of the + element. */ + if (no_escape) + econtent = xstrdup ((const char *) xcontent); + else + econtent = + _its_encode_special_chars ((const char *) xcontent, + node->type == XML_ATTRIBUTE_NODE); + xmlFree (xcontent); + + /* Skip whitespaces at the beginning of the text, if this + is the first node. */ + ccontent = econtent; + if (whitespace == ITS_WHITESPACE_NORMALIZE && !n->prev) + ccontent = ccontent + strspn (ccontent, " \t\n"); + content = + normalize_whitespace (ccontent, whitespace); + free (econtent); + + /* Skip whitespaces at the end of the text, if this + is the last node. */ + if (whitespace == ITS_WHITESPACE_NORMALIZE && !n->next) + { + char *p = content + strlen (content); + for (; p > content; p--) + { + int c = *(p - 1); + if (!(c == ' ' || c == '\t' || c == '\n')) + { + *p = '\0'; + break; + } + } + } + } + break; + + case XML_ELEMENT_NODE: + { + xmlOutputBuffer *buffer = xmlAllocOutputBuffer (NULL); + xmlTextWriter *writer = xmlNewTextWriter (buffer); + char *p = _its_collect_text_content (n, whitespace, + no_escape); + const char *ccontent; + + xmlTextWriterStartElement (writer, BAD_CAST n->name); + if (n->properties) + { + xmlAttr *attr = n->properties; + for (; attr; attr = attr->next) + { + xmlChar *prop = xmlGetProp (n, attr->name); + xmlTextWriterWriteAttribute (writer, + attr->name, + prop); + xmlFree (prop); + } + } + if (*p != '\0') + xmlTextWriterWriteRaw (writer, BAD_CAST p); + xmlTextWriterEndElement (writer); + ccontent = (const char *) xmlOutputBufferGetContent (buffer); + content = normalize_whitespace (ccontent, whitespace); + xmlFreeTextWriter (writer); + free (p); + } + break; + + case XML_ENTITY_REF_NODE: + content = xasprintf ("&%s;", (const char *) n->name); + break; + + default: + break; + } + + if (content != NULL) + { + size_t length = strlen (content); + + if (bufpos + length + 1 >= bufmax) + { + bufmax = 2 * bufmax + length + 1; + buffer = xrealloc (buffer, bufmax); + } + strcpy (&buffer[bufpos], content); + bufpos += length; + } + free (content); + } + + if (buffer == NULL) + buffer = xstrdup (""); + return buffer; +} + +static void +_its_error_missing_attribute (xmlNode *node, const char *attribute) +{ + error (0, 0, _("\"%s\" node does not contain \"%s\""), + node->name, attribute); +} + +/* Implementation of Translate data category. */ +static void +its_translate_rule_constructor (struct its_rule_ty *pop, xmlNode *node) +{ + char *prop; + + if (!xmlHasProp (node, BAD_CAST "selector")) + { + _its_error_missing_attribute (node, "selector"); + return; + } + + if (!xmlHasProp (node, BAD_CAST "translate")) + { + _its_error_missing_attribute (node, "translate"); + return; + } + + prop = _its_get_attribute (node, "selector", NULL); + if (prop) + pop->selector = prop; + + prop = _its_get_attribute (node, "translate", NULL); + its_value_list_append (&pop->values, "translate", prop); + free (prop); +} + +struct its_value_list_ty * +its_translate_rule_eval (struct its_rule_ty *pop, struct its_pool_ty *pool, + xmlNode *node) +{ + struct its_value_list_ty *result; + + result = XCALLOC (1, struct its_value_list_ty); + + switch (node->type) + { + case XML_ATTRIBUTE_NODE: + /* Attribute nodes don't inherit from the parent elements. */ + { + const char *value = + its_pool_get_value_for_node (pool, node, "translate"); + if (value != NULL) + { + its_value_list_set_value (result, "translate", value); + return result; + } + + /* The default value is translate="no". */ + its_value_list_append (result, "translate", "no"); + } + break; + + case XML_ELEMENT_NODE: + /* Inherit from the parent elements. */ + { + const char *value; + + /* A local attribute overrides the global rule. */ + if (xmlHasNsProp (node, BAD_CAST "translate", BAD_CAST ITS_NS)) + { + char *prop; + + prop = _its_get_attribute (node, "translate", ITS_NS); + its_value_list_append (result, "translate", prop); + free (prop); + return result; + } + + /* Check value for the current node. */ + value = its_pool_get_value_for_node (pool, node, "translate"); + if (value != NULL) + { + its_value_list_set_value (result, "translate", value); + return result; + } + + /* Recursively check value for the parent node. */ + if (node->parent == NULL + || node->parent->type != XML_ELEMENT_NODE) + /* The default value is translate="yes". */ + its_value_list_append (result, "translate", "yes"); + else + { + struct its_value_list_ty *values; + + values = its_translate_rule_eval (pop, pool, node->parent); + its_value_list_merge (result, values); + its_value_list_destroy (values); + free (values); + } + } + break; + + default: + break; + } + + return result; +} + +static struct its_rule_class_ty its_translate_rule_class = + { + sizeof (struct its_rule_ty), + its_translate_rule_constructor, + its_rule_destructor, + its_rule_apply, + its_translate_rule_eval, + }; + +/* Implementation of Localization Note data category. */ +static void +its_localization_note_rule_constructor (struct its_rule_ty *pop, xmlNode *node) +{ + char *prop; + xmlNode *n; + + if (!xmlHasProp (node, BAD_CAST "selector")) + { + _its_error_missing_attribute (node, "selector"); + return; + } + + if (!xmlHasProp (node, BAD_CAST "locNoteType")) + { + _its_error_missing_attribute (node, "locNoteType"); + return; + } + + prop = _its_get_attribute (node, "selector", NULL); + if (prop) + pop->selector = prop; + + for (n = node->children; n; n = n->next) + { + if (n->type == XML_ELEMENT_NODE + && xmlStrEqual (n->name, BAD_CAST "locNote") + && xmlStrEqual (n->ns->href, BAD_CAST ITS_NS)) + break; + } + + prop = _its_get_attribute (node, "locNoteType", NULL); + if (prop) + its_value_list_append (&pop->values, "locNoteType", prop); + free (prop); + + if (n) + { + /* FIXME: Respect space attribute. */ + char *content = _its_collect_text_content (n, ITS_WHITESPACE_NORMALIZE, + false); + its_value_list_append (&pop->values, "locNote", content); + free (content); + } + else if (xmlHasProp (node, BAD_CAST "locNotePointer")) + { + prop = _its_get_attribute (node, "locNotePointer", NULL); + its_value_list_append (&pop->values, "locNotePointer", prop); + free (prop); + } + /* FIXME: locNoteRef and locNoteRefPointer */ +} + +struct its_value_list_ty * +its_localization_note_rule_eval (struct its_rule_ty *pop, + struct its_pool_ty *pool, + xmlNode *node) +{ + struct its_value_list_ty *result; + + result = XCALLOC (1, struct its_value_list_ty); + + switch (node->type) + { + case XML_ATTRIBUTE_NODE: + /* Attribute nodes don't inherit from the parent elements. */ + { + const char *value; + + value = its_pool_get_value_for_node (pool, node, "locNoteType"); + if (value != NULL) + its_value_list_set_value (result, "locNoteType", value); + + value = its_pool_get_value_for_node (pool, node, "locNote"); + if (value != NULL) + { + its_value_list_set_value (result, "locNote", value); + return result; + } + + value = its_pool_get_value_for_node (pool, node, "locNotePointer"); + if (value != NULL) + { + its_value_list_set_value (result, "locNotePointer", value); + return result; + } + } + break; + + case XML_ELEMENT_NODE: + /* Inherit from the parent elements. */ + { + const char *value; + + /* Local attributes overrides the global rule. */ + if (xmlHasNsProp (node, BAD_CAST "locNote", BAD_CAST ITS_NS) + || xmlHasNsProp (node, BAD_CAST "locNoteRef", BAD_CAST ITS_NS) + || xmlHasNsProp (node, BAD_CAST "locNoteType", BAD_CAST ITS_NS)) + { + char *prop; + + if (xmlHasNsProp (node, BAD_CAST "locNote", BAD_CAST ITS_NS)) + { + prop = _its_get_attribute (node, "locNote", ITS_NS); + its_value_list_append (result, "locNote", prop); + free (prop); + } + + /* FIXME: locNoteRef */ + + if (xmlHasNsProp (node, BAD_CAST "locNoteType", BAD_CAST ITS_NS)) + { + prop = _its_get_attribute (node, "locNoteType", ITS_NS); + its_value_list_append (result, "locNoteType", prop); + free (prop); + } + + return result; + } + + /* Check value for the current node. */ + value = its_pool_get_value_for_node (pool, node, "locNoteType"); + if (value != NULL) + its_value_list_set_value (result, "locNoteType", value); + + value = its_pool_get_value_for_node (pool, node, "locNote"); + if (value != NULL) + { + its_value_list_set_value (result, "locNote", value); + return result; + } + + value = its_pool_get_value_for_node (pool, node, "locNotePointer"); + if (value != NULL) + { + its_value_list_set_value (result, "locNotePointer", value); + return result; + } + + /* Recursively check value for the parent node. */ + if (node->parent == NULL + || node->parent->type != XML_ELEMENT_NODE) + return result; + else + { + struct its_value_list_ty *values; + + values = its_localization_note_rule_eval (pop, pool, node->parent); + its_value_list_merge (result, values); + its_value_list_destroy (values); + free (values); + } + } + break; + + default: + break; + } + + /* The default value is None. */ + return result; +} + +static struct its_rule_class_ty its_localization_note_rule_class = + { + sizeof (struct its_rule_ty), + its_localization_note_rule_constructor, + its_rule_destructor, + its_rule_apply, + its_localization_note_rule_eval, + }; + +/* Implementation of Element Within Text data category. */ +static void +its_element_within_text_rule_constructor (struct its_rule_ty *pop, + xmlNode *node) +{ + char *prop; + + if (!xmlHasProp (node, BAD_CAST "selector")) + { + _its_error_missing_attribute (node, "selector"); + return; + } + + if (!xmlHasProp (node, BAD_CAST "withinText")) + { + _its_error_missing_attribute (node, "withinText"); + return; + } + + prop = _its_get_attribute (node, "selector", NULL); + if (prop) + pop->selector = prop; + + prop = _its_get_attribute (node, "withinText", NULL); + its_value_list_append (&pop->values, "withinText", prop); + free (prop); +} + +struct its_value_list_ty * +its_element_within_text_rule_eval (struct its_rule_ty *pop, + struct its_pool_ty *pool, + xmlNode *node) +{ + struct its_value_list_ty *result; + const char *value; + + result = XCALLOC (1, struct its_value_list_ty); + + if (node->type != XML_ELEMENT_NODE) + return result; + + /* A local attribute overrides the global rule. */ + if (xmlHasNsProp (node, BAD_CAST "withinText", BAD_CAST ITS_NS)) + { + char *prop; + + prop = _its_get_attribute (node, "withinText", ITS_NS); + its_value_list_append (result, "withinText", prop); + free (prop); + return result; + } + + /* Doesn't inherit from the parent elements, and the default value + is None. */ + value = its_pool_get_value_for_node (pool, node, "withinText"); + if (value != NULL) + its_value_list_set_value (result, "withinText", value); + + return result; +} + +static struct its_rule_class_ty its_element_within_text_rule_class = + { + sizeof (struct its_rule_ty), + its_element_within_text_rule_constructor, + its_rule_destructor, + its_rule_apply, + its_element_within_text_rule_eval, + }; + +/* Implementation of Preserve Space data category. */ +static void +its_preserve_space_rule_constructor (struct its_rule_ty *pop, + xmlNode *node) +{ + char *prop; + + if (!xmlHasProp (node, BAD_CAST "selector")) + { + _its_error_missing_attribute (node, "selector"); + return; + } + + if (!xmlHasProp (node, BAD_CAST "space")) + { + _its_error_missing_attribute (node, "space"); + return; + } + + prop = _its_get_attribute (node, "selector", NULL); + if (prop) + pop->selector = prop; + + prop = _its_get_attribute (node, "space", NULL); + if (prop + && !(strcmp (prop, "preserve") ==0 + || strcmp (prop, "default") == 0 + /* gettext extension: remove leading/trailing whitespaces only. */ + || (node->ns && xmlStrEqual (node->ns->href, BAD_CAST GT_NS) + && strcmp (prop, "trim") == 0))) + { + error (0, 0, _("invalid attribute value \"%s\" for \"%s\""), + prop, "space"); + free (prop); + return; + } + + its_value_list_append (&pop->values, "space", prop); + free (prop); +} + +struct its_value_list_ty * +its_preserve_space_rule_eval (struct its_rule_ty *pop, + struct its_pool_ty *pool, + xmlNode *node) +{ + struct its_value_list_ty *result; + struct its_value_list_ty *values; + const char *value; + + result = XCALLOC (1, struct its_value_list_ty); + + if (node->type != XML_ELEMENT_NODE) + return result; + + /* A local attribute overrides the global rule. */ + if (xmlHasNsProp (node, BAD_CAST "space", BAD_CAST XML_NS)) + { + char *prop; + + prop = _its_get_attribute (node, "space", XML_NS); + its_value_list_append (result, "space", prop); + free (prop); + return result; + } + + /* Check value for the current node. */ + value = its_pool_get_value_for_node (pool, node, "space"); + if (value != NULL) + { + its_value_list_set_value (result, "space", value); + return result; + } + + if (node->parent == NULL + || node->parent->type != XML_ELEMENT_NODE) + { + /* The default value is space="default". */ + its_value_list_append (result, "space", "default"); + return result; + } + + /* Recursively check value for the parent node. */ + values = its_preserve_space_rule_eval (pop, pool, node->parent); + its_value_list_merge (result, values); + its_value_list_destroy (values); + free (values); + + return result; +} + +static struct its_rule_class_ty its_preserve_space_rule_class = + { + sizeof (struct its_rule_ty), + its_preserve_space_rule_constructor, + its_rule_destructor, + its_rule_apply, + its_preserve_space_rule_eval, + }; + +/* Implementation of Context data category. */ +static void +its_extension_context_rule_constructor (struct its_rule_ty *pop, xmlNode *node) +{ + char *prop; + + if (!xmlHasProp (node, BAD_CAST "selector")) + { + _its_error_missing_attribute (node, "selector"); + return; + } + + if (!xmlHasProp (node, BAD_CAST "contextPointer")) + { + _its_error_missing_attribute (node, "contextPointer"); + return; + } + + prop = _its_get_attribute (node, "selector", NULL); + if (prop) + pop->selector = prop; + + prop = _its_get_attribute (node, "contextPointer", NULL); + its_value_list_append (&pop->values, "contextPointer", prop); + free (prop); + + if (xmlHasProp (node, BAD_CAST "textPointer")) + { + prop = _its_get_attribute (node, "textPointer", NULL); + its_value_list_append (&pop->values, "textPointer", prop); + free (prop); + } +} + +struct its_value_list_ty * +its_extension_context_rule_eval (struct its_rule_ty *pop, + struct its_pool_ty *pool, + xmlNode *node) +{ + struct its_value_list_ty *result; + const char *value; + + result = XCALLOC (1, struct its_value_list_ty); + + /* Doesn't inherit from the parent elements, and the default value + is None. */ + value = its_pool_get_value_for_node (pool, node, "contextPointer"); + if (value != NULL) + its_value_list_set_value (result, "contextPointer", value); + + value = its_pool_get_value_for_node (pool, node, "textPointer"); + if (value != NULL) + its_value_list_set_value (result, "textPointer", value); + + return result; +} + +static struct its_rule_class_ty its_extension_context_rule_class = + { + sizeof (struct its_rule_ty), + its_extension_context_rule_constructor, + its_rule_destructor, + its_rule_apply, + its_extension_context_rule_eval, + }; + +/* Implementation of Escape Special Characters data category. */ +static void +its_extension_escape_rule_constructor (struct its_rule_ty *pop, xmlNode *node) +{ + char *prop; + + if (!xmlHasProp (node, BAD_CAST "selector")) + { + _its_error_missing_attribute (node, "selector"); + return; + } + + if (!xmlHasProp (node, BAD_CAST "escape")) + { + _its_error_missing_attribute (node, "escape"); + return; + } + + prop = _its_get_attribute (node, "selector", NULL); + if (prop) + pop->selector = prop; + + prop = _its_get_attribute (node, "escape", NULL); + its_value_list_append (&pop->values, "escape", prop); + free (prop); +} + +struct its_value_list_ty * +its_extension_escape_rule_eval (struct its_rule_ty *pop, + struct its_pool_ty *pool, + xmlNode *node) +{ + struct its_value_list_ty *result; + + result = XCALLOC (1, struct its_value_list_ty); + + switch (node->type) + { + case XML_ATTRIBUTE_NODE: + /* Attribute nodes don't inherit from the parent elements. */ + { + const char *value = + its_pool_get_value_for_node (pool, node, "escape"); + if (value != NULL) + { + its_value_list_set_value (result, "escape", value); + return result; + } + } + break; + + case XML_ELEMENT_NODE: + /* Inherit from the parent elements. */ + { + const char *value; + + /* Check value for the current node. */ + value = its_pool_get_value_for_node (pool, node, "escape"); + if (value != NULL) + { + its_value_list_set_value (result, "escape", value); + return result; + } + + /* Recursively check value for the parent node. */ + if (node->parent != NULL + && node->parent->type == XML_ELEMENT_NODE) + { + struct its_value_list_ty *values; + + values = its_extension_escape_rule_eval (pop, pool, node->parent); + its_value_list_merge (result, values); + its_value_list_destroy (values); + free (values); + } + } + break; + + default: + break; + } + + return result; +} + +static struct its_rule_class_ty its_extension_escape_rule_class = + { + sizeof (struct its_rule_ty), + its_extension_escape_rule_constructor, + its_rule_destructor, + its_rule_apply, + its_extension_escape_rule_eval, + }; + +static struct its_rule_ty * +its_rule_alloc (struct its_rule_class_ty *method_table, xmlNode *node) +{ + struct its_rule_ty *pop; + + pop = (struct its_rule_ty *) xcalloc (1, method_table->size); + pop->methods = method_table; + if (method_table->constructor) + method_table->constructor (pop, node); + return pop; +} + +static struct its_rule_ty * +its_rule_parse (xmlDoc *doc, xmlNode *node) +{ + const char *name = (const char *) node->name; + void *value; + + if (hash_find_entry (&classes, name, strlen (name), &value) == 0) + { + struct its_rule_ty *result; + xmlNs **namespaces; + + result = its_rule_alloc ((struct its_rule_class_ty *) value, node); + namespaces = xmlGetNsList (doc, node); + if (namespaces) + { + size_t i; + for (i = 0; namespaces[i] != NULL; i++) + ; + result->namespaces = XCALLOC (i + 1, xmlNs *); + for (i = 0; namespaces[i] != NULL; i++) + result->namespaces[i] = xmlCopyNamespace (namespaces[i]); + } + xmlFree (namespaces); + return result; + } + + return NULL; +} + +static void +its_rule_destroy (struct its_rule_ty *pop) +{ + if (pop->methods->destructor) + pop->methods->destructor (pop); +} + +static void +init_classes (void) +{ +#define ADD_RULE_CLASS(n, c) \ + hash_insert_entry (&classes, n, strlen (n), &c); + + ADD_RULE_CLASS ("translateRule", its_translate_rule_class); + ADD_RULE_CLASS ("locNoteRule", its_localization_note_rule_class); + ADD_RULE_CLASS ("withinTextRule", its_element_within_text_rule_class); + ADD_RULE_CLASS ("preserveSpaceRule", its_preserve_space_rule_class); + ADD_RULE_CLASS ("contextRule", its_extension_context_rule_class); + ADD_RULE_CLASS ("escapeRule", its_extension_escape_rule_class); + +#undef ADD_RULE_CLASS +} + +struct its_rule_list_ty * +its_rule_list_alloc (void) +{ + struct its_rule_list_ty *result; + + if (classes.table == NULL) + { + hash_init (&classes, 10); + init_classes (); + } + + result = XCALLOC (1, struct its_rule_list_ty); + return result; +} + +void +its_rule_list_free (struct its_rule_list_ty *rules) +{ + size_t i; + + for (i = 0; i < rules->nitems; i++) + { + its_rule_destroy (rules->items[i]); + free (rules->items[i]); + } + free (rules->items); + its_pool_destroy (&rules->pool); +} + +static bool +its_rule_list_add_from_doc (struct its_rule_list_ty *rules, + xmlDoc *doc) +{ + xmlNode *root, *node; + + root = xmlDocGetRootElement (doc); + if (!(xmlStrEqual (root->name, BAD_CAST "rules") + && xmlStrEqual (root->ns->href, BAD_CAST ITS_NS))) + { + error (0, 0, _("the root element is not \"rules\"" + " under namespace %s"), + ITS_NS); + xmlFreeDoc (doc); + return false; + } + + for (node = root->children; node; node = node->next) + { + struct its_rule_ty *rule; + + rule = its_rule_parse (doc, node); + if (!rule) + continue; + + if (rules->nitems == rules->nitems_max) + { + rules->nitems_max = 2 * rules->nitems_max + 1; + rules->items = + xrealloc (rules->items, + sizeof (struct its_rule_ty *) * rules->nitems_max); + } + rules->items[rules->nitems++] = rule; + } + + return true; +} + +bool +its_rule_list_add_from_file (struct its_rule_list_ty *rules, + const char *filename) +{ + xmlDoc *doc; + bool result; + + doc = xmlReadFile (filename, "utf-8", + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOBLANKS + | XML_PARSE_NOERROR); + if (doc == NULL) + { + xmlError *err = xmlGetLastError (); + error (0, 0, _("cannot read %s: %s"), filename, err->message); + return false; + } + + result = its_rule_list_add_from_doc (rules, doc); + xmlFreeDoc (doc); + return result; +} + +bool +its_rule_list_add_from_string (struct its_rule_list_ty *rules, + const char *rule) +{ + xmlDoc *doc; + bool result; + + doc = xmlReadMemory (rule, strlen (rule), + "(internal)", + NULL, + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOBLANKS + | XML_PARSE_NOERROR); + if (doc == NULL) + { + xmlError *err = xmlGetLastError (); + error (0, 0, _("cannot read %s: %s"), "(internal)", err->message); + return false; + } + + result = its_rule_list_add_from_doc (rules, doc); + xmlFreeDoc (doc); + return result; +} + +static void +its_rule_list_apply (struct its_rule_list_ty *rules, xmlDoc *doc) +{ + size_t i; + + for (i = 0; i < rules->nitems; i++) + { + struct its_rule_ty *rule = rules->items[i]; + rule->methods->apply (rule, &rules->pool, doc); + } +} + +static struct its_value_list_ty * +its_rule_list_eval (its_rule_list_ty *rules, xmlNode *node) +{ + struct its_value_list_ty *result; + size_t i; + + result = XCALLOC (1, struct its_value_list_ty); + for (i = 0; i < rules->nitems; i++) + { + struct its_rule_ty *rule = rules->items[i]; + struct its_value_list_ty *values; + + values = rule->methods->eval (rule, &rules->pool, node); + its_value_list_merge (result, values); + its_value_list_destroy (values); + free (values); + } + + return result; +} + +static bool +its_rule_list_is_translatable (its_rule_list_ty *rules, + xmlNode *node, + int depth) +{ + struct its_value_list_ty *values; + const char *value; + xmlNode *n; + + if (node->type != XML_ELEMENT_NODE + && node->type != XML_ATTRIBUTE_NODE) + return false; + + values = its_rule_list_eval (rules, node); + + /* Check if NODE has translate="yes". */ + value = its_value_list_get_value (values, "translate"); + if (!(value && strcmp (value, "yes") == 0)) + { + its_value_list_destroy (values); + free (values); + return false; + } + + /* Check if NODE has withinText="yes", if NODE is not top-level. */ + if (depth > 0) + { + value = its_value_list_get_value (values, "withinText"); + if (!(value && strcmp (value, "yes") == 0)) + { + its_value_list_destroy (values); + free (values); + return false; + } + } + + its_value_list_destroy (values); + free (values); + + for (n = node->children; n; n = n->next) + { + switch (n->type) + { + case XML_ELEMENT_NODE: + if (!its_rule_list_is_translatable (rules, n, depth + 1)) + return false; + break; + + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_COMMENT_NODE: + break; + + default: + return false; + } + } + + return true; +} + +static void +its_rule_list_extract_nodes (its_rule_list_ty *rules, + struct its_node_list_ty *nodes, + xmlNode *node) +{ + if (node->type == XML_ELEMENT_NODE) + { + xmlNode *n; + + if (node->properties) + { + xmlAttr *attr = node->properties; + for (; attr; attr = attr->next) + { + xmlNode *n = (xmlNode *) attr; + if (its_rule_list_is_translatable (rules, n, 0)) + its_node_list_append (nodes, n); + } + } + + if (its_rule_list_is_translatable (rules, node, 0)) + its_node_list_append (nodes, node); + else + { + for (n = node->children; n; n = n->next) + its_rule_list_extract_nodes (rules, nodes, n); + } + } +} + +static char * +_its_get_content (struct its_rule_list_ty *rules, xmlNode *node, + const char *pointer, + enum its_whitespace_type_ty whitespace, + bool no_escape) +{ + xmlXPathContext *context; + xmlXPathObject *object; + size_t i; + char *result = NULL; + + context = xmlXPathNewContext (node->doc); + if (!context) + { + error (0, 0, _("cannot create XPath context")); + return NULL; + } + + for (i = 0; i < rules->nitems; i++) + { + struct its_rule_ty *rule = rules->items[i]; + if (rule->namespaces) + { + size_t i; + for (i = 0; rule->namespaces[i] != NULL; i++) + { + xmlNs *ns = rule->namespaces[i]; + xmlXPathRegisterNs (context, ns->prefix, ns->href); + } + } + } + + xmlXPathSetContextNode (node, context); + object = xmlXPathEvalExpression (BAD_CAST pointer, context); + if (!object) + { + xmlXPathFreeContext (context); + error (0, 0, _("cannot evaluate XPath location path: %s"), + pointer); + return NULL; + } + + switch (object->type) + { + case XPATH_NODESET: + { + xmlNodeSet *nodes = object->nodesetval; + string_list_ty sl; + size_t i; + + string_list_init (&sl); + for (i = 0; i < nodes->nodeNr; i++) + { + char *content = _its_collect_text_content (nodes->nodeTab[i], + whitespace, + no_escape); + string_list_append (&sl, content); + free (content); + } + result = string_list_concat (&sl); + string_list_destroy (&sl); + } + break; + + case XPATH_STRING: + result = xstrdup ((const char *) object->stringval); + break; + + default: + break; + } + + xmlXPathFreeObject (object); + xmlXPathFreeContext (context); + + return result; +} + +static void +_its_comment_append (string_list_ty *comments, const char *data) +{ + /* Split multiline comment into lines, and remove leading and trailing + whitespace. */ + char *copy = xstrdup (data); + char *p; + char *q; + + for (p = copy; (q = strchr (p, '\n')) != NULL; p = q + 1) + { + while (p[0] == ' ' || p[0] == '\t') + p++; + while (q > p && (q[-1] == ' ' || q[-1] == '\t')) + q--; + *q = '\0'; + string_list_append (comments, p); + } + q = p + strlen (p); + while (p[0] == ' ' || p[0] == '\t') + p++; + while (q > p && (q[-1] == ' ' || q[-1] == '\t')) + q--; + *q = '\0'; + string_list_append (comments, p); + free (copy); +} + +static void +its_rule_list_extract_text (its_rule_list_ty *rules, + xmlNode *node, + const char *logical_filename, + flag_context_list_table_ty *flag_table, + message_list_ty *mlp, + its_extract_callback_ty callback) +{ + if (node->type == XML_ELEMENT_NODE + || node->type == XML_ATTRIBUTE_NODE) + { + struct its_value_list_ty *values; + const char *value; + char *msgid = NULL, *msgctxt = NULL, *comment = NULL; + enum its_whitespace_type_ty whitespace; + bool no_escape; + + values = its_rule_list_eval (rules, node); + + value = its_value_list_get_value (values, "locNote"); + if (value) + comment = xstrdup (value); + else + { + value = its_value_list_get_value (values, "escape"); + no_escape = value != NULL && strcmp (value, "no") == 0; + + value = its_value_list_get_value (values, "locNotePointer"); + if (value) + comment = _its_get_content (rules, node, value, ITS_WHITESPACE_TRIM, + no_escape); + } + + if (comment != NULL && *comment != '\0') + { + string_list_ty comments; + char *tmp; + + string_list_init (&comments); + _its_comment_append (&comments, comment); + tmp = string_list_join (&comments, "\n", '\0', false); + free (comment); + comment = tmp; + } + else + /* Extract comments preceding the node. */ + { + xmlNode *sibling; + string_list_ty comments; + + string_list_init (&comments); + for (sibling = node->prev; sibling; sibling = sibling->prev) + if (sibling->type != XML_COMMENT_NODE || sibling->prev == NULL) + break; + if (sibling) + { + if (sibling->type != XML_COMMENT_NODE) + sibling = sibling->next; + for (; sibling && sibling->type == XML_COMMENT_NODE; + sibling = sibling->next) + { + xmlChar *content = xmlNodeGetContent (sibling); + _its_comment_append (&comments, (const char *) content); + xmlFree (content); + } + free (comment); + comment = string_list_join (&comments, "\n", '\0', false); + string_list_destroy (&comments); + } + } + + value = its_value_list_get_value (values, "space"); + if (value && strcmp (value, "preserve") == 0) + whitespace = ITS_WHITESPACE_PRESERVE; + else if (value && strcmp (value, "trim") == 0) + whitespace = ITS_WHITESPACE_TRIM; + else + whitespace = ITS_WHITESPACE_NORMALIZE; + + value = its_value_list_get_value (values, "escape"); + no_escape = value != NULL && strcmp (value, "no") == 0; + + value = its_value_list_get_value (values, "contextPointer"); + if (value) + msgctxt = _its_get_content (rules, node, value, ITS_WHITESPACE_PRESERVE, + no_escape); + + value = its_value_list_get_value (values, "textPointer"); + if (value) + msgid = _its_get_content (rules, node, value, ITS_WHITESPACE_PRESERVE, + no_escape); + its_value_list_destroy (values); + free (values); + + if (msgid == NULL) + msgid = _its_collect_text_content (node, whitespace, no_escape); + if (*msgid != '\0') + { + lex_pos_ty pos; + char *marker; + + pos.file_name = xstrdup (logical_filename); + pos.line_number = xmlGetLineNo (node); + + if (node->type == XML_ELEMENT_NODE) + { + assert (node->parent); + marker = xasprintf ("%s/%s", node->parent->name, node->name); + } + else + { + assert (node->parent && node->parent->parent); + marker = xasprintf ("%s/%s@%s", + node->parent->parent->name, + node->parent->name, + node->name); + } + + if (msgctxt != NULL && *msgctxt == '\0') + { + free (msgctxt); + msgctxt = NULL; + } + + callback (mlp, msgctxt, msgid, &pos, comment, marker, whitespace); + free (marker); + } + free (msgctxt); + free (msgid); + free (comment); + } +} + +void +its_rule_list_extract (its_rule_list_ty *rules, + FILE *fp, const char *real_filename, + const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp, + its_extract_callback_ty callback) +{ + xmlDoc *doc; + struct its_node_list_ty nodes; + size_t i; + + doc = xmlReadFd (fileno (fp), logical_filename, NULL, + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOBLANKS + | XML_PARSE_NOERROR); + if (doc == NULL) + { + xmlError *err = xmlGetLastError (); + error (0, 0, _("cannot read %s: %s"), logical_filename, err->message); + return; + } + + its_rule_list_apply (rules, doc); + + memset (&nodes, 0, sizeof (struct its_node_list_ty)); + its_rule_list_extract_nodes (rules, + &nodes, + xmlDocGetRootElement (doc)); + + for (i = 0; i < nodes.nitems; i++) + its_rule_list_extract_text (rules, nodes.items[i], + logical_filename, + flag_table, + mdlp->item[0]->messages, + callback); + + free (nodes.items); + xmlFreeDoc (doc); +} + +struct its_merge_context_ty +{ + its_rule_list_ty *rules; + xmlDoc *doc; + struct its_node_list_ty nodes; +}; + +static void +its_merge_context_merge_node (struct its_merge_context_ty *context, + xmlNode *node, + const char *language, + message_list_ty *mlp) +{ + if (node->type == XML_ELEMENT_NODE) + { + struct its_value_list_ty *values; + const char *value; + char *msgid = NULL, *msgctxt = NULL; + enum its_whitespace_type_ty whitespace; + bool no_escape; + + values = its_rule_list_eval (context->rules, node); + + value = its_value_list_get_value (values, "space"); + if (value && strcmp (value, "preserve") == 0) + whitespace = ITS_WHITESPACE_PRESERVE; + else if (value && strcmp (value, "trim") == 0) + whitespace = ITS_WHITESPACE_TRIM; + else + whitespace = ITS_WHITESPACE_NORMALIZE; + + value = its_value_list_get_value (values, "escape"); + no_escape = value != NULL && strcmp (value, "no") == 0; + + value = its_value_list_get_value (values, "contextPointer"); + if (value) + msgctxt = _its_get_content (context->rules, node, value, + ITS_WHITESPACE_PRESERVE, no_escape); + + value = its_value_list_get_value (values, "textPointer"); + if (value) + msgid = _its_get_content (context->rules, node, value, + ITS_WHITESPACE_PRESERVE, no_escape); + its_value_list_destroy (values); + free (values); + + if (msgid == NULL) + msgid = _its_collect_text_content (node, whitespace, no_escape); + if (*msgid != '\0') + { + message_ty *mp; + + mp = message_list_search (mlp, msgctxt, msgid); + if (mp && *mp->msgstr != '\0') + { + xmlNode *translated; + + translated = xmlNewNode (node->ns, node->name); + xmlSetProp (translated, BAD_CAST "xml:lang", BAD_CAST language); + + xmlNodeAddContent (translated, BAD_CAST mp->msgstr); + xmlAddNextSibling (node, translated); + } + } + free (msgctxt); + free (msgid); + } +} + +void +its_merge_context_merge (its_merge_context_ty *context, + const char *language, + message_list_ty *mlp) +{ + size_t i; + + for (i = 0; i < context->nodes.nitems; i++) + its_merge_context_merge_node (context, context->nodes.items[i], + language, + mlp); +} + +struct its_merge_context_ty * +its_merge_context_alloc (its_rule_list_ty *rules, + const char *filename) +{ + xmlDoc *doc; + struct its_merge_context_ty *result; + + doc = xmlReadFile (filename, NULL, + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOBLANKS + | XML_PARSE_NOERROR); + if (doc == NULL) + { + xmlError *err = xmlGetLastError (); + error (0, 0, _("cannot read %s: %s"), filename, err->message); + return NULL; + } + + its_rule_list_apply (rules, doc); + + result = XMALLOC (struct its_merge_context_ty); + result->rules = rules; + result->doc = doc; + + /* Collect translatable nodes. */ + memset (&result->nodes, 0, sizeof (struct its_node_list_ty)); + its_rule_list_extract_nodes (result->rules, + &result->nodes, + xmlDocGetRootElement (result->doc)); + + return result; +} + +void +its_merge_context_write (struct its_merge_context_ty *context, + FILE *fp) +{ + xmlDocFormatDump (fp, context->doc, 1); +} + +void +its_merge_context_free (struct its_merge_context_ty *context) +{ + xmlFreeDoc (context->doc); + free (context->nodes.items); + free (context); +} diff --git a/gettext-tools/src/its.h b/gettext-tools/src/its.h new file mode 100644 index 0000000..8d597f5 --- /dev/null +++ b/gettext-tools/src/its.h @@ -0,0 +1,85 @@ +/* Internationalization Tag Set (ITS) handling + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _ITS_H_ +#define _ITS_H_ + +#include "message.h" +#include "xgettext.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum its_whitespace_type_ty +{ + ITS_WHITESPACE_PRESERVE, + ITS_WHITESPACE_NORMALIZE, + ITS_WHITESPACE_TRIM +}; + +typedef struct its_rule_list_ty its_rule_list_ty; + +typedef message_ty * + (*its_extract_callback_ty) (message_list_ty *mlp, + const char *msgctxt, + const char *msgid, + lex_pos_ty *pos, + const char *extracted_comment, + const char *marker, + enum its_whitespace_type_ty whitespace); + +/* Creates a fresh its_rule_list_ty holding global ITS rules. */ +extern its_rule_list_ty *its_rule_list_alloc (void); + +/* Releases memory allocated for RULES. */ +extern void its_rule_list_free (its_rule_list_ty *rules); + +/* Loads global ITS rules from STRING. */ +extern bool its_rule_list_add_from_string (struct its_rule_list_ty *rules, + const char *rule); + +/* Loads global ITS rules from FILENAME. */ +extern bool its_rule_list_add_from_file (its_rule_list_ty *rules, + const char *filename); + +/* Extracts messages from FP, accoding to the loaded ITS rules. */ +extern void its_rule_list_extract (its_rule_list_ty *rules, + FILE *fp, const char *real_filename, + const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp, + its_extract_callback_ty callback); + +typedef struct its_merge_context_ty its_merge_context_ty; + +extern its_merge_context_ty * + its_merge_context_alloc (its_rule_list_ty *rules, const char *filename); +extern void its_merge_context_free (its_merge_context_ty *context); +extern void its_merge_context_merge (its_merge_context_ty *context, + const char *language, + message_list_ty *mlp); + +extern void its_merge_context_write (its_merge_context_ty *context, + FILE *fp); + +#ifdef __cplusplus +} +#endif + +#endif /* _ITS_H_ */ diff --git a/gettext-tools/src/lang-table.c b/gettext-tools/src/lang-table.c index 9cc1f55..ac69021 100644 --- a/gettext-tools/src/lang-table.c +++ b/gettext-tools/src/lang-table.c @@ -1,5 +1,5 @@ /* Table of languages. - Copyright (C) 2001-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2005. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/lang-table.h b/gettext-tools/src/lang-table.h index e72e4c4..59f5802 100644 --- a/gettext-tools/src/lang-table.h +++ b/gettext-tools/src/lang-table.h @@ -1,5 +1,5 @@ /* Table of languages. - Copyright (C) 2001-2007 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2005. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/libexpat-compat.c b/gettext-tools/src/libexpat-compat.c deleted file mode 100644 index ad680db..0000000 --- a/gettext-tools/src/libexpat-compat.c +++ /dev/null @@ -1,326 +0,0 @@ -/* xgettext libexpat compatibility. - Copyright (C) 2002-2003, 2005-2009, 2013 Free Software Foundation, Inc. - - This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. - - 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <stdlib.h> -#include <string.h> - -#if DYNLOAD_LIBEXPAT -# include <dlfcn.h> -#else -# if HAVE_LIBEXPAT -# include <expat.h> -# endif -#endif - -/* Keep the references to XML_GetCurrent{Line,Column}Number symbols - before loading libexpat-compat.h, since they are redefined to - rpl_XML_GetCurrent{Line,Column}Number . */ -#if !DYNLOAD_LIBEXPAT && XML_MAJOR_VERSION >= 2 -static void *p_XML_GetCurrentLineNumber = (void *) &XML_GetCurrentLineNumber; -static void *p_XML_GetCurrentColumnNumber = (void *) &XML_GetCurrentColumnNumber; -#endif - -#include "libexpat-compat.h" - -/* ======================= Different libexpat ABIs. ======================= */ - -/* There are three different ABIs of libexpat, regarding the functions - XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber. - In expat < 2.0, they return an 'int'. - In expat >= 2.0, they return - - a 'long' if expat was compiled with the default flags, or - - a 'long long' if expat was compiled with -DXML_LARGE_SIZE. - But the <expat.h> include file does not contain the information whether - expat was compiled with -DXML_LARGE_SIZE; so the include file is lying! - For this information, we need to call XML_GetFeatureList(), for - expat >= 2.0.1; for expat = 2.0.0, we have to assume the default flags. */ - -#if !DYNLOAD_LIBEXPAT && XML_MAJOR_VERSION >= 2 - -/* expat >= 2.0 -> Return type is 'int64_t' worst-case. */ - -/* Return true if libexpat was compiled with -DXML_LARGE_SIZE. */ -static bool -is_XML_LARGE_SIZE_ABI (void) -{ - static bool tested; - static bool is_large; - - if (!tested) - { - const XML_Feature *features; - - is_large = false; - for (features = XML_GetFeatureList (); features->name != NULL; features++) - if (strcmp (features->name, "XML_LARGE_SIZE") == 0) - { - is_large = true; - break; - } - - tested = true; - } - return is_large; -} - -int64_t -rpl_XML_GetCurrentLineNumber (XML_Parser parser) -{ - if (is_XML_LARGE_SIZE_ABI ()) - return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser); - else - return ((long (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser); -} - -int64_t -rpl_XML_GetCurrentColumnNumber (XML_Parser parser) -{ - if (is_XML_LARGE_SIZE_ABI ()) - return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser); - else - return ((long (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser); -} -#endif - - -/* ===================== Dynamic loading of libexpat. ===================== */ - -#if DYNLOAD_LIBEXPAT - -static XML_Expat_Version (*p_XML_ExpatVersionInfo) (void); - -XML_Expat_Version -XML_ExpatVersionInfo (void) -{ - return (*p_XML_ExpatVersionInfo) (); -} - -static const XML_Feature * (*p_XML_GetFeatureList) (void); - -const XML_Feature * -XML_GetFeatureList (void) -{ - return (*p_XML_GetFeatureList) (); -} - -enum XML_Size_ABI -get_XML_Size_ABI (void) -{ - static bool tested; - static enum XML_Size_ABI abi; - - if (!tested) - { - if (XML_ExpatVersionInfo () .major >= 2) - /* expat >= 2.0 -> XML_Size is 'int64_t' or 'long'. */ - { - const XML_Feature *features; - - abi = is_long; - for (features = XML_GetFeatureList (); - features->name != NULL; - features++) - if (strcmp (features->name, "XML_LARGE_SIZE") == 0) - { - abi = is_int64_t; - break; - } - } - else - /* expat < 2.0 -> XML_Size is 'int'. */ - abi = is_int; - tested = true; - } - return abi; -} - -static XML_Parser (*p_XML_ParserCreate) (const XML_Char *encoding); - -XML_Parser -XML_ParserCreate (const XML_Char *encoding) -{ - return (*p_XML_ParserCreate) (encoding); -} - -static void (*p_XML_SetElementHandler) (XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end); - -void -XML_SetElementHandler (XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end) -{ - (*p_XML_SetElementHandler) (parser, start, end); -} - - -static void (*p_XML_SetCharacterDataHandler) (XML_Parser parser, - XML_CharacterDataHandler handler); - -void -XML_SetCharacterDataHandler (XML_Parser parser, - XML_CharacterDataHandler handler) -{ - (*p_XML_SetCharacterDataHandler) (parser, handler); -} - - -static void (*p_XML_SetCommentHandler) (XML_Parser parser, - XML_CommentHandler handler); - -void -XML_SetCommentHandler (XML_Parser parser, XML_CommentHandler handler) -{ - (*p_XML_SetCommentHandler) (parser, handler); -} - - -static int (*p_XML_Parse) (XML_Parser parser, const char *s, - int len, int isFinal); - -int -XML_Parse (XML_Parser parser, const char *s, int len, int isFinal) -{ - return (*p_XML_Parse) (parser, s, len, isFinal); -} - - -static enum XML_Error (*p_XML_GetErrorCode) (XML_Parser parser); - -enum XML_Error -XML_GetErrorCode (XML_Parser parser) -{ - return (*p_XML_GetErrorCode) (parser); -} - - -static void *p_XML_GetCurrentLineNumber; - -int64_t -XML_GetCurrentLineNumber (XML_Parser parser) -{ - switch (get_XML_Size_ABI ()) - { - case is_int: - return ((int (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser); - case is_long: - return ((long (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser); - case is_int64_t: - return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentLineNumber) (parser); - default: - abort (); - } -} - -static void *p_XML_GetCurrentColumnNumber; - -int64_t -XML_GetCurrentColumnNumber (XML_Parser parser) -{ - switch (get_XML_Size_ABI ()) - { - case is_int: - return ((int (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser); - case is_long: - return ((long (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser); - case is_int64_t: - return ((int64_t (*) (XML_Parser)) p_XML_GetCurrentColumnNumber) (parser); - default: - abort (); - } -} - - -static const XML_LChar * (*p_XML_ErrorString) (int code); - -const XML_LChar * -XML_ErrorString (int code) -{ - return (*p_XML_ErrorString) (code); -} - -static void (*p_XML_ParserFree) (XML_Parser parser); - -void -XML_ParserFree (XML_Parser parser) -{ - return (*p_XML_ParserFree) (parser); -} - -static int libexpat_loaded = 0; - -bool -load_libexpat () -{ - if (libexpat_loaded == 0) - { - void *handle; - - /* Try to load libexpat-2.x. */ - handle = dlopen ("libexpat.so.1", RTLD_LAZY); - if (handle == NULL) - /* Try to load libexpat-1.x. */ - handle = dlopen ("libexpat.so.0", RTLD_LAZY); - if (handle != NULL - && (p_XML_ExpatVersionInfo = - (XML_Expat_Version (*) (void)) - dlsym (handle, "XML_ExpatVersionInfo")) != NULL - && (p_XML_GetFeatureList = - (const XML_Feature * (*) (void)) - dlsym (handle, "XML_GetFeatureList")) != NULL - && (p_XML_ParserCreate = - (XML_Parser (*) (const XML_Char *)) - dlsym (handle, "XML_ParserCreate")) != NULL - && (p_XML_SetElementHandler = - (void (*) (XML_Parser, XML_StartElementHandler, XML_EndElementHandler)) - dlsym (handle, "XML_SetElementHandler")) != NULL - && (p_XML_SetCharacterDataHandler = - (void (*) (XML_Parser, XML_CharacterDataHandler)) - dlsym (handle, "XML_SetCharacterDataHandler")) != NULL - && (p_XML_SetCommentHandler = - (void (*) (XML_Parser, XML_CommentHandler)) - dlsym (handle, "XML_SetCommentHandler")) != NULL - && (p_XML_Parse = - (int (*) (XML_Parser, const char *, int, int)) - dlsym (handle, "XML_Parse")) != NULL - && (p_XML_GetErrorCode = - (enum XML_Error (*) (XML_Parser)) - dlsym (handle, "XML_GetErrorCode")) != NULL - && (p_XML_GetCurrentLineNumber = - dlsym (handle, "XML_GetCurrentLineNumber")) != NULL - && (p_XML_GetCurrentColumnNumber = - dlsym (handle, "XML_GetCurrentColumnNumber")) != NULL - && (p_XML_ParserFree = - (void (*) (XML_Parser)) - dlsym (handle, "XML_ParserFree")) != NULL - && (p_XML_ErrorString = - (const XML_LChar * (*) (int)) - dlsym (handle, "XML_ErrorString")) != NULL) - libexpat_loaded = 1; - else - libexpat_loaded = -1; - } - return libexpat_loaded >= 0; -} - -#endif diff --git a/gettext-tools/src/libexpat-compat.h b/gettext-tools/src/libexpat-compat.h deleted file mode 100644 index 2ff6465..0000000 --- a/gettext-tools/src/libexpat-compat.h +++ /dev/null @@ -1,94 +0,0 @@ -/* xgettext libexpat compatibility. - Copyright (C) 2002-2003, 2005-2009, 2013 Free Software Foundation, Inc. - - This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. - - 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ - -#include <stdbool.h> -#include <stdint.h> -#if DYNLOAD_LIBEXPAT -# include <dlfcn.h> -#else -# if HAVE_LIBEXPAT -# include <expat.h> -# endif -#endif - -#if !DYNLOAD_LIBEXPAT && XML_MAJOR_VERSION >= 2 -int64_t rpl_XML_GetCurrentLineNumber (XML_Parser parser); -# undef XML_GetCurrentLineNumber -# define XML_GetCurrentLineNumber rpl_XML_GetCurrentLineNumber - -int64_t rpl_XML_GetCurrentColumnNumber (XML_Parser parser); -# undef XML_GetCurrentColumnNumber -# define XML_GetCurrentColumnNumber rpl_XML_GetCurrentColumnNumber -#endif - -/* ===================== Dynamic loading of libexpat. ===================== */ - -#if DYNLOAD_LIBEXPAT -typedef struct - { - int major; - int minor; - int micro; - } - XML_Expat_Version; -enum XML_FeatureEnum { XML_FEATURE_END = 0 }; -typedef struct - { - enum XML_FeatureEnum feature; - const char *name; - long int value; - } - XML_Feature; -typedef void *XML_Parser; -typedef char XML_Char; -typedef char XML_LChar; -enum XML_Error { XML_ERROR_NONE }; -typedef void (*XML_StartElementHandler) (void *userData, const XML_Char *name, const XML_Char **atts); -typedef void (*XML_EndElementHandler) (void *userData, const XML_Char *name); -typedef void (*XML_CharacterDataHandler) (void *userData, const XML_Char *s, int len); -typedef void (*XML_CommentHandler) (void *userData, const XML_Char *data); - -XML_Expat_Version XML_ExpatVersionInfo (void); -const XML_Feature * XML_GetFeatureList (void); - -enum XML_Size_ABI { is_int, is_long, is_int64_t }; -enum XML_Size_ABI get_XML_Size_ABI (void); - -XML_Parser XML_ParserCreate (const XML_Char *encoding); -void XML_SetElementHandler (XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end); -void XML_SetCharacterDataHandler (XML_Parser parser, - XML_CharacterDataHandler handler); -void XML_SetCommentHandler (XML_Parser parser, XML_CommentHandler handler); -int XML_Parse (XML_Parser parser, const char *s, int len, int isFinal); -enum XML_Error XML_GetErrorCode (XML_Parser parser); -int64_t XML_GetCurrentLineNumber (XML_Parser parser); -int64_t XML_GetCurrentColumnNumber (XML_Parser parser); -const XML_LChar * XML_ErrorString (int code); -void XML_ParserFree (XML_Parser parser); - -bool load_libexpat (); - -#define LIBEXPAT_AVAILABLE() (load_libexpat ()) - -#elif HAVE_LIBEXPAT - -#define LIBEXPAT_AVAILABLE() true - -#endif diff --git a/gettext-tools/src/locating-rule.c b/gettext-tools/src/locating-rule.c new file mode 100644 index 0000000..2a1de19 --- /dev/null +++ b/gettext-tools/src/locating-rule.c @@ -0,0 +1,437 @@ +/* XML resource locating rules + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "locating-rule.h" + +#include "basename.h" +#include "concat-filename.h" +#include "c-strcase.h" + +#if HAVE_DIRENT_H +# include <dirent.h> +#endif + +#if HAVE_DIRENT_H +# define HAVE_DIR 1 +#else +# define HAVE_DIR 0 +#endif + +#include "dir-list.h" +#include <errno.h> +#include "error.h" +#include "filename.h" +#include <fnmatch.h> +#include "gettext.h" +#include "hash.h" +#include <libxml/parser.h> +#include <libxml/uri.h> +#include "xalloc.h" + +#define _(str) gettext (str) + +#define LOCATING_RULES_NS "https://www.gnu.org/s/gettext/ns/locating-rules/1.0" + +struct document_locating_rule_ty +{ + char *ns; + char *local_name; + + char *target; +}; + +struct document_locating_rule_list_ty +{ + struct document_locating_rule_ty *items; + size_t nitems; + size_t nitems_max; +}; + +struct locating_rule_ty +{ + char *pattern; + char *name; + + struct document_locating_rule_list_ty doc_rules; + char *target; +}; + +struct locating_rule_list_ty +{ + struct locating_rule_ty *items; + size_t nitems; + size_t nitems_max; +}; + +static char * +get_attribute (xmlNode *node, const char *attr) +{ + xmlChar *value; + char *result; + + value = xmlGetProp (node, BAD_CAST attr); + result = xstrdup ((const char *) value); + xmlFree (value); + + return result; +} + +static const char * +document_locating_rule_match (struct document_locating_rule_ty *rule, + xmlDoc *doc) +{ + xmlNode *root; + + root = xmlDocGetRootElement (doc); + if (rule->ns != NULL) + { + if (root->ns == NULL + || !xmlStrEqual (root->ns->href, BAD_CAST rule->ns)) + return NULL; + } + + if (rule->local_name != NULL) + { + if (!xmlStrEqual (root->name, + BAD_CAST rule->local_name)) + return NULL; + } + + return rule->target; +} + +static const char * +locating_rule_match (struct locating_rule_ty *rule, + const char *filename, + const char *name) +{ + if (name != NULL) + { + if (rule->name == NULL || c_strcasecmp (name, rule->name) != 0) + return NULL; + } + else + { + const char *base; + char *reduced; + int err; + + base = strrchr (filename, '/'); + if (!base) + base = filename; + + reduced = xstrdup (base); + /* Remove a trailing ".in" - it's a generic suffix. */ + while (strlen (reduced) >= 3 + && memcmp (reduced + strlen (reduced) - 3, ".in", 3) == 0) + reduced[strlen (reduced) - 3] = '\0'; + + err = fnmatch (rule->pattern, basename (reduced), FNM_PATHNAME); + free (reduced); + if (err != 0) + return NULL; + } + + /* Check documentRules. */ + if (rule->doc_rules.nitems > 0) + { + const char *target; + xmlDoc *doc; + size_t i; + + doc = xmlReadFile (filename, NULL, + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOBLANKS + | XML_PARSE_NOERROR); + if (doc == NULL) + { + xmlError *err = xmlGetLastError (); + error (0, 0, _("cannot read %s: %s"), filename, err->message); + return NULL; + } + + for (i = 0, target = NULL; i < rule->doc_rules.nitems; i++) + { + target = + document_locating_rule_match (&rule->doc_rules.items[i], doc); + if (target) + break; + } + xmlFreeDoc (doc); + if (target != NULL) + return target; + } + + if (rule->target != NULL) + return rule->target; + + return NULL; +} + +const char * +locating_rule_list_locate (struct locating_rule_list_ty *rules, + const char *filename, + const char *name) +{ + const char *target = NULL; + size_t i; + + for (i = 0; i < rules->nitems; i++) + { + if (IS_ABSOLUTE_PATH (filename)) + { + target = locating_rule_match (&rules->items[i], filename, name); + if (target != NULL) + return target; + } + else + { + int j; + + for (j = 0; ; ++j) + { + const char *dir = dir_list_nth (j); + char *new_filename; + + if (dir == NULL) + break; + + new_filename = xconcatenated_filename (dir, filename, NULL); + target = locating_rule_match (&rules->items[i], new_filename, + name); + free (new_filename); + if (target != NULL) + return target; + } + } + } + + return NULL; +} + +static void +missing_attribute (xmlNode *node, const char *attribute) +{ + error (0, 0, _("\"%s\" node does not have \"%s\""), node->name, attribute); +} + +static void +document_locating_rule_destroy (struct document_locating_rule_ty *rule) +{ + free (rule->ns); + free (rule->local_name); + free (rule->target); +} + +static void +document_locating_rule_list_add (struct document_locating_rule_list_ty *rules, + xmlNode *node) +{ + struct document_locating_rule_ty rule; + + if (!xmlHasProp (node, BAD_CAST "target")) + { + missing_attribute (node, "target"); + return; + } + + memset (&rule, 0, sizeof (struct document_locating_rule_ty)); + + if (xmlHasProp (node, BAD_CAST "ns")) + rule.ns = get_attribute (node, "ns"); + if (xmlHasProp (node, BAD_CAST "localName")) + rule.local_name = get_attribute (node, "localName"); + rule.target = get_attribute (node, "target"); + + if (rules->nitems == rules->nitems_max) + { + rules->nitems_max = 2 * rules->nitems_max + 1; + rules->items = + xrealloc (rules->items, + sizeof (struct document_locating_rule_ty) + * rules->nitems_max); + } + memcpy (&rules->items[rules->nitems++], &rule, + sizeof (struct document_locating_rule_ty)); +} + +static void +locating_rule_destroy (struct locating_rule_ty *rule) +{ + size_t i; + + for (i = 0; i < rule->doc_rules.nitems; i++) + document_locating_rule_destroy (&rule->doc_rules.items[i]); + free (rule->doc_rules.items); + + free (rule->name); + free (rule->pattern); + free (rule->target); +} + +static bool +locating_rule_list_add_from_file (struct locating_rule_list_ty *rules, + const char *rule_file_name) +{ + xmlDoc *doc; + xmlNode *root, *node; + + doc = xmlReadFile (rule_file_name, "utf-8", + XML_PARSE_NONET + | XML_PARSE_NOWARNING + | XML_PARSE_NOBLANKS + | XML_PARSE_NOERROR); + if (doc == NULL) + { + error (0, 0, _("cannot read XML file %s"), rule_file_name); + return false; + } + + root = xmlDocGetRootElement (doc); + if (!(xmlStrEqual (root->name, BAD_CAST "locatingRules") +#if 0 + && root->ns + && xmlStrEqual (root->ns->href, BAD_CAST LOCATING_RULES_NS) +#endif + )) + { + error (0, 0, _("the root element is not \"locatingRules\"")); + xmlFreeDoc (doc); + return false; + } + + for (node = root->children; node; node = node->next) + { + if (xmlStrEqual (node->name, BAD_CAST "locatingRule")) + { + struct locating_rule_ty rule; + + if (!xmlHasProp (node, BAD_CAST "pattern")) + { + missing_attribute (node, "pattern"); + xmlFreeDoc (doc); + continue; + } + + memset (&rule, 0, sizeof (struct locating_rule_ty)); + rule.pattern = get_attribute (node, "pattern"); + if (xmlHasProp (node, BAD_CAST "name")) + rule.name = get_attribute (node, "name"); + if (xmlHasProp (node, BAD_CAST "target")) + rule.target = get_attribute (node, "target"); + else + { + xmlNode *n; + + for (n = node->children; n; n = n->next) + { + if (xmlStrEqual (n->name, BAD_CAST "documentRule")) + document_locating_rule_list_add (&rule.doc_rules, n); + } + } + if (rules->nitems == rules->nitems_max) + { + rules->nitems_max = 2 * rules->nitems_max + 1; + rules->items = + xrealloc (rules->items, + sizeof (struct locating_rule_ty) * rules->nitems_max); + } + memcpy (&rules->items[rules->nitems++], &rule, + sizeof (struct locating_rule_ty)); + } + } + + xmlFreeDoc (doc); + return true; +} + +bool +locating_rule_list_add_from_directory (struct locating_rule_list_ty *rules, + const char *directory) +{ +#if HAVE_DIR + DIR *dirp; + + dirp = opendir (directory); + if (dirp == NULL) + return false; + + for (;;) + { + struct dirent *dp; + + errno = 0; + dp = readdir (dirp); + if (dp != NULL) + { + const char *name = dp->d_name; + size_t namlen = strlen (name); + + if (namlen > 4 && memcmp (name + namlen - 4, ".loc", 4) == 0) + { + char *locator_file_name = + xconcatenated_filename (directory, name, NULL); + locating_rule_list_add_from_file (rules, locator_file_name); + free (locator_file_name); + } + } + else if (errno != 0) + return false; + else + break; + } + if (closedir (dirp)) + return false; + +#endif + return true; +} + +struct locating_rule_list_ty * +locating_rule_list_alloc (void) +{ + struct locating_rule_list_ty *result; + + xmlCheckVersion (LIBXML_VERSION); + + result = XCALLOC (1, struct locating_rule_list_ty); + + return result; +} + +void +locating_rule_list_destroy (struct locating_rule_list_ty *rules) +{ + while (rules->nitems-- > 0) + locating_rule_destroy (&rules->items[rules->nitems]); + free (rules->items); +} + +void +locating_rule_list_free (struct locating_rule_list_ty *rules) +{ + if (rules != NULL) + locating_rule_list_destroy (rules); + free (rules); +} diff --git a/gettext-tools/src/locating-rule.h b/gettext-tools/src/locating-rule.h new file mode 100644 index 0000000..f1214bc --- /dev/null +++ b/gettext-tools/src/locating-rule.h @@ -0,0 +1,50 @@ +/* XML resource locating rules + Copyright (C) 2015 Free Software Foundation, Inc. + + This file was written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LOCATING_RULE_H +#define _LOCATING_RULE_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct locating_rule_list_ty locating_rule_list_ty; + +/* Creates a fresh locating_rule_list_ty. */ +extern struct locating_rule_list_ty *locating_rule_list_alloc (void); + +extern bool + locating_rule_list_add_from_directory (locating_rule_list_ty *rules, + const char *directory); + +/* Determines the location of resource associated with FILENAME, + accoding to the loaded locating rules. */ +extern const char *locating_rule_list_locate (locating_rule_list_ty *rules, + const char *filename, + const char *name); + +/* Releases memory allocated for RULES. */ +extern void locating_rule_list_free (locating_rule_list_ty *rules); + +#ifdef __cplusplus +} +#endif + +#endif /* _LOCATING_RULE_H */ diff --git a/gettext-tools/src/message.c b/gettext-tools/src/message.c index 586675f..bc1604c 100644 --- a/gettext-tools/src/message.c +++ b/gettext-tools/src/message.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2009, 2015 Free Software Foundation, + Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> @@ -58,6 +59,7 @@ const char *const format_language[NFORMATS] = /* format_qt */ "qt", /* format_qt_plursl */ "qt-plural", /* format_kde */ "kde", + /* format_kde_kuit */ "kde-kuit", /* format_boost */ "boost", /* format_lua */ "lua", /* format_javascript */ "javascript" @@ -89,6 +91,7 @@ const char *const format_language_pretty[NFORMATS] = /* format_qt */ "Qt", /* format_qt_plural */ "Qt plural", /* format_kde */ "KDE", + /* format_kde_kuit */ "KDE KUIT", /* format_boost */ "Boost", /* format_lua */ "Lua", /* format_javascript */ "JavaScript" @@ -104,6 +107,14 @@ possible_format_p (enum is_format is_format) } +const char *const syntax_check_name[NSYNTAXCHECKS] = +{ + /* sc_ellipsis_unicode */ "ellipsis-unicode", + /* sc_space_ellipsis */ "space-ellipsis", + /* sc_quote_unicode */ "quote-unicode" +}; + + message_ty * message_alloc (const char *msgctxt, const char *msgid, const char *msgid_plural, @@ -130,6 +141,8 @@ message_alloc (const char *msgctxt, mp->range.min = -1; mp->range.max = -1; mp->do_wrap = undecided; + for (i = 0; i < NSYNTAXCHECKS; i++) + mp->do_syntax_check[i] = undecided; mp->prev_msgctxt = NULL; mp->prev_msgid = NULL; mp->prev_msgid_plural = NULL; @@ -235,6 +248,8 @@ message_copy (message_ty *mp) result->is_format[i] = mp->is_format[i]; result->range = mp->range; result->do_wrap = mp->do_wrap; + for (i = 0; i < NSYNTAXCHECKS; i++) + result->do_syntax_check[i] = mp->do_syntax_check[i]; for (j = 0; j < mp->filepos_count; ++j) { lex_pos_ty *pp = &mp->filepos[j]; diff --git a/gettext-tools/src/message.h b/gettext-tools/src/message.h index bf2215a..ec86ff1 100644 --- a/gettext-tools/src/message.h +++ b/gettext-tools/src/message.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2009, 2015 Free Software Foundation, + Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> @@ -67,11 +68,12 @@ enum format_type format_qt, format_qt_plural, format_kde, + format_kde_kuit, format_boost, format_lua, format_javascript }; -#define NFORMATS 27 /* Number of format_type enum values. */ +#define NFORMATS 28 /* Number of format_type enum values. */ extern DLL_VARIABLE const char *const format_language[NFORMATS]; extern DLL_VARIABLE const char *const format_language_pretty[NFORMATS]; @@ -114,6 +116,29 @@ enum is_wrap #endif +/* Kinds of syntax checks which apply to strings. */ +enum syntax_check_type +{ + sc_ellipsis_unicode, + sc_space_ellipsis, + sc_quote_unicode +}; +#define NSYNTAXCHECKS 3 +extern DLL_VARIABLE const char *const syntax_check_name[NSYNTAXCHECKS]; + +/* Is current msgid subject to a syntax check? */ +#if 0 +enum is_syntax_check +{ + undecided, + yes, + no +}; +#else /* HACK - C's enum concept is so stupid */ +#define is_syntax_check is_format +#endif + + struct altstr { const char *msgstr; @@ -175,6 +200,9 @@ struct message_ty /* Do we want the string to be wrapped in the emitted PO file? */ enum is_wrap do_wrap; + /* Do we want to apply extra syntax checks on the string? */ + enum is_syntax_check do_syntax_check[NSYNTAXCHECKS]; + /* The prev_msgctxt, prev_msgid and prev_msgid_plural strings appearing before the message, if present. Generated by msgmerge. */ const char *prev_msgctxt; diff --git a/gettext-tools/src/msgattrib.c b/gettext-tools/src/msgattrib.c index 326f28c..1f945b6 100644 --- a/gettext-tools/src/msgattrib.c +++ b/gettext-tools/src/msgattrib.c @@ -1,5 +1,6 @@ /* Manipulates attributes of messages in translation catalogs. - Copyright (C) 2001-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009-2010, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgcat.c b/gettext-tools/src/msgcat.c index 0cc432c..c0b6fd4 100644 --- a/gettext-tools/src/msgcat.c +++ b/gettext-tools/src/msgcat.c @@ -1,5 +1,6 @@ /* Concatenates several translation catalogs. - Copyright (C) 2001-2007, 2009-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009-2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgcmp.c b/gettext-tools/src/msgcmp.c index f82131d..4fadbb6 100644 --- a/gettext-tools/src/msgcmp.c +++ b/gettext-tools/src/msgcmp.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2010, 2012, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgcomm.c b/gettext-tools/src/msgcomm.c index daddf2b..c731297 100644 --- a/gettext-tools/src/msgcomm.c +++ b/gettext-tools/src/msgcomm.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1997-1998, 2000-2007, 2009-2012 Free Software Foundation, Inc. + Copyright (C) 1997-1998, 2000-2007, 2009-2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/msgconv.c b/gettext-tools/src/msgconv.c index 5c9f7ea..e407ac6 100644 --- a/gettext-tools/src/msgconv.c +++ b/gettext-tools/src/msgconv.c @@ -1,5 +1,6 @@ /* Converts a translation catalog to a different character encoding. - Copyright (C) 2001-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009-2010, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgen.c b/gettext-tools/src/msgen.c index e33c61a..e6eda09 100644 --- a/gettext-tools/src/msgen.c +++ b/gettext-tools/src/msgen.c @@ -1,5 +1,6 @@ /* Creates an English translation catalog. - Copyright (C) 2001-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009-2010, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgexec.c b/gettext-tools/src/msgexec.c index 5239518..e7594fc 100644 --- a/gettext-tools/src/msgexec.c +++ b/gettext-tools/src/msgexec.c @@ -1,5 +1,5 @@ /* Pass translations to a subprocess. - Copyright (C) 2001-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -71,6 +71,8 @@ static const char *sub_path; static char **sub_argv; static int sub_argc; +static bool newline; + /* Maximum exit code encountered. */ static int exitcode; @@ -80,6 +82,7 @@ static const struct option long_options[] = { "directory", required_argument, NULL, 'D' }, { "help", no_argument, NULL, 'h' }, { "input", required_argument, NULL, 'i' }, + { "newline", no_argument, NULL, CHAR_MAX + 2 }, { "properties-input", no_argument, NULL, 'P' }, { "stringtable-input", no_argument, NULL, CHAR_MAX + 1 }, { "version", no_argument, NULL, 'V' }, @@ -167,6 +170,10 @@ main (int argc, char **argv) input_syntax = &input_format_stringtable; break; + case CHAR_MAX + 2: /* --newline */ + newline = true; + break; + default: usage (EXIT_FAILURE); break; @@ -274,6 +281,11 @@ null byte. The output of \"msgexec 0\" is suitable as input for \"xargs -0\".\n ")); printf ("\n"); printf (_("\ +Command input:\n")); + printf (_("\ + --newline add newline at the end of input\n")); + printf ("\n"); + printf (_("\ Mandatory arguments to long options are mandatory for short options too.\n")); printf ("\n"); printf (_("\ @@ -352,6 +364,7 @@ process_string (const message_ty *mp, const char *str, size_t len) int fd[1]; void (*orig_sigpipe_handler)(int); int exitstatus; + char *newstr; /* Set environment variables for the subprocess. Note: These environment variables, especially MSGEXEC_MSGCTXT and @@ -399,11 +412,23 @@ process_string (const message_ty *mp, const char *str, size_t len) successfully without having read all of the input that we feed it. */ orig_sigpipe_handler = signal (SIGPIPE, SIG_IGN); - if (full_write (fd[0], str, len) < len) + if (newline) + { + newstr = XNMALLOC (len + 1, char); + memcpy (newstr, str, len); + newstr[len++] = '\n'; + } + else + newstr = (char *) str; + + if (full_write (fd[0], newstr, len) < len) if (errno != EPIPE) error (EXIT_FAILURE, errno, _("write to %s subprocess failed"), sub_name); + if (newstr != str) + free (newstr); + close (fd[0]); signal (SIGPIPE, orig_sigpipe_handler); diff --git a/gettext-tools/src/msgfilter.c b/gettext-tools/src/msgfilter.c index f9cb1cc..aa358e1 100644 --- a/gettext-tools/src/msgfilter.c +++ b/gettext-tools/src/msgfilter.c @@ -1,5 +1,5 @@ /* Edit translations using a subprocess. - Copyright (C) 2001-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2010, 2012, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -81,6 +81,8 @@ static const char *sub_path; static const char **sub_argv; static int sub_argc; +static bool newline; + /* Filter function. */ static void (*filter) (const char *str, size_t len, char **resultp, size_t *lengthp); @@ -96,6 +98,7 @@ static const struct option long_options[] = { "indent", no_argument, NULL, CHAR_MAX + 1 }, { "input", required_argument, NULL, 'i' }, { "keep-header", no_argument, &keep_header, 1 }, + { "newline", no_argument, NULL, CHAR_MAX + 9 }, { "no-escape", no_argument, NULL, CHAR_MAX + 2 }, { "no-location", no_argument, NULL, CHAR_MAX + 8 }, { "no-wrap", no_argument, NULL, CHAR_MAX + 3 }, @@ -269,6 +272,10 @@ main (int argc, char **argv) message_print_style_filepos (filepos_comment_none); break; + case CHAR_MAX + 9: /* --newline */ + newline = true; + break; + default: usage (EXIT_FAILURE); break; @@ -438,6 +445,12 @@ and writes a modified translation to standard output.\n\ ")); printf ("\n"); printf (_("\ +Filter input and output:\n")); + printf (_("\ + --newline add a newline at the end of input and\n\ + remove a newline from the end of output")); + printf ("\n"); + printf (_("\ Useful FILTER-OPTIONs when the FILTER is 'sed':\n")); printf (_("\ -e, --expression=SCRIPT add SCRIPT to the commands to be executed\n")); @@ -628,6 +641,35 @@ process_string (const char *str, size_t len, char **resultp, size_t *lengthp) } +/* Do the same thing as process_string but append a newline to STR + before processing, and remove a newline from the result. + */ +static void +process_string_with_newline (const char *str, size_t len, char **resultp, + size_t *lengthp) +{ + char *newstr; + char *result; + size_t length; + + newstr = XNMALLOC (len + 1, char); + memcpy (newstr, str, len); + newstr[len] = '\n'; + + process_string (newstr, len + 1, &result, &length); + + free (newstr); + + if (length > 0 && result[length - 1] == '\n') + result[--length] = '\0'; + else + error (0, 0, _("filter output is not terminated with a newline")); + + *resultp = result; + *lengthp = length; +} + + static void process_message (message_ty *mp) { @@ -705,7 +747,12 @@ process_message (message_ty *mp) } else unsetenv ("MSGFILTER_PLURAL_FORM"); - process_string (p, strlen (p), &result, &length); + + if (newline) + process_string_with_newline (p, strlen (p), &result, &length); + else + process_string (p, strlen (p), &result, &length); + result = (char *) xrealloc (result, length + 1); result[length] = '\0'; substrings[k] = result; diff --git a/gettext-tools/src/msgfmt.c b/gettext-tools/src/msgfmt.c index 3fabd87..0517c99 100644 --- a/gettext-tools/src/msgfmt.c +++ b/gettext-tools/src/msgfmt.c @@ -1,5 +1,6 @@ /* Converts Uniforum style .po files to binary .mo files - Copyright (C) 1995-1998, 2000-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2007, 2009-2010, 2012, 2015 Free + Software Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify @@ -49,6 +50,7 @@ #include "write-tcl.h" #include "write-qt.h" #include "write-desktop.h" +#include "write-xml.h" #include "propername.h" #include "message.h" #include "open-catalog.h" @@ -61,10 +63,14 @@ #include "msgl-check.h" #include "msgl-iconv.h" #include "concat-filename.h" +#include "its.h" +#include "locating-rule.h" #include "gettext.h" #define _(str) gettext (str) +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + /* Contains exit status for case in which no premature exit occurs. */ static int exit_status; @@ -110,6 +116,14 @@ static const char *desktop_base_directory; static hash_table desktop_keywords; static bool desktop_default_keywords = true; +/* XML mode output file specification. */ +static bool xml_mode; +static const char *xml_locale_name; +static const char *xml_template_name; +static const char *xml_base_directory; +static const char *xml_language; +static its_rule_list_ty *xml_its_rules; + /* We may have more than one input file. Domains with same names in different files have to merged. So we need a list of tables for each output file. */ @@ -180,6 +194,7 @@ static const struct option long_options[] = { "java", no_argument, NULL, 'j' }, { "java2", no_argument, NULL, CHAR_MAX + 5 }, { "keyword", required_argument, NULL, 'k' }, + { "language", required_argument, NULL, 'L' }, { "locale", required_argument, NULL, 'l' }, { "no-hash", no_argument, NULL, CHAR_MAX + 6 }, { "output-file", required_argument, NULL, 'o' }, @@ -196,6 +211,7 @@ static const struct option long_options[] = { "use-untranslated", no_argument, NULL, CHAR_MAX + 12 }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, + { "xml", no_argument, NULL, 'x' }, { NULL, 0, NULL, 0 } }; @@ -211,11 +227,14 @@ static struct msg_domain *new_domain (const char *name, const char *file_name); static bool is_nonobsolete (const message_ty *mp); static void read_catalog_file_msgfmt (char *filename, catalog_input_format_ty input_syntax); -static string_list_ty *get_languages (const char *directory); static int msgfmt_desktop_bulk (const char *directory, const char *template_file_name, hash_table *keywords, const char *file_name); +static int msgfmt_xml_bulk (const char *directory, + const char *template_file_name, + its_rule_list_ty *its_rules, + const char *file_name); int @@ -252,8 +271,8 @@ main (int argc, char *argv[]) /* Ensure that write errors on stdout are detected. */ atexit (close_stdout); - while ((opt = getopt_long (argc, argv, "a:cCd:D:fhjl:o:Pr:vV", long_options, - NULL)) + while ((opt = getopt_long (argc, argv, "a:cCd:D:fhjl:L:o:Pr:vVx", + long_options, NULL)) != EOF) switch (opt) { @@ -281,6 +300,7 @@ main (int argc, char *argv[]) csharp_base_directory = optarg; tcl_base_directory = optarg; desktop_base_directory = optarg; + xml_base_directory = optarg; break; case 'D': dir_list_append (optarg); @@ -313,6 +333,10 @@ main (int argc, char *argv[]) csharp_locale_name = optarg; tcl_locale_name = optarg; desktop_locale_name = optarg; + xml_locale_name = optarg; + break; + case 'L': + xml_language = optarg; break; case 'o': output_file_name = optarg; @@ -333,6 +357,9 @@ main (int argc, char *argv[]) case 'V': do_version = true; break; + case 'x': + xml_mode = true; + break; case CHAR_MAX + 1: /* --check-accelerators */ check_accelerators = true; if (optarg != NULL) @@ -402,6 +429,7 @@ main (int argc, char *argv[]) break; case CHAR_MAX + 16: /* --template=TEMPLATE */ desktop_template_name = optarg; + xml_template_name = optarg; break; default: usage (EXIT_FAILURE); @@ -428,16 +456,20 @@ There is NO WARRANTY, to the extent permitted by law.\n\ usage (EXIT_SUCCESS); /* Test whether we have a .po file name as argument. */ - if (optind >= argc && !(desktop_mode && desktop_base_directory)) + if (optind >= argc + && !(desktop_mode && desktop_base_directory) + && !(xml_mode && xml_base_directory)) { error (EXIT_SUCCESS, 0, _("no input file given")); usage (EXIT_FAILURE); } - if (optind < argc && desktop_mode && desktop_base_directory) + if (optind < argc + && ((desktop_mode && desktop_base_directory) + || (xml_mode && xml_base_directory))) { error (EXIT_SUCCESS, 0, _("no input file should be given if %s and %s are specified"), - "--desktop", "-d"); + desktop_mode ? "--desktop" : "--xml", "-d"); usage (EXIT_FAILURE); } @@ -449,10 +481,11 @@ There is NO WARRANTY, to the extent permitted by law.\n\ | (csharp_resources_mode ? 4 : 0) | (tcl_mode ? 8 : 0) | (qt_mode ? 16 : 0) - | (desktop_mode ? 32 : 0); + | (desktop_mode ? 32 : 0) + | (xml_mode ? 64 : 0); static const char *mode_options[] = { "--java", "--csharp", "--csharp-resources", "--tcl", "--qt", - "--desktop" }; + "--desktop", "--xml" }; /* More than one bit set? */ if (modes & (modes - 1)) { @@ -558,6 +591,34 @@ There is NO WARRANTY, to the extent permitted by law.\n\ usage (EXIT_FAILURE); } } + else if (xml_mode) + { + if (xml_template_name == NULL) + { + error (EXIT_SUCCESS, 0, + _("%s requires a \"--template template\" specification"), + "--xml"); + usage (EXIT_FAILURE); + } + if (output_file_name == NULL) + { + error (EXIT_SUCCESS, 0, + _("%s requires a \"-o file\" specification"), + "--xml"); + usage (EXIT_FAILURE); + } + if (xml_base_directory != NULL && xml_locale_name != NULL) + error (EXIT_FAILURE, 0, + _("%s and %s are mutually exclusive in %s"), + "-d", "-l", "--xml"); + if (xml_base_directory == NULL && xml_locale_name == NULL) + { + error (EXIT_SUCCESS, 0, + _("%s requires a \"-l locale\" specification"), + "--xml"); + usage (EXIT_FAILURE); + } + } else { if (java_resource_name != NULL) @@ -600,6 +661,80 @@ There is NO WARRANTY, to the extent permitted by law.\n\ exit (exit_status); } + if (xml_mode) + { + const char *gettextdatadir; + char *versioned_gettextdatadir; + char *its_dirs[2] = { NULL, NULL }; + locating_rule_list_ty *its_locating_rules; + const char *its_basename; + size_t i; + + /* Make it possible to override the locator file location. This + is necessary for running the testsuite before "make + install". */ + gettextdatadir = getenv ("GETTEXTDATADIR"); + if (gettextdatadir == NULL || gettextdatadir[0] == '\0') + gettextdatadir = relocate (GETTEXTDATADIR); + + its_dirs[0] = xconcatenated_filename (gettextdatadir, "its", NULL); + + versioned_gettextdatadir = + xasprintf ("%s%s", relocate (GETTEXTDATADIR), PACKAGE_SUFFIX); + its_dirs[1] = xconcatenated_filename (versioned_gettextdatadir, "its", + NULL); + free (versioned_gettextdatadir); + + its_locating_rules = locating_rule_list_alloc (); + for (i = 0; i < SIZEOF (its_dirs); i++) + locating_rule_list_add_from_directory (its_locating_rules, its_dirs[i]); + + its_basename = locating_rule_list_locate (its_locating_rules, + xml_template_name, + xml_language); + + if (its_basename != NULL) + { + size_t j; + + xml_its_rules = its_rule_list_alloc (); + for (j = 0; j < SIZEOF (its_dirs); j++) + { + char *its_filename = + xconcatenated_filename (its_dirs[j], its_basename, NULL); + struct stat statbuf; + bool ok = false; + + if (stat (its_filename, &statbuf) == 0) + ok = its_rule_list_add_from_file (xml_its_rules, its_filename); + free (its_filename); + if (ok) + break; + } + if (j == SIZEOF (its_dirs)) + { + its_rule_list_free (xml_its_rules); + xml_its_rules = NULL; + } + } + locating_rule_list_free (its_locating_rules); + + if (xml_its_rules == NULL) + error (EXIT_FAILURE, 0, _("cannot locate ITS rules for %s"), + xml_template_name); + } + + /* Bulk processing mode for XML files. + Process all .po files in xml_base_directory. */ + if (xml_mode && xml_base_directory) + { + exit_status = msgfmt_xml_bulk (xml_base_directory, + xml_template_name, + xml_its_rules, + output_file_name); + exit (exit_status); + } + /* The -o option determines the name of the domain and therefore the output file. */ if (output_file_name != NULL) @@ -705,6 +840,15 @@ There is NO WARRANTY, to the extent permitted by law.\n\ if (desktop_keywords.table != NULL) hash_destroy (&desktop_keywords); } + else if (xml_mode) + { + if (msgdomain_write_xml (domain->mlp, canon_encoding, + xml_locale_name, + xml_template_name, + xml_its_rules, + domain->file_name)) + exit_status = EXIT_FAILURE; + } else { if (msgdomain_write_mo (domain->mlp, domain->domain_name, @@ -810,6 +954,8 @@ Operation mode:\n")); --qt Qt mode: generate a Qt .qm file\n")); printf (_("\ --desktop Desktop Entry mode: generate a .desktop file\n")); + printf (_("\ + --xml XML mode: generate XML file\n")); printf ("\n"); printf (_("\ Output file location:\n")); @@ -876,6 +1022,22 @@ The -l, -o, and --template options are mandatory. If -D is specified, input\n\ files are read from the directory instead of the command line arguments.\n")); printf ("\n"); printf (_("\ +XML mode options:\n")); + printf (_("\ + -l, --locale=LOCALE locale name, either language or language_COUNTRY\n")); + printf (_("\ + -L, --language=NAME recognise the specified XML language\n")); + printf (_("\ + -o, --output-file=FILE write output to specified file\n")); + printf (_("\ + --template=TEMPLATE an XML file used as a template\n")); + printf (_("\ + -d DIRECTORY base directory of .po files\n")); + printf (_("\ +The -l, -o, and --template options are mandatory. If -D is specified, input\n\ +files are read from the directory instead of the command line arguments.\n")); + printf ("\n"); + printf (_("\ Input file syntax:\n")); printf (_("\ -P, --properties-input input files are in Java .properties syntax\n")); @@ -1063,7 +1225,7 @@ msgfmt_set_domain (default_catalog_reader_ty *this, char *name) /* If no output file was given, we change it with each 'domain' directive. */ if (!java_mode && !csharp_mode && !csharp_resources_mode && !tcl_mode - && !qt_mode && !desktop_mode && output_file_name == NULL) + && !qt_mode && !desktop_mode && !xml_mode && output_file_name == NULL) { size_t correct; @@ -1297,35 +1459,30 @@ add_languages (string_list_ty *languages, string_list_ty *desired_languages, /* Compute the languages list by reading the "LINGUAS" envvar or the LINGUAS file under DIRECTORY. */ -static string_list_ty * -get_languages (const char *directory) +static void +get_languages (string_list_ty *languages, const char *directory) { char *envval; - string_list_ty *languages; - string_list_ty *desired_languages = NULL; - char *linguas_file_name; + string_list_ty real_desired_languages, *desired_languages = NULL; + char *linguas_file_name = NULL; struct stat statbuf; FILE *fp; size_t line_len = 0; char *line_buf = NULL; - languages = string_list_alloc (); envval = getenv ("LINGUAS"); if (envval) { - desired_languages = string_list_alloc (); - add_languages (desired_languages, NULL, envval, strlen (envval)); + string_list_init (&real_desired_languages); + add_languages (&real_desired_languages, NULL, envval, strlen (envval)); + desired_languages = &real_desired_languages; } linguas_file_name = xconcatenated_filename (directory, "LINGUAS", NULL); if (stat (linguas_file_name, &statbuf) < 0) { error (EXIT_SUCCESS, 0, _("%s does not exist"), linguas_file_name); - string_list_free (languages); - if (desired_languages != NULL) - string_list_free (desired_languages); - free (linguas_file_name); - return NULL; + goto out; } fp = fopen (linguas_file_name, "r"); @@ -1333,11 +1490,7 @@ get_languages (const char *directory) { error (EXIT_SUCCESS, 0, _("%s exists but cannot read"), linguas_file_name); - string_list_free (languages); - if (desired_languages != NULL) - string_list_free (desired_languages); - free (linguas_file_name); - return NULL; + goto out; } while (!feof (fp)) @@ -1367,32 +1520,68 @@ get_languages (const char *directory) free (line_buf); fclose (fp); + + out: if (desired_languages != NULL) - string_list_free (desired_languages); + string_list_destroy (desired_languages); free (linguas_file_name); +} + +static void +msgfmt_operand_list_init (msgfmt_operand_list_ty *operands) +{ + operands->items = NULL; + operands->nitems = 0; + operands->nitems_max = 0; +} + +static void +msgfmt_operand_list_destroy (msgfmt_operand_list_ty *operands) +{ + size_t i; - return languages; + for (i = 0; i < operands->nitems; i++) + { + free (operands->items[i].language); + message_list_free (operands->items[i].mlp, 0); + } + free (operands->items); +} + +static void +msgfmt_operand_list_append (msgfmt_operand_list_ty *operands, + const char *language, + message_list_ty *messages) +{ + msgfmt_operand_ty *operand; + + if (operands->nitems == operands->nitems_max) + { + operands->nitems_max = operands->nitems_max * 2 + 1; + operands->items = xrealloc (operands->items, + sizeof (msgfmt_operand_ty) + * operands->nitems_max); + } + + operand = &operands->items[operands->nitems++]; + operand->language = xstrdup (language); + operand->mlp = messages; } -/* Helper function to support 'bulk' operation mode of --desktop. - This reads all .po files in DIRECTORY and merges them into a - .desktop file FILE_NAME. Currently it does not support some - options available in 'iterative' mode, such as --statistics. */ static int -msgfmt_desktop_bulk (const char *directory, - const char *template_file_name, - hash_table *keywords, - const char *file_name) +msgfmt_operand_list_add_from_directory (msgfmt_operand_list_ty *operands, + const char *directory) { - string_list_ty *languages = NULL; - message_list_ty **messages = NULL; + string_list_ty languages; void *saved_dir_list; int retval = 0; size_t i; - languages = get_languages (directory); - if (!languages) - return EXIT_FAILURE; + string_list_init (&languages); + get_languages (&languages, directory); + + if (languages.nitems == 0) + return 0; /* Reset the directory search list so only .po files under DIRECTORY will be read. */ @@ -1400,34 +1589,35 @@ msgfmt_desktop_bulk (const char *directory, dir_list_append (directory); /* Read all .po files. */ - messages = XNMALLOC (languages->nitems, message_list_ty *); - for (i = 0; i < languages->nitems; i++) + for (i = 0; i < languages.nitems; i++) { - const char *language = languages->item[i]; + const char *language = languages.item[i]; + message_list_ty *mlp; char *input_file_name; int nerrors; - current_domain = new_domain (file_name, file_name); + current_domain = new_domain (MESSAGE_DOMAIN_DEFAULT, + add_mo_suffix (MESSAGE_DOMAIN_DEFAULT)); input_file_name = xconcatenated_filename ("", language, ".po"); read_catalog_file_msgfmt (input_file_name, &input_format_po); free (input_file_name); - /* The domain directive is not supported by --desktop mode. + /* The domain directive is not supported in the bulk execution mode. Thus, domain_list should always contain a single domain. */ assert (current_domain == domain_list && domain_list->next == NULL); - messages[i] = current_domain->mlp; + mlp = current_domain->mlp; free (current_domain); current_domain = domain_list = NULL; /* Remove obsolete messages. They were only needed for duplicate checking. */ - message_list_remove_if_not (messages[i], is_nonobsolete); + message_list_remove_if_not (mlp, is_nonobsolete); /* Perform all kinds of checks: plural expressions, format strings, ... */ nerrors = - check_message_list (messages[i], + check_message_list (mlp, /* Untranslated and fuzzy messages have already been dealt with during parsing, see below in msgfmt_frob_new_message. */ @@ -1436,38 +1626,92 @@ msgfmt_desktop_bulk (const char *directory, check_compatibility, check_accelerators, accelerator_char); - /* Exit with status 1 on any error. */ + retval += nerrors; if (nerrors > 0) { error (0, 0, ngettext ("found %d fatal error", "found %d fatal errors", nerrors), nerrors); - retval = EXIT_FAILURE; - goto out; + continue; } /* Convert the messages to Unicode. */ - iconv_message_list (messages[i], NULL, po_charset_utf8, NULL); + iconv_message_list (mlp, NULL, po_charset_utf8, NULL); + + msgfmt_operand_list_append (operands, language, mlp); + } + + string_list_destroy (&languages); + dir_list_restore (saved_dir_list); + + return retval; +} + +/* Helper function to support 'bulk' operation mode of --desktop. + This reads all .po files in DIRECTORY and merges them into a + .desktop file FILE_NAME. Currently it does not support some + options available in 'iterative' mode, such as --statistics. */ +static int +msgfmt_desktop_bulk (const char *directory, + const char *template_file_name, + hash_table *keywords, + const char *file_name) +{ + msgfmt_operand_list_ty operands; + int nerrors, status; + + msgfmt_operand_list_init (&operands); + + /* Read all .po files. */ + nerrors = msgfmt_operand_list_add_from_directory (&operands, directory); + if (nerrors > 0) + { + msgfmt_operand_list_destroy (&operands); + return 1; } /* Write the messages into .desktop file. */ - if (msgdomain_write_desktop_bulk (languages, - messages, - template_file_name, - keywords, - file_name)) + status = msgdomain_write_desktop_bulk (&operands, + template_file_name, + keywords, + file_name); + + msgfmt_operand_list_destroy (&operands); + + return status; +} + +/* Helper function to support 'bulk' operation mode of --xml. + This reads all .po files in DIRECTORY and merges them into an + XML file FILE_NAME. Currently it does not support some + options available in 'iterative' mode, such as --statistics. */ +static int +msgfmt_xml_bulk (const char *directory, + const char *template_file_name, + its_rule_list_ty *its_rules, + const char *file_name) +{ + msgfmt_operand_list_ty operands; + int nerrors, status; + + msgfmt_operand_list_init (&operands); + + /* Read all .po files. */ + nerrors = msgfmt_operand_list_add_from_directory (&operands, directory); + if (nerrors > 0) { - retval = EXIT_FAILURE; - goto out; + msgfmt_operand_list_destroy (&operands); + return 1; } - out: - dir_list_restore (saved_dir_list); - for (i = 0; i < languages->nitems; i++) - message_list_free (messages[i], 0); - free (messages); - string_list_free (languages); + /* Write the messages into .xml file. */ + status = msgdomain_write_xml_bulk (&operands, + template_file_name, + its_rules, + file_name); - return retval; + msgfmt_operand_list_destroy (&operands); + + return status; } diff --git a/gettext-tools/src/msgfmt.cs b/gettext-tools/src/msgfmt.cs index e2f9e7d..1a97f64 100644 --- a/gettext-tools/src/msgfmt.cs +++ b/gettext-tools/src/msgfmt.cs @@ -1,5 +1,5 @@ /* GNU gettext for C# - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2015 Free Software Foundation, Inc. * Written by Bruno Haible <bruno@clisp.org>, 2003. * * This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgfmt.h b/gettext-tools/src/msgfmt.h index e61f72c..3651a30 100644 --- a/gettext-tools/src/msgfmt.h +++ b/gettext-tools/src/msgfmt.h @@ -1,5 +1,6 @@ /* msgfmt specifics - Copyright (C) 1995-1998, 2000-2001, 2009 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2001, 2009, 2015 Free Software + Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify @@ -18,10 +19,36 @@ #ifndef _MSGFMT_H #define _MSGFMT_H +#include "message.h" + +#ifdef __cplusplus +extern "C" { +#endif + /* Be more verbose. Use only 'fprintf' and 'multiline_warning' but not 'error' or 'multiline_error' to emit verbosity messages, because 'error' and 'multiline_error' during PO file parsing cause the program to exit with EXIT_FAILURE. See function lex_end(). */ extern int verbose; +/* Data types for bulk operation mode. */ +typedef struct msgfmt_operand_ty msgfmt_operand_ty; +struct msgfmt_operand_ty +{ + char *language; + message_list_ty *mlp; +}; + +typedef struct msgfmt_operand_list_ty msgfmt_operand_list_ty; +struct msgfmt_operand_list_ty +{ + msgfmt_operand_ty *items; + size_t nitems; + size_t nitems_max; +}; + +#ifdef __cplusplus +} +#endif + #endif /* _MSGFMT_H */ diff --git a/gettext-tools/src/msggrep.c b/gettext-tools/src/msggrep.c index 73ccb94..b0cb87a 100644 --- a/gettext-tools/src/msggrep.c +++ b/gettext-tools/src/msggrep.c @@ -1,5 +1,6 @@ /* Extract some translations of a translation catalog. - Copyright (C) 2001-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009-2010, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msginit.c b/gettext-tools/src/msginit.c index 951aa2e..f85b83c 100644 --- a/gettext-tools/src/msginit.c +++ b/gettext-tools/src/msginit.c @@ -1,5 +1,5 @@ /* Initializes a new PO file. - Copyright (C) 2001-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -649,7 +649,7 @@ catalogname_for_locale (const char *locale) "pa_IN", /* Punjabi India */ "pag_PH", /* Pangasinan Philippines */ "pam_PH", /* Pampanga Philippines */ - "pap_AN", /* Papiamento Netherlands Antilles */ + "pap_AN", /* Papiamento Netherlands Antilles - this line can be removed in 2018 */ "pbb_CO", /* Páez Colombia */ "pl_PL", /* Polish Poland */ "ps_AF", /* Pashto Afghanistan */ @@ -676,7 +676,6 @@ catalogname_for_locale (const char *locale) "so_SO", /* Somali Somalia */ "sq_AL", /* Albanian Albania */ "sr_RS", /* Serbian Serbia */ - "sr_YU", /* Serbian Yugoslavia - this line can be removed in 2010 */ "srr_SN", /* Serer Senegal */ "suk_TZ", /* Sukuma Tanzania */ "sus_GN", /* Susu Guinea */ @@ -1333,6 +1332,8 @@ content_transfer_encoding () static const char * plural_forms () { + const char *gettextcldrdir; + char *prog = NULL; size_t i; /* Search for a formula depending on the catalogname. */ @@ -1345,6 +1346,85 @@ plural_forms () if (strcmp (plural_table[i].lang, language) == 0) return plural_table[i].value; + gettextcldrdir = getenv ("GETTEXTCLDRDIR"); + if (gettextcldrdir != NULL && gettextcldrdir[0] != '\0') + { + const char *gettextlibdir; + char *dirs[3], *last_dir; + char *argv[4]; + pid_t child; + int fd[1]; + FILE *fp; + char *line; + size_t linesize; + size_t linelen; + int exitstatus; + + gettextlibdir = getenv ("GETTEXTLIBDIR"); + if (gettextlibdir == NULL || gettextlibdir[0] == '\0') + gettextlibdir = relocate (LIBDIR "/gettext"); + + prog = xconcatenated_filename (gettextlibdir, "cldr-plurals", NULL); + + last_dir = xstrdup (gettextcldrdir); + dirs[0] = "common"; + dirs[1] = "supplemental"; + dirs[2] = "plurals.xml"; + for (i = 0; i < SIZEOF (dirs); i++) + { + char *dir = xconcatenated_filename (last_dir, dirs[i], NULL); + free (last_dir); + last_dir = dir; + } + + /* Call the cldr-plurals command. */ + argv[0] = "cldr-plurals"; + argv[1] = (char *) language; + argv[2] = last_dir; + argv[3] = NULL; + child = create_pipe_in (prog, prog, argv, DEV_NULL, + false, true, false, + fd); + free (last_dir); + if (child == -1) + goto failed; + + /* Retrieve its result. */ + fp = fdopen (fd[0], "r"); + if (fp == NULL) + { + error (0, errno, _("fdopen() failed")); + goto failed; + } + + line = NULL; linesize = 0; + linelen = getline (&line, &linesize, fp); + if (linelen == (size_t)(-1)) + { + error (0, 0, _("%s subprocess I/O error"), prog); + fclose (fp); + goto failed; + } + if (linelen > 0 && line[linelen - 1] == '\n') + line[linelen - 1] = '\0'; + + fclose (fp); + + /* Remove zombie process from process list, and retrieve exit status. */ + exitstatus = wait_subprocess (child, prog, false, false, true, false, + NULL); + if (exitstatus != 0) + { + error (0, 0, _("%s subprocess failed with exit code %d"), + prog, exitstatus); + goto failed; + } + + return line; + } + + failed: + free (prog); return NULL; } diff --git a/gettext-tools/src/msgl-ascii.c b/gettext-tools/src/msgl-ascii.c index e3ca953..c92e4df 100644 --- a/gettext-tools/src/msgl-ascii.c +++ b/gettext-tools/src/msgl-ascii.c @@ -1,5 +1,6 @@ /* Message list test for ASCII character set. - Copyright (C) 2001-2002, 2005-2006 Free Software Foundation, Inc. + Copyright (C) 2001-2002, 2005-2006, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-ascii.h b/gettext-tools/src/msgl-ascii.h index fee41a9..b6e09f9 100644 --- a/gettext-tools/src/msgl-ascii.h +++ b/gettext-tools/src/msgl-ascii.h @@ -1,5 +1,5 @@ /* Message list test for ASCII character set. - Copyright (C) 2001-2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-cat.c b/gettext-tools/src/msgl-cat.c index 0bd58d4..dfedcb6 100644 --- a/gettext-tools/src/msgl-cat.c +++ b/gettext-tools/src/msgl-cat.c @@ -1,5 +1,6 @@ /* Message list concatenation and duplicate handling. - Copyright (C) 2001-2003, 2005-2008, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2008, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -308,6 +309,8 @@ domain \"%s\" in input file '%s' doesn't contain a header entry with a charset s tmp->range.min = - INT_MAX; tmp->range.max = - INT_MAX; tmp->do_wrap = yes; /* may be set to no later */ + for (i = 0; i < NSYNTAXCHECKS; i++) + tmp->do_syntax_check[i] = undecided; /* may be set to yes/no later */ tmp->obsolete = true; /* may be set to false later */ tmp->alternative_count = 0; tmp->alternative = NULL; @@ -535,6 +538,8 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"), tmp->is_format[i] = mp->is_format[i]; tmp->range = mp->range; tmp->do_wrap = mp->do_wrap; + for (i = 0; i < NSYNTAXCHECKS; i++) + tmp->do_syntax_check[i] = mp->do_syntax_check[i]; tmp->prev_msgctxt = mp->prev_msgctxt; tmp->prev_msgid = mp->prev_msgid; tmp->prev_msgid_plural = mp->prev_msgid_plural; @@ -583,6 +588,9 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"), } if (tmp->do_wrap == undecided) tmp->do_wrap = mp->do_wrap; + for (i = 0; i < NSYNTAXCHECKS; i++) + if (tmp->do_syntax_check[i] == undecided) + tmp->do_syntax_check[i] = mp->do_syntax_check[i]; tmp->obsolete = false; } else @@ -635,6 +643,12 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"), } if (mp->do_wrap == no) tmp->do_wrap = no; + for (i = 0; i < NSYNTAXCHECKS; i++) + if (mp->do_syntax_check[i] == yes) + tmp->do_syntax_check[i] = yes; + else if (mp->do_syntax_check[i] == no + && tmp->do_syntax_check[i] == undecided) + tmp->do_syntax_check[i] = no; /* Don't fill tmp->prev_msgid in this case. */ if (!mp->obsolete) tmp->obsolete = false; diff --git a/gettext-tools/src/msgl-cat.h b/gettext-tools/src/msgl-cat.h index 4de35d5..12a9f80 100644 --- a/gettext-tools/src/msgl-cat.h +++ b/gettext-tools/src/msgl-cat.h @@ -1,5 +1,5 @@ /* Message list concatenation and duplicate handling. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-charset.c b/gettext-tools/src/msgl-charset.c index e8deb58..278d270 100644 --- a/gettext-tools/src/msgl-charset.c +++ b/gettext-tools/src/msgl-charset.c @@ -1,5 +1,6 @@ /* Message list charset and locale charset handling. - Copyright (C) 2001-2003, 2005-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2007, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-charset.h b/gettext-tools/src/msgl-charset.h index 647a394..c673d1d 100644 --- a/gettext-tools/src/msgl-charset.h +++ b/gettext-tools/src/msgl-charset.h @@ -1,5 +1,5 @@ /* Message list charset and locale charset handling. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-check.c b/gettext-tools/src/msgl-check.c index d6f4a3d..7934120 100644 --- a/gettext-tools/src/msgl-check.c +++ b/gettext-tools/src/msgl-check.c @@ -1,5 +1,6 @@ /* Checking of messages in PO files. - Copyright (C) 1995-1998, 2000-2008, 2010-2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2008, 2010-2015 Free Software + Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify @@ -40,6 +41,10 @@ #include "plural-table.h" #include "c-strstr.h" #include "message.h" +#include "quote.h" +#include "sentence.h" +#include "unictype.h" +#include "unistr.h" #include "gettext.h" #define _(str) gettext (str) @@ -912,3 +917,204 @@ check_message_list (message_list_ty *mlp, return seen_errors; } + + +static int +syntax_check_ellipsis_unicode (const message_ty *mp, const char *msgid) +{ + const char *str = msgid; + const char *str_limit = str + strlen (msgid); + int seen_errors = 0; + + while (str < str_limit) + { + const char *end, *cp; + ucs4_t ending_char; + + end = sentence_end (str, &ending_char); + + /* sentence_end doesn't treat '...' specially. */ + cp = end - (ending_char == '.' ? 2 : 3); + if (cp >= str && memcmp (cp, "...", 3) == 0) + { + po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false, + _("ASCII ellipsis ('...') instead of Unicode")); + seen_errors++; + } + + str = end + 1; + } + + return seen_errors; +} + + +static int +syntax_check_space_ellipsis (const message_ty *mp, const char *msgid) +{ + const char *str = msgid; + const char *str_limit = str + strlen (msgid); + int seen_errors = 0; + + while (str < str_limit) + { + const char *end, *ellipsis = NULL; + ucs4_t ending_char; + + end = sentence_end (str, &ending_char); + + if (ending_char == 0x2026) + ellipsis = end; + else if (ending_char == '.') + { + /* sentence_end doesn't treat '...' specially. */ + const char *cp = end - 2; + if (cp >= str && memcmp (cp, "...", 3) == 0) + ellipsis = cp; + } + else + { + /* Look for a '...'. */ + const char *cp = end - 3; + if (cp >= str && memcmp (cp, "...", 3) == 0) + ellipsis = cp; + else + { + ucs4_t uc = 0xfffd; + + /* Look for a U+2026. */ + for (cp = end - 1; cp >= str; cp--) + { + u8_mbtouc (&uc, (const unsigned char *) cp, ellipsis - cp); + if (uc != 0xfffd) + break; + } + + if (uc == 0x2026) + ellipsis = cp; + } + } + + if (ellipsis) + { + const char *cp; + ucs4_t uc = 0xfffd; + + /* Look at the character before ellipsis. */ + for (cp = ellipsis - 1; cp >= str; cp--) + { + u8_mbtouc (&uc, (const unsigned char *) cp, ellipsis - cp); + if (uc != 0xfffd) + break; + } + + if (uc != 0xfffd && uc_is_space (uc)) + { + po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false, + _("\ +space before ellipsis found in user visible strings")); + seen_errors++; + } + } + + str = end + 1; + } + + return seen_errors; +} + + +struct callback_arg +{ + const message_ty *mp; + int seen_errors; +}; + +static void +syntax_check_quote_unicode_callback (char quote, const char *quoted, + size_t quoted_length, void *data) +{ + struct callback_arg *arg = data; + + switch (quote) + { + case '"': + po_xerror (PO_SEVERITY_ERROR, arg->mp, NULL, 0, 0, false, + _("ASCII double quote used instead of Unicode")); + arg->seen_errors++; + break; + + case '\'': + po_xerror (PO_SEVERITY_ERROR, arg->mp, NULL, 0, 0, false, + _("ASCII single quote used instead of Unicode")); + arg->seen_errors++; + break; + + default: + break; + } +} + +static int +syntax_check_quote_unicode (const message_ty *mp, const char *msgid) +{ + struct callback_arg arg; + + arg.mp = mp; + arg.seen_errors = 0; + + scan_quoted (msgid, strlen (msgid), + syntax_check_quote_unicode_callback, &arg); + + return arg.seen_errors; +} + + +typedef int (* syntax_check_function) (const message_ty *mp, const char *msgid); +static const syntax_check_function sc_funcs[NSYNTAXCHECKS] = +{ + syntax_check_ellipsis_unicode, + syntax_check_space_ellipsis, + syntax_check_quote_unicode +}; + +/* Perform all syntax checks on a non-obsolete message. + Return the number of errors that were seen. */ +static int +syntax_check_message (const message_ty *mp) +{ + int seen_errors = 0; + int i; + + for (i = 0; i < NSYNTAXCHECKS; i++) + { + if (mp->do_syntax_check[i] == yes) + { + seen_errors += sc_funcs[i] (mp, mp->msgid); + if (mp->msgid_plural) + seen_errors += sc_funcs[i] (mp, mp->msgid_plural); + } + } + + return seen_errors; +} + + +/* Perform all syntax checks on a message list. + Return the number of errors that were seen. */ +int +syntax_check_message_list (message_list_ty *mlp) +{ + int seen_errors = 0; + size_t j; + + for (j = 0; j < mlp->nitems; j++) + { + message_ty *mp = mlp->item[j]; + + if (!is_header (mp)) + seen_errors += syntax_check_message (mp); + } + + return seen_errors; +} diff --git a/gettext-tools/src/msgl-check.h b/gettext-tools/src/msgl-check.h index f03300c..cfb86fb 100644 --- a/gettext-tools/src/msgl-check.h +++ b/gettext-tools/src/msgl-check.h @@ -1,5 +1,5 @@ /* Checking of messages in PO files. - Copyright (C) 2005, 2008, 2010 Free Software Foundation, Inc. + Copyright (C) 2005, 2008, 2010, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2005. This program is free software: you can redistribute it and/or modify @@ -60,6 +60,9 @@ extern int check_message_list (message_list_ty *mlp, int check_compatibility, int check_accelerators, char accelerator_char); +/* Perform all syntax checks on a message list. + Return the number of errors that were seen. */ +extern int syntax_check_message_list (message_list_ty *mlp); #ifdef __cplusplus } diff --git a/gettext-tools/src/msgl-english.c b/gettext-tools/src/msgl-english.c index 69d95a9..6304504 100644 --- a/gettext-tools/src/msgl-english.c +++ b/gettext-tools/src/msgl-english.c @@ -1,5 +1,5 @@ /* Message translation initialization for English. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-english.h b/gettext-tools/src/msgl-english.h index ec77d2a..ce0af6b 100644 --- a/gettext-tools/src/msgl-english.h +++ b/gettext-tools/src/msgl-english.h @@ -1,5 +1,5 @@ /* Message translation initialization for English. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-equal.c b/gettext-tools/src/msgl-equal.c index 3c9efad..fd28d01 100644 --- a/gettext-tools/src/msgl-equal.c +++ b/gettext-tools/src/msgl-equal.c @@ -1,5 +1,6 @@ /* Message list test for equality. - Copyright (C) 2001-2002, 2005-2006, 2008 Free Software Foundation, Inc. + Copyright (C) 2001-2002, 2005-2006, 2008, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-equal.h b/gettext-tools/src/msgl-equal.h index 6497a7f..07f052e 100644 --- a/gettext-tools/src/msgl-equal.h +++ b/gettext-tools/src/msgl-equal.h @@ -1,5 +1,5 @@ /* Message list test for equality. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-fsearch.c b/gettext-tools/src/msgl-fsearch.c index d2aa865..5e087e2 100644 --- a/gettext-tools/src/msgl-fsearch.c +++ b/gettext-tools/src/msgl-fsearch.c @@ -1,5 +1,5 @@ /* Fast fuzzy searching among messages. - Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc. + Copyright (C) 2006, 2008, 2011, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-fsearch.h b/gettext-tools/src/msgl-fsearch.h index c523d93..825e2a8 100644 --- a/gettext-tools/src/msgl-fsearch.h +++ b/gettext-tools/src/msgl-fsearch.h @@ -1,5 +1,5 @@ /* Fast fuzzy searching among messages. - Copyright (C) 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 2006, 2008, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-header.c b/gettext-tools/src/msgl-header.c index d1dafdb..d5f6a88 100644 --- a/gettext-tools/src/msgl-header.c +++ b/gettext-tools/src/msgl-header.c @@ -1,5 +1,5 @@ /* Message list header manipulation. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2007. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-header.h b/gettext-tools/src/msgl-header.h index f26b1a8..6dc1779 100644 --- a/gettext-tools/src/msgl-header.h +++ b/gettext-tools/src/msgl-header.h @@ -1,5 +1,5 @@ /* Message list header manipulation. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2007. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-iconv.c b/gettext-tools/src/msgl-iconv.c index 958455b..06a961f 100644 --- a/gettext-tools/src/msgl-iconv.c +++ b/gettext-tools/src/msgl-iconv.c @@ -1,5 +1,6 @@ /* Message list charset and locale charset handling. - Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgl-iconv.h b/gettext-tools/src/msgl-iconv.h index 5a7fc00..ab61a5b 100644 --- a/gettext-tools/src/msgl-iconv.h +++ b/gettext-tools/src/msgl-iconv.h @@ -1,5 +1,6 @@ /* Message list character set conversion. - Copyright (C) 2001-2003, 2005-2006, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2006, 2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgmerge.c b/gettext-tools/src/msgmerge.c index d8e02ae..50faf2d 100644 --- a/gettext-tools/src/msgmerge.c +++ b/gettext-tools/src/msgmerge.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2010, 2012, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> This program is free software: you can redistribute it and/or modify @@ -1025,8 +1026,9 @@ message_merge (message_ty *def, message_ty *ref, bool force_fuzzy, char *extended = (char *) obstack_alloc (&pool, header_fields[UNKNOWN].len + len + 1); - memcpy (extended, header_fields[UNKNOWN].string, - header_fields[UNKNOWN].len); + if (header_fields[UNKNOWN].string) + memcpy (extended, header_fields[UNKNOWN].string, + header_fields[UNKNOWN].len); memcpy (&extended[header_fields[UNKNOWN].len], cp, len); extended[header_fields[UNKNOWN].len + len] = '\0'; header_fields[UNKNOWN].string = extended; @@ -1329,6 +1331,9 @@ message_merge (message_ty *def, message_ty *ref, bool force_fuzzy, result->do_wrap = ref->do_wrap; + for (i = 0; i < NSYNTAXCHECKS; i++) + result->do_syntax_check[i] = ref->do_syntax_check[i]; + /* Insert previous msgid, commented out with "#|". Do so only when --previous is specified, for backward compatibility. Since the "previous msgid" represents the original msgid that led to diff --git a/gettext-tools/src/msgunfmt.c b/gettext-tools/src/msgunfmt.c index 1e6dbd2..c5163be 100644 --- a/gettext-tools/src/msgunfmt.c +++ b/gettext-tools/src/msgunfmt.c @@ -1,5 +1,6 @@ /* msgunfmt - converts binary .mo files to Uniforum style .po files - Copyright (C) 1995-1998, 2000-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2007, 2009-2010, 2012, 2015 Free + Software Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgunfmt.cs b/gettext-tools/src/msgunfmt.cs index 28a66b8..e0e8874 100644 --- a/gettext-tools/src/msgunfmt.cs +++ b/gettext-tools/src/msgunfmt.cs @@ -1,5 +1,5 @@ /* GNU gettext for C# - * Copyright (C) 2003-2004, 2007 Free Software Foundation, Inc. + * Copyright (C) 2003-2004, 2007, 2015 Free Software Foundation, Inc. * Written by Bruno Haible <bruno@clisp.org>, 2003. * * This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgunfmt.h b/gettext-tools/src/msgunfmt.h index d1d79ec..fc0a505 100644 --- a/gettext-tools/src/msgunfmt.h +++ b/gettext-tools/src/msgunfmt.h @@ -1,5 +1,6 @@ /* msgunfmt specifics - Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2001, 2015 Free Software Foundation, + Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/msgunfmt.tcl b/gettext-tools/src/msgunfmt.tcl index 11c1d6f..2eadbc5 100644 --- a/gettext-tools/src/msgunfmt.tcl +++ b/gettext-tools/src/msgunfmt.tcl @@ -1,5 +1,5 @@ # Reading tcl/msgcat .msg files. -# Copyright (C) 2002 Free Software Foundation, Inc. +# Copyright (C) 2002, 2015 Free Software Foundation, Inc. # # 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 diff --git a/gettext-tools/src/msguniq.c b/gettext-tools/src/msguniq.c index 24f4c31..0a81d1e 100644 --- a/gettext-tools/src/msguniq.c +++ b/gettext-tools/src/msguniq.c @@ -1,5 +1,6 @@ /* Remove, select or merge duplicate translations. - Copyright (C) 2001-2007, 2009-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2009-2010, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/open-catalog.c b/gettext-tools/src/open-catalog.c index 27eed90..ed87010 100644 --- a/gettext-tools/src/open-catalog.c +++ b/gettext-tools/src/open-catalog.c @@ -1,5 +1,6 @@ /* open-po - search for .po file along search path list and open for reading - Copyright (C) 1995-1996, 2000-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 2000-2003, 2005-2009, 2015 Free Software + Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/open-catalog.h b/gettext-tools/src/open-catalog.h index 503371d..282c200 100644 --- a/gettext-tools/src/open-catalog.h +++ b/gettext-tools/src/open-catalog.h @@ -1,5 +1,6 @@ /* Opening PO files. - Copyright (C) 1995-1997, 2000-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 1995-1997, 2000-2003, 2006, 2015 Free Software + Foundation, Inc. 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 diff --git a/gettext-tools/src/plural-count.c b/gettext-tools/src/plural-count.c index 3fd8838..802ba5e 100644 --- a/gettext-tools/src/plural-count.c +++ b/gettext-tools/src/plural-count.c @@ -1,5 +1,5 @@ /* Plural form count. - Copyright (C) 2003, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2007, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-count.h b/gettext-tools/src/plural-count.h index 14eccf9..9b86a17 100644 --- a/gettext-tools/src/plural-count.h +++ b/gettext-tools/src/plural-count.h @@ -1,5 +1,5 @@ /* Plural form count. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-distrib.h b/gettext-tools/src/plural-distrib.h index 4376f9f..d7d2493 100644 --- a/gettext-tools/src/plural-distrib.h +++ b/gettext-tools/src/plural-distrib.h @@ -1,5 +1,5 @@ /* Value distribution of plural form expressions. - Copyright (C) 2001-2008 Free Software Foundation, Inc. + Copyright (C) 2001-2008, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2001-2005. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-eval.c b/gettext-tools/src/plural-eval.c index 6c63d4e..b2ab856 100644 --- a/gettext-tools/src/plural-eval.c +++ b/gettext-tools/src/plural-eval.c @@ -1,5 +1,5 @@ /* Expression evaluation for plural form selection. - Copyright (C) 2000-2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2000-2003, 2005, 2015 Free Software Foundation, Inc. Written by Ulrich Drepper <drepper@cygnus.com>, 2000. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-eval.h b/gettext-tools/src/plural-eval.h index b64c079..e480a9b 100644 --- a/gettext-tools/src/plural-eval.h +++ b/gettext-tools/src/plural-eval.h @@ -1,5 +1,5 @@ /* Expression evaluation for plural form selection. - Copyright (C) 2005-2006 Free Software Foundation, Inc. + Copyright (C) 2005-2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2005. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-exp.c b/gettext-tools/src/plural-exp.c index d3f4b5f..eb57ce1 100644 --- a/gettext-tools/src/plural-exp.c +++ b/gettext-tools/src/plural-exp.c @@ -1,5 +1,5 @@ /* Expression parsing for plural form selection. - Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc. + Copyright (C) 2000-2001, 2003, 2015 Free Software Foundation, Inc. Written by Ulrich Drepper <drepper@cygnus.com>, 2000. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-table.c b/gettext-tools/src/plural-table.c index 556cbcc..25c0bd6 100644 --- a/gettext-tools/src/plural-table.c +++ b/gettext-tools/src/plural-table.c @@ -1,5 +1,6 @@ /* Table of known plural form expressions. - Copyright (C) 2001-2006, 2009-2010 Free Software Foundation, Inc. + Copyright (C) 2001-2006, 2009-2010, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/plural-table.h b/gettext-tools/src/plural-table.h index 6af9bf6..7c82480 100644 --- a/gettext-tools/src/plural-table.h +++ b/gettext-tools/src/plural-table.h @@ -1,5 +1,5 @@ /* Table of known plural form expressions. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-charset.c b/gettext-tools/src/po-charset.c index 4c0dcdb..2f8bae4 100644 --- a/gettext-tools/src/po-charset.c +++ b/gettext-tools/src/po-charset.c @@ -1,5 +1,5 @@ /* Charset handling while reading PO files. - Copyright (C) 2001-2007, 2010 Free Software Foundation, Inc. + Copyright (C) 2001-2007, 2010, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-charset.h b/gettext-tools/src/po-charset.h index 65798e7..60484e0 100644 --- a/gettext-tools/src/po-charset.h +++ b/gettext-tools/src/po-charset.h @@ -1,5 +1,5 @@ /* Charset handling while reading PO files. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-error.c b/gettext-tools/src/po-error.c index 067264a..565b9ed 100644 --- a/gettext-tools/src/po-error.c +++ b/gettext-tools/src/po-error.c @@ -1,5 +1,5 @@ /* Error handling during reading and writing of PO files. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2004. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-error.h b/gettext-tools/src/po-error.h index 036a69b..b4eb500 100644 --- a/gettext-tools/src/po-error.h +++ b/gettext-tools/src/po-error.h @@ -1,5 +1,5 @@ /* Error handling during reading and writing of PO files. - Copyright (C) 2004, 2006, 2012 Free Software Foundation, Inc. + Copyright (C) 2004, 2006, 2012, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2004. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-gram-gen.c b/gettext-tools/src/po-gram-gen.c index 655684e..b3977f5 100644 --- a/gettext-tools/src/po-gram-gen.c +++ b/gettext-tools/src/po-gram-gen.c @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.0.2" +#define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -62,7 +62,7 @@ /* Copy the first part of user declarations. */ -#line 19 "po-gram-gen.y" /* yacc.c:339 */ +#line 20 "po-gram-gen.y" /* yacc.c:339 */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -238,10 +238,10 @@ extern int yydebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 143 "po-gram-gen.y" /* yacc.c:355 */ +#line 144 "po-gram-gen.y" /* yacc.c:355 */ struct { char *string; lex_pos_ty pos; bool obsolete; } string; struct { string_list_ty stringlist; lex_pos_ty pos; bool obsolete; } stringlist; @@ -253,6 +253,8 @@ union YYSTYPE #line 255 "po-gram-gen.c" /* yacc.c:355 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif @@ -266,7 +268,7 @@ int yyparse (void); /* Copy the second part of user declarations. */ -#line 270 "po-gram-gen.c" /* yacc.c:358 */ +#line 272 "po-gram-gen.c" /* yacc.c:358 */ #ifdef short # undef short @@ -565,10 +567,10 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 168, 168, 170, 171, 172, 173, 178, 186, 194, - 215, 239, 248, 257, 268, 277, 291, 300, 314, 320, - 331, 337, 349, 360, 371, 375, 390, 413, 421, 433, - 441 + 0, 169, 169, 171, 172, 173, 174, 179, 187, 195, + 216, 240, 249, 258, 269, 278, 292, 301, 315, 321, + 332, 338, 350, 361, 372, 376, 391, 414, 422, 434, + 442 }; #endif @@ -1368,23 +1370,23 @@ yyreduce: switch (yyn) { case 7: -#line 179 "po-gram-gen.y" /* yacc.c:1646 */ +#line 180 "po-gram-gen.y" /* yacc.c:1646 */ { po_callback_comment_dispatcher ((yyvsp[0].string).string); } -#line 1376 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1378 "po-gram-gen.c" /* yacc.c:1646 */ break; case 8: -#line 187 "po-gram-gen.y" /* yacc.c:1646 */ +#line 188 "po-gram-gen.y" /* yacc.c:1646 */ { po_callback_domain ((yyvsp[0].string).string); } -#line 1384 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1386 "po-gram-gen.c" /* yacc.c:1646 */ break; case 9: -#line 195 "po-gram-gen.y" /* yacc.c:1646 */ +#line 196 "po-gram-gen.y" /* yacc.c:1646 */ { char *string2 = string_list_concat_destroy (&(yyvsp[-2].stringlist).stringlist); char *string4 = string_list_concat_destroy (&(yyvsp[0].stringlist).stringlist); @@ -1405,11 +1407,11 @@ yyreduce: free (string4); } } -#line 1409 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1411 "po-gram-gen.c" /* yacc.c:1646 */ break; case 10: -#line 216 "po-gram-gen.y" /* yacc.c:1646 */ +#line 217 "po-gram-gen.y" /* yacc.c:1646 */ { char *string2 = string_list_concat_destroy (&(yyvsp[-2].stringlist).stringlist); @@ -1433,11 +1435,11 @@ yyreduce: free ((yyvsp[0].rhs).rhs.msgstr); } } -#line 1437 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1439 "po-gram-gen.c" /* yacc.c:1646 */ break; case 11: -#line 240 "po-gram-gen.y" /* yacc.c:1646 */ +#line 241 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-2].message_intro), (yyvsp[-1].stringlist)); check_obsolete ((yyvsp[-2].message_intro), (yyvsp[0].string)); @@ -1446,11 +1448,11 @@ yyreduce: string_list_destroy (&(yyvsp[-1].stringlist).stringlist); free ((yyvsp[0].string).string); } -#line 1450 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1452 "po-gram-gen.c" /* yacc.c:1646 */ break; case 12: -#line 249 "po-gram-gen.y" /* yacc.c:1646 */ +#line 250 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-2].message_intro), (yyvsp[-1].stringlist)); check_obsolete ((yyvsp[-2].message_intro), (yyvsp[0].rhs)); @@ -1459,22 +1461,22 @@ yyreduce: string_list_destroy (&(yyvsp[-1].stringlist).stringlist); free ((yyvsp[0].rhs).rhs.msgstr); } -#line 1463 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1465 "po-gram-gen.c" /* yacc.c:1646 */ break; case 13: -#line 258 "po-gram-gen.y" /* yacc.c:1646 */ +#line 259 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].message_intro), (yyvsp[0].stringlist)); po_gram_error_at_line (&(yyvsp[-1].message_intro).pos, _("missing 'msgstr' section")); free_message_intro ((yyvsp[-1].message_intro)); string_list_destroy (&(yyvsp[0].stringlist).stringlist); } -#line 1474 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1476 "po-gram-gen.c" /* yacc.c:1646 */ break; case 14: -#line 269 "po-gram-gen.y" /* yacc.c:1646 */ +#line 270 "po-gram-gen.y" /* yacc.c:1646 */ { (yyval.message_intro).prev_ctxt = NULL; (yyval.message_intro).prev_id = NULL; @@ -1483,11 +1485,11 @@ yyreduce: (yyval.message_intro).pos = (yyvsp[0].string).pos; (yyval.message_intro).obsolete = (yyvsp[0].string).obsolete; } -#line 1487 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1489 "po-gram-gen.c" /* yacc.c:1646 */ break; case 15: -#line 278 "po-gram-gen.y" /* yacc.c:1646 */ +#line 279 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].prev), (yyvsp[0].string)); (yyval.message_intro).prev_ctxt = (yyvsp[-1].prev).ctxt; @@ -1497,11 +1499,11 @@ yyreduce: (yyval.message_intro).pos = (yyvsp[0].string).pos; (yyval.message_intro).obsolete = (yyvsp[0].string).obsolete; } -#line 1501 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1503 "po-gram-gen.c" /* yacc.c:1646 */ break; case 16: -#line 292 "po-gram-gen.y" /* yacc.c:1646 */ +#line 293 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].string), (yyvsp[0].stringlist)); (yyval.prev).ctxt = (yyvsp[-1].string).string; @@ -1510,11 +1512,11 @@ yyreduce: (yyval.prev).pos = (yyvsp[-1].string).pos; (yyval.prev).obsolete = (yyvsp[-1].string).obsolete; } -#line 1514 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1516 "po-gram-gen.c" /* yacc.c:1646 */ break; case 17: -#line 301 "po-gram-gen.y" /* yacc.c:1646 */ +#line 302 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-2].string), (yyvsp[-1].stringlist)); check_obsolete ((yyvsp[-2].string), (yyvsp[0].string)); @@ -1524,21 +1526,21 @@ yyreduce: (yyval.prev).pos = (yyvsp[-2].string).pos; (yyval.prev).obsolete = (yyvsp[-2].string).obsolete; } -#line 1528 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1530 "po-gram-gen.c" /* yacc.c:1646 */ break; case 18: -#line 315 "po-gram-gen.y" /* yacc.c:1646 */ +#line 316 "po-gram-gen.y" /* yacc.c:1646 */ { (yyval.string).string = NULL; (yyval.string).pos = (yyvsp[0].pos).pos; (yyval.string).obsolete = (yyvsp[0].pos).obsolete; } -#line 1538 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1540 "po-gram-gen.c" /* yacc.c:1646 */ break; case 19: -#line 321 "po-gram-gen.y" /* yacc.c:1646 */ +#line 322 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-2].pos), (yyvsp[-1].stringlist)); check_obsolete ((yyvsp[-2].pos), (yyvsp[0].pos)); @@ -1546,21 +1548,21 @@ yyreduce: (yyval.string).pos = (yyvsp[0].pos).pos; (yyval.string).obsolete = (yyvsp[0].pos).obsolete; } -#line 1550 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1552 "po-gram-gen.c" /* yacc.c:1646 */ break; case 20: -#line 332 "po-gram-gen.y" /* yacc.c:1646 */ +#line 333 "po-gram-gen.y" /* yacc.c:1646 */ { (yyval.string).string = NULL; (yyval.string).pos = (yyvsp[0].pos).pos; (yyval.string).obsolete = (yyvsp[0].pos).obsolete; } -#line 1560 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1562 "po-gram-gen.c" /* yacc.c:1646 */ break; case 21: -#line 338 "po-gram-gen.y" /* yacc.c:1646 */ +#line 339 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-2].pos), (yyvsp[-1].stringlist)); check_obsolete ((yyvsp[-2].pos), (yyvsp[0].pos)); @@ -1568,11 +1570,11 @@ yyreduce: (yyval.string).pos = (yyvsp[0].pos).pos; (yyval.string).obsolete = (yyvsp[0].pos).obsolete; } -#line 1572 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1574 "po-gram-gen.c" /* yacc.c:1646 */ break; case 22: -#line 350 "po-gram-gen.y" /* yacc.c:1646 */ +#line 351 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].pos), (yyvsp[0].stringlist)); plural_counter = 0; @@ -1580,30 +1582,30 @@ yyreduce: (yyval.string).pos = (yyvsp[-1].pos).pos; (yyval.string).obsolete = (yyvsp[-1].pos).obsolete; } -#line 1584 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1586 "po-gram-gen.c" /* yacc.c:1646 */ break; case 23: -#line 361 "po-gram-gen.y" /* yacc.c:1646 */ +#line 362 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].pos), (yyvsp[0].stringlist)); (yyval.string).string = string_list_concat_destroy (&(yyvsp[0].stringlist).stringlist); (yyval.string).pos = (yyvsp[-1].pos).pos; (yyval.string).obsolete = (yyvsp[-1].pos).obsolete; } -#line 1595 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1597 "po-gram-gen.c" /* yacc.c:1646 */ break; case 24: -#line 372 "po-gram-gen.y" /* yacc.c:1646 */ +#line 373 "po-gram-gen.y" /* yacc.c:1646 */ { (yyval.rhs) = (yyvsp[0].rhs); } -#line 1603 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1605 "po-gram-gen.c" /* yacc.c:1646 */ break; case 25: -#line 376 "po-gram-gen.y" /* yacc.c:1646 */ +#line 377 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].rhs), (yyvsp[0].rhs)); (yyval.rhs).rhs.msgstr = XNMALLOC ((yyvsp[-1].rhs).rhs.msgstr_len + (yyvsp[0].rhs).rhs.msgstr_len, char); @@ -1615,11 +1617,11 @@ yyreduce: (yyval.rhs).pos = (yyvsp[-1].rhs).pos; (yyval.rhs).obsolete = (yyvsp[-1].rhs).obsolete; } -#line 1619 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1621 "po-gram-gen.c" /* yacc.c:1646 */ break; case 26: -#line 391 "po-gram-gen.y" /* yacc.c:1646 */ +#line 392 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-4].pos), (yyvsp[-3].pos)); check_obsolete ((yyvsp[-4].pos), (yyvsp[-2].number)); @@ -1638,11 +1640,11 @@ yyreduce: (yyval.rhs).pos = (yyvsp[-4].pos).pos; (yyval.rhs).obsolete = (yyvsp[-4].pos).obsolete; } -#line 1642 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1644 "po-gram-gen.c" /* yacc.c:1646 */ break; case 27: -#line 414 "po-gram-gen.y" /* yacc.c:1646 */ +#line 415 "po-gram-gen.y" /* yacc.c:1646 */ { string_list_init (&(yyval.stringlist).stringlist); string_list_append (&(yyval.stringlist).stringlist, (yyvsp[0].string).string); @@ -1650,11 +1652,11 @@ yyreduce: (yyval.stringlist).pos = (yyvsp[0].string).pos; (yyval.stringlist).obsolete = (yyvsp[0].string).obsolete; } -#line 1654 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1656 "po-gram-gen.c" /* yacc.c:1646 */ break; case 28: -#line 422 "po-gram-gen.y" /* yacc.c:1646 */ +#line 423 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].stringlist), (yyvsp[0].string)); (yyval.stringlist).stringlist = (yyvsp[-1].stringlist).stringlist; @@ -1663,11 +1665,11 @@ yyreduce: (yyval.stringlist).pos = (yyvsp[-1].stringlist).pos; (yyval.stringlist).obsolete = (yyvsp[-1].stringlist).obsolete; } -#line 1667 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1669 "po-gram-gen.c" /* yacc.c:1646 */ break; case 29: -#line 434 "po-gram-gen.y" /* yacc.c:1646 */ +#line 435 "po-gram-gen.y" /* yacc.c:1646 */ { string_list_init (&(yyval.stringlist).stringlist); string_list_append (&(yyval.stringlist).stringlist, (yyvsp[0].string).string); @@ -1675,11 +1677,11 @@ yyreduce: (yyval.stringlist).pos = (yyvsp[0].string).pos; (yyval.stringlist).obsolete = (yyvsp[0].string).obsolete; } -#line 1679 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1681 "po-gram-gen.c" /* yacc.c:1646 */ break; case 30: -#line 442 "po-gram-gen.y" /* yacc.c:1646 */ +#line 443 "po-gram-gen.y" /* yacc.c:1646 */ { check_obsolete ((yyvsp[-1].stringlist), (yyvsp[0].string)); (yyval.stringlist).stringlist = (yyvsp[-1].stringlist).stringlist; @@ -1688,11 +1690,11 @@ yyreduce: (yyval.stringlist).pos = (yyvsp[-1].stringlist).pos; (yyval.stringlist).obsolete = (yyvsp[-1].stringlist).obsolete; } -#line 1692 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1694 "po-gram-gen.c" /* yacc.c:1646 */ break; -#line 1696 "po-gram-gen.c" /* yacc.c:1646 */ +#line 1698 "po-gram-gen.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires diff --git a/gettext-tools/src/po-gram-gen.h b/gettext-tools/src/po-gram-gen.h index 3f20e75..97089df 100644 --- a/gettext-tools/src/po-gram-gen.h +++ b/gettext-tools/src/po-gram-gen.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -79,10 +79,10 @@ extern int yydebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 143 "po-gram-gen.y" /* yacc.c:1909 */ +#line 144 "po-gram-gen.y" /* yacc.c:1909 */ struct { char *string; lex_pos_ty pos; bool obsolete; } string; struct { string_list_ty stringlist; lex_pos_ty pos; bool obsolete; } stringlist; @@ -94,6 +94,8 @@ union YYSTYPE #line 96 "po-gram-gen.h" /* yacc.c:1909 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif diff --git a/gettext-tools/src/po-gram-gen.y b/gettext-tools/src/po-gram-gen.y index 8f888bd..0a34068 100644 --- a/gettext-tools/src/po-gram-gen.y +++ b/gettext-tools/src/po-gram-gen.y @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005-2006, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005-2006, 2012, 2015 + Free Software Foundation, Inc. This file was written by Peter Miller <pmiller@agso.gov.au> diff --git a/gettext-tools/src/po-gram-gen2.h b/gettext-tools/src/po-gram-gen2.h index 36e9f4b..683ccbf 100644 --- a/gettext-tools/src/po-gram-gen2.h +++ b/gettext-tools/src/po-gram-gen2.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -79,10 +79,10 @@ extern DLL_VARIABLE int po_gram_debug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 143 "po-gram-gen.y" /* yacc.c:1909 */ +#line 144 "po-gram-gen.y" /* yacc.c:1909 */ struct { char *string; lex_pos_ty pos; bool obsolete; } string; struct { string_list_ty stringlist; lex_pos_ty pos; bool obsolete; } stringlist; @@ -94,6 +94,8 @@ union YYSTYPE #line 96 "po-gram-gen.h" /* yacc.c:1909 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif diff --git a/gettext-tools/src/po-gram.h b/gettext-tools/src/po-gram.h index 0e2d079..4c8787e 100644 --- a/gettext-tools/src/po-gram.h +++ b/gettext-tools/src/po-gram.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995, 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 1995, 2002-2003, 2006, 2015 Free Software Foundation, + Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/po-lex.c b/gettext-tools/src/po-lex.c index 3bf5449..a48f59a 100644 --- a/gettext-tools/src/po-lex.c +++ b/gettext-tools/src/po-lex.c @@ -1,5 +1,5 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1999, 2000-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 1995-2009, 2011, 2015 Free Software Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au>. Multibyte character handling by Bruno Haible <haible@clisp.cons.org>. diff --git a/gettext-tools/src/po-lex.h b/gettext-tools/src/po-lex.h index da05f38..257e61a 100644 --- a/gettext-tools/src/po-lex.h +++ b/gettext-tools/src/po-lex.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2006, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2006, 2012, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/po-time.c b/gettext-tools/src/po-time.c index dd357f1..5147389 100644 --- a/gettext-tools/src/po-time.c +++ b/gettext-tools/src/po-time.c @@ -1,5 +1,6 @@ /* PO/POT file timestamps. - Copyright (C) 1995-1998, 2000-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2006, 2015 Free Software + Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-time.h b/gettext-tools/src/po-time.h index 846dea0..4c63006 100644 --- a/gettext-tools/src/po-time.h +++ b/gettext-tools/src/po-time.h @@ -1,5 +1,5 @@ /* PO/POT file timestamps. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-xerror.c b/gettext-tools/src/po-xerror.c index 8a889d8..f58d2bd 100644 --- a/gettext-tools/src/po-xerror.c +++ b/gettext-tools/src/po-xerror.c @@ -1,5 +1,5 @@ /* Error handling during reading and writing of PO files. - Copyright (C) 2005-2007 Free Software Foundation, Inc. + Copyright (C) 2005-2007, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2005. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/po-xerror.h b/gettext-tools/src/po-xerror.h index 521ec3f..0493de9 100644 --- a/gettext-tools/src/po-xerror.h +++ b/gettext-tools/src/po-xerror.h @@ -1,5 +1,5 @@ /* Error handling during reading and writing of PO files. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2005. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/pos.h b/gettext-tools/src/pos.h index 684986e..9c57290 100644 --- a/gettext-tools/src/pos.h +++ b/gettext-tools/src/pos.h @@ -1,5 +1,6 @@ /* Source file positions. - Copyright (C) 1995-1998, 2000-2001 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2001, 2015 Free Software Foundation, + Inc. 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 diff --git a/gettext-tools/src/project-id b/gettext-tools/src/project-id index e60c8e3..103f91f 100755 --- a/gettext-tools/src/project-id +++ b/gettext-tools/src/project-id @@ -1,7 +1,7 @@ #!/bin/sh # Prints a package's identification PACKAGE VERSION or PACKAGE. # -# Copyright (C) 2001-2003, 2005 Free Software Foundation, Inc. +# Copyright (C) 2001-2003, 2005, 2015 Free Software Foundation, Inc. # # 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 diff --git a/gettext-tools/src/quote.h b/gettext-tools/src/quote.h new file mode 100644 index 0000000..df8cde2 --- /dev/null +++ b/gettext-tools/src/quote.h @@ -0,0 +1,142 @@ +/* Handle quoted segments of a string. + Copyright (C) 2014-2015 Free Software Foundation, Inc. + Written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _QUOTE_H +#define _QUOTE_H + +#include <stdbool.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +static void +scan_quoted (const char *input, size_t length, + void (* callback) (char quote, const char *quoted, + size_t quoted_length, + void *data), + void *data) +{ + const char *p, *start, *end; + bool seen_opening; + + /* START shall point to the beginning of a quoted segment, END + points to the end of the entire input string. */ + start = input; + end = &input[length - 1]; + + /* True if we have seen a character which could be an opening + quotation mark. Note that we can't determine if it is really an + opening quotation mark until we see a closing quotation mark. */ + seen_opening = false; + + for (p = start; p <= end; p++) + { + switch (*p) + { + case '"': + if (seen_opening) + { + if (*start == '"') + { + if (p == start + 1) + /* Consider "" as "". */ + callback ('\0', "\"\"", 2, data); + else + /* "..." */ + callback ('"', start + 1, p - (start + 1), data); + + start = p + 1; + seen_opening = false; + } + } + else + { + callback ('\0', start, p - start, data); + start = p; + seen_opening = true; + } + break; + + case '`': + if (seen_opening) + { + if (*start == '`') + { + callback ('\0', start, p - start, data); + start = p; + } + } + else + { + callback ('\0', start, p - start, data); + start = p; + seen_opening = true; + } + break; + + case '\'': + if (seen_opening) + { + if (/* `...' */ + *start == '`' + /* '...', where + - The left quote is preceded by a space, and the + right quote is followed by a space. + - The left quote is preceded by a space, and the + right quote is at the end of line. + - The left quote is at the beginning of the line, and + the right quote is followed by a space. */ + || (*start == '\'' + && (((start > input && *(start - 1) == ' ') + && (p == end || *(p + 1) == '\n' || *(p + 1) == ' ')) + || ((start == input || *(start - 1) == '\n') + && p < end && *(p + 1) == ' ')))) + { + callback ('\'', start + 1, p - (start + 1), data); + start = p + 1; + } + else + { + callback ('\0', start, p - start, data); + start = p; + } + seen_opening = false; + } + else if (p == input || *(p - 1) == '\n' || *(p - 1) == ' ') + { + callback ('\0', start, p - start, data); + start = p; + seen_opening = true; + } + break; + } + } + + /* Copy the rest. */ + if (p > start) + callback ('\0', start, p - start, data); +} + + +#ifdef __cplusplus +} +#endif + + +#endif /* _QUOTE_H */ diff --git a/gettext-tools/src/read-catalog-abstract.c b/gettext-tools/src/read-catalog-abstract.c index d4e98ee..eaa624b 100644 --- a/gettext-tools/src/read-catalog-abstract.c +++ b/gettext-tools/src/read-catalog-abstract.c @@ -1,5 +1,6 @@ /* Reading PO files, abstract class. - Copyright (C) 1995-1996, 1998, 2000-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2009, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> @@ -262,7 +263,8 @@ po_callback_comment_special (const char *s) void po_parse_comment_special (const char *s, bool *fuzzyp, enum is_format formatp[NFORMATS], - struct argument_range *rangep, enum is_wrap *wrapp) + struct argument_range *rangep, enum is_wrap *wrapp, + enum is_syntax_check scp[NSYNTAXCHECKS]) { size_t i; @@ -272,6 +274,8 @@ po_parse_comment_special (const char *s, rangep->min = -1; rangep->max = -1; *wrapp = undecided; + for (i = 0; i < NSYNTAXCHECKS; i++) + scp[i] = undecided; while (*s != '\0') { @@ -405,6 +409,36 @@ po_parse_comment_special (const char *s, continue; } + /* Accept syntax check description. */ + if (len >= 6 && memcmp (t + len - 6, "-check", 6) == 0) + { + const char *p; + size_t n; + enum is_syntax_check value; + + p = t; + n = len - 6; + + if (n >= 3 && memcmp (p, "no-", 3) == 0) + { + p += 3; + n -= 3; + value = no; + } + else + value = yes; + + for (i = 0; i < NSYNTAXCHECKS; i++) + if (strlen (syntax_check_name[i]) == n + && memcmp (syntax_check_name[i], p, n) == 0) + { + scp[i] = value; + break; + } + if (i < NSYNTAXCHECKS) + continue; + } + /* Unknown special comment marker. It may have been generated from a future xgettext version. Ignore it. */ } diff --git a/gettext-tools/src/read-catalog-abstract.h b/gettext-tools/src/read-catalog-abstract.h index c3fc84f..7f6dbfa 100644 --- a/gettext-tools/src/read-catalog-abstract.h +++ b/gettext-tools/src/read-catalog-abstract.h @@ -1,5 +1,6 @@ /* Reading PO files, abstract class. - Copyright (C) 1995-1996, 1998, 2000-2003, 2005-2006, 2008-2009, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2003, 2005-2006, 2008-2009, 2012, + 2015 Free Software Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> @@ -184,7 +185,8 @@ extern void po_callback_comment_dispatcher (const char *s); extern void po_parse_comment_special (const char *s, bool *fuzzyp, enum is_format formatp[NFORMATS], struct argument_range *rangep, - enum is_wrap *wrapp); + enum is_wrap *wrapp, + enum is_syntax_check scp[NSYNTAXCHECKS]); #ifdef __cplusplus diff --git a/gettext-tools/src/read-catalog.c b/gettext-tools/src/read-catalog.c index 4642249..8a26581 100644 --- a/gettext-tools/src/read-catalog.c +++ b/gettext-tools/src/read-catalog.c @@ -1,5 +1,6 @@ /* Reading PO files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2015 Free + Software Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> This program is free software: you can redistribute it and/or modify @@ -105,6 +106,8 @@ default_constructor (abstract_catalog_reader_ty *that) this->range.min = -1; this->range.max = -1; this->do_wrap = undecided; + for (i = 0; i < NSYNTAXCHECKS; i++) + this->do_syntax_check[i] = undecided; } @@ -172,6 +175,8 @@ default_copy_comment_state (default_catalog_reader_ty *this, message_ty *mp) mp->is_format[i] = this->is_format[i]; mp->range = this->range; mp->do_wrap = this->do_wrap; + for (i = 0; i < NSYNTAXCHECKS; i++) + mp->do_syntax_check[i] = this->do_syntax_check[i]; } @@ -205,6 +210,8 @@ default_reset_comment_state (default_catalog_reader_ty *this) this->range.min = -1; this->range.max = -1; this->do_wrap = undecided; + for (i = 0; i < NSYNTAXCHECKS; i++) + this->do_syntax_check[i] = undecided; } @@ -299,7 +306,7 @@ default_comment_special (abstract_catalog_reader_ty *that, const char *s) default_catalog_reader_ty *this = (default_catalog_reader_ty *) that; po_parse_comment_special (s, &this->is_fuzzy, this->is_format, &this->range, - &this->do_wrap); + &this->do_wrap, this->do_syntax_check); } diff --git a/gettext-tools/src/read-catalog.h b/gettext-tools/src/read-catalog.h index f567d78..f50bcb0 100644 --- a/gettext-tools/src/read-catalog.h +++ b/gettext-tools/src/read-catalog.h @@ -1,5 +1,6 @@ /* Reading PO files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2015 Free + Software Foundation, Inc. This file was written by Bruno Haible <haible@clisp.cons.org>. This program is free software: you can redistribute it and/or modify @@ -113,6 +114,7 @@ struct default_catalog_reader_class_ty enum is_format is_format[NFORMATS]; \ struct argument_range range; \ enum is_wrap do_wrap; \ + enum is_syntax_check do_syntax_check[NSYNTAXCHECKS]; \ typedef struct default_catalog_reader_ty default_catalog_reader_ty; struct default_catalog_reader_ty diff --git a/gettext-tools/src/read-csharp.c b/gettext-tools/src/read-csharp.c index df5ca83..c2b3879 100644 --- a/gettext-tools/src/read-csharp.c +++ b/gettext-tools/src/read-csharp.c @@ -1,5 +1,6 @@ /* Reading C# satellite assemblies. - Copyright (C) 2003-2004, 2006-2008, 2011 Free Software Foundation, Inc. + Copyright (C) 2003-2004, 2006-2008, 2011, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-csharp.h b/gettext-tools/src/read-csharp.h index f8b66b3..3e03ccf 100644 --- a/gettext-tools/src/read-csharp.h +++ b/gettext-tools/src/read-csharp.h @@ -1,5 +1,5 @@ /* Reading C# satellite assemblies. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-desktop.c b/gettext-tools/src/read-desktop.c index 8f9243b..0de123c 100644 --- a/gettext-tools/src/read-desktop.c +++ b/gettext-tools/src/read-desktop.c @@ -1,5 +1,6 @@ /* Reading Desktop Entry files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2015 + Free Software Foundation, Inc. This file was written by Daiki Ueno <ueno@gnu.org>. This program is free software: you can redistribute it and/or modify @@ -271,16 +272,13 @@ desktop_lex (token_ty *tp) break; } /* Skip until newline. */ - if (c != '\n') + while (c != '\n' && c != EOF) { - for (;;) - { - if (c == '\n' || c == EOF) - break; - if (!c_isspace (c)) - non_blank = true; - c = phase2_getc (); - } + c = phase2_getc (); + if (c == EOF) + break; + if (!c_isspace (c)) + non_blank = true; } if (non_blank) po_xerror (PO_SEVERITY_WARNING, NULL, diff --git a/gettext-tools/src/read-desktop.h b/gettext-tools/src/read-desktop.h index 19ad8d8..eebd681 100644 --- a/gettext-tools/src/read-desktop.h +++ b/gettext-tools/src/read-desktop.h @@ -1,5 +1,6 @@ /* Reading Desktop Entry files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2015 + Free Software Foundation, Inc. This file was written by Daiki Ueno <ueno@gnu.org>. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-java.c b/gettext-tools/src/read-java.c index bc6f2f4..1e1cce0 100644 --- a/gettext-tools/src/read-java.c +++ b/gettext-tools/src/read-java.c @@ -1,5 +1,6 @@ /* Reading Java ResourceBundles. - Copyright (C) 2001-2003, 2006-2008, 2011 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006-2008, 2011, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-java.h b/gettext-tools/src/read-java.h index 6b4d037..169263b 100644 --- a/gettext-tools/src/read-java.h +++ b/gettext-tools/src/read-java.h @@ -1,5 +1,5 @@ /* Reading Java ResourceBundles. - Copyright (C) 2001-2002 Free Software Foundation, Inc. + Copyright (C) 2001-2002, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-mo.c b/gettext-tools/src/read-mo.c index b97bbad..c3bfb22 100644 --- a/gettext-tools/src/read-mo.c +++ b/gettext-tools/src/read-mo.c @@ -1,5 +1,6 @@ /* Reading binary .mo files. - Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2007, 2015 Free Software Foundation, + Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify @@ -149,6 +150,7 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset, nls_uint32 s_offset; /* Compute the length. */ + s_offset = get_uint32 (bfp, offset); length = 0; for (i = 4; ; i += 8) { @@ -158,9 +160,14 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset, nls_uint32 ss_length; nls_uint32 ss_offset; size_t ss_end; + size_t s_end; size_t n; + s_end = xsum (s_offset, segsize); + if (size_overflow_p (s_end) || s_end > bfp->size) + error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename); length += segsize; + s_offset += segsize; if (sysdepref == SEGMENTS_END) break; @@ -175,7 +182,7 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset, ss_end = xsum (ss_offset, ss_length); if (size_overflow_p (ss_end) || ss_end > bfp->size) error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename); - if (!(ss_length > 0 && bfp->data[ss_offset + ss_length - 1] == '\0')) + if (!(ss_length > 0 && bfp->data[ss_end - 1] == '\0')) { char location[30]; sprintf (location, "sysdep_segment[%u]", (unsigned int) sysdepref); @@ -198,11 +205,8 @@ get_sysdep_string (const struct binary_mo_file *bfp, size_t offset, nls_uint32 sysdep_segment_offset; nls_uint32 ss_length; nls_uint32 ss_offset; - size_t s_end = xsum (s_offset, segsize); size_t n; - if (size_overflow_p (s_end) || s_end > bfp->size) - error (EXIT_FAILURE, 0, _("file \"%s\" is truncated"), bfp->filename); memcpy (p, bfp->data + s_offset, segsize); p += segsize; s_offset += segsize; diff --git a/gettext-tools/src/read-mo.h b/gettext-tools/src/read-mo.h index c8e976c..d5f8f58 100644 --- a/gettext-tools/src/read-mo.h +++ b/gettext-tools/src/read-mo.h @@ -1,5 +1,6 @@ /* Reading binary .mo files. - Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2015 Free Software Foundation, + Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-po.c b/gettext-tools/src/read-po.c index 04f1b74..71eebc2 100644 --- a/gettext-tools/src/read-po.c +++ b/gettext-tools/src/read-po.c @@ -1,5 +1,6 @@ /* Reading PO files. - Copyright (C) 1995-1996, 1998, 2000-2006 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2006, 2015 Free Software + Foundation, Inc. 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 diff --git a/gettext-tools/src/read-po.h b/gettext-tools/src/read-po.h index e426eaa..aa9c173 100644 --- a/gettext-tools/src/read-po.h +++ b/gettext-tools/src/read-po.h @@ -1,5 +1,5 @@ /* Reading PO files. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-properties.c b/gettext-tools/src/read-properties.c index 0c64730..a4919a4 100644 --- a/gettext-tools/src/read-properties.c +++ b/gettext-tools/src/read-properties.c @@ -1,5 +1,6 @@ /* Reading Java .properties files. - Copyright (C) 2003, 2005-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2007, 2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-properties.h b/gettext-tools/src/read-properties.h index 8ac7852..bf2279b 100644 --- a/gettext-tools/src/read-properties.h +++ b/gettext-tools/src/read-properties.h @@ -1,5 +1,5 @@ /* Reading Java .properties files. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-resources.c b/gettext-tools/src/read-resources.c index a5eb8eb..d60394e 100644 --- a/gettext-tools/src/read-resources.c +++ b/gettext-tools/src/read-resources.c @@ -1,5 +1,6 @@ /* Reading C# .resources files. - Copyright (C) 2003, 2006-2008, 2011 Free Software Foundation, Inc. + Copyright (C) 2003, 2006-2008, 2011, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-resources.h b/gettext-tools/src/read-resources.h index b3c6076..58dccef 100644 --- a/gettext-tools/src/read-resources.h +++ b/gettext-tools/src/read-resources.h @@ -1,5 +1,5 @@ /* Reading C# .resources files. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-stringtable.c b/gettext-tools/src/read-stringtable.c index 27b8860..62073c4 100644 --- a/gettext-tools/src/read-stringtable.c +++ b/gettext-tools/src/read-stringtable.c @@ -1,5 +1,6 @@ /* Reading NeXTstep/GNUstep .strings files. - Copyright (C) 2003, 2005-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2007, 2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-stringtable.h b/gettext-tools/src/read-stringtable.h index d254434..6c3e069 100644 --- a/gettext-tools/src/read-stringtable.h +++ b/gettext-tools/src/read-stringtable.h @@ -1,5 +1,5 @@ /* Reading NeXTstep/GNUstep .strings files. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-tcl.c b/gettext-tools/src/read-tcl.c index 039dcfb..4191864 100644 --- a/gettext-tools/src/read-tcl.c +++ b/gettext-tools/src/read-tcl.c @@ -1,5 +1,6 @@ /* Reading tcl/msgcat .msg files. - Copyright (C) 2002-2003, 2005-2008, 2011 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2008, 2011, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/read-tcl.h b/gettext-tools/src/read-tcl.h index a2c2d9e..d66624d 100644 --- a/gettext-tools/src/read-tcl.h +++ b/gettext-tools/src/read-tcl.h @@ -1,5 +1,5 @@ /* Reading tcl/msgcat .msg files. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/recode-sr-latin.c b/gettext-tools/src/recode-sr-latin.c index 25b88f6..44a2f49 100644 --- a/gettext-tools/src/recode-sr-latin.c +++ b/gettext-tools/src/recode-sr-latin.c @@ -1,5 +1,6 @@ /* Recode Serbian text from Cyrillic to Latin script. - Copyright (C) 2006-2007, 2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2006-2007, 2010, 2012, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2006. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/sentence.c b/gettext-tools/src/sentence.c new file mode 100644 index 0000000..0a4883e --- /dev/null +++ b/gettext-tools/src/sentence.c @@ -0,0 +1,194 @@ +/* Sentence handling. + Copyright (C) 2015 Free Software Foundation, Inc. + Written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "sentence.h" + +#include <stdlib.h> +#include <string.h> +#include "unistr.h" + + +/* The minimal number of white spaces which should follow after the + end of sentence. */ +int sentence_end_required_spaces = 1; + +/* This function works in a similar way to 'forward-sentence' in + Emacs, which basically does a regular expression matching of: + + [.?!\u2026] + []"'\u201d)}]* + \($\|[ \u00a0]$\|\t\|[ \u00a0]\{REQUIRED_SPACES\}\) + + Since we are lacking a regular expression routine capable of + Unicode (though gnulib-lib/lib/regex.c provides a locale-dependent + version, we would rather avoid depending on it), apply a manually + constructed DFA, which consists of 8 states where 4 of them are a + terminal. */ +const char * +sentence_end (const char *string, ucs4_t *ending_charp) +{ + const char *str = string; + const char *str_limit = string + strlen (str); + /* States of the DFA, 0 to 7, where 3, 5, 6, and 7 are a terminal. */ + int state = 0; + /* Previous character before an end marker. */ + ucs4_t ending_char = 0xfffd; + /* Possible starting position of the match, and the next starting + position if the current match fails. */ + const char *match_start = NULL, *match_next = NULL; + /* Number of spaces. */ + int spaces = 0; + + while (str <= str_limit) + { + ucs4_t uc; + size_t length; + + length = u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str); + + if (state == 0) + { + switch (uc) + { + case '.': case '?': case '!': case 0x2026: + state = 1; + match_start = str; + match_next = str + length; + ending_char = uc; + spaces = 0; + break; + + default: + break; + } + + str += length; + continue; + } + + if (state == 1) + { + switch (uc) + { + case ']': case '"': case '\'': case ')': case '}': case 0x201d: + state = 2; + break; + + case '\0': case '\n': + /* State 3. */ + *ending_charp = ending_char; + return match_start; + + case ' ': case 0x00a0: + if (++spaces == sentence_end_required_spaces) + { + /* State 7. */ + *ending_charp = ending_char; + return match_start; + } + state = 4; + break; + + case '\t': + /* State 5. */ + *ending_charp = ending_char; + return match_start; + + default: + str = match_next; + state = 0; + continue; + } + + str += length; + continue; + } + + if (state == 2) + { + switch (uc) + { + case ']': case '"': case '\'': case ')': case '}': case 0x201d: + break; + + case '\0': case '\n': + /* State 3. */ + *ending_charp = ending_char; + return match_start; + + case ' ': case 0x00a0: + if (++spaces == sentence_end_required_spaces) + { + /* State 7. */ + *ending_charp = ending_char; + return match_start; + } + state = 4; + break; + + case '\t': + /* State 5. */ + *ending_charp = ending_char; + return match_start; + + default: + state = 0; + str = match_next; + continue; + } + + str += length; + continue; + } + + if (state == 4) + { + switch (uc) + { + case '\0': case '\n': + /* State 6. */ + *ending_charp = ending_char; + return match_start; + + case ' ': case 0x00a0: + if (++spaces == sentence_end_required_spaces) + { + /* State 7. */ + *ending_charp = ending_char; + return match_start; + } + break; + + default: + state = 0; + str = match_next; + continue; + } + + str += length; + continue; + } + } + + *ending_charp = 0xfffd; + return str_limit; +} diff --git a/gettext-tools/src/sentence.h b/gettext-tools/src/sentence.h new file mode 100644 index 0000000..02fdc16 --- /dev/null +++ b/gettext-tools/src/sentence.h @@ -0,0 +1,42 @@ +/* Sentence handling. + Copyright (C) 2015 Free Software Foundation, Inc. + Written by Daiki Ueno <ueno@gnu.org>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _SENTENCE_H +#define _SENTENCE_H + +#include "unitypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The minimal number of white spaces which should follow after the + end of sentence. */ +extern DLL_VARIABLE int sentence_end_required_spaces; + +/* Locate the position of a sentence end marker (a period, a question + mark, etc) in a null-terminated string STR. If there is no + sentence end marker found in STR, return a pointer to the null byte + at the end of STR. ENDING_CHARP is a return location of the end + marker character. */ +extern const char *sentence_end (const char *string, ucs4_t *ending_charp); + +#ifdef __cplusplus +} +#endif + +#endif /* _SENTENCE_H */ diff --git a/gettext-tools/src/str-list.c b/gettext-tools/src/str-list.c index 3f929c2..0e3a9ff 100644 --- a/gettext-tools/src/str-list.c +++ b/gettext-tools/src/str-list.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995, 1998, 2000-2004, 2006, 2009 Free Software Foundation, Inc. + Copyright (C) 1995, 1998, 2000-2004, 2006, 2009, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/str-list.h b/gettext-tools/src/str-list.h index 5b7b75d..0758171 100644 --- a/gettext-tools/src/str-list.h +++ b/gettext-tools/src/str-list.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1996, 1998, 2000-2004, 2009 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2004, 2009, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/urlget.c b/gettext-tools/src/urlget.c index f3243e1..482144c 100644 --- a/gettext-tools/src/urlget.c +++ b/gettext-tools/src/urlget.c @@ -1,5 +1,6 @@ /* Get the contents of an URL. - Copyright (C) 2001-2003, 2005-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2010, 2012, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/user-email.sh.in b/gettext-tools/src/user-email.sh.in index 5a35405..d5b5e49 100644 --- a/gettext-tools/src/user-email.sh.in +++ b/gettext-tools/src/user-email.sh.in @@ -1,7 +1,7 @@ #!/bin/sh # Prints the user's email address, with confirmation from the user. # -# Copyright (C) 2001-2003, 2005 Free Software Foundation, Inc. +# Copyright (C) 2001-2003, 2005, 2015 Free Software Foundation, Inc. # # 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 diff --git a/gettext-tools/src/write-catalog.c b/gettext-tools/src/write-catalog.c index bab8c36..4649efa 100644 --- a/gettext-tools/src/write-catalog.c +++ b/gettext-tools/src/write-catalog.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2008, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2008, 2012, 2015 Free Software + Foundation, Inc. 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 diff --git a/gettext-tools/src/write-catalog.h b/gettext-tools/src/write-catalog.h index 804592c..7cb18b8 100644 --- a/gettext-tools/src/write-catalog.h +++ b/gettext-tools/src/write-catalog.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2003, 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2006, 2008, 2015 Free Software + Foundation, Inc. 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 diff --git a/gettext-tools/src/write-csharp.c b/gettext-tools/src/write-csharp.c index 047361a..dd757ed 100644 --- a/gettext-tools/src/write-csharp.c +++ b/gettext-tools/src/write-csharp.c @@ -1,5 +1,5 @@ /* Writing C# satellite assemblies. - Copyright (C) 2003-2010 Free Software Foundation, Inc. + Copyright (C) 2003-2010, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-csharp.h b/gettext-tools/src/write-csharp.h index 55b71fb..509f8c1 100644 --- a/gettext-tools/src/write-csharp.h +++ b/gettext-tools/src/write-csharp.h @@ -1,5 +1,5 @@ /* Writing C# satellite assemblies. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-desktop.c b/gettext-tools/src/write-desktop.c index dd3fb60..6cf1db7 100644 --- a/gettext-tools/src/write-desktop.c +++ b/gettext-tools/src/write-desktop.c @@ -1,5 +1,6 @@ /* Writing Desktop Entry files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2015 + Free Software Foundation, Inc. This file was written by Daiki Ueno <ueno@gnu.org>. This program is free software: you can redistribute it and/or modify @@ -42,8 +43,7 @@ typedef struct msgfmt_desktop_reader_ty msgfmt_desktop_reader_ty; struct msgfmt_desktop_reader_ty { DESKTOP_READER_TY - string_list_ty *languages; - message_list_ty **messages; + msgfmt_operand_list_ty *operands; hash_table *keywords; FILE *output_file; }; @@ -77,13 +77,12 @@ msgfmt_desktop_handle_pair (desktop_reader_ty *reader, char *unescaped = desktop_unescape_string (value, is_list); size_t i; - for (i = 0; i < msgfmt_reader->languages->nitems; i++) + for (i = 0; i < msgfmt_reader->operands->nitems; i++) { - const char *language = msgfmt_reader->languages->item[i]; - message_list_ty *mlp = msgfmt_reader->messages[i]; + msgfmt_operand_ty *operand = &msgfmt_reader->operands->items[i]; message_ty *mp; - mp = message_list_search (mlp, NULL, unescaped); + mp = message_list_search (operand->mlp, NULL, unescaped); if (mp && *mp->msgstr != '\0') { char *escaped; @@ -91,7 +90,7 @@ msgfmt_desktop_handle_pair (desktop_reader_ty *reader, escaped = desktop_escape_string (mp->msgstr, is_list); fprintf (msgfmt_reader->output_file, "%s[%s]=%s\n", - key, language, escaped); + key, operand->language, escaped); free (escaped); } } @@ -137,8 +136,7 @@ desktop_reader_class_ty msgfmt_methods = }; int -msgdomain_write_desktop_bulk (string_list_ty *languages, - message_list_ty **messages, +msgdomain_write_desktop_bulk (msgfmt_operand_list_ty *operands, const char *template_file_name, hash_table *keywords, const char *file_name) @@ -150,8 +148,7 @@ msgdomain_write_desktop_bulk (string_list_ty *languages, reader = desktop_reader_alloc (&msgfmt_methods); msgfmt_reader = (msgfmt_desktop_reader_ty *) reader; - msgfmt_reader->languages = languages; - msgfmt_reader->messages = messages; + msgfmt_reader->operands = operands; msgfmt_reader->keywords = keywords; if (strcmp (file_name, "-") == 0) @@ -162,8 +159,7 @@ msgdomain_write_desktop_bulk (string_list_ty *languages, if (msgfmt_reader->output_file == NULL) { desktop_reader_free (reader); - error (EXIT_SUCCESS, - errno, _("error while opening \"%s\" for writing"), + error (0, errno, _("error while opening \"%s\" for writing"), file_name); return 1; } @@ -173,8 +169,7 @@ msgdomain_write_desktop_bulk (string_list_ty *languages, if (template_file == NULL) { desktop_reader_free (reader); - error (EXIT_SUCCESS, - errno, _("error while opening \"%s\" for reading"), + error (0, errno, _("error while opening \"%s\" for reading"), template_file_name); return 1; } @@ -183,8 +178,11 @@ msgdomain_write_desktop_bulk (string_list_ty *languages, /* Make sure nothing went wrong. */ if (fwriteerror (msgfmt_reader->output_file)) - error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"), - file_name); + { + error (0, errno, _("error while writing \"%s\" file"), + file_name); + return 1; + } desktop_reader_free (reader); @@ -199,27 +197,20 @@ msgdomain_write_desktop (message_list_ty *mlp, hash_table *keywords, const char *file_name) { - string_list_ty *languages; - message_list_ty **messages; - int retval; + msgfmt_operand_ty operand; + msgfmt_operand_list_ty operands; /* Convert the messages to Unicode. */ iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); - languages = string_list_alloc (); - string_list_append (languages, locale_name); - - messages = XNMALLOC (1, message_list_ty *); - messages[0] = mlp; - - retval = msgdomain_write_desktop_bulk (languages, - messages, - template_file_name, - keywords, - file_name); - - string_list_free (languages); - free (messages); + /* Create a single-element operands and run the bulk operation on it. */ + operand.language = (char *) locale_name; + operand.mlp = mlp; + operands.nitems = 1; + operands.items = &operand; - return retval; + return msgdomain_write_desktop_bulk (&operands, + template_file_name, + keywords, + file_name); } diff --git a/gettext-tools/src/write-desktop.h b/gettext-tools/src/write-desktop.h index 028b441..d6408e2 100644 --- a/gettext-tools/src/write-desktop.h +++ b/gettext-tools/src/write-desktop.h @@ -1,5 +1,6 @@ /* Reading Desktop Entry files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2015 + Free Software Foundation, Inc. This file was written by Daiki Ueno <ueno@gnu.org>. This program is free software: you can redistribute it and/or modify @@ -18,7 +19,7 @@ #ifndef _WRITE_DESKTOP_H #define _WRITE_DESKTOP_H -#include "message.h" +#include "msgfmt.h" #ifdef __cplusplus extern "C" { @@ -37,8 +38,7 @@ extern int const char *file_name); extern int - msgdomain_write_desktop_bulk (string_list_ty *languages, - message_list_ty **messages, + msgdomain_write_desktop_bulk (msgfmt_operand_list_ty *operands, const char *template_file_name, hash_table *keywords, const char *file_name); diff --git a/gettext-tools/src/write-java.c b/gettext-tools/src/write-java.c index 9cf4054..a21c002 100644 --- a/gettext-tools/src/write-java.c +++ b/gettext-tools/src/write-java.c @@ -1,5 +1,6 @@ /* Writing Java ResourceBundles. - Copyright (C) 2001-2003, 2005-2010 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2010, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-java.h b/gettext-tools/src/write-java.h index 4249edb..2bebc1f 100644 --- a/gettext-tools/src/write-java.h +++ b/gettext-tools/src/write-java.h @@ -1,5 +1,5 @@ /* Writing Java ResourceBundles. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-mo.c b/gettext-tools/src/write-mo.c index ce27415..92dbbe4 100644 --- a/gettext-tools/src/write-mo.c +++ b/gettext-tools/src/write-mo.c @@ -1,5 +1,6 @@ /* Writing binary .mo files. - Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2007, 2015 Free Software Foundation, + Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-mo.h b/gettext-tools/src/write-mo.h index b1ea8ea..249ed58 100644 --- a/gettext-tools/src/write-mo.h +++ b/gettext-tools/src/write-mo.h @@ -1,5 +1,6 @@ /* Writing binary .mo files. - Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2015 Free Software + Foundation, Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-po.c b/gettext-tools/src/write-po.c index d49a95f..ec413d4 100644 --- a/gettext-tools/src/write-po.c +++ b/gettext-tools/src/write-po.c @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2010, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2010, 2012, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> @@ -400,7 +401,7 @@ message_print_comment_filepos (const message_ty *mp, ostream_t stream, else sprintf (buffer, ":%ld", (long) pp->line_number); len = strlen (cp) + strlen (buffer) + 1; - if (column > 2 && column + len >= page_width) + if (column > 2 && column + len > page_width) { ostream_write_str (stream, "\n#:"); column = 2; diff --git a/gettext-tools/src/write-po.h b/gettext-tools/src/write-po.h index 9a243bf..ee8313a 100644 --- a/gettext-tools/src/write-po.h +++ b/gettext-tools/src/write-po.h @@ -1,5 +1,6 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1998, 2000-2003, 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2006, 2008, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/write-properties.c b/gettext-tools/src/write-properties.c index 8b6dcee..4aaf923 100644 --- a/gettext-tools/src/write-properties.c +++ b/gettext-tools/src/write-properties.c @@ -1,5 +1,5 @@ /* Writing Java .properties files. - Copyright (C) 2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-properties.h b/gettext-tools/src/write-properties.h index 9f614b5..b29154e 100644 --- a/gettext-tools/src/write-properties.h +++ b/gettext-tools/src/write-properties.h @@ -1,5 +1,5 @@ /* Writing Java .properties files. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-qt.c b/gettext-tools/src/write-qt.c index 50b96b7..42b2d84 100644 --- a/gettext-tools/src/write-qt.c +++ b/gettext-tools/src/write-qt.c @@ -1,5 +1,6 @@ /* Writing Qt .qm files. - Copyright (C) 2003, 2005-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2007, 2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-qt.h b/gettext-tools/src/write-qt.h index 2b36da2..d83622a 100644 --- a/gettext-tools/src/write-qt.h +++ b/gettext-tools/src/write-qt.h @@ -1,5 +1,5 @@ /* Writing Qt .qm files. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-resources.c b/gettext-tools/src/write-resources.c index 6759c1b..2fa7e48 100644 --- a/gettext-tools/src/write-resources.c +++ b/gettext-tools/src/write-resources.c @@ -1,5 +1,6 @@ /* Writing C# .resources files. - Copyright (C) 2003, 2005, 2007-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2007-2009, 2011, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-resources.h b/gettext-tools/src/write-resources.h index 7512f0f..2508816 100644 --- a/gettext-tools/src/write-resources.h +++ b/gettext-tools/src/write-resources.h @@ -1,5 +1,5 @@ /* Writing C# .resources files. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-stringtable.c b/gettext-tools/src/write-stringtable.c index 34e171f..8846ac7 100644 --- a/gettext-tools/src/write-stringtable.c +++ b/gettext-tools/src/write-stringtable.c @@ -1,5 +1,5 @@ /* Writing NeXTstep/GNUstep .strings files. - Copyright (C) 2003, 2006-2008 Free Software Foundation, Inc. + Copyright (C) 2003, 2006-2008, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-stringtable.h b/gettext-tools/src/write-stringtable.h index 3130467..4e60dc2 100644 --- a/gettext-tools/src/write-stringtable.h +++ b/gettext-tools/src/write-stringtable.h @@ -1,5 +1,5 @@ /* Writing NeXTstep/GNUstep .strings files. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-tcl.c b/gettext-tools/src/write-tcl.c index db582c6..1439431 100644 --- a/gettext-tools/src/write-tcl.c +++ b/gettext-tools/src/write-tcl.c @@ -1,5 +1,6 @@ /* Writing tcl/msgcat .msg files. - Copyright (C) 2002-2003, 2005, 2007-2009 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005, 2007-2009, 2015 Free Software + Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-tcl.h b/gettext-tools/src/write-tcl.h index e6a3dce..b10aa16 100644 --- a/gettext-tools/src/write-tcl.h +++ b/gettext-tools/src/write-tcl.h @@ -1,5 +1,5 @@ /* Writing tcl/msgcat .msg files. - Copyright (C) 2002-2003 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/write-xml.c b/gettext-tools/src/write-xml.c new file mode 100644 index 0000000..38e3195 --- /dev/null +++ b/gettext-tools/src/write-xml.c @@ -0,0 +1,107 @@ +/* Writing XML files. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2015 + Free Software Foundation, Inc. + This file was written by Daiki Ueno <ueno@gnu.org>. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "write-xml.h" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include "error.h" +#include "msgl-iconv.h" +#include "po-charset.h" +#include "read-catalog.h" +#include "read-po.h" +#include "fwriteerror.h" +#include "xalloc.h" +#include "gettext.h" + +#define _(str) gettext (str) + +int +msgdomain_write_xml_bulk (msgfmt_operand_list_ty *operands, + const char *template_file_name, + its_rule_list_ty *its_rules, + const char *file_name) +{ + its_merge_context_ty *context; + size_t i; + FILE *fp; + + if (strcmp (file_name, "-") == 0) + fp = stdout; + else + { + fp = fopen (file_name, "wb"); + if (fp == NULL) + { + error (0, errno, _("cannot create output file \"%s\""), + file_name); + return 1; + } + } + + context = its_merge_context_alloc (its_rules, template_file_name); + for (i = 0; i < operands->nitems; i++) + its_merge_context_merge (context, + operands->items[i].language, + operands->items[i].mlp); + its_merge_context_write (context, fp); + its_merge_context_free (context); + + /* Make sure nothing went wrong. */ + if (fwriteerror (fp)) + { + error (0, errno, _("error while writing \"%s\" file"), + file_name); + return 1; + } + + return 0; +} + +int +msgdomain_write_xml (message_list_ty *mlp, + const char *canon_encoding, + const char *locale_name, + const char *template_file_name, + its_rule_list_ty *its_rules, + const char *file_name) +{ + msgfmt_operand_ty operand; + msgfmt_operand_list_ty operands; + + /* Convert the messages to Unicode. */ + iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); + + /* Create a single-element operands and run the bulk operation on it. */ + operand.language = (char *) locale_name; + operand.mlp = mlp; + operands.nitems = 1; + operands.items = &operand; + + return msgdomain_write_xml_bulk (&operands, + template_file_name, + its_rules, + file_name); +} diff --git a/gettext-tools/src/write-xml.h b/gettext-tools/src/write-xml.h new file mode 100644 index 0000000..e627789 --- /dev/null +++ b/gettext-tools/src/write-xml.h @@ -0,0 +1,52 @@ +/* Reading XML files. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014-2015 + Free Software Foundation, Inc. + This file was written by Daiki Ueno <ueno@gnu.org>. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef _WRITE_XML_H +#define _WRITE_XML_H + +#include "its.h" +#include "msgfmt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Write an XML file. mlp is a list containing the messages + to be output. locale_name is the locale name. template_file_name + is the template file. file_name is the output file. Return 0 if + ok, nonzero on error. */ +extern int + msgdomain_write_xml (message_list_ty *mlp, + const char *canon_encoding, + const char *locale_name, + const char *template_file_name, + its_rule_list_ty *its_rules, + const char *file_name); + +extern int + msgdomain_write_xml_bulk (msgfmt_operand_list_ty *operands, + const char *template_file_name, + its_rule_list_ty *its_rules, + const char *file_name); + +#ifdef __cplusplus +} +#endif + + +#endif /* _WRITE_XML_H */ diff --git a/gettext-tools/src/x-appdata.h b/gettext-tools/src/x-appdata.h new file mode 100644 index 0000000..6171673 --- /dev/null +++ b/gettext-tools/src/x-appdata.h @@ -0,0 +1,42 @@ +/* xgettext AppData file backend. + Copyright (C) 2002-2003, 2006, 2013, 2015 Free Software Foundation, + Inc. + Written by Philip Withnall <philip.withnall@collabora.co.uk>, 2015. + + 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + + +#include <stdio.h> + +#include "message.h" +#include "xgettext.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* The scanner is implemented as ITS rules, in its/appdata.its. */ + +#define EXTENSIONS_APPDATA \ + { "appdata.xml", NULL }, \ + +#define SCANNERS_APPDATA \ + { "appdata", NULL, NULL, NULL, NULL, NULL }, \ + + +#ifdef __cplusplus +} +#endif diff --git a/gettext-tools/src/x-awk.c b/gettext-tools/src/x-awk.c index 6a6a9dc..648befe 100644 --- a/gettext-tools/src/x-awk.c +++ b/gettext-tools/src/x-awk.c @@ -1,5 +1,6 @@ /* xgettext awk backend. - Copyright (C) 2002-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2009, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. diff --git a/gettext-tools/src/x-awk.h b/gettext-tools/src/x-awk.h index 642c0e2..b0c1448 100644 --- a/gettext-tools/src/x-awk.h +++ b/gettext-tools/src/x-awk.h @@ -1,5 +1,5 @@ /* xgettext awk backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify @@ -29,6 +29,8 @@ extern "C" { #define EXTENSIONS_AWK \ { "awk", "awk" }, \ + { "gawk", "awk" }, \ + { "twjr", "awk" }, \ #define SCANNERS_AWK \ { "awk", extract_awk, \ diff --git a/gettext-tools/src/x-c.c b/gettext-tools/src/x-c.c index 001cfd9..68e9f5d 100644 --- a/gettext-tools/src/x-c.c +++ b/gettext-tools/src/x-c.c @@ -1,5 +1,6 @@ /* xgettext C/C++/ObjectiveC backend. - Copyright (C) 1995-1998, 2000-2009, 2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2009, 2012, 2015 Free Software + Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> @@ -143,6 +144,14 @@ x_objc_keyword (const char *name) add_keyword (name, &objc_keywords); } +static bool additional_keywords_kde; + +void +activate_additional_keywords_kde () +{ + additional_keywords_kde = true; +} + /* Finish initializing the keywords hash tables. Called after argument processing, before each file is processed. */ static void @@ -166,6 +175,50 @@ init_keywords () x_c_keyword ("dnpgettext:2c,3,4"); x_c_keyword ("dcnpgettext:2c,3,4"); + if (additional_keywords_kde) + { + x_c_keyword ("i18n:1"); + x_c_keyword ("i18nc:1c,2"); + x_c_keyword ("i18np:1,2"); + x_c_keyword ("i18ncp:1c,2,3"); + x_c_keyword ("i18nd:2"); + x_c_keyword ("i18ndc:2c,3"); + x_c_keyword ("i18ndp:2,3"); + x_c_keyword ("i18ndcp:2c,3,4"); + x_c_keyword ("ki18n:1"); + x_c_keyword ("ki18nc:1c,2"); + x_c_keyword ("ki18np:1,2"); + x_c_keyword ("ki18ncp:1c,2,3"); + x_c_keyword ("ki18nd:2"); + x_c_keyword ("ki18ndc:2c,3"); + x_c_keyword ("ki18ndp:2,3"); + x_c_keyword ("ki18ndcp:2c,3,4"); + x_c_keyword ("I18N_NOOP:1"); + x_c_keyword ("I18NC_NOOP:1c,2"); + x_c_keyword ("I18N_NOOP2:1c,2"); + x_c_keyword ("I18N_NOOP2_NOSTRIP:1c,2"); + x_c_keyword ("xi18n:1"); + x_c_keyword ("xi18nc:1c,2"); + x_c_keyword ("xi18np:1,2"); + x_c_keyword ("xi18ncp:1c,2,3"); + x_c_keyword ("xi18nd:2"); + x_c_keyword ("xi18ndc:2c,3"); + x_c_keyword ("xi18ndp:2,3"); + x_c_keyword ("xi18ndcp:2c,3,4"); + x_c_keyword ("kxi18n:1"); + x_c_keyword ("kxi18nc:1c,2"); + x_c_keyword ("kxi18np:1,2"); + x_c_keyword ("kxi18ncp:1c,2,3"); + x_c_keyword ("kxi18nd:2"); + x_c_keyword ("kxi18ndc:2c,3"); + x_c_keyword ("kxi18ndp:2,3"); + x_c_keyword ("kxi18ndcp:2c,3,4"); + x_c_keyword ("XI18N_NOOP:1"); + x_c_keyword ("XI18NC_NOOP:1c,2"); + x_c_keyword ("XI18N_NOOP2:1c,2"); + x_c_keyword ("XI18N_NOOP2_NOSTRIP:1c,2"); + } + x_objc_keyword ("gettext"); x_objc_keyword ("dgettext:2"); x_objc_keyword ("dcgettext:2"); @@ -449,6 +502,50 @@ init_flag_table_gcc_internal () #endif } +void +init_flag_table_kde () +{ + xgettext_record_flag ("i18n:1:kde-format"); + xgettext_record_flag ("i18nc:2:kde-format"); + xgettext_record_flag ("i18np:1:kde-format"); + xgettext_record_flag ("i18ncp:2:kde-format"); + xgettext_record_flag ("i18nd:2:kde-format"); + xgettext_record_flag ("i18ndc:3:kde-format"); + xgettext_record_flag ("i18ndp:2:kde-format"); + xgettext_record_flag ("i18ndcp:3:kde-format"); + xgettext_record_flag ("ki18n:1:kde-format"); + xgettext_record_flag ("ki18nc:2:kde-format"); + xgettext_record_flag ("ki18np:1:kde-format"); + xgettext_record_flag ("ki18ncp:2:kde-format"); + xgettext_record_flag ("ki18nd:2:kde-format"); + xgettext_record_flag ("ki18ndc:3:kde-format"); + xgettext_record_flag ("ki18ndp:2:kde-format"); + xgettext_record_flag ("ki18ndcp:3:kde-format"); + xgettext_record_flag ("I18N_NOOP:1:kde-format"); + xgettext_record_flag ("I18NC_NOOP:2:kde-format"); + xgettext_record_flag ("I18N_NOOP2:2:kde-format"); + xgettext_record_flag ("I18N_NOOP2_NOSTRIP:2:kde-format"); + xgettext_record_flag ("xi18n:1:kde-kuit-format"); + xgettext_record_flag ("xi18nc:2:kde-kuit-format"); + xgettext_record_flag ("xi18np:1:kde-kuit-format"); + xgettext_record_flag ("xi18ncp:2:kde-kuit-format"); + xgettext_record_flag ("xi18nd:2:kde-kuit-format"); + xgettext_record_flag ("xi18ndc:3:kde-kuit-format"); + xgettext_record_flag ("xi18ndp:2:kde-kuit-format"); + xgettext_record_flag ("xi18ndcp:3:kde-kuit-format"); + xgettext_record_flag ("kxi18n:1:kde-kuit-format"); + xgettext_record_flag ("kxi18nc:2:kde-kuit-format"); + xgettext_record_flag ("kxi18np:1:kde-kuit-format"); + xgettext_record_flag ("kxi18ncp:2:kde-kuit-format"); + xgettext_record_flag ("kxi18nd:2:kde-kuit-format"); + xgettext_record_flag ("kxi18ndc:3:kde-kuit-format"); + xgettext_record_flag ("kxi18ndp:2:kde-kuit-format"); + xgettext_record_flag ("kxi18ndcp:3:kde-kuit-format"); + xgettext_record_flag ("XI18N_NOOP:1:kde-kuit-format"); + xgettext_record_flag ("XI18NC_NOOP:2:kde-kuit-format"); + xgettext_record_flag ("XI18N_NOOP2:2:kde-kuit-format"); + xgettext_record_flag ("XI18N_NOOP2_NOSTRIP:2:kde-kuit-format"); +} /* ======================== Reading of characters. ======================== */ @@ -829,6 +926,9 @@ phase4_ungetc (int c) /* True if ObjectiveC extensions are recognized. */ static bool objc_extensions; +/* True if C++ extensions are recognized. */ +static bool cxx_extensions; + enum token_type_ty { token_type_character_constant, /* 'x' */ @@ -855,6 +955,7 @@ struct token_ty char *string; /* for token_type_name, token_type_string_literal */ refcounted_string_list_ty *comment; /* for token_type_string_literal, token_type_objc_special */ + enum literalstring_escape_type escape; /* for token_type_string_literal */ long number; int line_number; }; @@ -884,13 +985,16 @@ literalstring_parse (const char *string, lex_pos_ty *pos, logical_file_name, line_number); - for (p = string; *p != '\0'; p++) + for (p = string; ; ) { - int c; + int c = *p++; + + if (c == '\0') + break; - if (*p != '\\') + if (c != '\\') { - mixed_string_buffer_append_char (bp, *p); + mixed_string_buffer_append_char (bp, c); continue; } @@ -900,7 +1004,9 @@ literalstring_parse (const char *string, lex_pos_ty *pos, continue; } - c = *++p; + c = *p++; + if (c == '\0') + break; if (type & LET_ANSI_C) switch (c) @@ -940,7 +1046,9 @@ literalstring_parse (const char *string, lex_pos_ty *pos, continue; case 'x': - c = *++p; + c = *p++; + if (c == '\0') + break; switch (c) { default: @@ -956,26 +1064,26 @@ literalstring_parse (const char *string, lex_pos_ty *pos, { int n; - for (n = 0; ; ++p) + for (n = 0; ; c = *p++) { - switch (*p) + switch (c) { default: break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - n = n * 16 + *p - '0'; + n = n * 16 + c - '0'; continue; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - n = n * 16 + 10 + *p - 'A'; + n = n * 16 + 10 + c - 'A'; continue; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - n = n * 16 + 10 + *p - 'a'; + n = n * 16 + 10 + c - 'a'; continue; } break; @@ -996,7 +1104,7 @@ literalstring_parse (const char *string, lex_pos_ty *pos, for (n = 0, j = 0; j < 3; ++j) { n = n * 8 + c - '0'; - c = *++p; + c = *p++; switch (c) { default: @@ -1021,23 +1129,24 @@ literalstring_parse (const char *string, lex_pos_ty *pos, case 'U': case 'u': { unsigned char buf[8]; - int length = c == 'u' ? 4 : 8; + int prefix = c; + int length = prefix == 'u' ? 4 : 8; int n, j; for (n = 0, j = 0; j < length; j++) { - int c1 = *++p; - - if (c1 >= '0' && c1 <= '9') - n = (n << 4) + (c1 - '0'); - else if (c1 >= 'A' && c1 <= 'F') - n = (n << 4) + (c1 - 'A' + 10); - else if (c1 >= 'a' && c1 <= 'f') - n = (n << 4) + (c1 - 'a' + 10); + c = *p++; + + if (c >= '0' && c <= '9') + n = (n << 4) + (c - '0'); + else if (c >= 'A' && c <= 'F') + n = (n << 4) + (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + n = (n << 4) + (c - 'a' + 10); else break; - buf[j] = c1; + buf[j] = c; } if (j == length) @@ -1059,7 +1168,7 @@ warning: invalid Unicode character")); int i; mixed_string_buffer_append_char (bp, '\\'); - mixed_string_buffer_append_char (bp, c); + mixed_string_buffer_append_char (bp, prefix); for (i = 0; i < j; i++) mixed_string_buffer_append_char (bp, buf[i]); @@ -1070,6 +1179,9 @@ warning: invalid Unicode character")); continue; } + if (c == '\0') + break; + mixed_string_buffer_append_char (bp, c); } @@ -1098,6 +1210,9 @@ phase5_get (token_ty *tp) int c; int last_was_backslash; bool raw_expected = false; + int delimiter_left_end; + int delimiter_right_start; + int last_rparen; if (phase5_pushback_length) { @@ -1177,10 +1292,14 @@ phase5_get (token_ty *tp) continue; default: - /* Recognize C++ string literals prefixed by R, u8, u8R, - u, uR, U, UR, L, or LR. It is defined in ISO/IEC - 9899:2011 2.14.5. Since gettext's argument is a byte - sequence, we are only interested in u8, R, and u8R. */ + /* Recognize string literals prefixed by R, u8, u8R, u, + uR, U, UR, L, or LR. It is defined in the C standard + ISO/IEC 9899:201x and the C++ standard ISO/IEC + 14882:2011. The raw string literals prefixed by R, + u8R, uR, UR, or LR are only valid in C++. + + Since gettext's argument is a byte sequence, we are + only interested in u8, R, and u8R. */ if (c == '"') { bool is_prefix = false; @@ -1188,8 +1307,11 @@ phase5_get (token_ty *tp) switch (buffer[0]) { case 'R': - if (bufpos == 1) - is_prefix = true; + if (cxx_extensions && bufpos == 1) + { + is_prefix = true; + raw_expected = true; + } break; case 'u': if (bufpos == 1) @@ -1198,30 +1320,39 @@ phase5_get (token_ty *tp) switch (buffer[1]) { case 'R': - if (bufpos == 2) - is_prefix = true; + if (cxx_extensions && bufpos == 2) + { + is_prefix = true; + raw_expected = true; + } break; case '8': - if (bufpos == 2 - || (bufpos == 3 && buffer[2] == 'R')) + if (bufpos == 2) is_prefix = true; + else if (cxx_extensions + && bufpos == 3 && buffer[2] == 'R') + { + is_prefix = true; + raw_expected = true; + } break; } break; case 'U': case 'L': - if (bufpos == 1 - || (bufpos == 2 && buffer[1] == 'R')) + if (bufpos == 1) is_prefix = true; + else if (cxx_extensions + && bufpos == 2 && buffer[1] == 'R') + { + is_prefix = true; + raw_expected = true; + } break; } if (is_prefix) - { - raw_expected = buffer[bufpos - 1] == 'R'; - bufpos = 0; - goto string; - } + goto string; } phase4_ungetc (c); break; @@ -1362,11 +1493,14 @@ phase5_get (token_ty *tp) let the compiler complain about the argument not matching the prototype. Just pretend it won't happen. */ last_was_backslash = false; + delimiter_left_end = -1; + delimiter_right_start = -1; + last_rparen = -1; bufpos = 0; for (;;) { c = phase3_getc (); - if (last_was_backslash) + if (last_was_backslash && !raw_expected) { last_was_backslash = false; if (bufpos >= bufmax) @@ -1383,7 +1517,14 @@ phase5_get (token_ty *tp) last_was_backslash = true; /* FALLTHROUGH */ default: - if (c == '\n' && !raw_expected) + if (raw_expected) + { + if (c == '(' && delimiter_left_end < 0) + delimiter_left_end = bufpos; + else if (c == ')' && delimiter_left_end >= 0) + last_rparen = bufpos; + } + else if (c == '\n') { error_with_progname = false; error (0, 0, @@ -1393,18 +1534,35 @@ phase5_get (token_ty *tp) phase3_ungetc ('\n'); break; } - else + if (bufpos >= bufmax) { - if (bufpos >= bufmax) + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax); + } + buffer[bufpos++] = c; + continue; + + case '"': + if (raw_expected && delimiter_left_end >= 0) + { + if (last_rparen < 0 + || delimiter_left_end != bufpos - (last_rparen + 1) + || strncmp (buffer, buffer + last_rparen + 1, + delimiter_left_end) != 0) { - bufmax = 2 * bufmax + 10; - buffer = xrealloc (buffer, bufmax); + if (bufpos >= bufmax) + { + bufmax = 2 * bufmax + 10; + buffer = xrealloc (buffer, bufmax); + } + buffer[bufpos++] = c; + continue; } - buffer[bufpos++] = c; - continue; + delimiter_right_start = last_rparen; } + break; - case EOF: case '"': + case EOF: break; } break; @@ -1418,13 +1576,7 @@ phase5_get (token_ty *tp) if (raw_expected) { - char *delimiter_left_end; - char *delimiter_right_start; - - if (!(delimiter_left_end = strchr (buffer, '(')) - || !(delimiter_right_start = strrchr (buffer, ')')) - || strncmp (buffer, delimiter_right_start + 1, - (delimiter_left_end - buffer)) != 0) + if (delimiter_left_end < 0 || delimiter_right_start < 0) { error_with_progname = false; error (0, 0, _("%s:%d: warning: unterminated string literal"), @@ -1433,15 +1585,17 @@ phase5_get (token_ty *tp) } else { - *delimiter_right_start = '\0'; + buffer[delimiter_right_start] = '\0'; tp->type = token_type_string_literal; - tp->string = xstrdup (delimiter_left_end + 1); + tp->string = xstrdup (&buffer[delimiter_left_end + 1]); + tp->escape = LET_NONE; tp->comment = add_reference (savable_comment); return; } } tp->type = token_type_string_literal; tp->string = xstrdup (buffer); + tp->escape = LET_ANSI_C | LET_UNICODE; tp->comment = add_reference (savable_comment); return; } @@ -1695,6 +1849,7 @@ phase8a_get (token_ty *tp) tp->string = new_string; tp->comment = add_reference (savable_comment); tp->type = token_type_string_literal; + tp->escape = LET_ANSI_C | LET_UNICODE; } } @@ -1775,7 +1930,10 @@ phase8c_unget (token_ty *tp) /* 8. Concatenate adjacent string literals to form single string literals (because we don't expand macros, there are a few things we - will miss). */ + will miss). + + FIXME: handle the case when the string literals have different + tp->escape setting. */ static void phase8_get (token_ty *tp) @@ -1832,6 +1990,9 @@ struct xgettext_token_ty char *string; /* This field is used only for xgettext_token_type_string_literal. */ + enum literalstring_escape_type escape; + + /* This field is used only for xgettext_token_type_string_literal. */ refcounted_string_list_ty *comment; /* These fields are only for @@ -1906,6 +2067,7 @@ x_c_lex (xgettext_token_ty *tp) tp->type = xgettext_token_type_string_literal; tp->string = token.string; + tp->escape = token.escape; tp->comment = token.comment; tp->pos.file_name = logical_file_name; tp->pos.line_number = token.line_number; @@ -2067,7 +2229,7 @@ extract_parenthesized (message_list_ty *mlp, const char *encoding; string = literalstring_parse (token.string, &token.pos, - LET_ANSI_C | LET_UNICODE); + token.escape); free (token.string); token.string = string; @@ -2094,7 +2256,7 @@ extract_parenthesized (message_list_ty *mlp, token.pos.file_name, token.pos.line_number, token.comment, - LET_ANSI_C | LET_UNICODE); + token.escape); drop_reference (token.comment); next_context_iter = null_context_list_iterator; selectorcall_context_iter = null_context_list_iterator; @@ -2160,6 +2322,18 @@ extract_c (FILE *f, msgdomain_list_ty *mdlp) { objc_extensions = false; + cxx_extensions = false; + extract_whole_file (f, real_filename, logical_filename, flag_table, mdlp); +} + +void +extract_cxx (FILE *f, + const char *real_filename, const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp) +{ + objc_extensions = false; + cxx_extensions = true; extract_whole_file (f, real_filename, logical_filename, flag_table, mdlp); } @@ -2170,5 +2344,6 @@ extract_objc (FILE *f, msgdomain_list_ty *mdlp) { objc_extensions = true; + cxx_extensions = false; extract_whole_file (f, real_filename, logical_filename, flag_table, mdlp); } diff --git a/gettext-tools/src/x-c.h b/gettext-tools/src/x-c.h index 64e4953..9dc82b0 100644 --- a/gettext-tools/src/x-c.h +++ b/gettext-tools/src/x-c.h @@ -1,5 +1,6 @@ /* xgettext C/C++/ObjectiveC backend. - Copyright (C) 2001-2003, 2006, 2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2009, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify @@ -45,7 +46,7 @@ extern "C" { &flag_table_c, \ &formatstring_c, NULL, \ &literalstring_c }, \ - { "C++", extract_c, \ + { "C++", extract_cxx, \ &flag_table_c, \ &formatstring_c, NULL, \ &literalstring_c }, \ @@ -58,11 +59,16 @@ extern "C" { &formatstring_gcc_internal, &formatstring_gfc_internal, \ &literalstring_c }, \ -/* Scan a C/C++ file and add its translatable strings to mdlp. */ +/* Scan a C file and add its translatable strings to mdlp. */ extern void extract_c (FILE *fp, const char *real_filename, const char *logical_filename, flag_context_list_table_ty *flag_table, msgdomain_list_ty *mdlp); +/* Scan a C++ file and add its translatable strings to mdlp. */ +extern void extract_cxx (FILE *fp, const char *real_filename, + const char *logical_filename, + flag_context_list_table_ty *flag_table, + msgdomain_list_ty *mdlp); /* Scan an ObjectiveC file and add its translatable strings to mdlp. */ extern void extract_objc (FILE *fp, const char *real_filename, const char *logical_filename, @@ -79,9 +85,12 @@ extern void x_objc_keyword (const char *name); extern void x_c_trigraphs (void); +extern void activate_additional_keywords_kde (void); + extern void init_flag_table_c (void); extern void init_flag_table_objc (void); extern void init_flag_table_gcc_internal (void); +extern void init_flag_table_kde (void); extern struct literalstring_parser literalstring_c; diff --git a/gettext-tools/src/x-csharp.c b/gettext-tools/src/x-csharp.c index 5091c3b..8bb87d4 100644 --- a/gettext-tools/src/x-csharp.c +++ b/gettext-tools/src/x-csharp.c @@ -1,5 +1,6 @@ /* xgettext C# backend. - Copyright (C) 2003, 2005-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2009, 2011, 2015 Free Software Foundation, + Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-csharp.h b/gettext-tools/src/x-csharp.h index de37789..e3c6173 100644 --- a/gettext-tools/src/x-csharp.h +++ b/gettext-tools/src/x-csharp.h @@ -1,5 +1,5 @@ /* xgettext C# backend. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-desktop.c b/gettext-tools/src/x-desktop.c index 320266e..e4ce5b3 100644 --- a/gettext-tools/src/x-desktop.c +++ b/gettext-tools/src/x-desktop.c @@ -1,5 +1,5 @@ /* xgettext Desktop Entry backend. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014-2015 Free Software Foundation, Inc. This file was written by Daiki Ueno <ueno@gnu.org>, 2014. diff --git a/gettext-tools/src/x-desktop.h b/gettext-tools/src/x-desktop.h index d24f174..a5c954b 100644 --- a/gettext-tools/src/x-desktop.h +++ b/gettext-tools/src/x-desktop.h @@ -1,5 +1,5 @@ /* xgettext Desktop Entry backend. - Copyright (C) 2014 Free Software Foundation, Inc. + Copyright (C) 2014-2015 Free Software Foundation, Inc. Written by Daiki Ueno <ueno@gnu.org>, 2014. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-elisp.c b/gettext-tools/src/x-elisp.c index 50c3d55..bbe7121 100644 --- a/gettext-tools/src/x-elisp.c +++ b/gettext-tools/src/x-elisp.c @@ -1,5 +1,6 @@ /* xgettext Emacs Lisp backend. - Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2009, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2001-2002. diff --git a/gettext-tools/src/x-elisp.h b/gettext-tools/src/x-elisp.h index f939957..618a495 100644 --- a/gettext-tools/src/x-elisp.h +++ b/gettext-tools/src/x-elisp.h @@ -1,5 +1,5 @@ /* xgettext Emacs Lisp backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-glade.c b/gettext-tools/src/x-glade.c deleted file mode 100644 index eebce00..0000000 --- a/gettext-tools/src/x-glade.c +++ /dev/null @@ -1,612 +0,0 @@ -/* xgettext glade backend. - Copyright (C) 2002-2003, 2005-2009, 2013 Free Software Foundation, Inc. - - This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. - - 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -/* Specification. */ -#include "x-glade.h" - -#include <errno.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "message.h" -#include "xgettext.h" -#include "error.h" -#include "xerror.h" -#include "xvasprintf.h" -#include "basename.h" -#include "progname.h" -#include "xalloc.h" -#include "hash.h" -#include "po-charset.h" -#include "gettext.h" -#include "libexpat-compat.h" - -#define _(s) gettext(s) - - -/* Glade is an XML based format with three variants. The syntax for - each format is defined as follows. - - - Glade 1 - Some example files are contained in libglade-0.16. - - - Glade 2 - See http://library.gnome.org/devel/libglade/unstable/libglade-dtd.html - - - GtkBuilder - See https://developer.gnome.org/gtk3/stable/GtkBuilder.html#BUILDER-UI */ - - -/* ====================== Keyword set customization. ====================== */ - -/* If true extract all strings. */ -static bool extract_all = false; - -/* The keywords correspond to the translatable elements in Glade 1. - For Glade 2 and GtkBuilder, translatable content is determined by - the translatable="..." attribute, thus those keywords are not used. */ -static hash_table keywords; -static bool default_keywords = true; - - -void -x_glade_extract_all () -{ - extract_all = true; -} - - -void -x_glade_keyword (const char *name) -{ - if (name == NULL) - default_keywords = false; - else - { - if (keywords.table == NULL) - hash_init (&keywords, 100); - - hash_insert_entry (&keywords, name, strlen (name), NULL); - } -} - -/* Finish initializing the keywords hash table. - Called after argument processing, before each file is processed. */ -static void -init_keywords () -{ - if (default_keywords) - { - /* When adding new keywords here, also update the documentation in - xgettext.texi! */ - x_glade_keyword ("label"); - x_glade_keyword ("title"); - x_glade_keyword ("text"); - x_glade_keyword ("format"); - x_glade_keyword ("copyright"); - x_glade_keyword ("comments"); - x_glade_keyword ("preview_text"); - x_glade_keyword ("tooltip"); - default_keywords = false; - } -} - - - -/* ============================= XML parsing. ============================= */ - -#if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT - -/* Accumulator for the extracted messages. */ -static message_list_ty *mlp; - -/* Logical filename, used to label the extracted messages. */ -static char *logical_file_name; - -/* XML parser. */ -static XML_Parser parser; - -struct element_state -{ - bool extract_string; - bool extract_context; /* used by Glade 2 */ - char *extracted_comment; /* used by Glade 2 or GtkBuilder */ - char *extracted_context; /* used by GtkBuilder */ - int lineno; - char *buffer; - size_t bufmax; - size_t buflen; -}; -static struct element_state *stack; -static size_t stack_size; - -/* Ensures stack_size >= size. */ -static void -ensure_stack_size (size_t size) -{ - if (size > stack_size) - { - stack_size = 2 * stack_size; - if (stack_size < size) - stack_size = size; - stack = - (struct element_state *) - xrealloc (stack, stack_size * sizeof (struct element_state)); - } -} - -static size_t stack_depth; - -/* Parser logic for each Glade compatible file format. */ -struct element_parser -{ - void (*start_element) (struct element_state *p, const char *name, - const char **attributes); - void (*end_element) (struct element_state *p, const char *name); -}; -static struct element_parser *element_parser; - -static void -start_element_null (struct element_state *p, const char *name, - const char **attributes) -{ -} - -static void -end_element_null (struct element_state *p, const char *name) -{ -} - -static void -start_element_glade1 (struct element_state *p, const char *name, - const char **attributes) -{ - void *hash_result; - - /* In Glade 1, a few specific elements are translatable without - --extract-all option. */ - p->extract_string = extract_all; - if (!p->extract_string) - p->extract_string = - (hash_find_entry (&keywords, name, strlen (name), &hash_result) == 0); -} - -static void -end_element_glade1 (struct element_state *p, const char *name) -{ - lex_pos_ty pos; - - pos.file_name = logical_file_name; - pos.line_number = p->lineno; - - if (p->buffer != NULL) - { - remember_a_message (mlp, NULL, p->buffer, - null_context, &pos, - p->extracted_comment, savable_comment); - p->buffer = NULL; - } -} - -static void -start_element_glade2 (struct element_state *p, const char *name, - const char **attributes) -{ - /* In Glade 2, all <property> and <atkproperty> elements are translatable - that have the attribute translatable="yes". - See <http://library.gnome.org/devel/libglade/unstable/libglade-dtd.html>. - The translator comment is found in the attribute comments="...". - See <http://live.gnome.org/TranslationProject/DevGuidelines/Use comments>. - If the element has the attribute context="yes", the content of - the element is in the form "msgctxt|msgid". */ - if (strcmp (name, "property") == 0 || strcmp (name, "atkproperty") == 0) - { - bool has_translatable = false; - bool has_context = false; - const char *extracted_comment = NULL; - const char **attp = attributes; - while (*attp != NULL) - { - if (strcmp (attp[0], "translatable") == 0) - has_translatable = (strcmp (attp[1], "yes") == 0); - else if (strcmp (attp[0], "comments") == 0) - extracted_comment = attp[1]; - else if (strcmp (attp[0], "context") == 0) - has_context = (strcmp (attp[1], "yes") == 0); - attp += 2; - } - p->extract_string = has_translatable; - p->extract_context = has_context; - p->extracted_comment = - (has_translatable && extracted_comment != NULL - ? xstrdup (extracted_comment) - : NULL); - } - - /* In Glade 2, the attribute description="..." of <atkaction> - element is also translatable. */ - if (strcmp (name, "atkaction") == 0) - { - const char **attp = attributes; - while (*attp != NULL) - { - if (strcmp (attp[0], "description") == 0) - { - if (strcmp (attp[1], "") != 0) - { - lex_pos_ty pos; - - pos.file_name = logical_file_name; - pos.line_number = XML_GetCurrentLineNumber (parser); - - remember_a_message (mlp, NULL, xstrdup (attp[1]), - null_context, &pos, - NULL, savable_comment); - } - break; - } - attp += 2; - } - } -} - -static void -end_element_glade2 (struct element_state *p, const char *name) -{ - lex_pos_ty pos; - char *msgid = NULL; - char *msgctxt = NULL; - - pos.file_name = logical_file_name; - pos.line_number = p->lineno; - - if (p->extract_context) - { - char *separator = strchr (p->buffer, '|'); - - if (separator == NULL) - { - error_with_progname = false; - error_at_line (0, 0, - pos.file_name, - pos.line_number, - _("\ -Missing context for the string extracted from '%s' element"), - name); - error_with_progname = true; - } - else - { - *separator = '\0'; - msgid = xstrdup (separator + 1); - msgctxt = xstrdup (p->buffer); - } - } - else - { - msgid = p->buffer; - p->buffer = NULL; - } - - if (msgid != NULL) - remember_a_message (mlp, msgctxt, msgid, - null_context, &pos, - p->extracted_comment, savable_comment); -} - -static void -start_element_gtkbuilder (struct element_state *p, const char *name, - const char **attributes) -{ - /* In GtkBuilder (used by Glade 3), all elements are translatable - that have the attribute translatable="yes". - See <https://developer.gnome.org/gtk3/stable/GtkBuilder.html#BUILDER-UI>. - The translator comment is found in the attribute comments="..." - and context is found in the attribute context="...". */ - bool has_translatable = false; - const char *extracted_comment = NULL; - const char *extracted_context = NULL; - const char **attp = attributes; - while (*attp != NULL) - { - if (strcmp (attp[0], "translatable") == 0) - has_translatable = (strcmp (attp[1], "yes") == 0); - else if (strcmp (attp[0], "comments") == 0) - extracted_comment = attp[1]; - else if (strcmp (attp[0], "context") == 0) - extracted_context = attp[1]; - attp += 2; - } - p->extract_string = has_translatable; - p->extracted_comment = - (has_translatable && extracted_comment != NULL - ? xstrdup (extracted_comment) - : NULL); - p->extracted_context = - (has_translatable && extracted_context != NULL - ? xstrdup (extracted_context) - : NULL); -} - -static void -end_element_gtkbuilder (struct element_state *p, const char *name) -{ - lex_pos_ty pos; - - pos.file_name = logical_file_name; - pos.line_number = p->lineno; - - if (p->buffer != NULL) - { - remember_a_message (mlp, p->extracted_context, p->buffer, - null_context, &pos, - p->extracted_comment, savable_comment); - p->buffer = NULL; - p->extracted_context = NULL; - } -} - -static struct element_parser element_parser_null = -{ - start_element_null, - end_element_null -}; - -static struct element_parser element_parser_glade1 = -{ - start_element_glade1, - end_element_glade1 -}; - -static struct element_parser element_parser_glade2 = -{ - start_element_glade2, - end_element_glade2 -}; - -static struct element_parser element_parser_gtkbuilder = -{ - start_element_gtkbuilder, - end_element_gtkbuilder -}; - -/* Callback called when <element> is seen. */ -static void -start_element_handler (void *userData, const char *name, - const char **attributes) -{ - struct element_state *p; - - if (!stack_depth) - { - if (strcmp (name, "GTK-Interface") == 0) - element_parser = &element_parser_glade1; - else if (strcmp (name, "glade-interface") == 0) - element_parser = &element_parser_glade2; - else if (strcmp (name, "interface") == 0) - element_parser = &element_parser_gtkbuilder; - else - { - element_parser = &element_parser_null; - error_with_progname = false; - error_at_line (0, 0, - logical_file_name, - XML_GetCurrentLineNumber (parser), - _("\ -The root element <%s> is not allowed in a valid Glade file"), - name); - error_with_progname = true; - } - } - - /* Increase stack depth. */ - stack_depth++; - ensure_stack_size (stack_depth + 1); - - /* Don't extract a string for the containing element. */ - stack[stack_depth - 1].extract_string = false; - - p = &stack[stack_depth]; - p->extract_string = false; - p->extract_context = false; - p->extracted_comment = NULL; - p->extracted_context = NULL; - - element_parser->start_element (p, name, attributes); - - p->lineno = XML_GetCurrentLineNumber (parser); - p->buffer = NULL; - p->bufmax = 0; - p->buflen = 0; - if (!p->extract_string) - savable_comment_reset (); -} - -/* Callback called when </element> is seen. */ -static void -end_element_handler (void *userData, const char *name) -{ - struct element_state *p = &stack[stack_depth]; - - /* Actually extract string. */ - if (p->extract_string) - { - /* Don't extract the empty string. */ - if (p->buflen > 0) - { - if (p->buflen == p->bufmax) - p->buffer = (char *) xrealloc (p->buffer, p->buflen + 1); - p->buffer[p->buflen] = '\0'; - - element_parser->end_element (p, name); - } - } - - /* Free memory for this stack level. */ - if (p->extracted_comment != NULL) - free (p->extracted_comment); - if (p->extracted_context != NULL) - free (p->extracted_context); - if (p->buffer != NULL) - free (p->buffer); - - /* Decrease stack depth. */ - stack_depth--; - - savable_comment_reset (); -} - -/* Callback called when some text is seen. */ -static void -character_data_handler (void *userData, const char *s, int len) -{ - struct element_state *p = &stack[stack_depth]; - - /* Accumulate character data. */ - if (len > 0) - { - if (p->buflen + len > p->bufmax) - { - p->bufmax = 2 * p->bufmax; - if (p->bufmax < p->buflen + len) - p->bufmax = p->buflen + len; - p->buffer = (char *) xrealloc (p->buffer, p->bufmax); - } - memcpy (p->buffer + p->buflen, s, len); - p->buflen += len; - } -} - -/* Callback called when some comment text is seen. */ -static void -comment_handler (void *userData, const char *data) -{ - /* Split multiline comment into lines, and remove leading and trailing - whitespace. */ - char *copy = xstrdup (data); - char *p; - char *q; - - for (p = copy; (q = strchr (p, '\n')) != NULL; p = q + 1) - { - while (p[0] == ' ' || p[0] == '\t') - p++; - while (q > p && (q[-1] == ' ' || q[-1] == '\t')) - q--; - *q = '\0'; - savable_comment_add (p); - } - q = p + strlen (p); - while (p[0] == ' ' || p[0] == '\t') - p++; - while (q > p && (q[-1] == ' ' || q[-1] == '\t')) - q--; - *q = '\0'; - savable_comment_add (p); - free (copy); -} - - -static void -do_extract_glade (FILE *fp, - const char *real_filename, const char *logical_filename, - msgdomain_list_ty *mdlp) -{ - mlp = mdlp->item[0]->messages; - - /* expat feeds us strings in UTF-8 encoding. */ - xgettext_current_source_encoding = po_charset_utf8; - - logical_file_name = xstrdup (logical_filename); - - init_keywords (); - - parser = XML_ParserCreate (NULL); - if (parser == NULL) - error (EXIT_FAILURE, 0, _("memory exhausted")); - - XML_SetElementHandler (parser, start_element_handler, end_element_handler); - XML_SetCharacterDataHandler (parser, character_data_handler); - XML_SetCommentHandler (parser, comment_handler); - - stack_depth = 0; - element_parser = &element_parser_null; - - while (!feof (fp)) - { - char buf[4096]; - int count = fread (buf, 1, sizeof buf, fp); - - if (count == 0) - { - if (ferror (fp)) - error (EXIT_FAILURE, errno, _("\ -error while reading \"%s\""), real_filename); - /* EOF reached. */ - break; - } - - if (XML_Parse (parser, buf, count, 0) == 0) - error (EXIT_FAILURE, 0, _("%s:%lu:%lu: %s"), logical_filename, - (unsigned long) XML_GetCurrentLineNumber (parser), - (unsigned long) XML_GetCurrentColumnNumber (parser) + 1, - XML_ErrorString (XML_GetErrorCode (parser))); - } - - if (XML_Parse (parser, NULL, 0, 1) == 0) - error (EXIT_FAILURE, 0, _("%s:%lu:%lu: %s"), logical_filename, - (unsigned long) XML_GetCurrentLineNumber (parser), - (unsigned long) XML_GetCurrentColumnNumber (parser) + 1, - XML_ErrorString (XML_GetErrorCode (parser))); - - XML_ParserFree (parser); - - /* Close scanner. */ - logical_file_name = NULL; - parser = NULL; -} - -#endif - -void -extract_glade (FILE *fp, - const char *real_filename, const char *logical_filename, - flag_context_list_table_ty *flag_table, - msgdomain_list_ty *mdlp) -{ -#if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT - if (LIBEXPAT_AVAILABLE ()) - do_extract_glade (fp, real_filename, logical_filename, mdlp); - else -#endif - { - multiline_error (xstrdup (""), - xasprintf (_("\ -Language \"glade\" is not supported. %s relies on expat.\n\ -This version was built without expat.\n"), - basename (program_name))); - exit (EXIT_FAILURE); - } -} diff --git a/gettext-tools/src/x-glade.h b/gettext-tools/src/x-glade.h index f212d2b..fda5876 100644 --- a/gettext-tools/src/x-glade.h +++ b/gettext-tools/src/x-glade.h @@ -1,5 +1,5 @@ /* xgettext glade backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify @@ -27,25 +27,16 @@ extern "C" { #endif -#define EXTENSIONS_GLADE \ - { "glade", "glade" }, \ - { "glade2", "glade" }, \ - { "ui", "glade" }, \ - -#define SCANNERS_GLADE \ - { "glade", extract_glade, NULL, NULL, NULL, NULL }, \ - -/* Scan a glade XML file and add its translatable strings to mdlp. */ -extern void extract_glade (FILE *fp, const char *real_filename, - const char *logical_filename, - flag_context_list_table_ty *flag_table, - msgdomain_list_ty *mdlp); +/* The scanner is implemented as ITS rules, in its/glade[12].its and + its/gtkbuilder.its. */ +#define EXTENSIONS_GLADE \ + { "glade", NULL }, \ + { "glade2", NULL }, \ + { "ui", NULL }, \ -/* Handling of options specific to this language. */ - -extern void x_glade_extract_all (void); -extern void x_glade_keyword (const char *name); +#define SCANNERS_GLADE \ + { "glade", NULL, NULL, NULL, NULL, NULL }, \ #ifdef __cplusplus diff --git a/gettext-tools/src/x-gsettings.c b/gettext-tools/src/x-gsettings.c deleted file mode 100644 index 14a2584..0000000 --- a/gettext-tools/src/x-gsettings.c +++ /dev/null @@ -1,386 +0,0 @@ -/* xgettext GSettings schema file backend. - Copyright (C) 2002-2003, 2005-2009, 2013 Free Software Foundation, Inc. - - This file was written by Daiki Ueno <ueno@gnu.org>, 2013. - - 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -/* Specification. */ -#include "x-gsettings.h" - -#include <errno.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "message.h" -#include "xgettext.h" -#include "error.h" -#include "xerror.h" -#include "xvasprintf.h" -#include "basename.h" -#include "progname.h" -#include "xalloc.h" -#include "hash.h" -#include "po-charset.h" -#include "gettext.h" -#include "libexpat-compat.h" - -#define _(s) gettext(s) - - -/* GSettings schema file is an XML based format. - The syntax is defined in glib/gio/gschema.dtd and: - https://developer.gnome.org/gio/unstable/GSettings.html */ - - -/* ====================== Keyword set customization. ====================== */ - -/* If true extract all strings. */ -static bool extract_all = false; - - -/* ============================= XML parsing. ============================= */ - -#if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT - -/* Accumulator for the extracted messages. */ -static message_list_ty *mlp; - -/* Logical filename, used to label the extracted messages. */ -static char *logical_file_name; - -/* XML parser. */ -static XML_Parser parser; - -enum whitespace_type_ty -{ - none, - normalize, - strip -}; -typedef enum whitespace_type_ty whitespace_type_ty; - -struct element_state -{ - bool extract_string; - whitespace_type_ty whitespace; - char *extracted_context; - int lineno; - char *buffer; - size_t bufmax; - size_t buflen; -}; -static struct element_state *stack; -static size_t stack_size; - -static char * -normalize_whitespace (const char *text, whitespace_type_ty whitespace) -{ - if (whitespace == none) - return xstrdup (text); - else - { - char *result, *p; - - /* Strip whitespaces at the beginning/end of the text. */ - result = xstrdup (text + strspn (text, " \t\n")); - for (p = result + strlen (result); - p > result && (*p == '\0' || *p == ' ' || *p == '\t' || *p == '\n'); - p--) - ; - if (p > result) - *++p = '\0'; - - /* Normalize whitespaces within the text. */ - if (whitespace == normalize) - { - char *end = result + strlen (result); - for (p = result; *p != '\0';) - { - size_t len = strspn (p, " \t\n"); - if (len > 0) - { - *p = ' '; - memmove (p + 1, p + len, end - (p + len)); - end -= len - 1; - *end = '\0'; - p++; - } - p += strcspn (p, " \t\n"); - } - } - return result; - } -} - -/* Ensures stack_size >= size. */ -static void -ensure_stack_size (size_t size) -{ - if (size > stack_size) - { - stack_size = 2 * stack_size; - if (stack_size < size) - stack_size = size; - stack = - (struct element_state *) - xrealloc (stack, stack_size * sizeof (struct element_state)); - } -} - -static size_t stack_depth; - -/* Callback called when <element> is seen. */ -static void -start_element_handler (void *userData, const char *name, - const char **attributes) -{ - struct element_state *p; - - /* Increase stack depth. */ - stack_depth++; - ensure_stack_size (stack_depth + 1); - - /* Don't extract a string for the containing element. */ - stack[stack_depth - 1].extract_string = false; - - p = &stack[stack_depth]; - p->extract_string = extract_all; - p->extracted_context = NULL; - - if (!p->extract_string) - { - bool has_translatable = false; - whitespace_type_ty whitespace = none; - const char *extracted_context = NULL; - if (strcmp (name, "summary") == 0 || strcmp (name, "description") == 0) - { - has_translatable = true; - whitespace = normalize; - } - else if (strcmp (name, "default") == 0) - { - const char *extracted_l10n = NULL; - const char **attp = attributes; - while (*attp != NULL) - { - if (strcmp (attp[0], "context") == 0) - extracted_context = attp[1]; - else if (strcmp (attp[0], "l10n") == 0) - extracted_l10n = attp[1]; - attp += 2; - } - if (extracted_l10n != NULL) - { - has_translatable = true; - whitespace = strip; - } - } - p->extract_string = has_translatable; - p->whitespace = whitespace; - p->extracted_context = - (has_translatable && extracted_context != NULL - ? xstrdup (extracted_context) - : NULL); - } - - p->lineno = XML_GetCurrentLineNumber (parser); - p->buffer = NULL; - p->bufmax = 0; - p->buflen = 0; - if (!p->extract_string) - savable_comment_reset (); -} - -/* Callback called when </element> is seen. */ -static void -end_element_handler (void *userData, const char *name) -{ - struct element_state *p = &stack[stack_depth]; - - /* Actually extract string. */ - if (p->extract_string) - { - /* Don't extract the empty string. */ - if (p->buflen > 0) - { - lex_pos_ty pos; - - if (p->buflen == p->bufmax) - p->buffer = (char *) xrealloc (p->buffer, p->buflen + 1); - p->buffer[p->buflen] = '\0'; - - pos.file_name = logical_file_name; - pos.line_number = p->lineno; - - if (p->buffer != NULL) - { - remember_a_message (mlp, p->extracted_context, - normalize_whitespace (p->buffer, - p->whitespace), - null_context, &pos, - NULL, savable_comment); - p->extracted_context = NULL; - } - } - } - - /* Free memory for this stack level. */ - if (p->extracted_context != NULL) - free (p->extracted_context); - if (p->buffer != NULL) - free (p->buffer); - - /* Decrease stack depth. */ - stack_depth--; - - savable_comment_reset (); -} - -/* Callback called when some text is seen. */ -static void -character_data_handler (void *userData, const char *s, int len) -{ - struct element_state *p = &stack[stack_depth]; - - /* Accumulate character data. */ - if (len > 0) - { - if (p->buflen + len > p->bufmax) - { - p->bufmax = 2 * p->bufmax; - if (p->bufmax < p->buflen + len) - p->bufmax = p->buflen + len; - p->buffer = (char *) xrealloc (p->buffer, p->bufmax); - } - memcpy (p->buffer + p->buflen, s, len); - p->buflen += len; - } -} - -/* Callback called when some comment text is seen. */ -static void -comment_handler (void *userData, const char *data) -{ - /* Split multiline comment into lines, and remove leading and trailing - whitespace. */ - char *copy = xstrdup (data); - char *p; - char *q; - - for (p = copy; (q = strchr (p, '\n')) != NULL; p = q + 1) - { - while (p[0] == ' ' || p[0] == '\t') - p++; - while (q > p && (q[-1] == ' ' || q[-1] == '\t')) - q--; - *q = '\0'; - savable_comment_add (p); - } - q = p + strlen (p); - while (p[0] == ' ' || p[0] == '\t') - p++; - while (q > p && (q[-1] == ' ' || q[-1] == '\t')) - q--; - *q = '\0'; - savable_comment_add (p); - free (copy); -} - - -static void -do_extract_gsettings (FILE *fp, - const char *real_filename, const char *logical_filename, - msgdomain_list_ty *mdlp) -{ - mlp = mdlp->item[0]->messages; - - /* expat feeds us strings in UTF-8 encoding. */ - xgettext_current_source_encoding = po_charset_utf8; - - logical_file_name = xstrdup (logical_filename); - - parser = XML_ParserCreate (NULL); - if (parser == NULL) - error (EXIT_FAILURE, 0, _("memory exhausted")); - - XML_SetElementHandler (parser, start_element_handler, end_element_handler); - XML_SetCharacterDataHandler (parser, character_data_handler); - XML_SetCommentHandler (parser, comment_handler); - - stack_depth = 0; - - while (!feof (fp)) - { - char buf[4096]; - int count = fread (buf, 1, sizeof buf, fp); - - if (count == 0) - { - if (ferror (fp)) - error (EXIT_FAILURE, errno, _("\ -error while reading \"%s\""), real_filename); - /* EOF reached. */ - break; - } - - if (XML_Parse (parser, buf, count, 0) == 0) - error (EXIT_FAILURE, 0, _("%s:%lu:%lu: %s"), logical_filename, - (unsigned long) XML_GetCurrentLineNumber (parser), - (unsigned long) XML_GetCurrentColumnNumber (parser) + 1, - XML_ErrorString (XML_GetErrorCode (parser))); - } - - if (XML_Parse (parser, NULL, 0, 1) == 0) - error (EXIT_FAILURE, 0, _("%s:%lu:%lu: %s"), logical_filename, - (unsigned long) XML_GetCurrentLineNumber (parser), - (unsigned long) XML_GetCurrentColumnNumber (parser) + 1, - XML_ErrorString (XML_GetErrorCode (parser))); - - XML_ParserFree (parser); - - /* Close scanner. */ - logical_file_name = NULL; - parser = NULL; -} - -#endif - -void -extract_gsettings (FILE *fp, - const char *real_filename, const char *logical_filename, - flag_context_list_table_ty *flag_table, - msgdomain_list_ty *mdlp) -{ -#if DYNLOAD_LIBEXPAT || HAVE_LIBEXPAT - if (LIBEXPAT_AVAILABLE ()) - do_extract_gsettings (fp, real_filename, logical_filename, mdlp); - else -#endif - { - multiline_error (xstrdup (""), - xasprintf (_("\ -Language \"gsettings\" is not supported. %s relies on expat.\n\ -This version was built without expat.\n"), - basename (program_name))); - exit (EXIT_FAILURE); - } -} diff --git a/gettext-tools/src/x-gsettings.h b/gettext-tools/src/x-gsettings.h index b06016d..00b968c 100644 --- a/gettext-tools/src/x-gsettings.h +++ b/gettext-tools/src/x-gsettings.h @@ -1,5 +1,6 @@ /* xgettext GSettings schema file backend. - Copyright (C) 2002-2003, 2006, 2013 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2013, 2015 Free Software Foundation, + Inc. Written by Daiki Ueno <ueno@gnu.org>, 2013. This program is free software: you can redistribute it and/or modify @@ -27,17 +28,13 @@ extern "C" { #endif -#define EXTENSIONS_GSETTINGS \ - { "gschema.xml", "gsettings" }, \ +/* The scanner is implemented as ITS rules, in its/gsettings.its. */ -#define SCANNERS_GSETTINGS \ - { "gsettings", extract_gsettings, NULL, NULL, NULL, NULL }, \ +#define EXTENSIONS_GSETTINGS \ + { "gschema.xml", NULL }, \ -/* Scan a gsettings XML file and add its translatable strings to mdlp. */ -extern void extract_gsettings (FILE *fp, const char *real_filename, - const char *logical_filename, - flag_context_list_table_ty *flag_table, - msgdomain_list_ty *mdlp); +#define SCANNERS_GSETTINGS \ + { "gsettings", NULL, NULL, NULL, NULL, NULL }, \ #ifdef __cplusplus diff --git a/gettext-tools/src/x-java.c b/gettext-tools/src/x-java.c index 58c1ad7..3bc75fe 100644 --- a/gettext-tools/src/x-java.c +++ b/gettext-tools/src/x-java.c @@ -1,5 +1,5 @@ /* xgettext Java backend. - Copyright (C) 2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-java.h b/gettext-tools/src/x-java.h index 49f2af9..2719c42 100644 --- a/gettext-tools/src/x-java.h +++ b/gettext-tools/src/x-java.h @@ -1,5 +1,5 @@ /* xgettext Java backend. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Tommy Johansson <tommy.johansson@kanalen.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-javascript.c b/gettext-tools/src/x-javascript.c index 35c9a9e..bc4d4c8 100644 --- a/gettext-tools/src/x-javascript.c +++ b/gettext-tools/src/x-javascript.c @@ -1,5 +1,6 @@ /* xgettext JavaScript backend. - Copyright (C) 2002-2003, 2005-2009, 2013 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2009, 2013, 2015 Free Software + Foundation, Inc. This file was written by Andreas Stricker <andy@knitter.ch>, 2010 It's based on x-python from Bruno Haible. diff --git a/gettext-tools/src/x-javascript.h b/gettext-tools/src/x-javascript.h index a2f6418..5d2d980 100644 --- a/gettext-tools/src/x-javascript.h +++ b/gettext-tools/src/x-javascript.h @@ -1,5 +1,6 @@ /* xgettext JavaScript backend. - Copyright (C) 2002-2003, 2006, 2013 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2013, 2015 Free Software Foundation, + Inc. This file was written by Andreas Stricker <andy@knitter.ch>, 2010. It's based on x-python from Bruno Haible. diff --git a/gettext-tools/src/x-librep.c b/gettext-tools/src/x-librep.c index c91d22a..a515f29 100644 --- a/gettext-tools/src/x-librep.c +++ b/gettext-tools/src/x-librep.c @@ -1,5 +1,6 @@ /* xgettext librep backend. - Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2009, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2001. diff --git a/gettext-tools/src/x-librep.h b/gettext-tools/src/x-librep.h index 5747db1..129a6c3 100644 --- a/gettext-tools/src/x-librep.h +++ b/gettext-tools/src/x-librep.h @@ -1,5 +1,5 @@ /* xgettext librep backend. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-lisp.c b/gettext-tools/src/x-lisp.c index 20d88a2..0d3a1c4 100644 --- a/gettext-tools/src/x-lisp.c +++ b/gettext-tools/src/x-lisp.c @@ -1,5 +1,6 @@ /* xgettext Lisp backend. - Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2009, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2001. diff --git a/gettext-tools/src/x-lisp.h b/gettext-tools/src/x-lisp.h index 97b593d..e9d0a0b 100644 --- a/gettext-tools/src/x-lisp.h +++ b/gettext-tools/src/x-lisp.h @@ -1,5 +1,5 @@ /* xgettext Lisp backend. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-lua.c b/gettext-tools/src/x-lua.c index 9fcc20d..5050838 100644 --- a/gettext-tools/src/x-lua.c +++ b/gettext-tools/src/x-lua.c @@ -1,5 +1,5 @@ /* xgettext Lua backend. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. This file was written by Ľubomír Remák <lubomirr@lubomirr.eu>, 2012. diff --git a/gettext-tools/src/x-lua.h b/gettext-tools/src/x-lua.h index 3161638..7af3525 100644 --- a/gettext-tools/src/x-lua.h +++ b/gettext-tools/src/x-lua.h @@ -1,5 +1,5 @@ /* xgettext Lua backend. - Copyright (C) 2011 Free Software Foundation, Inc. + Copyright (C) 2011, 2015 Free Software Foundation, Inc. Written by Ľubomír Remák <lubomirrk@lubomirr.eu>, 2011 This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-perl.c b/gettext-tools/src/x-perl.c index 571f6de..396b7b5 100644 --- a/gettext-tools/src/x-perl.c +++ b/gettext-tools/src/x-perl.c @@ -1,5 +1,5 @@ /* xgettext Perl backend. - Copyright (C) 2002-2010 Free Software Foundation, Inc. + Copyright (C) 2002-2010, 2015 Free Software Foundation, Inc. This file was written by Guido Flohr <guido@imperia.net>, 2002-2010. diff --git a/gettext-tools/src/x-perl.h b/gettext-tools/src/x-perl.h index 8e140e9..4f7a2b3 100644 --- a/gettext-tools/src/x-perl.h +++ b/gettext-tools/src/x-perl.h @@ -1,5 +1,6 @@ /* xgettext Perl backend. - Copyright (C) 2002-2003, 2006, 2010 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2010, 2015 Free Software Foundation, + Inc. Written by Guido Flohr <guido@imperia.net>, 2002-2003 This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-php.c b/gettext-tools/src/x-php.c index 74b8ece..ac5cf96 100644 --- a/gettext-tools/src/x-php.c +++ b/gettext-tools/src/x-php.c @@ -1,5 +1,6 @@ /* xgettext PHP backend. - Copyright (C) 2001-2003, 2005-2010 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2010, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <bruno@clisp.org>, 2002. diff --git a/gettext-tools/src/x-php.h b/gettext-tools/src/x-php.h index 79442b4..0d13fee 100644 --- a/gettext-tools/src/x-php.h +++ b/gettext-tools/src/x-php.h @@ -1,5 +1,5 @@ /* xgettext PHP backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-po.c b/gettext-tools/src/x-po.c index 89824e2..65d8cc0 100644 --- a/gettext-tools/src/x-po.c +++ b/gettext-tools/src/x-po.c @@ -1,5 +1,6 @@ /* xgettext PO and JavaProperties backends. - Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2015 Free + Software Foundation, Inc. This file was written by Peter Miller <millerp@canb.auug.org.au> diff --git a/gettext-tools/src/x-po.h b/gettext-tools/src/x-po.h index 0d350d8..e76d77b 100644 --- a/gettext-tools/src/x-po.h +++ b/gettext-tools/src/x-po.h @@ -1,5 +1,5 @@ /* xgettext PO backend. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-properties.h b/gettext-tools/src/x-properties.h index fd16ab3..0935466 100644 --- a/gettext-tools/src/x-properties.h +++ b/gettext-tools/src/x-properties.h @@ -1,5 +1,5 @@ /* xgettext JavaProperties backend. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-python.c b/gettext-tools/src/x-python.c index d781ef2..8122c34 100644 --- a/gettext-tools/src/x-python.c +++ b/gettext-tools/src/x-python.c @@ -1,5 +1,6 @@ /* xgettext Python backend. - Copyright (C) 2002-2003, 2005-2013 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. diff --git a/gettext-tools/src/x-python.h b/gettext-tools/src/x-python.h index f7861fb..57d379d 100644 --- a/gettext-tools/src/x-python.h +++ b/gettext-tools/src/x-python.h @@ -1,5 +1,5 @@ /* xgettext Python backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-rst.c b/gettext-tools/src/x-rst.c index 8b5a26a..f673299 100644 --- a/gettext-tools/src/x-rst.c +++ b/gettext-tools/src/x-rst.c @@ -1,5 +1,6 @@ /* xgettext RST backend. - Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2009, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2001. diff --git a/gettext-tools/src/x-rst.h b/gettext-tools/src/x-rst.h index 6507d0d..a6ac552 100644 --- a/gettext-tools/src/x-rst.h +++ b/gettext-tools/src/x-rst.h @@ -1,5 +1,5 @@ /* xgettext RST backend. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-scheme.c b/gettext-tools/src/x-scheme.c index e8cfe84..abbe0e5 100644 --- a/gettext-tools/src/x-scheme.c +++ b/gettext-tools/src/x-scheme.c @@ -1,5 +1,5 @@ /* xgettext Scheme backend. - Copyright (C) 2004-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2004-2009, 2011, 2015 Free Software Foundation, Inc. This file was written by Bruno Haible <bruno@clisp.org>, 2004-2005. diff --git a/gettext-tools/src/x-scheme.h b/gettext-tools/src/x-scheme.h index a159ab1..039979f 100644 --- a/gettext-tools/src/x-scheme.h +++ b/gettext-tools/src/x-scheme.h @@ -1,5 +1,5 @@ /* xgettext Scheme backend. - Copyright (C) 2004, 2006 Free Software Foundation, Inc. + Copyright (C) 2004, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2004. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-sh.c b/gettext-tools/src/x-sh.c index 9a0614f..3746a9a 100644 --- a/gettext-tools/src/x-sh.c +++ b/gettext-tools/src/x-sh.c @@ -1,5 +1,5 @@ /* xgettext sh backend. - Copyright (C) 2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2003, 2005-2009, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-sh.h b/gettext-tools/src/x-sh.h index d235751..a31eeff 100644 --- a/gettext-tools/src/x-sh.h +++ b/gettext-tools/src/x-sh.h @@ -1,5 +1,5 @@ /* xgettext sh backend. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-smalltalk.c b/gettext-tools/src/x-smalltalk.c index c3f9699..9c079cc 100644 --- a/gettext-tools/src/x-smalltalk.c +++ b/gettext-tools/src/x-smalltalk.c @@ -1,5 +1,6 @@ /* xgettext Smalltalk backend. - Copyright (C) 2002-2003, 2005-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2009, 2011, 2015 Free Software + Foundation, Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. diff --git a/gettext-tools/src/x-smalltalk.h b/gettext-tools/src/x-smalltalk.h index 10767d9..9061f29 100644 --- a/gettext-tools/src/x-smalltalk.h +++ b/gettext-tools/src/x-smalltalk.h @@ -1,5 +1,5 @@ /* xgettext Smalltalk backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-stringtable.h b/gettext-tools/src/x-stringtable.h index 57df745..2c519e8 100644 --- a/gettext-tools/src/x-stringtable.h +++ b/gettext-tools/src/x-stringtable.h @@ -1,5 +1,5 @@ /* xgettext NXStringTable backend. - Copyright (C) 2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <bruno@clisp.org>, 2003. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-tcl.c b/gettext-tools/src/x-tcl.c index 37dd19e..905d55c 100644 --- a/gettext-tools/src/x-tcl.c +++ b/gettext-tools/src/x-tcl.c @@ -1,5 +1,6 @@ /* xgettext Tcl backend. - Copyright (C) 2002-2003, 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2009, 2015 Free Software Foundation, + Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2002. diff --git a/gettext-tools/src/x-tcl.h b/gettext-tools/src/x-tcl.h index 1dc5412..00f6fc5 100644 --- a/gettext-tools/src/x-tcl.h +++ b/gettext-tools/src/x-tcl.h @@ -1,5 +1,5 @@ /* xgettext Tcl Lisp backend. - Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2002. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/x-vala.c b/gettext-tools/src/x-vala.c index 4806b36..4e53b50 100644 --- a/gettext-tools/src/x-vala.c +++ b/gettext-tools/src/x-vala.c @@ -1,5 +1,5 @@ /* xgettext Vala backend. - Copyright (C) 2013 Free Software Foundation, Inc. + Copyright (C) 2013, 2015 Free Software Foundation, Inc. This file was written by Daiki Ueno <ueno@gnu.org>, 2013. diff --git a/gettext-tools/src/x-vala.h b/gettext-tools/src/x-vala.h index 9eb730b..fcd0cfb 100644 --- a/gettext-tools/src/x-vala.h +++ b/gettext-tools/src/x-vala.h @@ -1,5 +1,6 @@ /* xgettext Vala backend. - Copyright (C) 2002-2003, 2006, 2013 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2006, 2013, 2015 Free Software Foundation, + Inc. 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 diff --git a/gettext-tools/src/x-ycp.c b/gettext-tools/src/x-ycp.c index ff8642b..62ab94d 100644 --- a/gettext-tools/src/x-ycp.c +++ b/gettext-tools/src/x-ycp.c @@ -1,5 +1,6 @@ /* xgettext YCP backend. - Copyright (C) 2001-2003, 2005-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2009, 2011, 2015 Free Software + Foundation, Inc. This file was written by Bruno Haible <haible@clisp.cons.org>, 2001. diff --git a/gettext-tools/src/x-ycp.h b/gettext-tools/src/x-ycp.h index 78cc853..3ecb097 100644 --- a/gettext-tools/src/x-ycp.h +++ b/gettext-tools/src/x-ycp.h @@ -1,5 +1,5 @@ /* xgettext YCP backend. - Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006, 2015 Free Software Foundation, Inc. Written by Bruno Haible <haible@clisp.cons.org>, 2001. This program is free software: you can redistribute it and/or modify diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c index 28d28a0..314d35c 100644 --- a/gettext-tools/src/xgettext.c +++ b/gettext-tools/src/xgettext.c @@ -1,5 +1,6 @@ /* Extracts strings from C source file to Uniforum style .po file. - Copyright (C) 1995-1998, 2000-2012 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2015 Free Software Foundation, + Inc. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995. This program is free software: you can redistribute it and/or modify @@ -28,6 +29,7 @@ #include <stdlib.h> #include <stdbool.h> #include <string.h> +#include <sys/stat.h> #include <locale.h> #include <limits.h> @@ -58,6 +60,8 @@ #include "po-charset.h" #include "msgl-iconv.h" #include "msgl-ascii.h" +#include "msgl-check.h" +#include "po-xerror.h" #include "po-time.h" #include "write-catalog.h" #include "write-po.h" @@ -66,7 +70,10 @@ #include "color.h" #include "format.h" #include "propername.h" +#include "sentence.h" #include "unistr.h" +#include "its.h" +#include "locating-rule.h" #include "gettext.h" /* A convenience macro. I don't like writing gettext() every time. */ @@ -85,6 +92,7 @@ #include "x-java.h" #include "x-properties.h" #include "x-csharp.h" +#include "x-appdata.h" #include "x-awk.h" #include "x-ycp.h" #include "x-tcl.h" @@ -100,6 +108,10 @@ #include "x-desktop.h" +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) +#define ENDOF(a) ((a) + SIZEOF(a)) + + /* If nonzero add all comments immediately preceding one of the keywords. */ static bool add_all_comments = false; @@ -179,6 +191,9 @@ static bool recognize_format_kde; /* If true, recognize Boost format strings. */ static bool recognize_format_boost; +/* Syntax checks enabled by default. */ +static enum is_syntax_check default_syntax_check[NSYNTAXCHECKS]; + /* Canonicalized encoding name for all input files. */ const char *xgettext_global_source_encoding; @@ -197,6 +212,17 @@ const char *xgettext_current_source_encoding; iconv_t xgettext_current_source_iconv; #endif +static locating_rule_list_ty *its_locating_rules; + +#define ITS_ROOT_UNTRANSLATABLE \ + "<its:rules xmlns:its=\"http://www.w3.org/2005/11/its\"" \ + " version=\"2.0\">" \ + " <its:translateRule selector=\"/*\" translate=\"no\"/>" \ + "</its:rules>" + +/* If nonzero add comments used by itstool. */ +static bool add_itstool_comments = false; + /* Long options. */ static const struct option long_options[] = { @@ -204,6 +230,7 @@ static const struct option long_options[] = { "add-location", optional_argument, NULL, 'n' }, { "boost", no_argument, NULL, CHAR_MAX + 11 }, { "c++", no_argument, NULL, 'C' }, + { "check", required_argument, NULL, CHAR_MAX + 17 }, { "color", optional_argument, NULL, CHAR_MAX + 14 }, { "copyright-holder", required_argument, NULL, CHAR_MAX + 1 }, { "debug", no_argument, &do_debug, 1 }, @@ -219,6 +246,8 @@ static const struct option long_options[] = { "from-code", required_argument, NULL, CHAR_MAX + 3 }, { "help", no_argument, NULL, 'h' }, { "indent", no_argument, NULL, 'i' }, + { "its", required_argument, NULL, CHAR_MAX + 20 }, + { "itstool", no_argument, NULL, CHAR_MAX + 19 }, { "join-existing", no_argument, NULL, 'j' }, { "kde", no_argument, NULL, CHAR_MAX + 10 }, { "keyword", optional_argument, NULL, 'k' }, @@ -236,6 +265,7 @@ static const struct option long_options[] = { "package-version", required_argument, NULL, CHAR_MAX + 13 }, { "properties-output", no_argument, NULL, CHAR_MAX + 6 }, { "qt", no_argument, NULL, CHAR_MAX + 9 }, + { "sentence-end", required_argument, NULL, CHAR_MAX + 18 }, { "sort-by-file", no_argument, NULL, 'F' }, { "sort-output", no_argument, NULL, 's' }, { "strict", no_argument, NULL, 'S' }, @@ -278,6 +308,9 @@ static void usage (int status) static void read_exclusion_file (char *file_name); static void extract_from_file (const char *file_name, extractor_ty extractor, msgdomain_list_ty *mdlp); +static void extract_from_xml_file (const char *file_name, + its_rule_list_ty *rules, + msgdomain_list_ty *mdlp); static message_ty *construct_header (void); static void finalize_header (msgdomain_list_ty *mdlp); static extractor_ty language_to_extractor (const char *name); @@ -296,6 +329,8 @@ main (int argc, char *argv[]) bool some_additional_keywords = false; bool sort_by_msgid = false; bool sort_by_filepos = false; + char *its_dirs[2] = { NULL, NULL }; + char *explicit_its_filename = NULL; const char *file_name; const char *files_from = NULL; string_list_ty *file_list; @@ -328,6 +363,7 @@ main (int argc, char *argv[]) init_flag_table_c (); init_flag_table_objc (); init_flag_table_gcc_internal (); + init_flag_table_kde (); init_flag_table_sh (); init_flag_table_python (); init_flag_table_lisp (); @@ -346,7 +382,7 @@ main (int argc, char *argv[]) init_flag_table_vala (); while ((optchar = getopt_long (argc, argv, - "ac::Cd:D:eEf:Fhijk::l:L:m::M::no:p:sTVw:x:", + "ac::Cd:D:eEf:Fhijk::l:L:m::M::no:p:sTVw:W:x:", long_options, NULL)) != EOF) switch (optchar) { @@ -367,7 +403,6 @@ main (int argc, char *argv[]) x_tcl_extract_all (); x_perl_extract_all (); x_php_extract_all (); - x_glade_extract_all (); x_lua_extract_all (); x_javascript_extract_all (); x_vala_extract_all (); @@ -447,7 +482,6 @@ main (int argc, char *argv[]) x_tcl_keyword (optarg); x_perl_keyword (optarg); x_php_keyword (optarg); - x_glade_keyword (optarg); x_lua_keyword (optarg); x_javascript_keyword (optarg); x_vala_keyword (optarg); @@ -575,6 +609,7 @@ main (int argc, char *argv[]) case CHAR_MAX + 10: /* --kde */ recognize_format_kde = true; + activate_additional_keywords_kde (); break; case CHAR_MAX + 11: /* --boost */ @@ -602,6 +637,34 @@ main (int argc, char *argv[]) message_print_style_filepos (filepos_comment_none); break; + case CHAR_MAX + 17: /* --check */ + if (strcmp (optarg, "ellipsis-unicode") == 0) + default_syntax_check[sc_ellipsis_unicode] = yes; + else if (strcmp (optarg, "space-ellipsis") == 0) + default_syntax_check[sc_space_ellipsis] = yes; + else if (strcmp (optarg, "quote-unicode") == 0) + default_syntax_check[sc_quote_unicode] = yes; + else + error (EXIT_FAILURE, 0, _("syntax check '%s' unknown"), optarg); + break; + + case CHAR_MAX + 18: /* --sentence-end */ + if (strcmp (optarg, "single-space") == 0) + sentence_end_required_spaces = 1; + else if (strcmp (optarg, "double-space") == 0) + sentence_end_required_spaces = 2; + else + error (EXIT_FAILURE, 0, _("sentence end type '%s' unknown"), optarg); + break; + + case CHAR_MAX + 20: /* --its */ + explicit_its_filename = optarg; + break; + + case CHAR_MAX + 19: /* --itstool */ + add_itstool_comments = true; + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -662,6 +725,36 @@ xgettext cannot work without keywords to look for")); usage (EXIT_FAILURE); } + { + const char *gettextdatadir; + char *versioned_gettextdatadir; + + /* Make it possible to override the locator file location. This + is necessary for running the testsuite before "make + install". */ + gettextdatadir = getenv ("GETTEXTDATADIR"); + if (gettextdatadir == NULL || gettextdatadir[0] == '\0') + gettextdatadir = relocate (GETTEXTDATADIR); + + its_dirs[0] = xconcatenated_filename (gettextdatadir, "its", NULL); + + versioned_gettextdatadir = + xasprintf ("%s%s", relocate (GETTEXTDATADIR), PACKAGE_SUFFIX); + its_dirs[1] = xconcatenated_filename (versioned_gettextdatadir, "its", + NULL); + free (versioned_gettextdatadir); + + its_locating_rules = locating_rule_list_alloc (); + for (i = 0; i < SIZEOF (its_dirs); i++) + locating_rule_list_add_from_directory (its_locating_rules, its_dirs[i]); + } + + /* Explicit ITS file selection and language specification are + mutually exclusive. */ + if (explicit_its_filename != NULL && language != NULL) + error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"), + "--its", "--language"); + /* Determine extractor from language. */ if (language != NULL) extractor = language_to_extractor (language); @@ -760,18 +853,27 @@ This version was built without iconv()."), { const char *filename; extractor_ty this_file_extractor; + its_rule_list_ty *its_rules = NULL; filename = file_list->item[i]; if (extractor.func) this_file_extractor = extractor; + else if (explicit_its_filename != NULL) + { + its_rules = its_rule_list_alloc (); + if (!its_rule_list_add_from_file (its_rules, + explicit_its_filename)) + { + error (EXIT_FAILURE, 0, _("\ +warning: ITS rule file '%s' does not exist"), explicit_its_filename); + } + } else { + const char *language_from_extension = NULL; const char *base; char *reduced; - const char *extension; - const char *language; - const char *p; base = strrchr (filename, '/'); if (!base) @@ -783,39 +885,106 @@ This version was built without iconv()."), && memcmp (reduced + strlen (reduced) - 3, ".in", 3) == 0) reduced[strlen (reduced) - 3] = '\0'; - /* Work out what the file extension is. */ - language = NULL; - p = reduced + strlen (reduced); - for (; p > reduced && language == NULL; p--) + /* If no language is specified with -L, deduce it the extension. */ + if (language == NULL) { - if (*p == '.') + const char *p; + + /* Work out what the file extension is. */ + p = reduced + strlen (reduced); + for (; p > reduced && language_from_extension == NULL; p--) { - extension = p + 1; + if (*p == '.') + { + const char *extension = p + 1; - /* Derive the language from the extension, and the extractor - function from the language. */ - language = extension_to_language (extension); + /* Derive the language from the extension, and + the extractor function from the language. */ + language_from_extension = + extension_to_language (extension); + } } } - if (language == NULL) + /* If language is not determined from the file name + extension, check ITS locating rules. */ + if (language_from_extension == NULL + && strcmp (filename, "-") != 0) { - extension = strrchr (reduced, '.'); - if (extension == NULL) - extension = ""; - else - extension++; - error (0, 0, _("\ + const char *its_basename; + + its_basename = locating_rule_list_locate (its_locating_rules, + filename, + language); + + if (its_basename != NULL) + { + size_t j; + + its_rules = its_rule_list_alloc (); + + /* If the ITS file is identified by the name, + set the root element untranslatable. */ + if (language != NULL) + its_rule_list_add_from_string (its_rules, + ITS_ROOT_UNTRANSLATABLE); + + for (j = 0; j < SIZEOF (its_dirs); j++) + { + char *its_filename = + xconcatenated_filename (its_dirs[j], its_basename, + NULL); + struct stat statbuf; + bool ok = false; + + if (stat (its_filename, &statbuf) == 0) + ok = its_rule_list_add_from_file (its_rules, + its_filename); + free (its_filename); + if (ok) + break; + } + if (j == SIZEOF (its_dirs)) + { + error (0, 0, _("\ +warning: ITS rule file '%s' does not exist; check your gettext installation"), + its_basename); + its_rule_list_free (its_rules); + its_rules = NULL; + } + } + } + + if (its_rules == NULL) + { + if (language_from_extension == NULL) + { + const char *extension = strrchr (reduced, '.'); + if (extension == NULL) + extension = ""; + else + extension++; + error (0, 0, _("\ warning: file '%s' extension '%s' is unknown; will try C"), filename, extension); - language = "C"; + language_from_extension = "C"; + } + + this_file_extractor = + language_to_extractor (language_from_extension); } - this_file_extractor = language_to_extractor (language); free (reduced); } - /* Extract the strings from the file. */ - extract_from_file (filename, this_file_extractor, mdlp); + if (its_rules != NULL) + { + /* Extract the strings from the file, using ITS. */ + extract_from_xml_file (filename, its_rules, mdlp); + its_rule_list_free (its_rules); + } + else + /* Extract the strings from the file. */ + extract_from_file (filename, this_file_extractor, mdlp); } string_list_free (file_list); @@ -836,9 +1005,33 @@ warning: file '%s' extension '%s' is unknown; will try C"), filename, extension) else if (sort_by_msgid) msgdomain_list_sort_by_msgid (mdlp); + /* Check syntax of messages. */ + { + int nerrors = 0; + + for (i = 0; i < mdlp->nitems; i++) + { + message_list_ty *mlp = mdlp->item[i]->messages; + nerrors = syntax_check_message_list (mlp); + } + + /* Exit with status 1 on any error. */ + if (nerrors > 0) + error (EXIT_FAILURE, 0, + ngettext ("found %d fatal error", "found %d fatal errors", + nerrors), + nerrors); + } + /* Write the PO file. */ msgdomain_list_print (mdlp, file_name, output_syntax, force_po, do_debug); + if (its_locating_rules) + locating_rule_list_free (its_locating_rules); + + for (i = 0; i < SIZEOF (its_dirs); i++) + free (its_dirs[i]); + exit (EXIT_SUCCESS); } @@ -921,6 +1114,14 @@ Operation mode:\n")); preceding keyword lines in output file\n\ -c, --add-comments place all comment blocks preceding keyword lines\n\ in output file\n")); + printf (_("\ + --check=NAME perform syntax check on messages\n\ + (ellipsis-unicode, space-ellipsis,\n\ + quote-unicode)\n")); + printf (_("\ + --sentence-end=TYPE type describing the end of sentence\n\ + (single-space, which is the default, \n\ + or double-space)\n")); printf ("\n"); printf (_("\ Language specific options:\n")); @@ -993,6 +1194,10 @@ Output details:\n")); printf (_("\ --stringtable-output write out a NeXTstep/GNUstep .strings file\n")); printf (_("\ + --its=FILE apply ITS rules from FILE\n")); + printf (_("\ + --itstool write out itstool comments\n")); + printf (_("\ -w, --width=NUMBER set output page width\n")); printf (_("\ --no-wrap do not break long message lines, longer than\n\ @@ -1644,8 +1849,8 @@ xgettext_record_flag (const char *optionstring) flag += 5; } - /* Unlike po_parse_comment_special(), we don't accept "fuzzy" or "wrap" - here - it has no sense. */ + /* Unlike po_parse_comment_special(), we don't accept "fuzzy", + "wrap", or "check" here - it has no sense. */ if (strlen (flag) >= 7 && memcmp (flag + strlen (flag) - 7, "-format", 7) == 0) { @@ -1810,6 +2015,11 @@ xgettext_record_flag (const char *optionstring) name_start, name_end, argnum, value, pass); break; + case format_kde_kuit: + flag_context_list_table_insert (&flag_table_cxx_kde, 2, + name_start, name_end, + argnum, value, pass); + break; case format_boost: flag_context_list_table_insert (&flag_table_cxx_boost, 1, name_start, name_end, @@ -2049,6 +2259,65 @@ extract_from_file (const char *file_name, extractor_ty extractor, free (real_file_name); } +static message_ty * +xgettext_its_extract_callback (message_list_ty *mlp, + const char *msgctxt, + const char *msgid, + lex_pos_ty *pos, + const char *extracted_comment, + const char *marker, + enum its_whitespace_type_ty whitespace) +{ + message_ty *message; + + message = remember_a_message (mlp, + msgctxt == NULL ? NULL : xstrdup (msgctxt), + xstrdup (msgid), + null_context, pos, + extracted_comment, NULL); + + if (add_itstool_comments) + { + char *dot = xasprintf ("(itstool) path: %s", marker); + message_comment_dot_append (message, dot); + free (dot); + + if (whitespace == ITS_WHITESPACE_PRESERVE) + message->do_wrap = no; + } + + return message; +} + +static void +extract_from_xml_file (const char *file_name, + its_rule_list_ty *rules, + msgdomain_list_ty *mdlp) +{ + char *logical_file_name; + char *real_file_name; + FILE *fp = xgettext_open (file_name, &logical_file_name, &real_file_name); + + /* The default encoding for XML is UTF-8. It can be overridden by + an XML declaration in the XML file itself, not through the + --from-code option. */ + xgettext_current_source_encoding = po_charset_utf8; + +#if HAVE_ICONV + xgettext_current_source_iconv = xgettext_global_source_iconv; +#endif + + its_rule_list_extract (rules, fp, real_file_name, logical_file_name, + NULL, + mdlp, + xgettext_its_extract_callback); + + if (fp != stdin) + fclose (fp); + free (logical_file_name); + free (real_file_name); +} + /* Error message about non-ASCII character in a specific lexical context. */ @@ -2238,6 +2507,7 @@ remember_a_message (message_list_ty *mlp, char *msgctxt, char *msgid, enum is_format is_format[NFORMATS]; struct argument_range range; enum is_wrap do_wrap; + enum is_syntax_check do_syntax_check[NSYNTAXCHECKS]; message_ty *mp; char *msgstr; size_t i; @@ -2264,6 +2534,8 @@ remember_a_message (message_list_ty *mlp, char *msgctxt, char *msgid, range.min = -1; range.max = -1; do_wrap = undecided; + for (i = 0; i < NSYNTAXCHECKS; i++) + do_syntax_check[i] = undecided; if (msgctxt != NULL) CONVERT_STRING (msgctxt, lc_string); @@ -2297,6 +2569,8 @@ meta information, not the empty string.\n"))); for (i = 0; i < NFORMATS; i++) is_format[i] = mp->is_format[i]; do_wrap = mp->do_wrap; + for (i = 0; i < NSYNTAXCHECKS; i++) + do_syntax_check[i] = mp->do_syntax_check[i]; } else { @@ -2327,7 +2601,7 @@ meta information, not the empty string.\n"))); /* The string before the comment tag. For example, If "** TRANSLATORS:" is seen and the comment tag is "TRANSLATORS:", then comment_tag_prefix is set to "** ". */ - const char *comment_tag_prefix = NULL; + const char *comment_tag_prefix = ""; size_t comment_tag_prefix_length = 0; nitems_before = (mp->comment_dot != NULL ? mp->comment_dot->nitems : 0); @@ -2376,12 +2650,13 @@ meta information, not the empty string.\n"))); enum is_format tmp_format[NFORMATS]; struct argument_range tmp_range; enum is_wrap tmp_wrap; + enum is_syntax_check tmp_syntax_check[NSYNTAXCHECKS]; bool interesting; t += strlen ("xgettext:"); po_parse_comment_special (t, &tmp_fuzzy, tmp_format, &tmp_range, - &tmp_wrap); + &tmp_wrap, tmp_syntax_check); interesting = false; for (i = 0; i < NFORMATS; i++) @@ -2400,6 +2675,12 @@ meta information, not the empty string.\n"))); do_wrap = tmp_wrap; interesting = true; } + for (i = 0; i < NSYNTAXCHECKS; i++) + if (tmp_syntax_check[i] != undecided) + { + do_syntax_check[i] = tmp_syntax_check[i]; + interesting = true; + } /* If the "xgettext:" marker was followed by an interesting keyword, and we updated our is_format/do_wrap variables, @@ -2477,7 +2758,19 @@ meta information, not the empty string.\n"))); && (possible_format_p (is_format[format_qt]) || possible_format_p (is_format[format_qt_plural]) || possible_format_p (is_format[format_kde]) - || possible_format_p (is_format[format_boost])))) + || possible_format_p (is_format[format_kde_kuit]) + || possible_format_p (is_format[format_boost]))) + /* Avoid flagging a string as kde-format when it's known to + be a kde-kuit-format string. */ + && !(i == format_kde + && possible_format_p (is_format[format_kde_kuit])) + /* Avoid flagging a string as kde-kuit-format when it's + known to be a kde-format string. Note that this relies + on the fact that format_kde < format_kde_kuit, so a + string will be marked as kde-format if both are + undecided. */ + && !(i == format_kde_kuit + && possible_format_p (is_format[format_kde]))) { struct formatstring_parser *parser = formatstring_parsers[i]; char *invalid_reason = NULL; @@ -2525,6 +2818,14 @@ meta information, not the empty string.\n"))); mp->do_wrap = do_wrap == no ? no : yes; /* By default we wrap. */ + for (i = 0; i < NSYNTAXCHECKS; i++) + { + if (do_syntax_check[i] == undecided) + do_syntax_check[i] = default_syntax_check[i] == yes ? yes : no; + + mp->do_syntax_check[i] = do_syntax_check[i]; + } + /* Warn about the use of non-reorderable format strings when the programming language also provides reorderable format strings. */ warn_format_string (is_format, mp->msgid, pos, "msgid"); @@ -2604,7 +2905,19 @@ remember_a_message_plural (message_ty *mp, char *string, && (possible_format_p (mp->is_format[format_qt]) || possible_format_p (mp->is_format[format_qt_plural]) || possible_format_p (mp->is_format[format_kde]) - || possible_format_p (mp->is_format[format_boost])))) + || possible_format_p (mp->is_format[format_kde_kuit]) + || possible_format_p (mp->is_format[format_boost]))) + /* Avoid flagging a string as kde-format when it's known + to be a kde-kuit-format string. */ + && !(i == format_kde + && possible_format_p (mp->is_format[format_kde_kuit])) + /* Avoid flagging a string as kde-kuit-format when it's + known to be a kde-format string. Note that this relies + on the fact that format_kde < format_kde_kuit, so a + string will be marked as kde-format if both are + undecided. */ + && !(i == format_kde_kuit + && possible_format_p (mp->is_format[format_kde]))) { struct formatstring_parser *parser = formatstring_parsers[i]; char *invalid_reason = NULL; @@ -3457,9 +3770,10 @@ Content-Transfer-Encoding: 8bit\n", comment = xasprintf ("\ SOME DESCRIPTIVE TITLE.\n\ Copyright (C) YEAR %s\n\ -This file is distributed under the same license as the PACKAGE package.\n\ +This file is distributed under the same license as the %s package.\n\ FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n", - copyright_holder); + copyright_holder, + package_name != NULL ? package_name : "PACKAGE"); else comment = xstrdup ("\ SOME DESCRIPTIVE TITLE.\n\ @@ -3555,10 +3869,6 @@ finalize_header (msgdomain_list_ty *mdlp) } -#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) -#define ENDOF(a) ((a) + SIZEOF(a)) - - static extractor_ty language_to_extractor (const char *name) { @@ -3600,6 +3910,7 @@ language_to_extractor (const char *name) SCANNERS_VALA SCANNERS_GSETTINGS SCANNERS_DESKTOP + SCANNERS_APPDATA /* Here may follow more languages and their scanners: pike, etc... Make sure new scanners honor the --exclude-file option. */ }; @@ -3632,6 +3943,7 @@ language_to_extractor (const char *name) { result.flag_table = &flag_table_cxx_kde; result.formatstring_parser2 = &formatstring_kde; + result.formatstring_parser3 = &formatstring_kde_kuit; } /* Likewise for --boost. */ if (recognize_format_boost && strcmp (tp->name, "C++") == 0) @@ -3689,6 +4001,7 @@ extension_to_language (const char *extension) EXTENSIONS_VALA EXTENSIONS_GSETTINGS EXTENSIONS_DESKTOP + EXTENSIONS_APPDATA /* Here may follow more file extensions... */ }; diff --git a/gettext-tools/src/xgettext.h b/gettext-tools/src/xgettext.h index c852ae3..167fcd3 100644 --- a/gettext-tools/src/xgettext.h +++ b/gettext-tools/src/xgettext.h @@ -1,5 +1,6 @@ /* xgettext common functions. - Copyright (C) 2001-2003, 2005-2006, 2008-2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005-2006, 2008-2009, 2011, 2015 Free + Software Foundation, Inc. Written by Peter Miller <millerp@canb.auug.org.au> and Bruno Haible <haible@clisp.cons.org>, 2001. |