]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Recognize format strings depending on their position.
authorBruno Haible <bruno@clisp.org>
Fri, 10 Oct 2003 10:45:55 +0000 (10:45 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:11:03 +0000 (12:11 +0200)
58 files changed:
NEWS
gettext-runtime/po/ChangeLog
gettext-runtime/po/Makevars
gettext-tools/doc/ChangeLog
gettext-tools/doc/xgettext.texi
gettext-tools/po/ChangeLog
gettext-tools/po/Makevars
gettext-tools/src/ChangeLog
gettext-tools/src/message.c
gettext-tools/src/message.h
gettext-tools/src/po-lex.c
gettext-tools/src/write-po.c
gettext-tools/src/x-awk.c
gettext-tools/src/x-awk.h
gettext-tools/src/x-c.c
gettext-tools/src/x-c.h
gettext-tools/src/x-elisp.c
gettext-tools/src/x-elisp.h
gettext-tools/src/x-glade.c
gettext-tools/src/x-glade.h
gettext-tools/src/x-java.c
gettext-tools/src/x-java.h
gettext-tools/src/x-librep.c
gettext-tools/src/x-librep.h
gettext-tools/src/x-lisp.c
gettext-tools/src/x-lisp.h
gettext-tools/src/x-perl.c
gettext-tools/src/x-perl.h
gettext-tools/src/x-php.c
gettext-tools/src/x-php.h
gettext-tools/src/x-po.c
gettext-tools/src/x-po.h
gettext-tools/src/x-properties.h
gettext-tools/src/x-python.c
gettext-tools/src/x-python.h
gettext-tools/src/x-rst.c
gettext-tools/src/x-rst.h
gettext-tools/src/x-sh.c
gettext-tools/src/x-sh.h
gettext-tools/src/x-smalltalk.c
gettext-tools/src/x-smalltalk.h
gettext-tools/src/x-tcl.c
gettext-tools/src/x-tcl.h
gettext-tools/src/x-ycp.c
gettext-tools/src/x-ycp.h
gettext-tools/src/xgettext.c
gettext-tools/src/xgettext.h
gettext-tools/tests/ChangeLog
gettext-tools/tests/Makefile.am
gettext-tools/tests/lang-perl-1
gettext-tools/tests/lang-perl-2
gettext-tools/tests/xgettext-24
gettext-tools/tests/xgettext-26
gettext-tools/tests/xgettext-31 [new file with mode: 0755]
gettext-tools/tests/xgettext-4
gettext-tools/tests/xgettext-5
gettext-tools/tests/xgettext-6
gettext-tools/tests/xgettext-8

diff --git a/NEWS b/NEWS
index 2ae339296fcda82b5f30f5ca4f4e1cc3016010c2..334e735abb50e919340621d52d0d5e814c8282c1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,12 @@ Version 0.12.2 - September 2003
   - Glade:
     xgettext now also supports Glade version 2.
 
+* xgettext has a more reliable detection of format strings.  It now
+  recognizes format strings depending on their position, for example as the
+  second argument of fprintf(), regardless whether the literal string contains
+  format directives.  This behaviour can be customized through the --flag
+  option.
+
 * libgettextpo library:
 
   - New functions for testing the obsolete/fuzzy/*-format flags of a message.
index a84a9aec73cb99eae10900bc2dfcdd00a407dec3..630a1eb21bc94c318c09209345c88d814481597c 100644 (file)
@@ -1,3 +1,7 @@
+2003-10-05  Bruno Haible  <bruno@clisp.org>
+
+       * Makevars (XGETTEXT_OPTIONS): Add --flag options.
+
 2003-09-14  Bruno Haible  <bruno@clisp.org>
 
        * POTFILES.in: Add ../gettext-tools/lib/closeout.c, src/envsubst.c.
index 5c118c507aae36cae2cb7f61ebbf98ca326b3525..7b66638bf0a0d2b8dbd176a4d587e945773dce35 100644 (file)
@@ -8,7 +8,10 @@ subdir = po
 top_builddir = ..
 
 # These options get passed to xgettext.
-XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+XGETTEXT_OPTIONS = \
+  --keyword=_ --flag=_:1:pass-c-format \
+  --keyword=N_ --flag=N_:1:pass-c-format \
+  --flag=error:3:c-format --flag=error_at_line:5:c-format
 
 # This is the copyright holder that gets inserted into the header of the
 # $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
index 5058d68d416cab72f4ca546de1724ac81ca055e2..4e679c8b817bfd7848e45a62f671f41cf3e0b1d9 100644 (file)
@@ -1,3 +1,9 @@
+2003-10-05  Bruno Haible  <bruno@clisp.org>
+
+       * xgettext.texi (Language specific options): Renamed section. Document
+       the languages to which --extract-all, --keyword, --trigraphs are
+       applicable. Document option --flag.
+
 2003-09-13  Bruno Haible  <bruno@clisp.org>
 
        * gettext.texi: Update menus.
index 7e4593fd39bfce5ce7ab3894a7f49be5b84362d5..a29cbc76fd7a1f4bc3aa4fbc3c6bb8cb699d0fe3 100644 (file)
@@ -124,7 +124,7 @@ in output file.
 
 @end table
 
-@subsection Language=C/C++ specific options
+@subsection Language specific options
 
 @table @samp
 @item -a
@@ -133,6 +133,9 @@ in output file.
 @opindex --extract-all@r{, @code{xgettext} option}
 Extract all strings.
 
+This option has an effect with most languages, namely C, C++, ObjectiveC, Shell,
+Python, Lisp, EmacsLisp, librep, Java, awk, Tcl, Perl, PHP, GCC-source, Glade.
+
 @item -k @var{keywordspec}
 @itemx --keyword[=@var{keywordspec}]
 @opindex -k@r{, @code{xgettext} option}
@@ -150,11 +153,58 @@ for strings in the first argument of each call to the function or macro
 strings in the @var{argnum1}st argument and in the @var{argnum2}nd argument
 of the call, and treats them as singular/plural variants for a message
 with plural handling.
-
+@*
 The default keyword specifications, which are always looked for if not
 explicitly disabled, are @code{gettext}, @code{dgettext:2},
 @code{dcgettext:2}, @code{ngettext:1,2}, @code{dngettext:2,3},
 @code{dcngettext:2,3}, and @code{gettext_noop}.
+@*
+This option has an effect with most languages, namely C, C++, ObjectiveC, Shell,
+Python, Lisp, EmacsLisp, librep, Java, awk, Tcl, Perl, PHP, GCC-source, Glade.
+
+@item --flag=@var{word}:@var{arg}:@var{flag}
+@opindex --flag@r{, @code{xgettext} option}
+Specifies additional flags for strings occurring as part of the @var{arg}th
+argument of the function @var{word}.  The possible flags are the possible
+format string indicators, such as @samp{c-format}, and their negations,
+such as @samp{no-c-format}, possibly prefixed with @samp{pass-}.
+@*
+@cindex function attribute, __format__
+The meaning of @code{--flag=@var{function}:@var{arg}:@var{lang}-format}
+is that in language @var{lang}, the specified @var{function} expects as
+@var{arg}th argument a format string.  (For those of you familiar with
+GCC function attributes, @code{--flag=@var{function}:@var{arg}:c-format} is
+roughly equivalent to the declaration
+@samp{__attribute__ ((__format__ (__printf__, @var{arg}, ...)))} attached
+to @var{function} in a C source file.)
+For example, if you use the @samp{error} function from GNU libc, you can
+specify its behaviour through @code{--flag=error:3:c-format}.  The effect of
+this specification is that @code{xgettext} will mark as format strings all
+@code{gettext} invocations that occur as @var{arg}th argument of
+@var{function}.
+This is useful when such strings contain no format string directives:
+together with the checks done by @samp{msgfmt -c} it will ensure that
+translators cannot accidentally use format string directives that would
+lead to a crash at runtime.
+@*
+@cindex function attribute, __format_arg__
+The meaning of @code{--flag=@var{function}:@var{arg}:pass-@var{lang}-format}
+is that in language @var{lang}, if the @var{function} call occurs in a
+position that must yield a format string, then its @var{arg}th argument
+must yield a format string of the same type as well.  (If you know GCC
+function attributes, the @code{--flag=@var{function}:@var{arg}:pass-c-format}
+option is roughly equivalent to the declaration
+@samp{__attribute__ ((__format_arg__ (@var{arg})))} attached to @var{function}
+in a C source file.)
+For example, if you use the @samp{_} shortcut for the @code{gettext} function,
+you should use @code{--flag=_:1:pass-c-format}.  The effect of this
+specification is that @code{xgettext} will propagate a format string
+requirement for a @code{_("string")} call to its first argument, the literal
+@code{"string"}, and thus mark it as a format string.
+This is useful when such strings contain no format string directives:
+together with the checks done by @samp{msgfmt -c} it will ensure that
+translators cannot accidentally use format string directives that would
+lead to a crash at runtime.
 
 @item -T
 @itemx --trigraphs
@@ -162,6 +212,8 @@ explicitly disabled, are @code{gettext}, @code{dgettext:2},
 @opindex --trigraphs@r{, @code{xgettext} option}
 @cindex C trigraphs
 Understand ANSI C trigraphs for input.
+@*
+This option has an effect only with the languages C, C++, ObjectiveC.
 
 @itemx --debug
 @opindex --debug@r{, @code{xgettext} option}
index 7cf8f895cc6e01939b5f50629b4ff02d23decfdd..c1370dbedcb4aee2aa76497963982e38515b4fc4 100644 (file)
@@ -1,3 +1,7 @@
+2003-10-05  Bruno Haible  <bruno@clisp.org>
+
+       * Makevars (XGETTEXT_OPTIONS): Add --flag options.
+
 2003-09-14  Bruno Haible  <bruno@clisp.org>
 
        * POTFILES.in: Add src/format-sh.c, src/x-sh.c, lib/closeout.c.
index 5c118c507aae36cae2cb7f61ebbf98ca326b3525..17be10a4e9f43f18698e7b6d141541182630d8da 100644 (file)
@@ -8,7 +8,13 @@ subdir = po
 top_builddir = ..
 
 # These options get passed to xgettext.
-XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+XGETTEXT_OPTIONS = \
+  --keyword=_ --flag=_:1:pass-c-format \
+  --keyword=N_ --flag=N_:1:pass-c-format \
+  --flag=error:3:c-format --flag=error_at_line:5:c-format \
+  --flag=asprintf:2:c-format --flag=vasprintf:2:c-format \
+  --flag=xasprintf:1:c-format \
+  --flag=po_gram_error:1:c-format --flag=po_gram_error_at_line:2:c-format
 
 # This is the copyright holder that gets inserted into the header of the
 # $(DOMAIN).pot file.  Set this to the copyright holder of the surrounding
index 2217514ec65fbedfc0061f2ae052c05bf80a07db..b7bf53bc42b061ef5769d6e6718f7adb840ce006 100644 (file)
@@ -1,3 +1,225 @@
+2003-10-05  Bruno Haible  <bruno@clisp.org>
+
+       * message.h (enum is_format): New item yes_according_to_context.
+       * message.c (possible_format_p): Handle also yes_according_to_context.
+       * write-po.c (make_format_description_string): Likewise.
+
+       * xgettext.h (struct flag_context_ty): New type.
+       (null_context, passthrough_context): New declarations.
+       (inherited_context): New declaration.
+       (struct flag_context_list_ty): New type.
+       (struct flag_context_list_iterator_ty): New type.
+       (null_context_list_iterator, passthrough_context_list_iterator): New
+       declarations.
+       (flag_context_list_iterator): New declaration.
+       (flag_context_list_iterator_advance): New declaration.
+       (flag_context_list_table_ty): New type.
+       (flag_context_list_table_lookup): New declaration.
+       (xgettext_record_flag): New declaration.
+       (remember_a_message, remember_a_message_plural): Add context argument.
+       * xgettext.c: Include alloca.h.
+       (flag_table_c, flag_table_gcc_internal, flag_table_sh,
+       flag_table_python, flag_table_lisp, flag_table_elisp,
+       flag_table_librep, flag_table_java, flag_table_awk, flag_table_ycp,
+       flag_table_tcl, flag_table_perl, flag_table_php): New variables.
+       (long_options): Add option --flag.
+       (extractor_func): Add argument flag_table.
+       (struct extractor_ty): New type.
+       (main): Use type 'extractor_ty' instead of 'extractor_func'.
+       Invoke init_flag_table_c(), init_flag_table_gcc_internal(),
+       init_flag_table_sh(), init_flag_table_python(), init_flag_table_lisp(),
+       init_flag_table_elisp(), init_flag_table_librep(),
+       init_flag_table_java(), init_flag_table_awk(), init_flag_table_ycp(),
+       init_flag_table_tcl(), init_flag_table_perl(), init_flag_table_php().
+       Implement option --flag.
+       (usage): Rename a section to "Language specific options". Document
+       the languages to which --extract-all, --keyword, --trigraphs are
+       applicable. Document option --flag.
+       (null_context): New variable.
+       (passthrough_context): New variable.
+       (inherited_context): New function.
+       (null_context_list_iterator): New variable.
+       (passthrough_context_circular_list, passthrough_context_list_iterator):
+       New variables.
+       (flag_context_list_iterator): New function.
+       (flag_context_list_iterator_advance): New function.
+       (flag_context_list_table_lookup): New function.
+       (xgettext_record_flag): New function.
+       (extract_from_file): Change argument type to 'extractor_ty' instead of
+       'extractor_func'. Set current_formatstring_parser{1,2} before invoking
+       the extractor.
+       (set_format_flags_from_context): New function.
+       (remember_a_message): Add context argument. Set some *-format flag if
+       the context specifies it.
+       (remember_a_message_plural): Likewise.
+       (language_to_extractor): Change return type to 'extractor_ty' instead
+       of 'extractor_func'.
+
+       * x-awk.h (SCANNERS_AWK): Refer to flag_table_awk.
+       (extract_awk): Add argument flag_table.
+       (init_flag_table_awk): New declaration.
+       * x-awk.c (init_flag_table_awk): New function.
+       (enum token_type_ty): New enum item token_type_semicolon.
+       (x_awk_lex): Recognize semicolon.
+       (flag_context_list_table): New variable.
+       (extract_parenthesized): Add arguments outer_context, context_iter.
+       Implement context handling depending on symbol before '('. Also
+       recognize argument lists that start without '(', but only up to the
+       next semicolon.
+       (extract_awk): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-c.h (SCANNERS_C): Refer to flag_table_c, flag_table_gcc_internal.
+       (extract_c): Add argument flag_table.
+       (init_flag_table_c): New declaration.
+       (init_flag_table_gcc_internal): New declaration.
+       * x-c.c (init_flag_table_c): New function.
+       (init_flag_table_gcc_internal): New function.
+       (enum xgettext_token_type_ty): New item xgettext_token_type_other.
+       (x_c_lex): For token_type_name, put the string into the resulting
+       token instead of freeing it. Return token type
+       xgettext_token_type_other instead of xgettext_token_type_symbol in
+       some cases.
+       (flag_context_list_table): New variable.
+       (extract_parenthesized): Add arguments outer_context, context_iter.
+       Implement context handling depending on symbol before '('.
+       (extract_c): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-elisp.h (SCANNERS_ELISP): Refer to flag_table_elisp.
+       (extract_elisp): Add argument flag_table.
+       (init_flag_table_elisp): New declaration.
+       * x-elisp.c (init_flag_table_elisp): New function.
+       (flag_context_list_table): New variable.
+       (read_object): Add argument outer_context. Implement context handling
+       depending on first symbol after '('.
+       (extract_elisp): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-glade.h (SCANNERS_GLADE): Update.
+       (extract_glade): Add argument flag_table.
+       * x-glade.c (start_element_handler, end_element_handler): Pass null
+       context to remember_a_message.
+       (extract_glade): Add argument flag_table.
+
+       * x-java.h (SCANNERS_JAVA): Refer to flag_table_java.
+       (extract_java): Add argument flag_table.
+       (init_flag_table_java): New declaration.
+       * x-java.c (init_flag_table_java): New function.
+       (flag_context_list_table): New variable.
+       (extract_parenthesized): Add arguments outer_context, context_iter.
+       Implement context handling depending on symbol before '('.
+       (extract_java): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-librep.h (SCANNERS_ELISP): Refer to flag_table_librep.
+       (extract_librep): Add argument flag_table.
+       (init_flag_table_librep): New declaration.
+       * x-librep.c (init_flag_table_librep): New function.
+       (flag_context_list_table): New variable.
+       (read_object): Add argument outer_context. Implement context handling
+       depending on first symbol after '('.
+       (extract_librep): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-lisp.h (SCANNERS_LISP): Refer to flag_table_lisp.
+       (extract_lisp): Add argument flag_table.
+       (init_flag_table_lisp): New declaration.
+       * x-lisp.c (init_flag_table_lisp): New function.
+       (flag_context_list_table): New variable.
+       (read_object): Add argument outer_context. Implement context handling
+       depending on first symbol after '('.
+       (extract_lisp): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-perl.h (SCANNERS_PERL): Refer to flag_table_perl.
+       (extract_perl): Add argument flag_table.
+       (init_flag_table_perl): New declaration.
+       * x-perl.c (init_flag_table_java): New function.
+       (flag_context_list_table): New variable.
+       (extract_variable): Update. Implement context handling depending on
+       symbol before '{'...'}'.
+       (interpolate_keywords): Implement context handling depending on symbol
+       before '->' or '{'...'}'.
+       (extract_balanced): Add arguments outer_context, context_iter.
+       Implement context handling depending on symbol before '('. Also
+       recognize argument lists that start without '('.
+       (extract_perl): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-php.h (SCANNERS_PHP): Refer to flag_table_php.
+       (extract_php): Add argument flag_table.
+       (init_flag_table_php): New declaration.
+       * x-php.c (init_flag_table_php): New function.
+       (flag_context_list_table): New variable.
+       (extract_parenthesized): Add arguments outer_context, context_iter.
+       Implement context handling depending on symbol before '('.
+       (extract_php): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-po.h (SCANNERS_PO): Update.
+       (extract_po): Add argument flag_table.
+       * x-properties.h (SCANNERS_PROPERTIES): Update.
+       (extract_properties): Add argument flag_table.
+       * x-po.c (extract_po): Add argument flag_table.
+       (extract_properties): Add argument flag_table.
+
+       * x-python.h (SCANNERS_PYTHON): Refer to flag_table_python.
+       (extract_python): Add argument flag_table.
+       (init_flag_table_python): New declaration.
+       * x-python.c (init_flag_table_python): New function.
+       (flag_context_list_table): New variable.
+       (extract_parenthesized): Add arguments outer_context, context_iter.
+       Implement context handling depending on symbol before '('.
+       (extract_python): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-rst.h (SCANNERS_RST): Update.
+       (extract_rst): Add argument flag_table.
+       * x-rst.c (extract_rst): Add argument flag_table.
+
+       * x-sh.h (SCANNERS_SH): Refer to flag_table_sh.
+       (extract_sh): Add argument flag_table.
+       (init_flag_table_sh): New declaration.
+       * x-sh.c (init_flag_table_sh): New function.
+       (flag_context_list_table): New variable.
+       (read_word): Add context argument.
+       (read_command): Add outer_context argument. Implement context handling
+       depending on first symbol of command.
+       (read_command_list): Add outer_context argument.
+       (extract_sh): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-smalltalk.h (SCANNERS_SMALLTALK): Update.
+       (extract_smalltalk): Add argument flag_table.
+       * x-smalltalk.c (extract_smalltalk): Add argument flag_table.
+
+       * x-tcl.h (SCANNERS_TCL): Refer to flag_table_tcl.
+       (extract_tcl): Add argument flag_table.
+       (init_flag_table_tcl): New declaration.
+       * x-tcl.c (init_flag_table_tcl): New function.
+       (flag_context_list_table): New variable.
+       (accumulate_word): Add context argument.
+       (read_word): Add context argument.
+       (read_command): Add outer_context argument. Implement context handling
+       depending on first symbol of command.
+       (read_command_list): Add outer_context argument.
+       (extract_tcl): Add argument flag_table. Initialize
+       flag_context_list_table.
+
+       * x-ycp.h (SCANNERS_YCP): Refer to flag_table_ycp.
+       (extract_ycp): Add argument flag_table.
+       (init_flag_table_ycp): New declaration.
+       * x-ycp.c (init_flag_table_ycp): New function.
+       (flag_context_list_table): New variable.
+       (extract_parenthesized): New function, split off from extract_ycp.
+       Implement context handling depending on symbol before '('.
+       (extract_ycp): Add argument flag_table. Initialize
+       flag_context_list_table. Call extract_parenthesized to do the work.
+
+       * po-lex.c (mbfile_getc, control_sequence): Remove explicit marking of
+       strings as c-format, now done by xgettext.
+
 2003-09-23  Bruno Haible  <bruno@clisp.org>
 
        * x-awk.c (extract_parenthesized): Remove optimization of the
index f3845a0ee7f0f51f2203999181167495688b37b9..505567aecc7d7a3173fbbae44ff3c8f032156661 100644 (file)
@@ -76,7 +76,9 @@ const char *const format_language_pretty[NFORMATS] =
 bool
 possible_format_p (enum is_format is_format)
 {
-  return is_format == possible || is_format == yes;
+  return is_format == possible
+        || is_format == yes_according_to_context
+        || is_format == yes;
 }
 
 
index 46a2f2d3f0f1ada6350438598cd1dfec97eb6513..9d9dbe58cc9e0e3f4696162da96cbe027065e65c 100644 (file)
@@ -67,6 +67,7 @@ enum is_format
   undecided,
   yes,
   no,
+  yes_according_to_context,
   possible,
   impossible
 };
index 7e7f2503d0c2c38b3c83207e5e8cd60768617796..a7d58015a5a45e1b3a30f247bab169b92bdb78e6 100644 (file)
@@ -455,7 +455,6 @@ mbfile_getc (mbchar_t mbc, mbfile_t mbf)
                  /* An invalid multibyte sequence was encountered.  */
                  /* Return a single byte.  */
                  if (signal_eilseq)
-                   /* xgettext: c-format */
                    po_gram_error (_("invalid multibyte sequence"));
                  bytes = 1;
                  mbc->uc_valid = false;
@@ -484,7 +483,6 @@ mbfile_getc (mbchar_t mbc, mbfile_t mbf)
                      if (ferror (mbf->fp))
                        goto eof;
                      if (signal_eilseq)
-                       /* xgettext: c-format */
                        po_gram_error (_("\
 incomplete multibyte sequence at end of file"));
                      bytes = mbf->bufcount;
@@ -495,7 +493,6 @@ incomplete multibyte sequence at end of file"));
                  if (c == '\n')
                    {
                      if (signal_eilseq)
-                       /* xgettext: c-format */
                        po_gram_error (_("\
 incomplete multibyte sequence at end of line"));
                      bytes = mbf->bufcount - 1;
@@ -847,7 +844,6 @@ control_sequence ()
       /* FIXME: \u and \U are not handled.  */
       }
   lex_ungetc (mbc);
-  /* xgettext: c-format */
   po_gram_error (_("invalid control sequence"));
   return ' ';
 }
index 9992ddbf75a353b35987126066f4f239340e0629..ef5a04fe913503c321e7b4a1ce383335de501444 100644 (file)
@@ -79,6 +79,7 @@ make_format_description_string (enum is_format is_format, const char *lang,
          break;
        }
       /* FALLTHROUGH */
+    case yes_according_to_context:
     case yes:
       sprintf (result, " %s-format", lang);
       break;
index 5d5dfefa419fc586c2d2fe4733eae67821ffa885..b3296210a8cf86649b79a29229251467593667e9 100644 (file)
@@ -28,8 +28,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-awk.h"
 #include "xgettext.h"
+#include "x-awk.h"
 #include "error.h"
 #include "error-progname.h"
 #include "xmalloc.h"
@@ -102,6 +102,15 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_awk ()
+{
+  xgettext_record_flag ("dcgettext:1:pass-awk-format");
+  xgettext_record_flag ("dcngettext:1:pass-awk-format");
+  xgettext_record_flag ("dcngettext:2:pass-awk-format");
+  xgettext_record_flag ("printf:1:awk-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -217,6 +226,7 @@ enum token_type_ty
   token_type_string,           /* "abc" */
   token_type_i18nstring,       /* _"abc" */
   token_type_symbol,           /* symbol, number */
+  token_type_semicolon,                /* ; */
   token_type_other             /* regexp, misc. operator */
 };
 typedef enum token_type_ty token_type_ty;
@@ -386,7 +396,9 @@ x_awk_lex (token_ty *tp)
          if (last_non_comment_line > last_comment_line)
            xgettext_comment_reset ();
          /* Newline is not allowed inside expressions.  It usually
-            introduces a fresh statement.  */
+            introduces a fresh statement.
+            FIXME: Newlines after any of ',' '{' '?' ':' '||' '&&' 'do' 'else'
+            does *not* introduce a fresh statement.  */
          prefer_division_over_regexp = false;
          /* FALLTHROUGH */
        case '\t':
@@ -538,6 +550,11 @@ x_awk_lex (token_ty *tp)
          prefer_division_over_regexp = false;
          return;
 
+       case ';':
+         tp->type = token_type_semicolon;
+         prefer_division_over_regexp = false;
+         return;
+
        case ']':
          tp->type = token_type_other;
          prefer_division_over_regexp = true;
@@ -643,6 +660,11 @@ x_awk_lex (token_ty *tp)
 
 /* ========================= Extracting strings.  ========================== */
 
+
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* The file is broken into tokens.  Scan the token stream, looking for
    a keyword, followed by a left paren, followed by a string.  When we
    see this sequence, we have something to remember.  We assume we are
@@ -667,6 +689,8 @@ x_awk_lex (token_ty *tp)
    Return true upon eof, false upon closing parenthesis.  */
 static bool
 extract_parenthesized (message_list_ty *mlp,
+                      flag_context_ty outer_context,
+                      flag_context_list_iterator_ty context_iter,
                       int commas_to_skip, int plural_commas)
 {
   /* Remember the message containing the msgid, for msgid_plural.  */
@@ -677,6 +701,16 @@ extract_parenthesized (message_list_ty *mlp,
   /* Parameters of the keyword just seen.  Defined only in state 1.  */
   int next_commas_to_skip = -1;
   int next_plural_commas = 0;
+  /* Whether to implicitly assume the next tokens are arguments even without
+     a '('.  */
+  bool next_is_argument = false;
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
 
   /* Start state is 0.  */
   state = 0;
@@ -686,6 +720,18 @@ extract_parenthesized (message_list_ty *mlp,
       token_ty token;
 
       x_awk_lex (&token);
+
+      if (next_is_argument && token.type != token_type_lparen)
+       {
+         /* An argument list starts, even though there is no '('.  */
+         context_iter = next_context_iter;
+         outer_context = inner_context;
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+       }
+
       switch (token.type)
        {
        case token_type_symbol:
@@ -706,15 +752,24 @@ extract_parenthesized (message_list_ty *mlp,
            else
              state = 0;
          }
+         next_is_argument =
+           (strcmp (token.string, "print") == 0
+            || strcmp (token.string, "printf") == 0);
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               token.string, strlen (token.string)));
          free (token.string);
          continue;
 
        case token_type_lparen:
-         if (state
-             ? extract_parenthesized (mlp, next_commas_to_skip,
-                                      next_plural_commas)
-             : extract_parenthesized (mlp, -1, 0))
+         if (extract_parenthesized (mlp, inner_context, next_context_iter,
+                                    state ? next_commas_to_skip : -1,
+                                    state ? next_plural_commas : 0))
            return true;
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -735,6 +790,12 @@ extract_parenthesized (message_list_ty *mlp,
                else
                  commas_to_skip = -1;
            }
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_is_argument = false;
+         next_context_iter = passthrough_context_list_iterator;
          state = 0;
          continue;
 
@@ -745,7 +806,7 @@ extract_parenthesized (message_list_ty *mlp,
            pos.line_number = token.line_number;
 
            if (extract_all)
-             remember_a_message (mlp, token.string, &pos);
+             remember_a_message (mlp, token.string, inner_context, &pos);
            else
              {
                if (commas_to_skip == 0)
@@ -753,8 +814,9 @@ extract_parenthesized (message_list_ty *mlp,
                    if (plural_mp == NULL)
                      {
                        /* Seen an msgid.  */
-                       message_ty *mp = remember_a_message (mlp, token.string,
-                                                            &pos);
+                       message_ty *mp =
+                         remember_a_message (mlp, token.string,
+                                             inner_context, &pos);
                        if (plural_commas > 0)
                          plural_mp = mp;
                      }
@@ -762,7 +824,7 @@ extract_parenthesized (message_list_ty *mlp,
                      {
                        /* Seen an msgid_plural.  */
                        remember_a_message_plural (plural_mp, token.string,
-                                                  &pos);
+                                                  inner_context, &pos);
                        plural_mp = NULL;
                      }
                  }
@@ -770,6 +832,8 @@ extract_parenthesized (message_list_ty *mlp,
                  free (token.string);
              }
          }
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -779,8 +843,28 @@ extract_parenthesized (message_list_ty *mlp,
            pos.file_name = logical_file_name;
            pos.line_number = token.line_number;
 
-           remember_a_message (mlp, token.string, &pos);
+           remember_a_message (mlp, token.string, inner_context, &pos);
          }
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
+         state = 0;
+         continue;
+
+       case token_type_semicolon:
+         /* An argument list ends, and a new statement begins.  */
+         /* FIXME: Should handle newline that acts as statement separator
+            in the same way.  */
+         /* FIXME: Instead of resetting outer_context here, it may be better
+            to recurse in the next_is_argument handling above, waiting for
+            the next semicolon or other statement terminator.  */
+         outer_context = null_context;
+         context_iter = null_context_list_iterator;
+         next_is_argument = false;
+         next_context_iter = passthrough_context_list_iterator;
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
          state = 0;
          continue;
 
@@ -788,6 +872,8 @@ extract_parenthesized (message_list_ty *mlp,
          return true;
 
        case token_type_other:
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -801,6 +887,7 @@ extract_parenthesized (message_list_ty *mlp,
 void
 extract_awk (FILE *f,
             const char *real_filename, const char *logical_filename,
+            flag_context_list_table_ty *flag_table,
             msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -815,11 +902,14 @@ extract_awk (FILE *f,
 
   prefer_division_over_regexp = false;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When extract_parenthesized returns
      due to an unbalanced closing parenthesis, just restart it.  */
-  while (!extract_parenthesized (mlp, -1, 0))
+  while (!extract_parenthesized (mlp, null_context, null_context_list_iterator,
+                                -1, 0))
     ;
 
   fp = NULL;
index 44ca341dbc13db5a41bffe7ae82bd67976d7541e..3838cbd711f1cf4aa4ebbdaaef3517e6b447d3fa 100644 (file)
   { "awk",    "awk"   },                                               \
 
 #define SCANNERS_AWK \
-  { "awk",        extract_awk, &formatstring_awk, NULL },              \
+  { "awk",             extract_awk,                                    \
+                       &flag_table_awk, &formatstring_awk, NULL },     \
 
 /* Scan an awk file and add its translatable strings to mdlp.  */
 extern void extract_awk (FILE *fp, const char *real_filename,
                         const char *logical_filename,
+                        flag_context_list_table_ty *flag_table,
                         msgdomain_list_ty *mdlp);
 
 extern void x_awk_keyword (const char *keyword);
 extern void x_awk_extract_all (void);
+
+extern void init_flag_table_awk (void);
index cb0d548d9163a3b4d9f98671955b8ec5a9bd2eea..b7f83446a0e7b90df602666b01d666b6ec9c0b28 100644 (file)
@@ -28,8 +28,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-c.h"
 #include "xgettext.h"
+#include "x-c.h"
 #include "error.h"
 #include "error-progname.h"
 #include "xmalloc.h"
@@ -155,6 +155,120 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_c ()
+{
+  xgettext_record_flag ("gettext:1:pass-c-format");
+  xgettext_record_flag ("dgettext:2:pass-c-format");
+  xgettext_record_flag ("dcgettext:2:pass-c-format");
+  xgettext_record_flag ("ngettext:1:pass-c-format");
+  xgettext_record_flag ("ngettext:2:pass-c-format");
+  xgettext_record_flag ("dngettext:2:pass-c-format");
+  xgettext_record_flag ("dngettext:3:pass-c-format");
+  xgettext_record_flag ("dcngettext:2:pass-c-format");
+  xgettext_record_flag ("dcngettext:3:pass-c-format");
+  xgettext_record_flag ("gettext_noop:1:pass-c-format");
+  /* <stdio.h> */
+  xgettext_record_flag ("fprintf:2:c-format");
+  xgettext_record_flag ("vfprintf:2:c-format");
+  xgettext_record_flag ("printf:1:c-format");
+  xgettext_record_flag ("vprintf:1:c-format");
+  xgettext_record_flag ("sprintf:2:c-format");
+  xgettext_record_flag ("vsprintf:2:c-format");
+  xgettext_record_flag ("snprintf:3:c-format");
+  xgettext_record_flag ("vsnprintf:3:c-format");
+#if 0 /* These functions are not standard.  */
+  /* <stdio.h> */
+  xgettext_record_flag ("asprintf:2:c-format");
+  xgettext_record_flag ("vasprintf:2:c-format");
+  xgettext_record_flag ("dprintf:2:c-format");
+  xgettext_record_flag ("vdprintf:2:c-format");
+  xgettext_record_flag ("obstack_printf:2:c-format");
+  xgettext_record_flag ("obstack_vprintf:2:c-format");
+  /* <error.h> */
+  xgettext_record_flag ("error:3:c-format");
+  xgettext_record_flag ("error_at_line:5:c-format");
+  /* <argp.h> */
+  xgettext_record_flag ("argp_error:2:c-format");
+  xgettext_record_flag ("argp_failure:2:c-format");
+#endif
+}
+
+void
+init_flag_table_gcc_internal ()
+{
+  xgettext_record_flag ("gettext:1:pass-gcc-internal-format");
+  xgettext_record_flag ("dgettext:2:pass-gcc-internal-format");
+  xgettext_record_flag ("dcgettext:2:pass-gcc-internal-format");
+  xgettext_record_flag ("ngettext:1:pass-gcc-internal-format");
+  xgettext_record_flag ("ngettext:2:pass-gcc-internal-format");
+  xgettext_record_flag ("dngettext:2:pass-gcc-internal-format");
+  xgettext_record_flag ("dngettext:3:pass-gcc-internal-format");
+  xgettext_record_flag ("dcngettext:2:pass-gcc-internal-format");
+  xgettext_record_flag ("dcngettext:3:pass-gcc-internal-format");
+  xgettext_record_flag ("gettext_noop:1:pass-gcc-internal-format");
+#if 0 /* This should better be done inside GCC.  */
+  /* grepping for ATTRIBUTE_PRINTF in gcc-3.3/gcc/?*.h */
+  /* c-format.c */
+  xgettext_record_flag ("status_warning:2:gcc-internal-format");
+  /* c-tree.h */
+  xgettext_record_flag ("pedwarn_c99:1:pass-gcc-internal-format");
+  /* collect2.h */
+  //xgettext_record_flag ("error:1:c-format"); // 3 different versions
+  xgettext_record_flag ("notice:1:c-format");
+  //xgettext_record_flag ("fatal:1:c-format"); // 2 different versions
+  xgettext_record_flag ("fatal_perror:1:c-format");
+  /* cpplib.h */
+  xgettext_record_flag ("cpp_error:3:c-format");
+  xgettext_record_flag ("cpp_error_with_line:5:c-format");
+  /* diagnostic.h */
+  xgettext_record_flag ("diagnostic_set_info:2:pass-gcc-internal-format");
+  xgettext_record_flag ("output_printf:2:gcc-internal-format");
+  xgettext_record_flag ("output_verbatim:2:pass-gcc-internal-format");
+  xgettext_record_flag ("verbatim:1:gcc-internal-format");
+  xgettext_record_flag ("inform:1:pass-gcc-internal-format");
+  /* gcc.h */
+  //xgettext_record_flag ("fatal:1:c-format"); // 2 different versions
+  //xgettext_record_flag ("error:1:c-format"); // 3 different versions
+  /* genattrtab.h */
+  xgettext_record_flag ("attr_printf:2:pass-c-format");
+  /* gengtype.h */
+  xgettext_record_flag ("error_at_line:2:pass-c-format");
+  xgettext_record_flag ("xvasprintf:2:pass-c-format");
+  xgettext_record_flag ("xasprintf:1:pass-c-format");
+  xgettext_record_flag ("oprintf:2:pass-c-format");
+  /* gensupport.h */
+  xgettext_record_flag ("message_with_line:2:pass-c-format");
+  /* output.h */
+  xgettext_record_flag ("output_operand_lossage:1:c-format");
+  /* ra.h */
+   xgettext_record_flag ("ra_debug_msg:2:pass-c-format");
+  /* toplev.h */
+  xgettext_record_flag ("fnotice:2:c-format");
+  xgettext_record_flag ("fatal_io_error:2:gcc-internal-format");
+  xgettext_record_flag ("error_for_asm:2:pass-gcc-internal-format");
+  xgettext_record_flag ("warning_for_asm:2:pass-gcc-internal-format");
+  xgettext_record_flag ("error_with_file_and_line:3:pass-gcc-internal-format");
+  xgettext_record_flag ("error_with_decl:2:pass-gcc-internal-format");
+  xgettext_record_flag ("pedwarn:1:gcc-internal-format");
+  xgettext_record_flag ("pedwarn_with_file_and_line:3:gcc-internal-format");
+  xgettext_record_flag ("pedwarn_with_decl:2:gcc-internal-format");
+  xgettext_record_flag ("sorry:1:gcc-internal-format");
+  xgettext_record_flag ("error:1:pass-gcc-internal-format");
+  xgettext_record_flag ("fatal_error:1:pass-gcc-internal-format");
+  xgettext_record_flag ("internal_error:1:pass-gcc-internal-format");
+  xgettext_record_flag ("warning:1:pass-gcc-internal-format");
+  xgettext_record_flag ("warning_with_file_and_line:3:pass-gcc-internal-format");
+  xgettext_record_flag ("warning_with_decl:2:pass-gcc-internal-format");
+  /* f/com.h */
+  xgettext_record_flag ("ffecom_get_invented_identifier:1:pass-c-format");
+  /* f/sts.h */
+  xgettext_record_flag ("ffests_printf:2:pass-c-format");
+  /* java/java-tree.h */
+  xgettext_record_flag ("parse_error_context:2:pass-c-format");
+#endif
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -1208,11 +1322,12 @@ enum xgettext_token_type_ty
 {
   xgettext_token_type_eof,
   xgettext_token_type_keyword,
+  xgettext_token_type_symbol,
   xgettext_token_type_lparen,
   xgettext_token_type_rparen,
   xgettext_token_type_comma,
   xgettext_token_type_string_literal,
-  xgettext_token_type_symbol
+  xgettext_token_type_other
 };
 typedef enum xgettext_token_type_ty xgettext_token_type_ty;
 
@@ -1225,7 +1340,8 @@ struct xgettext_token_ty
   int argnum1;
   int argnum2;
 
-  /* This field is used only for xgettext_token_type_string_literal.  */
+  /* This field is used only for xgettext_token_type_string_literal,
+     xgettext_token_type_keyword, xgettext_token_type_symbol.  */
   char *string;
 
   /* These fields are only for
@@ -1285,7 +1401,7 @@ x_c_lex (xgettext_token_ty *tp)
            }
          else
            tp->type = xgettext_token_type_symbol;
-         free (token.string);
+         tp->string = token.string;
          return;
 
        case token_type_lparen:
@@ -1318,7 +1434,7 @@ x_c_lex (xgettext_token_ty *tp)
        default:
          last_non_comment_line = newline_count;
 
-         tp->type = xgettext_token_type_symbol;
+         tp->type = xgettext_token_type_other;
          return;
        }
     }
@@ -1327,6 +1443,11 @@ x_c_lex (xgettext_token_ty *tp)
 
 /* ========================= Extracting strings.  ========================== */
 
+
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* The file is broken into tokens.  Scan the token stream, looking for
    a keyword, followed by a left paren, followed by a string.  When we
    see this sequence, we have something to remember.  We assume we are
@@ -1351,6 +1472,8 @@ x_c_lex (xgettext_token_ty *tp)
    Return true upon eof, false upon closing parenthesis.  */
 static bool
 extract_parenthesized (message_list_ty *mlp,
+                      flag_context_ty outer_context,
+                      flag_context_list_iterator_ty context_iter,
                       int commas_to_skip, int plural_commas)
 {
   /* Remember the message containing the msgid, for msgid_plural.  */
@@ -1361,6 +1484,13 @@ extract_parenthesized (message_list_ty *mlp,
   /* Parameters of the keyword just seen.  Defined only in state 1.  */
   int next_commas_to_skip = -1;
   int next_plural_commas = 0;
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
 
   /* Start state is 0.  */
   state = 0;
@@ -1376,15 +1506,31 @@ extract_parenthesized (message_list_ty *mlp,
          next_commas_to_skip = token.argnum1 - 1;
          next_plural_commas = (token.argnum2 > token.argnum1
                                ? token.argnum2 - token.argnum1 : 0);
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               token.string, strlen (token.string)));
+         free (token.string);
          state = 1;
          continue;
 
+       case xgettext_token_type_symbol:
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               token.string, strlen (token.string)));
+         free (token.string);
+         state = 0;
+         continue;
+
        case xgettext_token_type_lparen:
-         if (state
-             ? extract_parenthesized (mlp, next_commas_to_skip,
-                                      next_plural_commas)
-             : extract_parenthesized (mlp, -1, 0))
+         if (extract_parenthesized (mlp, inner_context, next_context_iter,
+                                    state ? next_commas_to_skip : -1,
+                                    state ? next_plural_commas : 0))
            return true;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1405,12 +1551,17 @@ extract_parenthesized (message_list_ty *mlp,
                else
                  commas_to_skip = -1;
            }
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_context_iter = passthrough_context_list_iterator;
          state = 0;
          continue;
 
        case xgettext_token_type_string_literal:
          if (extract_all)
-           remember_a_message (mlp, token.string, &token.pos);
+           remember_a_message (mlp, token.string, inner_context, &token.pos);
          else
            {
              if (commas_to_skip == 0)
@@ -1418,8 +1569,9 @@ extract_parenthesized (message_list_ty *mlp,
                  if (plural_mp == NULL)
                    {
                      /* Seen an msgid.  */
-                     message_ty *mp = remember_a_message (mlp, token.string,
-                                                          &token.pos);
+                     message_ty *mp =
+                       remember_a_message (mlp, token.string,
+                                           inner_context, &token.pos);
                      if (plural_commas > 0)
                        plural_mp = mp;
                    }
@@ -1427,17 +1579,19 @@ extract_parenthesized (message_list_ty *mlp,
                    {
                      /* Seen an msgid_plural.  */
                      remember_a_message_plural (plural_mp, token.string,
-                                                &token.pos);
+                                                inner_context, &token.pos);
                      plural_mp = NULL;
                    }
                }
              else
                free (token.string);
            }
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
-       case xgettext_token_type_symbol:
+       case xgettext_token_type_other:
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1454,6 +1608,7 @@ extract_parenthesized (message_list_ty *mlp,
 void
 extract_c (FILE *f,
           const char *real_filename, const char *logical_filename,
+          flag_context_list_table_ty *flag_table,
           msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -1467,11 +1622,14 @@ extract_c (FILE *f,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When extract_parenthesized returns
      due to an unbalanced closing parenthesis, just restart it.  */
-  while (!extract_parenthesized (mlp, -1, 0))
+  while (!extract_parenthesized (mlp, null_context, null_context_list_iterator,
+                                -1, 0))
     ;
 
   /* Close scanner.  */
index f79e7964642db1beb96aeca697f95ee288714188..df6ff9a62844fd6dd4f9bdcdaa5111d0cf7278c2 100644 (file)
   { "m",      "ObjectiveC" },                                          \
 
 #define SCANNERS_C \
-  { "C",          extract_c, &formatstring_c, NULL },                  \
-  { "C++",        extract_c, &formatstring_c, NULL },                  \
-  { "ObjectiveC", extract_c, &formatstring_c, NULL },                  \
-  { "GCC-source", extract_c, &formatstring_gcc_internal, NULL },       \
+  { "C",               extract_c,                                      \
+                       &flag_table_c, &formatstring_c, NULL },         \
+  { "C++",             extract_c,                                      \
+                       &flag_table_c, &formatstring_c, NULL },         \
+  { "ObjectiveC",      extract_c,                                      \
+                       &flag_table_c, &formatstring_c, NULL },         \
+  { "GCC-source",      extract_c,                                      \
+               &flag_table_gcc_internal, &formatstring_gcc_internal, NULL }, \
 
 /* Scan a C/C++/ObjectiveC 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);
 
 
@@ -50,3 +55,6 @@ extern void x_c_keyword (const char *name);
 extern bool x_c_any_keywords (void);
 
 extern void x_c_trigraphs (void);
+
+extern void init_flag_table_c (void);
+extern void init_flag_table_gcc_internal (void);
index 7bd7b3e10a0410af21b7274b808744cf80d8ced6..bde71c1d44cc2789f72eb4f429b07e20e75ef0a6 100644 (file)
@@ -28,8 +28,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-elisp.h"
 #include "xgettext.h"
+#include "x-elisp.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -116,6 +116,13 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_elisp ()
+{
+  xgettext_record_flag ("_:1:pass-elisp-format");
+  xgettext_record_flag ("format:1:elisp-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -424,6 +431,9 @@ string_of_object (const struct object *op)
   return str;
 }
 
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
 /* Returns the character represented by an escape sequence.  */
 #define IGNORABLE_ESCAPE (EOF - 1)
 static int
@@ -609,7 +619,8 @@ do_getc_escaped (int c, bool in_string)
    'first_in_list' and 'new_backquote_flag' are used for reading old
    backquote syntax and new backquote syntax.  */
 static void
-read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
+read_object (struct object *op, bool first_in_list, bool new_backquote_flag,
+            flag_context_ty outer_context)
 {
   for (;;)
     {
@@ -634,6 +645,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
        case '(':
          {
            int arg = 0;                /* Current argument number.  */
+           flag_context_list_iterator_ty context_iter;
            int argnum1 = 0;            /* First string position.  */
            int argnum2 = 0;            /* Plural string position.  */
            message_ty *plural_mp = NULL;       /* Remember the msgid.  */
@@ -641,8 +653,18 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
            for (;; arg++)
              {
                struct object inner;
+               flag_context_ty inner_context;
 
-               read_object (&inner, arg == 0, new_backquote_flag);
+               if (arg == 0)
+                 inner_context = null_context;
+               else
+                 inner_context =
+                   inherited_context (outer_context,
+                                      flag_context_list_iterator_advance (
+                                        &context_iter));
+
+               read_object (&inner, arg == 0, new_backquote_flag,
+                            inner_context);
 
                /* Recognize end of list.  */
                if (inner.type == t_listclose)
@@ -677,8 +699,16 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
                            argnum2 = (int) (long) keyword_value >> 10;
                          }
 
+                       context_iter =
+                         flag_context_list_iterator (
+                           flag_context_list_table_lookup (
+                             flag_context_list_table,
+                             symbol_name, strlen (symbol_name)));
+
                        free (symbol_name);
                      }
+                   else
+                     context_iter = null_context_list_iterator;
                  }
                else
                  {
@@ -694,7 +724,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
 
                            pos.file_name = logical_file_name;
                            pos.line_number = inner.line_number_at_start;
-                           mp = remember_a_message (mlp, string_of_object (&inner), &pos);
+                           mp = remember_a_message (mlp, string_of_object (&inner),
+                                                    inner_context, &pos);
                            if (argnum2 > 0)
                              plural_mp = mp;
                          }
@@ -707,7 +738,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
 
                            pos.file_name = logical_file_name;
                            pos.line_number = inner.line_number_at_start;
-                           remember_a_message_plural (plural_mp, string_of_object (&inner), &pos);
+                           remember_a_message_plural (plural_mp, string_of_object (&inner),
+                                                      inner_context, &pos);
                          }
                      }
                  }
@@ -732,7 +764,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
              {
                struct object inner;
 
-               read_object (&inner, false, new_backquote_flag);
+               read_object (&inner, false, new_backquote_flag, null_context);
 
                /* Recognize end of vector.  */
                if (inner.type == t_vectorclose)
@@ -766,7 +798,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
          {
            struct object inner;
 
-           read_object (&inner, false, new_backquote_flag);
+           read_object (&inner, false, new_backquote_flag, null_context);
 
            /* Dots and EOF are not allowed here.  But be tolerant.  */
 
@@ -783,7 +815,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
          {
            struct object inner;
 
-           read_object (&inner, false, true);
+           read_object (&inner, false, true, null_context);
 
            /* Dots and EOF are not allowed here.  But be tolerant.  */
 
@@ -807,7 +839,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
          {
            struct object inner;
 
-           read_object (&inner, false, false);
+           read_object (&inner, false, false, null_context);
 
            /* Dots and EOF are not allowed here.  But be tolerant.  */
 
@@ -884,7 +916,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
 
                pos.file_name = logical_file_name;
                pos.line_number = op->line_number_at_start;
-               remember_a_message (mlp, string_of_object (op), &pos);
+               remember_a_message (mlp, string_of_object (op),
+                                   null_context, &pos);
              }
            last_non_comment_line = line_number;
            return;
@@ -937,7 +970,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
                    {
                      struct object inner;
 
-                     read_object (&inner, false, new_backquote_flag);
+                     read_object (&inner, false, new_backquote_flag,
+                                  null_context);
 
                      /* Recognize end of vector.  */
                      if (inner.type == t_vectorclose)
@@ -972,7 +1006,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
              /* Read a bit vector.  */
              {
                struct object length;
-               read_object (&length, first_in_list, new_backquote_flag);
+               read_object (&length, first_in_list, new_backquote_flag,
+                            null_context);
                /* Dots and EOF are not allowed here.
                   But be tolerant.  */
                free_object (&length);
@@ -981,7 +1016,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
              if (c == '"')
                {
                  struct object string;
-                 read_object (&string, first_in_list, new_backquote_flag);
+                 read_object (&string, first_in_list, new_backquote_flag,
+                              null_context);
                  free_object (&string);
                }
              else
@@ -998,7 +1034,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
              {
                struct object inner;
                do_ungetc (c);
-               read_object (&inner, false, new_backquote_flag);
+               read_object (&inner, false, new_backquote_flag, null_context);
                /* Dots and EOF are not allowed here.
                   But be tolerant.  */
                free_object (&inner);
@@ -1039,7 +1075,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
            case 'S': case 's': /* XEmacs only */
              {
                struct object inner;
-               read_object (&inner, false, new_backquote_flag);
+               read_object (&inner, false, new_backquote_flag, null_context);
                /* Dots and EOF are not allowed here.
                   But be tolerant.  */
                free_object (&inner);
@@ -1065,7 +1101,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
                }
              if (c == '=')
                {
-                 read_object (op, false, new_backquote_flag);
+                 read_object (op, false, new_backquote_flag, outer_context);
                  last_non_comment_line = line_number;
                  return;
                }
@@ -1133,7 +1169,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
              /* Simply assume every feature expression is true.  */
              {
                struct object inner;
-               read_object (&inner, false, new_backquote_flag);
+               read_object (&inner, false, new_backquote_flag, null_context);
                /* Dots and EOF are not allowed here.
                   But be tolerant.  */
                free_object (&inner);
@@ -1198,6 +1234,7 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag)
 void
 extract_elisp (FILE *f,
               const char *real_filename, const char *logical_filename,
+              flag_context_list_table_ty *flag_table,
               msgdomain_list_ty *mdlp)
 {
   mlp = mdlp->item[0]->messages;
@@ -1210,6 +1247,8 @@ extract_elisp (FILE *f,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When read_object returns
@@ -1218,7 +1257,7 @@ extract_elisp (FILE *f,
     {
       struct object toplevel_object;
 
-      read_object (&toplevel_object, false, false);
+      read_object (&toplevel_object, false, false, null_context);
 
       if (toplevel_object.type == t_eof)
        break;
index a9d338e9dda71a90c901af17b5015ff5d3b1724e..e9059ad42e46d9b3db5eb6559b423bdaf837b64f 100644 (file)
   { "el",        "EmacsLisp"     },                                    \
 
 #define SCANNERS_ELISP \
-  { "EmacsLisp",  extract_elisp, &formatstring_elisp, NULL },          \
+  { "EmacsLisp",       extract_elisp,                                  \
+                       &flag_table_elisp, &formatstring_elisp, NULL }, \
 
 /* Scan an Emacs Lisp file and add its translatable strings to mdlp.  */
 extern void extract_elisp (FILE *fp, const char *real_filename,
                           const char *logical_filename,
+                          flag_context_list_table_ty *flag_table,
                           msgdomain_list_ty *mdlp);
 
 
@@ -33,3 +35,5 @@ extern void extract_elisp (FILE *fp, const char *real_filename,
 
 extern void x_elisp_extract_all (void);
 extern void x_elisp_keyword (const char *name);
+
+extern void init_flag_table_elisp (void);
index 72e4e5d72044e19e3d409bafa871fda166587466..38a2a903cc44dcec2c2a4d02210cee2ae7d202f6 100644 (file)
@@ -35,8 +35,8 @@
 #endif
 
 #include "message.h"
-#include "x-glade.h"
 #include "xgettext.h"
+#include "x-glade.h"
 #include "error.h"
 #include "xerror.h"
 #include "basename.h"
@@ -268,7 +268,8 @@ start_element_handler (void *userData, const char *name,
                  pos.file_name = logical_file_name;
                  pos.line_number = XML_GetCurrentLineNumber (parser);
 
-                 remember_a_message (mlp, xstrdup (attp[1]), &pos);
+                 remember_a_message (mlp, xstrdup (attp[1]),
+                                     null_context, &pos);
                }
              break;
            }
@@ -304,7 +305,7 @@ end_element_handler (void *userData, const char *name)
          pos.file_name = logical_file_name;
          pos.line_number = p->lineno;
 
-         remember_a_message (mlp, p->buffer, &pos);
+         remember_a_message (mlp, p->buffer, null_context, &pos);
          p->buffer = NULL;
        }
     }
@@ -433,6 +434,7 @@ error while reading \"%s\""), real_filename);
 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
index b7872fd0d92b18b8744bfd85d1651e6836a4eb0b..37b446498fe0cd44a110094099d6559ba5e529af 100644 (file)
   { "glade2",    "glade"    },                                         \
 
 #define SCANNERS_GLADE \
-  { "glade",      extract_glade, NULL, NULL },                         \
+  { "glade",           extract_glade, 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);
 
 
index dd0f9cd2780e9b2e510e037f4f1a67196dffe762..68452fc9f22038064fa15797112039a64916294b 100644 (file)
@@ -27,8 +27,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-java.h"
 #include "xgettext.h"
+#include "x-java.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -110,6 +110,20 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_java ()
+{
+  xgettext_record_flag ("GettextResource.gettext:2:pass-java-format");
+  xgettext_record_flag ("GettextResource.ngettext:2:pass-java-format");
+  xgettext_record_flag ("GettextResource.ngettext:3:pass-java-format");
+  xgettext_record_flag ("gettext:1:pass-java-format");
+  xgettext_record_flag ("ngettext:1:pass-java-format");
+  xgettext_record_flag ("ngettext:2:pass-java-format");
+  xgettext_record_flag ("getString:1:pass-java-format");
+  xgettext_record_flag ("MessageFormat:1:java-format");
+  xgettext_record_flag ("MessageFormat.format:1:java-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -1202,6 +1216,11 @@ x_java_unlex (token_ty *tp)
 
 /* ========================= Extracting strings.  ========================== */
 
+
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* The file is broken into tokens.  Scan the token stream, looking for
    a keyword, followed by a left paren, followed by a string.  When we
    see this sequence, we have something to remember.  We assume we are
@@ -1227,6 +1246,8 @@ x_java_unlex (token_ty *tp)
    Return true upon eof, false upon closing parenthesis or brace.  */
 static bool
 extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
+                      flag_context_ty outer_context,
+                      flag_context_list_iterator_ty context_iter,
                       int commas_to_skip, int plural_commas)
 {
   /* Remember the message containing the msgid, for msgid_plural.  */
@@ -1237,6 +1258,13 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
   /* Parameters of the keyword just seen.  Defined only in state 1.  */
   int next_commas_to_skip = -1;
   int next_plural_commas = 0;
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
 
   /* Start state is 0.  */
   state = 0;
@@ -1258,6 +1286,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
            char *sum = token.string;
            size_t sum_len = strlen (sum);
            const char *dottedname;
+           flag_context_list_ty *context_list;
 
            for (;;)
              {
@@ -1315,15 +1344,34 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
                  }
                dottedname++;
              }
+
+           for (dottedname = sum;;)
+             {
+               context_list =
+                 flag_context_list_table_lookup (
+                   flag_context_list_table,
+                   dottedname, strlen (dottedname));
+               if (context_list != NULL)
+                 break;
+
+               dottedname = strchr (dottedname, '.');
+               if (dottedname == NULL)
+                 break;
+               dottedname++;
+             }
+           next_context_iter = flag_context_list_iterator (context_list);
+
            free (sum);
            continue;
          }
 
        case token_type_lparen:
          if (extract_parenthesized (mlp, token_type_rparen,
+                                    inner_context, next_context_iter,
                                     state ? next_commas_to_skip : -1,
                                     state ? next_plural_commas : 0))
            return true;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1338,12 +1386,16 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
                     logical_file_name, token.line_number);
              error_with_progname = true;
            }
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
        case token_type_lbrace:
-         if (extract_parenthesized (mlp, token_type_rbrace, -1, 0))
+         if (extract_parenthesized (mlp, token_type_rbrace,
+                                    null_context, null_context_list_iterator,
+                                    -1, 0))
            return true;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1358,6 +1410,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
                     logical_file_name, token.line_number);
              error_with_progname = true;
            }
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1375,6 +1428,11 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
                else
                  commas_to_skip = -1;
            }
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_context_iter = passthrough_context_list_iterator;
          state = 0;
          continue;
 
@@ -1388,7 +1446,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
              {
                xgettext_current_source_encoding = po_charset_utf8;
                x_java_comment_to_xgettext_comment (token.comment);
-               remember_a_message (mlp, token.string, &pos);
+               remember_a_message (mlp, token.string, inner_context, &pos);
                x_java_comment_reset ();
                xgettext_current_source_encoding = xgettext_global_source_encoding;
              }
@@ -1403,7 +1461,8 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
 
                        xgettext_current_source_encoding = po_charset_utf8;
                        x_java_comment_to_xgettext_comment (token.comment);
-                       mp = remember_a_message (mlp, token.string, &pos);
+                       mp = remember_a_message (mlp, token.string,
+                                                inner_context, &pos);
                        x_java_comment_reset ();
                        xgettext_current_source_encoding = xgettext_global_source_encoding;
                        if (plural_commas > 0)
@@ -1414,7 +1473,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
                        /* Seen an msgid_plural.  */
                        xgettext_current_source_encoding = po_charset_utf8;
                        remember_a_message_plural (plural_mp, token.string,
-                                                  &pos);
+                                                  inner_context, &pos);
                        xgettext_current_source_encoding = xgettext_global_source_encoding;
                        plural_mp = NULL;
                      }
@@ -1424,6 +1483,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
              }
          }
          drop_reference (token.comment);
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1434,6 +1494,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
        case token_type_number:
        case token_type_plus:
        case token_type_other:
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1447,6 +1508,7 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
 void
 extract_java (FILE *f,
              const char *real_filename, const char *logical_filename,
+             flag_context_list_table_ty *flag_table,
              msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -1461,11 +1523,15 @@ extract_java (FILE *f,
 
   phase6_last = token_type_eof;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When extract_parenthesized returns
      due to an unbalanced closing parenthesis, just restart it.  */
-  while (!extract_parenthesized (mlp, token_type_eof, -1, 0))
+  while (!extract_parenthesized (mlp, token_type_eof,
+                                null_context, null_context_list_iterator,
+                                -1, 0))
     ;
 
   fp = NULL;
index 50d17f6abf69ed0a1a3ac0fc41640c990db18034..1aa61f50a6c396f3414741061767a488459418bb 100644 (file)
   { "java",    "Java"  },                                              \
 
 #define SCANNERS_JAVA \
-  { "Java",        extract_java, &formatstring_java, NULL },           \
+  { "Java",            extract_java,                                   \
+                       &flag_table_java, &formatstring_java, NULL },   \
 
 extern void extract_java (FILE *fp, const char *real_filename,
                          const char *logical_filename,
+                         flag_context_list_table_ty *flag_table,
                          msgdomain_list_ty *mdlp);
 
 extern void x_java_keyword (const char *keyword);
 extern void x_java_extract_all (void);
+
+extern void init_flag_table_java (void);
index 036c3686f11a0e1b5758ec18347e3ab9929c0138..78858929ea86a90c91555a8ebbf7c52a35f0d927 100644 (file)
@@ -29,8 +29,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-librep.h"
 #include "xgettext.h"
+#include "x-librep.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -118,6 +118,13 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_librep ()
+{
+  xgettext_record_flag ("_:1:pass-librep-format");
+  xgettext_record_flag ("format:2:librep-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -504,6 +511,9 @@ string_of_object (const struct object *op)
   return str;
 }
 
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
 /* Returns the character represented by an escape sequence.  */
 static int
 do_getc_escaped (int c)
@@ -582,7 +592,7 @@ do_getc_escaped (int c)
 
 /* Read the next object.  */
 static void
-read_object (struct object *op)
+read_object (struct object *op, flag_context_ty outer_context)
 {
   for (;;)
     {
@@ -610,6 +620,7 @@ read_object (struct object *op)
        case '(':
          {
            int arg = 0;                /* Current argument number.  */
+           flag_context_list_iterator_ty context_iter;
            int argnum1 = 0;            /* First string position.  */
            int argnum2 = 0;            /* Plural string position.  */
            message_ty *plural_mp = NULL;       /* Remember the msgid.  */
@@ -617,8 +628,17 @@ read_object (struct object *op)
            for (;; arg++)
              {
                struct object inner;
+               flag_context_ty inner_context;
 
-               read_object (&inner);
+               if (arg == 0)
+                 inner_context = null_context;
+               else
+                 inner_context =
+                   inherited_context (outer_context,
+                                      flag_context_list_iterator_advance (
+                                        &context_iter));
+
+               read_object (&inner, inner_context);
 
                /* Recognize end of list.  */
                if (inner.type == t_close)
@@ -653,8 +673,16 @@ read_object (struct object *op)
                            argnum2 = (int) (long) keyword_value >> 10;
                          }
 
+                       context_iter =
+                         flag_context_list_iterator (
+                           flag_context_list_table_lookup (
+                             flag_context_list_table,
+                             symbol_name, strlen (symbol_name)));
+
                        free (symbol_name);
                      }
+                   else
+                     context_iter = null_context_list_iterator;
                  }
                else
                  {
@@ -670,7 +698,8 @@ read_object (struct object *op)
 
                            pos.file_name = logical_file_name;
                            pos.line_number = inner.line_number_at_start;
-                           mp = remember_a_message (mlp, string_of_object (&inner), &pos);
+                           mp = remember_a_message (mlp, string_of_object (&inner),
+                                                    inner_context, &pos);
                            if (argnum2 > 0)
                              plural_mp = mp;
                          }
@@ -683,7 +712,8 @@ read_object (struct object *op)
 
                            pos.file_name = logical_file_name;
                            pos.line_number = inner.line_number_at_start;
-                           remember_a_message_plural (plural_mp, string_of_object (&inner), &pos);
+                           remember_a_message_plural (plural_mp, string_of_object (&inner),
+                                                      inner_context, &pos);
                          }
                      }
                  }
@@ -701,7 +731,7 @@ read_object (struct object *op)
              {
                struct object inner;
 
-               read_object (&inner);
+               read_object (&inner, null_context);
 
                /* Recognize end of vector.  */
                if (inner.type == t_close)
@@ -745,7 +775,7 @@ read_object (struct object *op)
          {
            struct object inner;
 
-           read_object (&inner);
+           read_object (&inner, null_context);
 
            /* Dots and EOF are not allowed here.  But be tolerant.  */
 
@@ -822,7 +852,8 @@ read_object (struct object *op)
 
                pos.file_name = logical_file_name;
                pos.line_number = op->line_number_at_start;
-               remember_a_message (mlp, string_of_object (op), &pos);
+               remember_a_message (mlp, string_of_object (op),
+                                   null_context, &pos);
              }
            last_non_comment_line = line_number;
            return;
@@ -894,7 +925,7 @@ read_object (struct object *op)
            case ':':
              {
                struct object inner;
-               read_object (&inner);
+               read_object (&inner, null_context);
                /* Dots and EOF are not allowed here.
                   But be tolerant.  */
                free_object (&inner);
@@ -908,7 +939,7 @@ read_object (struct object *op)
              {
                struct object inner;
                do_ungetc (c);
-               read_object (&inner);
+               read_object (&inner, null_context);
                /* Dots and EOF are not allowed here.
                   But be tolerant.  */
                free_object (&inner);
@@ -1081,6 +1112,7 @@ read_object (struct object *op)
 void
 extract_librep (FILE *f,
                const char *real_filename, const char *logical_filename,
+               flag_context_list_table_ty *flag_table,
                msgdomain_list_ty *mdlp)
 {
   mlp = mdlp->item[0]->messages;
@@ -1093,6 +1125,8 @@ extract_librep (FILE *f,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When read_object returns
@@ -1101,7 +1135,7 @@ extract_librep (FILE *f,
     {
       struct object toplevel_object;
 
-      read_object (&toplevel_object);
+      read_object (&toplevel_object, null_context);
 
       if (toplevel_object.type == t_eof)
        break;
index 2dc4cc5f5626b31eb10cafc3fcd49fece573631b..aaa766402a488dcf8727ffe78b352e2bb82edbeb 100644 (file)
   { "jl",        "librep"     },                                       \
 
 #define SCANNERS_LIBREP \
-  { "librep",     extract_librep, &formatstring_librep, NULL },                \
+  { "librep",          extract_librep,                                   \
+                       &flag_table_librep, &formatstring_librep, NULL }, \
 
 /* Scan a librep file and add its translatable strings to mdlp.  */
 extern void extract_librep (FILE *fp, const char *real_filename,
                            const char *logical_filename,
+                           flag_context_list_table_ty *flag_table,
                            msgdomain_list_ty *mdlp);
 
 
@@ -33,3 +35,5 @@ extern void extract_librep (FILE *fp, const char *real_filename,
 
 extern void x_librep_extract_all (void);
 extern void x_librep_keyword (const char *name);
+
+extern void init_flag_table_librep (void);
index 14cf7db463bfeee9a7e1f9e74c43d474ccd43d28..4a1e7bff9db8e7e88b398a6e8bd5f4e8c423f00a 100644 (file)
@@ -28,8 +28,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-lisp.h"
 #include "xgettext.h"
+#include "x-lisp.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -178,6 +178,16 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_lisp ()
+{
+  xgettext_record_flag ("gettext:1:pass-lisp-format");
+  xgettext_record_flag ("ngettext:1:pass-lisp-format");
+  xgettext_record_flag ("ngettext:2:pass-lisp-format");
+  xgettext_record_flag ("gettext-noop:1:pass-lisp-format");
+  xgettext_record_flag ("format:2:lisp-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -919,9 +929,12 @@ string_of_object (const struct object *op)
   return str;
 }
 
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
 /* Read the next object.  */
 static void
-read_object (struct object *op)
+read_object (struct object *op, flag_context_ty outer_context)
 {
   for (;;)
     {
@@ -998,6 +1011,7 @@ read_object (struct object *op)
            case '(':
              {
                int arg = 0;            /* Current argument number.  */
+               flag_context_list_iterator_ty context_iter;
                int argnum1 = 0;        /* First string position.  */
                int argnum2 = 0;        /* Plural string position.  */
                message_ty *plural_mp = NULL;   /* Remember the msgid.  */
@@ -1005,8 +1019,17 @@ read_object (struct object *op)
                for (;; arg++)
                  {
                    struct object inner;
+                   flag_context_ty inner_context;
+
+                   if (arg == 0)
+                     inner_context = null_context;
+                   else
+                     inner_context =
+                       inherited_context (outer_context,
+                                          flag_context_list_iterator_advance (
+                                            &context_iter));
 
-                   read_object (&inner);
+                   read_object (&inner, inner_context);
 
                    /* Recognize end of list.  */
                    if (inner.type == t_close)
@@ -1052,8 +1075,16 @@ read_object (struct object *op)
                                argnum2 = (int) (long) keyword_value >> 10;
                              }
 
+                           context_iter =
+                             flag_context_list_iterator (
+                               flag_context_list_table_lookup (
+                                 flag_context_list_table,
+                                 symbol_name, strlen (symbol_name)));
+
                            free (symbol_name);
                          }
+                       else
+                         context_iter = null_context_list_iterator;
                      }
                    else
                      {
@@ -1069,7 +1100,8 @@ read_object (struct object *op)
 
                                pos.file_name = logical_file_name;
                                pos.line_number = inner.line_number_at_start;
-                               mp = remember_a_message (mlp, string_of_object (&inner), &pos);
+                               mp = remember_a_message (mlp, string_of_object (&inner),
+                                                        inner_context, &pos);
                                if (argnum2 > 0)
                                  plural_mp = mp;
                              }
@@ -1082,7 +1114,8 @@ read_object (struct object *op)
 
                                pos.file_name = logical_file_name;
                                pos.line_number = inner.line_number_at_start;
-                               remember_a_message_plural (plural_mp, string_of_object (&inner), &pos);
+                               remember_a_message_plural (plural_mp, string_of_object (&inner),
+                                                          inner_context, &pos);
                              }
                          }
                      }
@@ -1116,7 +1149,7 @@ read_object (struct object *op)
              {
                struct object inner;
 
-               read_object (&inner);
+               read_object (&inner, null_context);
 
                /* Dots and EOF are not allowed here.  But be tolerant.  */
 
@@ -1178,7 +1211,8 @@ read_object (struct object *op)
 
                    pos.file_name = logical_file_name;
                    pos.line_number = op->line_number_at_start;
-                   remember_a_message (mlp, string_of_object (op), &pos);
+                   remember_a_message (mlp, string_of_object (op),
+                                       null_context, &pos);
                  }
                last_non_comment_line = line_number;
                return;
@@ -1218,7 +1252,7 @@ read_object (struct object *op)
                  case 'S': case 's':
                    {
                      struct object inner;
-                     read_object (&inner);
+                     read_object (&inner, null_context);
                      /* Dots and EOF are not allowed here.
                         But be tolerant.  */
                      free_object (&inner);
@@ -1336,7 +1370,7 @@ read_object (struct object *op)
                    /* Simply assume every feature expression is true.  */
                    {
                      struct object inner;
-                     read_object (&inner);
+                     read_object (&inner, null_context);
                      /* Dots and EOF are not allowed here.
                         But be tolerant.  */
                      free_object (&inner);
@@ -1368,6 +1402,7 @@ read_object (struct object *op)
 void
 extract_lisp (FILE *f,
              const char *real_filename, const char *logical_filename,
+             flag_context_list_table_ty *flag_table,
              msgdomain_list_ty *mdlp)
 {
   mlp = mdlp->item[0]->messages;
@@ -1380,6 +1415,8 @@ extract_lisp (FILE *f,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When read_object returns
@@ -1388,7 +1425,7 @@ extract_lisp (FILE *f,
     {
       struct object toplevel_object;
 
-      read_object (&toplevel_object);
+      read_object (&toplevel_object, null_context);
 
       if (toplevel_object.type == t_eof)
        break;
index 63c447cd2e5872b06a5aa15d17929da630a03450..fb919a140c31f160a15b3a34fce6037c1705387e 100644 (file)
   { "lisp",      "Lisp"     },                                         \
 
 #define SCANNERS_LISP \
-  { "Lisp",       extract_lisp, &formatstring_lisp, NULL },            \
+  { "Lisp",            extract_lisp,                                   \
+                       &flag_table_lisp, &formatstring_lisp, NULL },   \
 
 /* Scan a Lisp file and add its translatable strings to mdlp.  */
 extern void extract_lisp (FILE *fp, const char *real_filename,
                          const char *logical_filename,
+                         flag_context_list_table_ty *flag_table,
                          msgdomain_list_ty *mdlp);
 
 
@@ -33,3 +35,5 @@ extern void extract_lisp (FILE *fp, const char *real_filename,
 
 extern void x_lisp_extract_all (void);
 extern void x_lisp_keyword (const char *name);
+
+extern void init_flag_table_lisp (void);
index 03a8b1cfe778b9c267b063fe253488b760f4ab43..3928cf6ed8a09d1d2089e4873e585c73f6d7fa3c 100644 (file)
@@ -28,8 +28,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-perl.h"
 #include "xgettext.h"
+#include "x-perl.h"
 #include "error.h"
 #include "error-progname.h"
 #include "xmalloc.h"
@@ -112,10 +112,70 @@ init_keywords ()
       x_perl_keyword ("dngettext:2,3");
       x_perl_keyword ("dcngettext:2,3");
       x_perl_keyword ("gettext_noop");
+#if 0
+      x_perl_keyword ("__");
+      x_perl_keyword ("$__");
+      x_perl_keyword ("%__");
+      x_perl_keyword ("__x");
+      x_perl_keyword ("__n:1,2");
+      x_perl_keyword ("__nx:1,2");
+      x_perl_keyword ("__xn:1,2");
+      x_perl_keyword ("N__");
+#endif
       default_keywords = false;
     }
 }
 
+void
+init_flag_table_perl ()
+{
+  xgettext_record_flag ("gettext:1:pass-perl-format");
+  xgettext_record_flag ("gettext:1:pass-perl-brace-format");
+  xgettext_record_flag ("%gettext:1:pass-perl-format");
+  xgettext_record_flag ("%gettext:1:pass-perl-brace-format");
+  xgettext_record_flag ("$gettext:1:pass-perl-format");
+  xgettext_record_flag ("$gettext:1:pass-perl-brace-format");
+  xgettext_record_flag ("dgettext:2:pass-perl-format");
+  xgettext_record_flag ("dgettext:2:pass-perl-brace-format");
+  xgettext_record_flag ("dcgettext:2:pass-perl-format");
+  xgettext_record_flag ("dcgettext:2:pass-perl-brace-format");
+  xgettext_record_flag ("ngettext:1:pass-perl-format");
+  xgettext_record_flag ("ngettext:2:pass-perl-format");
+  xgettext_record_flag ("ngettext:1:pass-perl-brace-format");
+  xgettext_record_flag ("ngettext:2:pass-perl-brace-format");
+  xgettext_record_flag ("dngettext:2:pass-perl-format");
+  xgettext_record_flag ("dngettext:3:pass-perl-format");
+  xgettext_record_flag ("dngettext:2:pass-perl-brace-format");
+  xgettext_record_flag ("dngettext:3:pass-perl-brace-format");
+  xgettext_record_flag ("dcngettext:2:pass-perl-format");
+  xgettext_record_flag ("dcngettext:3:pass-perl-format");
+  xgettext_record_flag ("dcngettext:2:pass-perl-brace-format");
+  xgettext_record_flag ("dcngettext:3:pass-perl-brace-format");
+  xgettext_record_flag ("gettext_noop:1:pass-perl-format");
+  xgettext_record_flag ("gettext_noop:1:pass-perl-brace-format");
+  xgettext_record_flag ("printf:1:perl-format"); /* argument 1 or 2 ?? */
+  xgettext_record_flag ("sprintf:1:perl-format");
+#if 0 
+  xgettext_record_flag ("__:1:pass-perl-format");
+  xgettext_record_flag ("__:1:pass-perl-brace-format");
+  xgettext_record_flag ("%__:1:pass-perl-format");
+  xgettext_record_flag ("%__:1:pass-perl-brace-format");
+  xgettext_record_flag ("$__:1:pass-perl-format");
+  xgettext_record_flag ("$__:1:pass-perl-brace-format");
+  xgettext_record_flag ("__x:1:perl-brace-format");
+  xgettext_record_flag ("__n:1:pass-perl-format");
+  xgettext_record_flag ("__n:2:pass-perl-format");
+  xgettext_record_flag ("__n:1:pass-perl-brace-format");
+  xgettext_record_flag ("__n:2:pass-perl-brace-format");
+  xgettext_record_flag ("__nx:1:perl-brace-format");
+  xgettext_record_flag ("__nx:2:perl-brace-format");
+  xgettext_record_flag ("__xn:1:perl-brace-format");
+  xgettext_record_flag ("__xn:2:perl-brace-format");
+  xgettext_record_flag ("N__:1:pass-perl-format");
+  xgettext_record_flag ("N__:1:pass-perl-brace-format");
+#endif
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -694,12 +754,20 @@ extract_quotelike_pass1_utf8 (int delim)
    of an expression, it's a regexp.  */
 static bool prefer_division_over_regexp;
 
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
 
 /* Forward declaration of local functions.  */
-static void interpolate_keywords (message_list_ty *mlp, const char *string, int lineno);
+static void interpolate_keywords (message_list_ty *mlp, const char *string,
+                                 int lineno);
 static token_ty *x_perl_lex (message_list_ty *mlp);
 static void x_perl_unlex (token_ty *tp);
-static bool extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state, token_type_ty delim);
+static bool extract_balanced (message_list_ty *mlp, int state,
+                             token_type_ty delim,
+                             flag_context_ty outer_context,
+                             flag_context_list_iterator_ty context_iter,
+                             int arg_sg, int arg_pl);
 
 
 /* Extract an unsigned hexadecimal number from STRING, considering at
@@ -1305,7 +1373,8 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
               real_file_name, line_number);
 #endif
 
-      if (extract_balanced (mlp, -1, -1, 0, token_type_rbrace))
+      if (extract_balanced (mlp, 0, token_type_rbrace,
+                           null_context, null_context_list_iterator, -1, -1))
        return;
       buffer[bufpos++] = c;
     }
@@ -1432,6 +1501,11 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
              /* Extract a possible string from the key.  Before proceeding
                 we check whether the open curly is followed by a symbol and
                 then by a right curly.  */
+             flag_context_list_iterator_ty context_iter =
+               flag_context_list_iterator (
+                 flag_context_list_table_lookup (
+                   flag_context_list_table,
+                   tp->string, strlen (tp->string)));
              token_ty *t1 = x_perl_lex (mlp);
 
 #if DEBUG_PERL
@@ -1445,11 +1519,19 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
                  token_ty *t2 = x_perl_lex (mlp);
                  if (t2->type == token_type_rbrace)
                    {
+                     flag_context_ty context;
                      lex_pos_ty pos;
+
+                     context =
+                       inherited_context (null_context,
+                                          flag_context_list_iterator_advance (
+                                            &context_iter));
+
                      pos.line_number = line_number;
                      pos.file_name = logical_file_name;
+
                      xgettext_current_source_encoding = po_charset_utf8;
-                     remember_a_message (mlp, xstrdup (t1->string), &pos);
+                     remember_a_message (mlp, xstrdup (t1->string), context, &pos);
                      xgettext_current_source_encoding = xgettext_global_source_encoding;
                      free_token (t2);
                      free_token (t1);
@@ -1462,7 +1544,8 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
              else
                {
                  x_perl_unlex (t1);
-                 if (extract_balanced (mlp, 1, -1, 1, token_type_rbrace))
+                 if (extract_balanced (mlp, 1, token_type_rbrace,
+                                       null_context, context_iter, 1, -1))
                    return;
                }
            }
@@ -1490,7 +1573,8 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
          fprintf (stderr, "%s:%d: extracting balanced '{' after varname\n",
                   real_file_name, line_number);
 #endif
-         extract_balanced (mlp, -1, -1, 0, token_type_rbrace);
+         extract_balanced (mlp, 0, token_type_rbrace,
+                           null_context, null_context_list_iterator, -1, -1);
          break;
 
        case '[':
@@ -1498,7 +1582,8 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
          fprintf (stderr, "%s:%d: extracting balanced '[' after varname\n",
                   real_file_name, line_number);
 #endif
-         extract_balanced (mlp, -1, -1, 0, token_type_rbracket);
+         extract_balanced (mlp, 0, token_type_rbracket,
+                           null_context, null_context_list_iterator, -1, -1);
          break;
 
        case '-':
@@ -1541,7 +1626,8 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
   static char *buffer;
   static int bufmax = 0;
   int bufpos = 0;
-  int c = (unsigned char) string[0];
+  flag_context_ty context;
+  int c;
   bool maybe_hash_deref = false;
   enum parser_state
     {
@@ -1576,8 +1662,13 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
    * squote:       a single-quote has been seen in state WAIT_QUOTE
    * barekey:      an bareword character has been seen in state WAIT_QUOTE
    * wait_rbrace:  closing quote has been seen in state DQUOTE or SQUOTE
+   *
+   * In the states initial...identifier the context is null_context; in the
+   * states minus...wait_rbrace the context is the one suitable for the first
+   * argument of the last seen identifier.
    */
   state = initial;
+  context = null_context;
 
   token.type = token_type_string;
   token.sub_type = string_type_qq;
@@ -1653,19 +1744,27 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
            {
              buffer[bufpos++] = c;
              state = identifier;
-             break;
            }
          else
-           {
-             state = initial;
-           }
+           state = initial;
          break;
        case identifier:
          switch (c)
            {
            case '-':
              if (find_entry (&keywords, buffer, bufpos, &keyword_value) == 0)
-               state = minus;
+               {
+                 flag_context_list_iterator_ty context_iter =
+                   flag_context_list_iterator (
+                     flag_context_list_table_lookup (
+                       flag_context_list_table,
+                       buffer, bufpos));
+                 context =
+                   inherited_context (null_context,
+                                      flag_context_list_iterator_advance (
+                                        &context_iter));
+                 state = minus;
+               }
              else
                state = initial;
              break;
@@ -1673,7 +1772,18 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
              if (!maybe_hash_deref)
                buffer[0] = '%';
              if (find_entry (&keywords, buffer, bufpos, &keyword_value) == 0)
-               state = wait_quote;
+               {
+                 flag_context_list_iterator_ty context_iter =
+                   flag_context_list_iterator (
+                     flag_context_list_table_lookup (
+                       flag_context_list_table,
+                       buffer, bufpos));
+                 context =
+                   inherited_context (null_context,
+                                      flag_context_list_iterator_advance (
+                                        &context_iter));
+                 state = wait_quote;
+               }
              else
                state = initial;
              break;
@@ -1697,6 +1807,7 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
              state = wait_lbrace;
              break;
            default:
+             context = null_context;
              state = initial;
              break;
            }
@@ -1708,6 +1819,7 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
              state = wait_quote;
              break;
            default:
+             context = null_context;
              state = initial;
              break;
            }
@@ -1731,13 +1843,16 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
              if (c == '_' || (c >= '0' && c <= '9') || c >= 0x80
                  || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
                {
-                 state = barekey;
                  pos.line_number = lineno;
                  bufpos = 0;
                  buffer[bufpos++] = c;
+                 state = barekey;
                }
              else
-               state = initial;
+               {
+                 context = null_context;
+                 state = initial;
+               }
              break;
            }
          break;
@@ -1768,7 +1883,10 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
                  buffer[bufpos++] = string++[0];
                }
              else
-               state = initial;
+               {
+                 context = null_context;
+                 state = initial;
+               }
              break;
            default:
              buffer[bufpos++] = c;
@@ -1792,7 +1910,10 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
                  buffer[bufpos++] = string++[0];
                }
              else
-               state = initial;
+               {
+                 context = null_context;
+                 state = initial;
+               }
              break;
            default:
              buffer[bufpos++] = c;
@@ -1800,25 +1921,24 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
            }
          break;
        case barekey:
-         {
-           if (c == '_' || (c >= '0' && c <= '9') || c >= 0x80
-               || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
-             {
-               buffer[bufpos++] = c;
-               break;
-             }
-           else if (is_whitespace (c))
-             {
-               state = wait_rbrace;
-               break;
-             }
-           else if (c != '}')
-             {
-               state = initial;
-               break;
-             }
-           /* Must be right brace.  */
-         }
+         if (c == '_' || (c >= '0' && c <= '9') || c >= 0x80
+             || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+           {
+             buffer[bufpos++] = c;
+             break;
+           }
+         else if (is_whitespace (c))
+           {
+             state = wait_rbrace;
+             break;
+           }
+         else if (c != '}')
+           {
+             context = null_context;
+             state = initial;
+             break;
+           }
+         /* Must be right brace.  */
          /* FALLTHROUGH */
        case wait_rbrace:
          switch (c)
@@ -1830,10 +1950,11 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
              token.string = xstrdup (buffer);
              extract_quotelike_pass3 (&token, EXIT_FAILURE);
              xgettext_current_source_encoding = po_charset_utf8;
-             remember_a_message (mlp, token.string, &pos);
+             remember_a_message (mlp, token.string, context, &pos);
              xgettext_current_source_encoding = xgettext_global_source_encoding;
              /* FALLTHROUGH */
            default:
+             context = null_context;
              state = initial;
              break;
            }
@@ -2648,10 +2769,7 @@ collect_message (message_list_ty *mlp, token_ty *tp, int error_level)
    When specific arguments shall be extracted, ARG_SG and ARG_PL are
    set to the corresponding argument number or -1 if not applicable.
 
-   Returns the number of requested arguments consumed or -1 for eof.
-   If - instead of consuming requested arguments - a complete message
-   has been extracted, the return value will be sufficiently high to
-   avoid any mis-interpretation.
+   Returns true for EOF, false otherwise.
 
    States are:
 
@@ -2673,8 +2791,10 @@ collect_message (message_list_ty *mlp, token_ty *tp, int error_level)
    tokens will cause a warning.  */
 
 static bool
-extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
-                 token_type_ty delim)
+extract_balanced (message_list_ty *mlp, int state, token_type_ty delim,
+                 flag_context_ty outer_context,
+                 flag_context_list_iterator_ty context_iter,
+                 int arg_sg, int arg_pl)
 {
   /* Remember the message containing the msgid, for msgid_plural.  */
   message_ty *plural_mp = NULL;
@@ -2686,6 +2806,18 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
   /* Number of left parentheses seen.  */
   int paren_seen = 0;
 
+  /* Whether to implicitly assume the next tokens are arguments even without
+     a '('.  */
+  bool next_is_argument = false;
+
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
+
 #if DEBUG_PERL
   static int nesting_level = 0;
 
@@ -2715,6 +2847,17 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          return false;
        }
 
+      if (next_is_argument && tp->type != token_type_lparen)
+       {
+         /* An argument list starts, even though there is no '('.  */
+         context_iter = next_context_iter;
+         outer_context = inner_context;
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+       }
+
       switch (tp->type)
        {
        case token_type_symbol:
@@ -2739,6 +2882,12 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
                state = 2;
              }
          }
+         next_is_argument = true;
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               tp->string, strlen (tp->string)));
          break;
 
        case token_type_variable:
@@ -2747,6 +2896,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
                   logical_file_name, tp->line_number, nesting_level, tp->string);
 #endif
          prefer_division_over_regexp = true;
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_lparen:
@@ -2756,15 +2907,17 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
 #endif
          ++paren_seen;
 
-         if (extract_balanced (mlp, arg_sg - arg_count + 1,
-                               arg_pl - arg_count + 1, state,
-                               token_type_rparen))
+         if (extract_balanced (mlp, state, token_type_rparen,
+                               inner_context, next_context_iter,
+                               arg_sg - arg_count + 1, arg_pl - arg_count + 1))
            {
              free_token (tp);
              return true;
            }
          if (my_last_token == token_type_keyword_symbol)
            arg_sg = arg_pl = -1;
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_rparen:
@@ -2773,6 +2926,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
                   logical_file_name, tp->line_number, nesting_level);
 #endif
          --paren_seen;
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_comma:
@@ -2789,10 +2944,16 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
              arg_count = 0;
            }
 #if DEBUG_PERL
-          fprintf (stderr, "%s:%d: arg_count: %d, arg_sg: %d, arg_pl: %d\n",
-                   real_file_name, tp->line_number,
-                   arg_count, arg_sg, arg_pl);
+         fprintf (stderr, "%s:%d: arg_count: %d, arg_sg: %d, arg_pl: %d\n",
+                  real_file_name, tp->line_number,
+                  arg_count, arg_sg, arg_pl);
 #endif
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_is_argument = false;
+         next_context_iter = passthrough_context_list_iterator;
          break;
 
        case token_type_string:
@@ -2811,7 +2972,7 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
              pos.line_number = tp->line_number;
              string = collect_message (mlp, tp, EXIT_SUCCESS);
              xgettext_current_source_encoding = po_charset_utf8;
-             remember_a_message (mlp, string, &pos);
+             remember_a_message (mlp, string, inner_context, &pos);
              xgettext_current_source_encoding = xgettext_global_source_encoding;
            }
          else if (state)
@@ -2826,22 +2987,20 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
                {
                  string = collect_message (mlp, tp, EXIT_FAILURE);
                  xgettext_current_source_encoding = po_charset_utf8;
-                 plural_mp = remember_a_message (mlp, string, &pos);
+                 plural_mp = remember_a_message (mlp, string, inner_context, &pos);
                  xgettext_current_source_encoding = xgettext_global_source_encoding;
                  arg_sg = -1;
                }
-             else if (arg_count == arg_pl && plural_mp == NULL)
+             else if (arg_count == arg_pl)
                {
                  if (plural_mp == NULL)
                    error (EXIT_FAILURE, 0, _("\
 %s:%d: fatal: plural message seen before singular message\n"),
                           real_file_name, tp->line_number);
-               }
-             else if (arg_count == arg_pl)
-               {
+
                  string = collect_message (mlp, tp, EXIT_FAILURE);
                  xgettext_current_source_encoding = po_charset_utf8;
-                 remember_a_message_plural (plural_mp, string, &pos);
+                 remember_a_message_plural (plural_mp, string, inner_context, &pos);
                  xgettext_current_source_encoding = xgettext_global_source_encoding;
                  arg_pl = -1;
                }
@@ -2853,6 +3012,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
              plural_mp = NULL;
            }
 
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_eof:
@@ -2868,11 +3029,15 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type lbrace (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
-         if (extract_balanced (mlp, -1, -1, 0, token_type_rbrace))
+         if (extract_balanced (mlp, 0, token_type_rbrace,
+                               null_context, null_context_list_iterator,
+                               -1, -1))
            {
              free_token (tp);
              return true;
            }
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_rbrace:
@@ -2880,6 +3045,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type rbrace (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          break;
 
@@ -2888,11 +3055,15 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type lbracket (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
-         if (extract_balanced (mlp, -1, -1, 0, token_type_rbracket))
+         if (extract_balanced (mlp, 0, token_type_rbracket,
+                               null_context, null_context_list_iterator,
+                               -1, -1))
            {
              free_token (tp);
              return true;
            }
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_rbracket:
@@ -2900,6 +3071,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type rbracket (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          break;
 
@@ -2913,6 +3086,17 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          /* The ultimate sign.  */
          arg_sg = arg_pl = -1;
 
+         /* FIXME: Instead of resetting outer_context here, it may be better
+            to recurse in the next_is_argument handling above, waiting for
+            the next semicolon or other statement terminator.  */
+         outer_context = null_context;
+         context_iter = null_context_list_iterator;
+         next_is_argument = false;
+         next_context_iter = passthrough_context_list_iterator;
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
          break;
 
        case token_type_dereference:
@@ -2920,6 +3104,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type dereference (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_dot:
@@ -2927,6 +3113,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type dot (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          break;
 
@@ -2936,6 +3124,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
                   logical_file_name, tp->line_number, nesting_level,
                   tp->string);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          break;
 
@@ -2944,6 +3134,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type regex operator (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          break;
 
        case token_type_other:
@@ -2951,6 +3143,8 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
          fprintf (stderr, "%s:%d: type other (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
+         next_is_argument = false;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          break;
 
@@ -2966,6 +3160,7 @@ extract_balanced (message_list_ty *mlp, int arg_sg, int arg_pl, int state,
 
 void
 extract_perl (FILE *f, const char *real_filename, const char *logical_filename,
+             flag_context_list_table_ty *flag_table,
              msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -2978,6 +3173,8 @@ extract_perl (FILE *f, const char *real_filename, const char *logical_filename,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   token_stack.items = NULL;
@@ -2990,7 +3187,9 @@ extract_perl (FILE *f, const char *real_filename, const char *logical_filename,
 
   /* Eat tokens until eof is seen.  When extract_balanced returns
      due to an unbalanced closing brace, just restart it.  */
-  while (!extract_balanced (mlp, -1, -1, 0, token_type_rbrace))
+  while (!extract_balanced (mlp, 0, token_type_rbrace,
+                           null_context, null_context_list_iterator,
+                           -1, -1))
     ;
 
   fp = NULL;
index 9c28df66ba1c2ac094c01f27edee851a6ffc6067..95135016c99f619bf2000528617d884f97e7762b 100644 (file)
   { "cgi",   "perl"   },                                               \
 
 #define SCANNERS_PERL \
-  { "perl",  extract_perl, &formatstring_perl, &formatstring_perl_brace }, \
+  { "perl",            extract_perl,                                   \
+           &flag_table_perl, &formatstring_perl, &formatstring_perl_brace }, \
 
 /* Scan a Perl file and add its translatable strings to mdlp.  */
 extern void extract_perl (FILE *fp, const char *real_filename,
                          const char *logical_filename,
+                         flag_context_list_table_ty *flag_table,
                          msgdomain_list_ty *mdlp);
 
 extern void x_perl_keyword (const char *keyword);
 extern void x_perl_extract_all (void);
+
+extern void init_flag_table_perl (void);
index 027b74e1c85c2cc830a03433ce99245b7414b813..f45806f6f926e82f9caadfceb9abce865fae3bc9 100644 (file)
@@ -27,8 +27,8 @@
 #include <stdlib.h>
 
 #include "message.h"
-#include "x-php.h"
 #include "xgettext.h"
+#include "x-php.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -106,6 +106,23 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_php ()
+{
+  xgettext_record_flag ("_:1:pass-php-format");
+  xgettext_record_flag ("gettext:1:pass-php-format");
+  xgettext_record_flag ("dgettext:2:pass-php-format");
+  xgettext_record_flag ("dcgettext:2:pass-php-format");
+  xgettext_record_flag ("ngettext:1:pass-php-format");
+  xgettext_record_flag ("ngettext:2:pass-php-format");
+  xgettext_record_flag ("dngettext:2:pass-php-format");
+  xgettext_record_flag ("dngettext:3:pass-php-format");
+  xgettext_record_flag ("dcngettext:2:pass-php-format");
+  xgettext_record_flag ("dcngettext:3:pass-php-format");
+  xgettext_record_flag ("sprintf:1:php-format");
+  xgettext_record_flag ("printf:1:php-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -1165,6 +1182,11 @@ x_php_lex (token_ty *tp)
 
 /* ========================= Extracting strings.  ========================== */
 
+
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* The file is broken into tokens.  Scan the token stream, looking for
    a keyword, followed by a left paren, followed by a string.  When we
    see this sequence, we have something to remember.  We assume we are
@@ -1189,6 +1211,8 @@ x_php_lex (token_ty *tp)
    Return true upon eof, false upon closing parenthesis.  */
 static bool
 extract_parenthesized (message_list_ty *mlp,
+                      flag_context_ty outer_context,
+                      flag_context_list_iterator_ty context_iter,
                       int commas_to_skip, int plural_commas)
 {
   /* Remember the message containing the msgid, for msgid_plural.  */
@@ -1199,6 +1223,13 @@ extract_parenthesized (message_list_ty *mlp,
   /* Parameters of the keyword just seen.  Defined only in state 1.  */
   int next_commas_to_skip = -1;
   int next_plural_commas = 0;
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
 
   /* Start state is 0.  */
   state = 0;
@@ -1228,15 +1259,20 @@ extract_parenthesized (message_list_ty *mlp,
            else
              state = 0;
          }
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               token.string, strlen (token.string)));
          free (token.string);
          continue;
 
        case token_type_lparen:
-         if (state
-             ? extract_parenthesized (mlp, next_commas_to_skip,
-                                      next_plural_commas)
-             : extract_parenthesized (mlp, -1, 0))
+         if (extract_parenthesized (mlp, inner_context, next_context_iter,
+                                    state ? next_commas_to_skip : -1,
+                                    state ? next_plural_commas: 0))
            return true;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1257,6 +1293,11 @@ extract_parenthesized (message_list_ty *mlp,
                else
                  commas_to_skip = -1;
            }
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_context_iter = passthrough_context_list_iterator;
          state = 0;
          continue;
 
@@ -1267,7 +1308,7 @@ extract_parenthesized (message_list_ty *mlp,
            pos.line_number = token.line_number;
 
            if (extract_all)
-             remember_a_message (mlp, token.string, &pos);
+             remember_a_message (mlp, token.string, inner_context, &pos);
            else
              {
                if (commas_to_skip == 0)
@@ -1275,8 +1316,9 @@ extract_parenthesized (message_list_ty *mlp,
                    if (plural_mp == NULL)
                      {
                        /* Seen an msgid.  */
-                       message_ty *mp = remember_a_message (mlp, token.string,
-                                                            &pos);
+                       message_ty *mp =
+                         remember_a_message (mlp, token.string,
+                                             inner_context, &pos);
                        if (plural_commas > 0)
                          plural_mp = mp;
                      }
@@ -1284,7 +1326,7 @@ extract_parenthesized (message_list_ty *mlp,
                      {
                        /* Seen an msgid_plural.  */
                        remember_a_message_plural (plural_mp, token.string,
-                                                  &pos);
+                                                  inner_context, &pos);
                        plural_mp = NULL;
                      }
                  }
@@ -1292,10 +1334,12 @@ extract_parenthesized (message_list_ty *mlp,
                  free (token.string);
              }
          }
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
        case token_type_other:
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1312,6 +1356,7 @@ extract_parenthesized (message_list_ty *mlp,
 void
 extract_php (FILE *f,
             const char *real_filename, const char *logical_filename,
+            flag_context_list_table_ty *flag_table,
             msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -1324,6 +1369,8 @@ extract_php (FILE *f,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Initial mode is HTML mode, not PHP mode.  */
@@ -1331,7 +1378,8 @@ extract_php (FILE *f,
 
   /* Eat tokens until eof is seen.  When extract_parenthesized returns
      due to an unbalanced closing parenthesis, just restart it.  */
-  while (!extract_parenthesized (mlp, -1, 0))
+  while (!extract_parenthesized (mlp, null_context, null_context_list_iterator,
+                                -1, 0))
     ;
 
   /* Close scanner.  */
index 7ec6cddaf8b495e75829972eb3e2452702810ae1..309e679db48b65b373e846ece6beaba8ae468bba 100644 (file)
   { "php4",   "PHP"   },                                               \
 
 #define SCANNERS_PHP \
-  { "PHP",        extract_php, &formatstring_php, NULL },              \
+  { "PHP",             extract_php,                                    \
+                       &flag_table_php, &formatstring_php, NULL },     \
 
 /* Scan a PHP file and add its translatable strings to mdlp.  */
 extern void extract_php (FILE *fp, const char *real_filename,
                         const char *logical_filename,
+                        flag_context_list_table_ty *flag_table,
                         msgdomain_list_ty *mdlp);
 
 extern void x_php_keyword (const char *keyword);
 extern void x_php_extract_all (void);
+
+extern void init_flag_table_php (void);
index b51f6d5649844832d2a05c0bc2473541a32ff45f..3c55a476a7f6589b02b0e1707f39d6154788cf37 100644 (file)
@@ -27,9 +27,9 @@
 #include <string.h>
 
 #include "message.h"
+#include "xgettext.h"
 #include "x-po.h"
 #include "x-properties.h"
-#include "xgettext.h"
 #include "xmalloc.h"
 #include "read-po.h"
 #include "po-lex.h"
@@ -124,6 +124,7 @@ extract (FILE *fp,
 void
 extract_po (FILE *fp,
            const char *real_filename, const char *logical_filename,
+           flag_context_list_table_ty *flag_table,
            msgdomain_list_ty *mdlp)
 {
   extract (fp, real_filename,  logical_filename, syntax_po, mdlp);
@@ -133,6 +134,7 @@ extract_po (FILE *fp,
 void
 extract_properties (FILE *fp,
                    const char *real_filename, const char *logical_filename,
+                   flag_context_list_table_ty *flag_table,
                    msgdomain_list_ty *mdlp)
 {
   extract (fp, real_filename,  logical_filename, syntax_properties, mdlp);
index 72ae8b05a8e373abad72f9368089f4c4302c89d0..7a096ce6f81724d49fea00885b536768a5f7dbca 100644 (file)
   { "pot",    "PO"    },                                               \
 
 #define SCANNERS_PO \
-  { "PO", extract_po, NULL, NULL },                                    \
+  { "PO",              extract_po, NULL, NULL, NULL },                 \
 
 /* Scan a PO file and add its translatable strings to mdlp.  */
 extern void extract_po (FILE *fp, const char *real_filename,
                        const char *logical_filename,
+                       flag_context_list_table_ty *flag_table,
                        msgdomain_list_ty *mdlp);
index 10c1acb0491272067e069cdaa2ca6df4d2c8702d..360229a980e51293edcde1c1d4c4ef9e3e26d542 100644 (file)
   { "properties", "JavaProperties" },                                  \
 
 #define SCANNERS_PROPERTIES \
-  { "JavaProperties", extract_properties, NULL, NULL },                        \
+  { "JavaProperties",  extract_properties, NULL, NULL, NULL },         \
 
 /* Scan a JavaProperties file and add its translatable strings to mdlp.  */
 extern void extract_properties (FILE *fp, const char *real_filename,
                                const char *logical_filename,
+                               flag_context_list_table_ty *flag_table,
                                msgdomain_list_ty *mdlp);
index e59ee750c38aeffc62a7bd581f9909f4f155abef..c007eae1bdcaa38b29c7a893f53ad8e1242a5f6c 100644 (file)
@@ -29,8 +29,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-python.h"
 #include "xgettext.h"
+#include "x-python.h"
 #include "error.h"
 #include "error-progname.h"
 #include "xmalloc.h"
@@ -114,6 +114,22 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_python ()
+{
+  xgettext_record_flag ("gettext:1:pass-python-format");
+  xgettext_record_flag ("ugettext:1:pass-python-format");
+  xgettext_record_flag ("dgettext:2:pass-python-format");
+  xgettext_record_flag ("ngettext:1:pass-python-format");
+  xgettext_record_flag ("ngettext:2:pass-python-format");
+  xgettext_record_flag ("ungettext:1:pass-python-format");
+  xgettext_record_flag ("ungettext:2:pass-python-format");
+  xgettext_record_flag ("dngettext:2:pass-python-format");
+  xgettext_record_flag ("dngettext:3:pass-python-format");
+  xgettext_record_flag ("_:1:pass-python-format");
+  /* xgettext_record_flag ("%:1:python-format"); // % is an infix operator! */
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -968,6 +984,11 @@ x_python_lex (token_ty *tp)
 
 /* ========================= Extracting strings.  ========================== */
 
+
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* The file is broken into tokens.  Scan the token stream, looking for
    a keyword, followed by a left paren, followed by a string.  When we
    see this sequence, we have something to remember.  We assume we are
@@ -992,6 +1013,8 @@ x_python_lex (token_ty *tp)
    Return true upon eof, false upon closing parenthesis.  */
 static bool
 extract_parenthesized (message_list_ty *mlp,
+                      flag_context_ty outer_context,
+                      flag_context_list_iterator_ty context_iter,
                       int commas_to_skip, int plural_commas)
 {
   /* Remember the message containing the msgid, for msgid_plural.  */
@@ -1002,6 +1025,13 @@ extract_parenthesized (message_list_ty *mlp,
   /* Parameters of the keyword just seen.  Defined only in state 1.  */
   int next_commas_to_skip = -1;
   int next_plural_commas = 0;
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
 
   /* Start state is 0.  */
   state = 0;
@@ -1031,15 +1061,20 @@ extract_parenthesized (message_list_ty *mlp,
            else
              state = 0;
          }
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               token.string, strlen (token.string)));
          free (token.string);
          continue;
 
        case token_type_lparen:
-         if (state
-             ? extract_parenthesized (mlp, next_commas_to_skip,
-                                      next_plural_commas)
-             : extract_parenthesized (mlp, -1, 0))
+         if (extract_parenthesized (mlp, inner_context, next_context_iter,
+                                    state ? next_commas_to_skip : -1,
+                                    state ? next_plural_commas : 0))
            return true;
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1060,6 +1095,11 @@ extract_parenthesized (message_list_ty *mlp,
                else
                  commas_to_skip = -1;
            }
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_context_iter = passthrough_context_list_iterator;
          state = 0;
          continue;
 
@@ -1070,7 +1110,7 @@ extract_parenthesized (message_list_ty *mlp,
            pos.line_number = token.line_number;
 
            if (extract_all)
-             remember_a_message (mlp, token.string, &pos);
+             remember_a_message (mlp, token.string, inner_context, &pos);
            else
              {
                if (commas_to_skip == 0)
@@ -1078,8 +1118,9 @@ extract_parenthesized (message_list_ty *mlp,
                    if (plural_mp == NULL)
                      {
                        /* Seen an msgid.  */
-                       message_ty *mp = remember_a_message (mlp, token.string,
-                                                            &pos);
+                       message_ty *mp =
+                         remember_a_message (mlp, token.string,
+                                             inner_context, &pos);
                        if (plural_commas > 0)
                          plural_mp = mp;
                      }
@@ -1087,7 +1128,7 @@ extract_parenthesized (message_list_ty *mlp,
                      {
                        /* Seen an msgid_plural.  */
                        remember_a_message_plural (plural_mp, token.string,
-                                                  &pos);
+                                                  inner_context, &pos);
                        plural_mp = NULL;
                      }
                  }
@@ -1095,6 +1136,7 @@ extract_parenthesized (message_list_ty *mlp,
                  free (token.string);
              }
          }
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1102,6 +1144,7 @@ extract_parenthesized (message_list_ty *mlp,
          return true;
 
        case token_type_other:
+         next_context_iter = null_context_list_iterator;
          state = 0;
          continue;
 
@@ -1115,6 +1158,7 @@ extract_parenthesized (message_list_ty *mlp,
 void
 extract_python (FILE *f,
                const char *real_filename, const char *logical_filename,
+               flag_context_list_table_ty *flag_table,
                msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -1132,11 +1176,14 @@ extract_python (FILE *f,
 
   open_pbb = 0;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  When extract_parenthesized returns
      due to an unbalanced closing parenthesis, just restart it.  */
-  while (!extract_parenthesized (mlp, -1, 0))
+  while (!extract_parenthesized (mlp, null_context, null_context_list_iterator,
+                                -1, 0))
     ;
 
   fp = NULL;
index af96927d00211d94c2786c9e118e5430b672b1e4..eeaac8b5b4d1ba8e04028f632b6028a759d436ce 100644 (file)
   { "py",        "Python"   },                                         \
 
 #define SCANNERS_PYTHON \
-  { "Python",     extract_python, &formatstring_python, NULL },                \
+  { "Python",          extract_python,                                   \
+                       &flag_table_python, &formatstring_python, NULL }, \
 
 /* Scan a Python file and add its translatable strings to mdlp.  */
 extern void extract_python (FILE *fp, const char *real_filename,
                            const char *logical_filename,
+                           flag_context_list_table_ty *flag_table,
                            msgdomain_list_ty *mdlp);
 
 extern void x_python_keyword (const char *keyword);
 extern void x_python_extract_all (void);
+
+extern void init_flag_table_python (void);
index 15bf6b501bfe55eea01b74029dfd9cf612e5ae50..2e4dc8b6cfade569ab40f74482fd3924eec612fe 100644 (file)
@@ -27,8 +27,8 @@
 #include <stddef.h>
 
 #include "message.h"
-#include "x-rst.h"
 #include "xgettext.h"
+#include "x-rst.h"
 #include "error.h"
 #include "error-progname.h"
 #include "xmalloc.h"
@@ -57,6 +57,7 @@
 void
 extract_rst (FILE *f,
             const char *real_filename, const char *logical_filename,
+            flag_context_list_table_ty *flag_table,
             msgdomain_list_ty *mdlp)
 {
   static char *buffer;
@@ -218,7 +219,7 @@ extract_rst (FILE *f,
       pos.file_name = location;
       pos.line_number = (size_t)(-1);
 
-      remember_a_message (mlp, msgid, &pos);
+      remember_a_message (mlp, msgid, null_context, &pos);
 
       /* Here c is the last read character: EOF or '\n'.  */
       if (c == EOF)
index 4dfe206e7d89423a6235c7a30980d01920c7f8d1..329e68b44304d7014787ec3ee952e2c9e3b1a6bf 100644 (file)
   { "rst",    "RST"   },                                               \
 
 #define SCANNERS_RST \
-  { "RST",        extract_rst, &formatstring_pascal, NULL },           \
+  { "RST",             extract_rst,                                    \
+                       NULL, &formatstring_pascal, NULL },             \
 
 /* Scan an RST file and add its translatable strings to mdlp.  */
 extern void extract_rst (FILE *fp, const char *real_filename,
                         const char *logical_filename,
+                        flag_context_list_table_ty *flag_table,
                         msgdomain_list_ty *mdlp);
index 3cef49f95e808ea466bac8695778e498f341aa90..129f5321467ee037de4af43cdfed9e377b36efe4 100644 (file)
@@ -28,8 +28,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-sh.h"
 #include "xgettext.h"
+#include "x-sh.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -119,6 +119,17 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_sh ()
+{
+  xgettext_record_flag ("gettext:1:pass-sh-format");
+  xgettext_record_flag ("ngettext:1:pass-sh-format");
+  xgettext_record_flag ("ngettext:2:pass-sh-format");
+  xgettext_record_flag ("eval_gettext:1:sh-format");
+  xgettext_record_flag ("eval_ngettext:1:sh-format");
+  xgettext_record_flag ("eval_ngettext:2:sh-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -671,8 +682,13 @@ phase2_ungetc (int c)
 }
 
 
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* Forward declaration of local functions.  */
-static enum word_type read_command_list (int looking_for);
+static enum word_type read_command_list (int looking_for,
+                                        flag_context_ty outer_context);
 
 
 
@@ -680,7 +696,7 @@ static enum word_type read_command_list (int looking_for);
    'looking_for' denotes a parse terminator, either CLOSING_BACKQUOTE, ')'
    or '\0'.  */
 static void
-read_word (struct word *wp, int looking_for)
+read_word (struct word *wp, int looking_for, flag_context_ty context)
 {
   int c;
   bool all_unquoted_digits;
@@ -827,7 +843,7 @@ read_word (struct word *wp, int looking_for)
                {
                  /* Command substitution.  */
                  phase2_ungetc (c3);
-                 read_command_list (')');
+                 read_command_list (')', context);
                }
            }
          else if (c2 == '\'' && !open_singlequote)
@@ -986,7 +1002,8 @@ read_word (struct word *wp, int looking_for)
                  grow_token (&string);
                  string.chars[string.charcount++] = (unsigned char) c;
                }
-             remember_a_message (mlp, string_of_token (&string), &pos);
+             remember_a_message (mlp, string_of_token (&string),
+                                 context, &pos);
              free_token (&string);
 
              error_with_progname = false;
@@ -1038,7 +1055,7 @@ read_word (struct word *wp, int looking_for)
          /* Handle an opening backquote.  */
          saw_opening_backquote ();
 
-         read_command_list (CLOSING_BACKQUOTE);
+         read_command_list (CLOSING_BACKQUOTE, context);
 
          wp->type = t_other;
          continue;
@@ -1073,7 +1090,7 @@ read_word (struct word *wp, int looking_for)
    or '\0'.
    Returns the type of the word that terminated the command.  */
 static enum word_type
-read_command (int looking_for)
+read_command (int looking_for, flag_context_ty outer_context)
 {
   /* Read the words that make up the command.
      Here we completely ignore field splitting at whitespace and wildcard
@@ -1087,6 +1104,7 @@ read_command (int looking_for)
      command.  */
   int arg = 0;                 /* Current argument number.  */
   bool arg_of_redirect = false;        /* True right after a redirection operator.  */
+  flag_context_list_iterator_ty context_iter;
   int argnum1 = -1;            /* First string position.  */
   int argnum2 = -1;            /* Plural string position.  */
   message_ty *plural_mp = NULL;        /* Remember the msgid.  */
@@ -1094,8 +1112,17 @@ read_command (int looking_for)
   for (;;)
     {
       struct word inner;
+      flag_context_ty inner_context;
+
+      if (arg == 0)
+       inner_context = null_context;
+      else
+       inner_context =
+         inherited_context (outer_context,
+                            flag_context_list_iterator_advance (
+                              &context_iter));
 
-      read_word (&inner, looking_for);
+      read_word (&inner, looking_for, inner_context);
 
       /* Recognize end of command.  */
       if (inner.type == t_separator
@@ -1111,7 +1138,8 @@ read_command (int looking_for)
 
              pos.file_name = logical_file_name;
              pos.line_number = inner.line_number_at_start;
-             remember_a_message (mlp, string_of_word (&inner), &pos);
+             remember_a_message (mlp, string_of_word (&inner),
+                                 inner_context, &pos);
            }
        }
 
@@ -1145,8 +1173,16 @@ read_command (int looking_for)
                      argnum2 = (int) (long) keyword_value >> 10;
                    }
 
+                 context_iter =
+                   flag_context_list_iterator (
+                     flag_context_list_table_lookup (
+                       flag_context_list_table,
+                       function_name, strlen (function_name)));
+
                  free (function_name);
                }
+             else
+               context_iter = null_context_list_iterator;
            }
          else
            {
@@ -1162,7 +1198,8 @@ read_command (int looking_for)
 
                      pos.file_name = logical_file_name;
                      pos.line_number = inner.line_number_at_start;
-                     mp = remember_a_message (mlp, string_of_word (&inner), &pos);
+                     mp = remember_a_message (mlp, string_of_word (&inner),
+                                              inner_context, &pos);
                      if (argnum2 > 0)
                        plural_mp = mp;
                    }
@@ -1175,13 +1212,15 @@ read_command (int looking_for)
 
                      pos.file_name = logical_file_name;
                      pos.line_number = inner.line_number_at_start;
-                     remember_a_message_plural (plural_mp, string_of_word (&inner), &pos);
+                     remember_a_message_plural (plural_mp, string_of_word (&inner),
+                                                inner_context, &pos);
                    }
                }
 
              if (arg >= argnum1 && arg >= argnum2)
                {
                  /* Stop looking for arguments of the last function_name.  */
+                 /* FIXME: What about context_iter?  */
                  argnum1 = -1;
                  argnum2 = -1;
                  plural_mp = NULL;
@@ -1201,13 +1240,13 @@ read_command (int looking_for)
    or '\0'.
    Returns the type of the word that terminated the command list.  */
 static enum word_type
-read_command_list (int looking_for)
+read_command_list (int looking_for, flag_context_ty outer_context)
 {
   for (;;)
     {
       enum word_type terminator;
 
-      terminator = read_command (looking_for);
+      terminator = read_command (looking_for, outer_context);
       if (terminator != t_separator)
        return terminator;
     }
@@ -1217,6 +1256,7 @@ read_command_list (int looking_for)
 void
 extract_sh (FILE *f,
            const char *real_filename, const char *logical_filename,
+           flag_context_list_table_ty *flag_table,
            msgdomain_list_ty *mdlp)
 {
   mlp = mdlp->item[0]->messages;
@@ -1234,10 +1274,12 @@ extract_sh (FILE *f,
   open_doublequote = false;
   open_singlequote = false;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  */
-  read_command_list ('\0');
+  read_command_list ('\0', null_context);
 
   fp = NULL;
   real_file_name = NULL;
index 84b8b2793114fde8799f8c46afb810984276a7ac..cc80981a775825576050ead6ef70f8e0c8af1b00 100644 (file)
   { "bash",  "Shell"   },                                              \
 
 #define SCANNERS_SH \
-  { "Shell",      extract_sh, &formatstring_sh, NULL },                        \
+  { "Shell",           extract_sh,                                     \
+                       &flag_table_sh, &formatstring_sh, NULL },       \
 
 /* Scan a shell script file and add its translatable strings to mdlp.  */
 extern void extract_sh (FILE *fp, const char *real_filename,
                        const char *logical_filename,
+                       flag_context_list_table_ty *flag_table,
                        msgdomain_list_ty *mdlp);
 
 extern void x_sh_keyword (const char *keyword);
 extern void x_sh_extract_all (void);
+
+extern void init_flag_table_sh (void);
index fcefdfeea4d1c23d34cd1eee06589dceac3da840..12aa259c96fbccfcbf43221f60d2b99c569294c9 100644 (file)
@@ -26,8 +26,8 @@
 #include <stdlib.h>
 
 #include "message.h"
-#include "x-smalltalk.h"
 #include "xgettext.h"
+#include "x-smalltalk.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -481,6 +481,7 @@ x_smalltalk_lex (token_ty *tp)
 void
 extract_smalltalk (FILE *f,
                   const char *real_filename, const char *logical_filename,
+                  flag_context_list_table_ty *flag_table,
                   msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
@@ -532,7 +533,7 @@ extract_smalltalk (FILE *f,
                lex_pos_ty pos;
                pos.file_name = logical_file_name;
                pos.line_number = token.line_number;
-               remember_a_message (mlp, token.string, &pos);
+               remember_a_message (mlp, token.string, null_context, &pos);
                state = 0;
                break;
              }
@@ -541,7 +542,8 @@ extract_smalltalk (FILE *f,
                lex_pos_ty pos;
                pos.file_name = logical_file_name;
                pos.line_number = token.line_number;
-               plural_mp = remember_a_message (mlp, token.string, &pos);
+               plural_mp = remember_a_message (mlp, token.string,
+                                               null_context, &pos);
                state = 4;
                break;
              }
@@ -550,7 +552,8 @@ extract_smalltalk (FILE *f,
                lex_pos_ty pos;
                pos.file_name = logical_file_name;
                pos.line_number = token.line_number;
-               remember_a_message_plural (plural_mp, token.string, &pos);
+               remember_a_message_plural (plural_mp, token.string,
+                                          null_context, &pos);
                state = 0;
                break;
              }
index 407ce44619b59d1ce525d1d7f70841f511697516..858f1eac43fdc407ba9980812eb11f223dbda424 100644 (file)
   { "st",     "Smalltalk"   },                                         \
 
 #define SCANNERS_SMALLTALK \
-  { "Smalltalk",  extract_smalltalk, &formatstring_smalltalk, NULL },  \
+  { "Smalltalk",       extract_smalltalk,                              \
+                       NULL, &formatstring_smalltalk, NULL },          \
 
 /* Scan a Smalltalk file and add its translatable strings to mdlp.  */
 extern void extract_smalltalk (FILE *fp, const char *real_filename,
                               const char *logical_filename,
+                              flag_context_list_table_ty *flag_table,
                               msgdomain_list_ty *mdlp);
index 8112fd3b1bdf642ad655500c6b8f669f2f2f126e..549b3d13323c7782050be61ae7fe6c88364083f4 100644 (file)
@@ -30,8 +30,8 @@
 #include <string.h>
 
 #include "message.h"
-#include "x-tcl.h"
 #include "xgettext.h"
+#include "x-tcl.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
@@ -117,6 +117,13 @@ init_keywords ()
     }
 }
 
+void
+init_flag_table_tcl ()
+{
+  xgettext_record_flag ("::msgcat::mc:1:pass-tcl-format");
+  xgettext_record_flag ("format:1:tcl-format");
+}
+
 
 /* ======================== Reading of characters.  ======================== */
 
@@ -446,6 +453,10 @@ string_of_word (const struct word *wp)
 }
 
 
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
 /* Read an escape sequence.  The value is an ISO-8859-1 character (in the
    range 0x00..0xff) or a Unicode character (in the range 0x0000..0xffff).  */
 static int
@@ -555,12 +566,14 @@ enum terminator
 };
 
 /* Forward declaration of local functions.  */
-static enum word_type read_command_list (int looking_for);
+static enum word_type read_command_list (int looking_for,
+                                        flag_context_ty outer_context);
 
 /* Accumulate tokens into the given word.
    'looking_for' denotes a parse terminator combination.  */
 static int
-accumulate_word (struct word *wp, enum terminator looking_for)
+accumulate_word (struct word *wp, enum terminator looking_for,
+                flag_context_ty context)
 {
   int c;
 
@@ -630,7 +643,7 @@ accumulate_word (struct word *wp, enum terminator looking_for)
                  struct word index_word;
 
                  index_word.type = t_other;
-                 c = accumulate_word (&index_word, te_paren);
+                 c = accumulate_word (&index_word, te_paren, null_context);
                  if (c != EOF && c != ')')
                    phase2_ungetc (c);
                  wp->type = t_other;
@@ -657,7 +670,7 @@ accumulate_word (struct word *wp, enum terminator looking_for)
        }
       else if (c == '[')
        {
-         read_command_list (']');
+         read_command_list (']', context);
          wp->type = t_other;
        }
       else if (c == '\\')
@@ -693,7 +706,7 @@ accumulate_word (struct word *wp, enum terminator looking_for)
 /* Read the next word.
    'looking_for' denotes a parse terminator, either ']' or '\0'.  */
 static void
-read_word (struct word *wp, int looking_for)
+read_word (struct word *wp, int looking_for, flag_context_ty context)
 {
   int c;
 
@@ -748,7 +761,7 @@ read_word (struct word *wp, int looking_for)
       previous_depth = phase2_push () - 1;
 
       /* Interpret it as a command list.  */
-      terminator = read_command_list ('\0');
+      terminator = read_command_list ('\0', null_context);
 
       if (terminator == t_brace)
        phase2_pop (previous_depth);
@@ -765,7 +778,7 @@ read_word (struct word *wp, int looking_for)
 
   if (c == '"')
     {
-      c = accumulate_word (wp, te_quote);
+      c = accumulate_word (wp, te_quote, context);
       if (c != EOF && c != '"')
        phase2_ungetc (c);
     }
@@ -775,7 +788,8 @@ read_word (struct word *wp, int looking_for)
       c = accumulate_word (wp,
                           looking_for == ']'
                           ? te_space_separator_bracket
-                          : te_space_separator);
+                          : te_space_separator,
+                          context);
       if (c != EOF)
        phase2_ungetc (c);
     }
@@ -794,7 +808,7 @@ read_word (struct word *wp, int looking_for)
    Returns the type of the word that terminated the command: t_separator or
    t_bracket (only if looking_for is ']') or t_brace or t_eof.  */
 static enum word_type
-read_command (int looking_for)
+read_command (int looking_for, flag_context_ty outer_context)
 {
   int c;
 
@@ -828,6 +842,7 @@ read_command (int looking_for)
   /* Read the words that make up the command.  */
   {
     int arg = 0;               /* Current argument number.  */
+    flag_context_list_iterator_ty context_iter;
     int argnum1 = 0;           /* First string position.  */
     int argnum2 = 0;           /* Plural string position.  */
     message_ty *plural_mp = NULL;      /* Remember the msgid.  */
@@ -835,8 +850,17 @@ read_command (int looking_for)
     for (;; arg++)
       {
        struct word inner;
+       flag_context_ty inner_context;
+
+       if (arg == 0)
+         inner_context = null_context;
+       else
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
 
-       read_word (&inner, looking_for);
+       read_word (&inner, looking_for, inner_context);
 
        /* Recognize end of command.  */
        if (inner.type == t_separator || inner.type == t_bracket
@@ -851,66 +875,75 @@ read_command (int looking_for)
 
                pos.file_name = logical_file_name;
                pos.line_number = inner.line_number_at_start;
-               remember_a_message (mlp, string_of_word (&inner), &pos);
+               remember_a_message (mlp, string_of_word (&inner),
+                                   inner_context, &pos);
              }
          }
-       else
+
+       if (arg == 0)
          {
-           if (arg == 0)
+           /* This is the function position.  */
+           if (inner.type == t_string)
              {
-               /* This is the function position.  */
-               if (inner.type == t_string)
+               char *function_name = string_of_word (&inner);
+               char *stripped_name;
+               void *keyword_value;
+
+               /* A leading "::" is redundant.  */
+               stripped_name = function_name;
+               if (function_name[0] == ':' && function_name[1] == ':')
+                 stripped_name += 2;
+
+               if (find_entry (&keywords,
+                               stripped_name, strlen (stripped_name),
+                               &keyword_value)
+                   == 0)
                  {
-                   char *function_name = string_of_word (&inner);
-                   char *stripped_name;
-                   void *keyword_value;
-
-                   /* A leading "::" is redundant.  */
-                   stripped_name = function_name;
-                   if (function_name[0] == ':' && function_name[1] == ':')
-                     stripped_name += 2;
-
-                   if (find_entry (&keywords,
-                                   stripped_name, strlen (stripped_name),
-                                   &keyword_value)
-                       == 0)
-                     {
-                       argnum1 = (int) (long) keyword_value & ((1 << 10) - 1);
-                       argnum2 = (int) (long) keyword_value >> 10;
-                     }
-
-                   free (function_name);
+                   argnum1 = (int) (long) keyword_value & ((1 << 10) - 1);
+                   argnum2 = (int) (long) keyword_value >> 10;
                  }
+
+               context_iter =
+                 flag_context_list_iterator (
+                   flag_context_list_table_lookup (
+                     flag_context_list_table,
+                     stripped_name, strlen (stripped_name)));
+
+               free (function_name);
              }
            else
+             context_iter = null_context_list_iterator;
+         }
+       else
+         {
+           /* These are the argument positions.
+              Extract a string if we have reached the right
+              argument position.  */
+           if (arg == argnum1)
              {
-               /* These are the argument positions.
-                  Extract a string if we have reached the right
-                  argument position.  */
-               if (arg == argnum1)
+               if (inner.type == t_string)
                  {
-                   if (inner.type == t_string)
-                     {
-                       lex_pos_ty pos;
-                       message_ty *mp;
-
-                       pos.file_name = logical_file_name;
-                       pos.line_number = inner.line_number_at_start;
-                       mp = remember_a_message (mlp, string_of_word (&inner), &pos);
-                       if (argnum2 > 0)
-                         plural_mp = mp;
-                     }
+                   lex_pos_ty pos;
+                   message_ty *mp;
+
+                   pos.file_name = logical_file_name;
+                   pos.line_number = inner.line_number_at_start;
+                   mp = remember_a_message (mlp, string_of_word (&inner),
+                                            inner_context, &pos);
+                   if (argnum2 > 0)
+                     plural_mp = mp;
                  }
-               else if (arg == argnum2)
+             }
+           else if (arg == argnum2)
+             {
+               if (inner.type == t_string && plural_mp != NULL)
                  {
-                   if (inner.type == t_string && plural_mp != NULL)
-                     {
-                       lex_pos_ty pos;
-
-                       pos.file_name = logical_file_name;
-                       pos.line_number = inner.line_number_at_start;
-                       remember_a_message_plural (plural_mp, string_of_word (&inner), &pos);
-                     }
+                   lex_pos_ty pos;
+
+                   pos.file_name = logical_file_name;
+                   pos.line_number = inner.line_number_at_start;
+                   remember_a_message_plural (plural_mp, string_of_word (&inner),
+                                              inner_context, &pos);
                  }
              }
          }
@@ -926,13 +959,13 @@ read_command (int looking_for)
    Returns the type of the word that terminated the command list:
    t_bracket (only if looking_for is ']') or t_brace or t_eof.  */
 static enum word_type
-read_command_list (int looking_for)
+read_command_list (int looking_for, flag_context_ty outer_context)
 {
   for (;;)
     {
       enum word_type terminator;
 
-      terminator = read_command (looking_for);
+      terminator = read_command (looking_for, outer_context);
       if (terminator != t_separator)
        return terminator;
     }
@@ -942,6 +975,7 @@ read_command_list (int looking_for)
 void
 extract_tcl (FILE *f,
             const char *real_filename, const char *logical_filename,
+            flag_context_list_table_ty *flag_table,
             msgdomain_list_ty *mdlp)
 {
   mlp = mdlp->item[0]->messages;
@@ -960,10 +994,12 @@ extract_tcl (FILE *f,
   last_comment_line = -1;
   last_non_comment_line = -1;
 
+  flag_context_list_table = flag_table;
+
   init_keywords ();
 
   /* Eat tokens until eof is seen.  */
-  read_command_list ('\0');
+  read_command_list ('\0', null_context);
 
   fp = NULL;
   real_file_name = NULL;
index 13d1551934e0c506d4b3ff8b93a4e573fb60851b..89a08394960d9ec60c99ef0b057d4835774516de 100644 (file)
   { "tcl",       "Tcl"           },                                    \
 
 #define SCANNERS_TCL \
-  { "Tcl",        extract_tcl, &formatstring_tcl, NULL },              \
+  { "Tcl",             extract_tcl,                                    \
+                       &flag_table_tcl, &formatstring_tcl, NULL },     \
 
 /* Scan a Tcl file and add its translatable strings to mdlp.  */
 extern void extract_tcl (FILE *fp, const char *real_filename,
                         const char *logical_filename,
+                        flag_context_list_table_ty *flag_table,
                         msgdomain_list_ty *mdlp);
 
 
@@ -33,3 +35,5 @@ extern void extract_tcl (FILE *fp, const char *real_filename,
 
 extern void x_tcl_extract_all (void);
 extern void x_tcl_keyword (const char *name);
+
+extern void init_flag_table_tcl (void);
index d8ee34503cf38d089f4f174f8f162e91c54ded02..9116b4f8930049124cb56dbe13f40039eb4180eb 100644 (file)
@@ -29,8 +29,8 @@
 #include <stdlib.h>
 
 #include "message.h"
-#include "x-ycp.h"
 #include "xgettext.h"
+#include "x-ycp.h"
 #include "error.h"
 #include "xmalloc.h"
 #include "exit.h"
    See also libycp/src/scanner.ll.  */
 
 
+void
+init_flag_table_ycp ()
+{
+  xgettext_record_flag ("sformat:1:ycp-format");
+  xgettext_record_flag ("y2debug:1:ycp-format");
+  xgettext_record_flag ("y2milestone:1:ycp-format");
+  xgettext_record_flag ("y2warning:1:ycp-format");
+  xgettext_record_flag ("y2error:1:ycp-format");
+  xgettext_record_flag ("y2security:1:ycp-format");
+  xgettext_record_flag ("y2internal:1:ycp-format");
+}
+
+
 /* ======================== Reading of characters.  ======================== */
 
 
@@ -520,16 +533,13 @@ x_ycp_lex (token_ty *tp)
 
 /* ========================= Extracting strings.  ========================== */
 
-void
-extract_ycp (FILE *f,
-            const char *real_filename, const char *logical_filename,
-            msgdomain_list_ty *mdlp)
-{
-  message_list_ty *mlp = mdlp->item[0]->messages;
-  int state;
-  message_ty *plural_mp = NULL;        /* defined only when in states 1 and 2 */
 
-  /* The file is broken into tokens.
+/* Context lookup table.  */
+static flag_context_list_table_ty *flag_context_list_table;
+
+
+/* The file is broken into tokens.
+
      Normal handling: Look for
        [A] _( [B] msgid ... )
      Plural handling: Look for
@@ -537,19 +547,33 @@ extract_ycp (FILE *f,
      At point [A]: state == 0.
      At point [B]: state == 1, plural_mp == NULL.
      At point [C]: state == 2, plural_mp != NULL.
-     At point [D]: state == 1, plural_mp != NULL.  */
+     At point [D]: state == 1, plural_mp != NULL.
 
-  fp = f;
-  real_file_name = real_filename;
-  logical_file_name = xstrdup (logical_filename);
-  line_number = 1;
-  char_in_line = 0;
+   We use recursion because we have to set the context according to the given
+   flags.  */
 
-  last_comment_line = -1;
-  last_non_comment_line = -1;
 
-  /* Start state is 0.  */
-  state = 0;
+/* Extract messages until the next balanced closing parenthesis.
+   Extracted messages are added to MLP.
+   Return true upon eof, false upon closing parenthesis.  */
+static bool
+extract_parenthesized (message_list_ty *mlp,
+                      flag_context_ty outer_context,
+                      flag_context_list_iterator_ty context_iter,
+                      bool in_i18n)
+{
+  int state; /* 1 or 2 inside _( ... ), otherwise 0 */
+  message_ty *plural_mp = NULL;        /* defined only when in states 1 and 2 */
+  /* Context iterator that will be used if the next token is a '('.  */
+  flag_context_list_iterator_ty next_context_iter =
+    passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty inner_context =
+    inherited_context (outer_context,
+                      flag_context_list_iterator_advance (&context_iter));
+
+  /* Start state is 0 or 1.  */
+  state = (in_i18n ? 1 : 0);
 
   for (;;)
     {
@@ -559,8 +583,11 @@ extract_ycp (FILE *f,
       switch (token.type)
        {
        case token_type_i18n:
-         state = 1;
-         plural_mp = NULL;
+         if (extract_parenthesized (mlp, inner_context, next_context_iter,
+                                    true))
+           return true;
+         next_context_iter = null_context_list_iterator;
+         state = 0;
          continue;
 
        case token_type_string_literal:
@@ -573,13 +600,15 @@ extract_ycp (FILE *f,
              if (plural_mp == NULL)
                {
                  /* Seen an msgid.  */
-                 plural_mp = remember_a_message (mlp, token.string, &pos);
+                 plural_mp = remember_a_message (mlp, token.string,
+                                                 inner_context, &pos);
                  state = 2;
                }
              else
                {
                  /* Seen an msgid_plural.  */
-                 remember_a_message_plural (plural_mp, token.string, &pos);
+                 remember_a_message_plural (plural_mp, token.string,
+                                            inner_context, &pos);
                  state = 0;
                }
            }
@@ -588,27 +617,81 @@ extract_ycp (FILE *f,
              free (token.string);
              state = 0;
            }
+         next_context_iter = null_context_list_iterator;
+         continue;
+
+       case token_type_symbol:
+         next_context_iter =
+           flag_context_list_iterator (
+             flag_context_list_table_lookup (
+               flag_context_list_table,
+               token.string, strlen (token.string)));
+         free (token.string);
+         state = 0;
          continue;
 
+       case token_type_lparen:
+         if (extract_parenthesized (mlp, inner_context, next_context_iter,
+                                    false))
+           return true;
+         next_context_iter = null_context_list_iterator;
+         state = 0;
+         continue;
+
+       case token_type_rparen:
+         return false;
+
        case token_type_comma:
          if (state == 2)
            state = 1;
          else
            state = 0;
+         inner_context =
+           inherited_context (outer_context,
+                              flag_context_list_iterator_advance (
+                                &context_iter));
+         next_context_iter = passthrough_context_list_iterator;
+         continue;
+
+       case token_type_other:
+         next_context_iter = null_context_list_iterator;
+         state = 0;
          continue;
 
        case token_type_eof:
-         break;
+         return true;
 
-       case token_type_symbol:
-         free (token.string);
-         /* FALLTHROUGH */
        default:
-         state = 0;
-         continue;
+         abort ();
        }
-      break;
     }
+}
+
+
+void
+extract_ycp (FILE *f,
+            const char *real_filename, const char *logical_filename,
+            flag_context_list_table_ty *flag_table,
+            msgdomain_list_ty *mdlp)
+{
+  message_list_ty *mlp = mdlp->item[0]->messages;
+
+  fp = f;
+  real_file_name = real_filename;
+  logical_file_name = xstrdup (logical_filename);
+  line_number = 1;
+  char_in_line = 0;
+
+  last_comment_line = -1;
+  last_non_comment_line = -1;
+
+  flag_context_list_table = flag_table;
+
+  /* Eat tokens until eof is seen.  When extract_parenthesized returns
+     due to an unbalanced closing parenthesis, just restart it.  */
+  while (!extract_parenthesized (mlp, null_context, null_context_list_iterator,
+                                false))
+    ;
 
   fp = NULL;
   real_file_name = NULL;
index e092452fdbbefbdfe34b9874ce98910e26089f8f..f188342a0f4233e5730acd370d4110c6f8a5c4fa 100644 (file)
   { "ycp",    "YCP"   },                                               \
 
 #define SCANNERS_YCP \
-  { "YCP",        extract_ycp, &formatstring_ycp, NULL },              \
+  { "YCP",             extract_ycp,                                    \
+                       &flag_table_ycp, &formatstring_ycp, NULL },     \
 
 /* Scan an YCP file and add its translatable strings to mdlp.  */
 extern void extract_ycp (FILE *fp, const char *real_filename,
                         const char *logical_filename,
+                        flag_context_list_table_ty *flag_table,
                         msgdomain_list_ty *mdlp);
+
+extern void init_flag_table_ycp (void);
index 1b83d0ed119ad148316875c80b6f7d2885a16771..47717e7771b60b758ca7e3ed1a45493206fba674 100644 (file)
@@ -19,6 +19,7 @@
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
+#include <alloca.h>
 
 #include <ctype.h>
 #include <errno.h>
@@ -135,6 +136,21 @@ static input_syntax_ty output_syntax = syntax_po;
 /* If nonzero omit header with information about this run.  */
 int xgettext_omit_header;
 
+/* Table of flag_context_list_ty tables.  */
+static flag_context_list_table_ty flag_table_c;
+static flag_context_list_table_ty flag_table_gcc_internal;
+static flag_context_list_table_ty flag_table_sh;
+static flag_context_list_table_ty flag_table_python;
+static flag_context_list_table_ty flag_table_lisp;
+static flag_context_list_table_ty flag_table_elisp;
+static flag_context_list_table_ty flag_table_librep;
+static flag_context_list_table_ty flag_table_java;
+static flag_context_list_table_ty flag_table_awk;
+static flag_context_list_table_ty flag_table_ycp;
+static flag_context_list_table_ty flag_table_tcl;
+static flag_context_list_table_ty flag_table_perl;
+static flag_context_list_table_ty flag_table_php;
+
 /* Canonicalized encoding name for all input files.  */
 const char *xgettext_global_source_encoding;
 
@@ -167,6 +183,7 @@ static const struct option long_options[] =
   { "exclude-file", required_argument, NULL, 'x' },
   { "extract-all", no_argument, NULL, 'a' },
   { "files-from", required_argument, NULL, 'f' },
+  { "flag", required_argument, NULL, CHAR_MAX + 7 },
   { "force-po", no_argument, &force_po, 1 },
   { "foreign-user", no_argument, NULL, CHAR_MAX + 2 },
   { "from-code", required_argument, NULL, CHAR_MAX + 3 },
@@ -202,8 +219,18 @@ static const struct option long_options[] =
    in which to add the messages.  */
 typedef void (*extractor_func) (FILE *fp, const char *real_filename,
                                const char *logical_filename,
+                               flag_context_list_table_ty *flag_table,
                                msgdomain_list_ty *mdlp);
 
+typedef struct extractor_ty extractor_ty;
+struct extractor_ty
+{
+  extractor_func func;
+  flag_context_list_table_ty *flag_table;
+  struct formatstring_parser *formatstring_parser1;
+  struct formatstring_parser *formatstring_parser2;
+};
+
 
 /* Forward declaration of local functions.  */
 static void usage (int status)
@@ -212,11 +239,11 @@ static void usage (int status)
 #endif
 ;
 static void read_exclusion_file (char *file_name);
-static void extract_from_file (const char *file_name, extractor_func extractor,
+static void extract_from_file (const char *file_name, extractor_ty extractor,
                               msgdomain_list_ty *mdlp);
 static message_ty *construct_header (void);
 static void finalize_header (msgdomain_list_ty *mdlp);
-static extractor_func language_to_extractor (const char *name);
+static extractor_ty language_to_extractor (const char *name);
 static const char *extension_to_language (const char *extension);
 
 
@@ -235,7 +262,7 @@ main (int argc, char *argv[])
   const char *files_from = NULL;
   string_list_ty *file_list;
   char *output_file = NULL;
-  extractor_func extractor = NULL;
+  extractor_ty extractor = { NULL, NULL, NULL, NULL };
 
   /* Set program name for messages.  */
   set_program_name (argv[0]);
@@ -256,6 +283,19 @@ main (int argc, char *argv[])
   /* Set initial value of variables.  */
   default_domain = MESSAGE_DOMAIN_DEFAULT;
   xgettext_global_source_encoding = po_charset_ascii;
+  init_flag_table_c ();
+  init_flag_table_gcc_internal ();
+  init_flag_table_sh ();
+  init_flag_table_python ();
+  init_flag_table_lisp ();
+  init_flag_table_elisp ();
+  init_flag_table_librep ();
+  init_flag_table_java ();
+  init_flag_table_awk ();
+  init_flag_table_ycp ();
+  init_flag_table_tcl ();
+  init_flag_table_perl ();
+  init_flag_table_php ();
 
   while ((optchar = getopt_long (argc, argv,
                                 "ac::Cd:D:eEf:Fhijk::l:L:m::M::no:p:sTVw:x:",
@@ -421,6 +461,9 @@ main (int argc, char *argv[])
        message_print_syntax_properties ();
        output_syntax = syntax_properties;
        break;
+      case CHAR_MAX + 7:       /* --flag */
+       xgettext_record_flag (optarg);
+       break;
       default:
        usage (EXIT_FAILURE);
        /* NOTREACHED */
@@ -550,8 +593,9 @@ This version was built without iconv()."),
       /* Temporarily reset the directory list to empty, because file_name
         is an output file and therefore should not be searched for.  */
       void *saved_directory_list = dir_list_save_reset ();
+      extractor_ty po_extractor = { extract_po, NULL, NULL, NULL };
 
-      extract_from_file (file_name, extract_po, mdlp);
+      extract_from_file (file_name, po_extractor, mdlp);
 
       dir_list_restore (saved_directory_list);
     }
@@ -560,11 +604,11 @@ This version was built without iconv()."),
   for (cnt = 0; cnt < file_list->nitems; ++cnt)
     {
       const char *fname;
-      extractor_func this_file_extractor;
+      extractor_ty this_file_extractor;
 
       fname = file_list->item[cnt];
 
-      if (extractor)
+      if (extractor.func)
        this_file_extractor = extractor;
       else
        {
@@ -699,14 +743,31 @@ Operation mode:\n"));
                               preceding keyword lines) in output file\n"));
       printf ("\n");
       printf (_("\
-Language=C/C++ specific options:\n"));
+Language specific options:\n"));
       printf (_("\
   -a, --extract-all           extract all strings\n"));
+      printf (_("\
+                                (only languages C, C++, ObjectiveC, Shell,\n\
+                                Python, Lisp, EmacsLisp, librep, Java, awk,\n\
+                                Tcl, Perl, PHP, GCC-source, Glade)\n"));
       printf (_("\
   -k, --keyword[=WORD]        additional keyword to be looked for (without\n\
                               WORD means not to use default keywords)\n"));
+      printf (_("\
+                                (only languages C, C++, ObjectiveC, Shell,\n\
+                                Python, Lisp, EmacsLisp, librep, Java, awk,\n\
+                                Tcl, Perl, PHP, GCC-source, Glade)\n"));
+      printf (_("\
+      --flag=WORD:ARG:FLAG    additional flag for strings inside the argument\n\
+                              number ARG of keyword WORD\n"));
+      printf (_("\
+                                (only languages C, C++, ObjectiveC, Shell,\n\
+                                Python, Lisp, EmacsLisp, librep, Java, awk,\n\
+                                YCP, Tcl, Perl, PHP, GCC-source)\n"));
       printf (_("\
   -T, --trigraphs             understand ANSI C trigraphs for input\n"));
+      printf (_("\
+                                (only languages C, C++, ObjectiveC)\n"));
       printf (_("\
       --debug                 more detailed formatstring recognition result\n"));
       printf ("\n");
@@ -903,6 +964,405 @@ split_keywordspec (const char *spec,
 }
 
 
+/* Null context.  */
+flag_context_ty null_context = { undecided, false, undecided, false };
+
+/* Transparent context.  */
+flag_context_ty passthrough_context = { undecided, true, undecided, true };
+
+
+flag_context_ty
+inherited_context (flag_context_ty outer_context,
+                  flag_context_ty modifier_context)
+{
+  flag_context_ty result = modifier_context;
+
+  if (result.pass_format1)
+    {
+      result.is_format1 = outer_context.is_format1;
+      result.pass_format1 = false;
+    }
+  if (result.pass_format2)
+    {
+      result.is_format2 = outer_context.is_format2;
+      result.pass_format2 = false;
+    }
+  return result;
+}
+
+
+/* Null context list iterator.  */
+flag_context_list_iterator_ty null_context_list_iterator = { 1, NULL };
+
+/* Transparent context list iterator.  */
+static flag_context_list_ty passthrough_context_circular_list =
+  {
+    1,
+    { undecided, true, undecided, true },
+    &passthrough_context_circular_list
+  };
+flag_context_list_iterator_ty passthrough_context_list_iterator =
+  {
+    1,
+    &passthrough_context_circular_list
+  };
+
+
+flag_context_list_iterator_ty
+flag_context_list_iterator (flag_context_list_ty *list)
+{
+  flag_context_list_iterator_ty result = { 1, list };
+
+  return result;
+}
+
+
+flag_context_ty
+flag_context_list_iterator_advance (flag_context_list_iterator_ty *iter)
+{
+  if (iter->head == NULL)
+    return null_context;
+  if (iter->argnum == iter->head->argnum)
+    {
+      flag_context_ty result = iter->head->flags;
+
+      /* Special casing of circular list.  */
+      if (iter->head != iter->head->next)
+       {
+         iter->head = iter->head->next;
+         iter->argnum++;
+       }
+
+      return result;
+    }
+  else
+    {
+      iter->argnum++;
+      return null_context;
+    }
+}
+
+
+flag_context_list_ty *
+flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
+                               const void *key, size_t keylen)
+{
+  void *entry;
+
+  if (flag_table->table != NULL
+      && find_entry (flag_table, key, keylen, &entry) == 0)
+    return (flag_context_list_ty *) entry;
+  else
+    return NULL;
+}
+
+
+void
+xgettext_record_flag (const char *optionstring)
+{
+  /* Check the string has at least two colons.  (Colons in the name are
+     allowed, needed for the Lisp and the Tcl backends.)  */
+  const char *colon1;
+  const char *colon2;
+
+  for (colon2 = optionstring + strlen (optionstring); ; )
+    {
+      if (colon2 == optionstring)
+       goto err;
+      colon2--;
+      if (*colon2 == ':')
+       break;
+    }
+  for (colon1 = colon2; ; )
+    {
+      if (colon1 == optionstring)
+       goto err;
+      colon1--;
+      if (*colon1 == ':')
+       break;
+    }
+  {
+    const char *name_start = optionstring;
+    const char *name_end = colon1;
+    const char *argnum_start = colon1 + 1;
+    const char *argnum_end = colon2;
+    const char *flag = colon2 + 1;
+    int argnum;
+
+    /* Check the parts' syntax.  */
+    if (name_end == name_start)
+      goto err;
+    if (argnum_end == argnum_start)
+      goto err;
+    {
+      char *endp;
+      argnum = strtol (argnum_start, &endp, 10);
+      if (endp != argnum_end)
+       goto err;
+    }
+    if (argnum <= 0)
+      goto err;
+
+    /* Analyze the flag part.  */
+    {
+      bool pass;
+
+      pass = false;
+      if (strlen (flag) >= 5 && memcmp (flag, "pass-", 5) == 0)
+       {
+         pass = true;
+         flag += 5;
+       }
+
+      /* Unlike po_parse_comment_special(), we don't accept "fuzzy" or "wrap"
+        here - it has no sense.  */
+      if (strlen (flag) >= 7
+         && memcmp (flag + strlen (flag) - 7, "-format", 7) == 0)
+       {
+         const char *p;
+         size_t n;
+         enum is_format value;
+         size_t type;
+
+         p = flag;
+         n = strlen (flag) - 7;
+
+         if (n >= 3 && memcmp (p, "no-", 3) == 0)
+           {
+             p += 3;
+             n -= 3;
+             value = no;
+           }
+         else if (n >= 9 && memcmp (p, "possible-", 9) == 0)
+           {
+             p += 9;
+             n -= 9;
+             value = possible;
+           }
+         else if (n >= 11 && memcmp (p, "impossible-", 11) == 0)
+           {
+             p += 11;
+             n -= 11;
+             value = impossible;
+           }
+         else
+           value = yes_according_to_context;
+
+         for (type = 0; type < NFORMATS; type++)
+           if (strlen (format_language[type]) == n
+               && memcmp (format_language[type], p, n) == 0)
+             {
+               flag_context_list_table_ty *table;
+               unsigned int index;
+
+               index = 0;
+               switch (type)
+                 {
+                 case format_c:
+                   table = &flag_table_c;
+                   break;
+                 case format_sh:
+                   table = &flag_table_sh;
+                   break;
+                 case format_python:
+                   table = &flag_table_python;
+                   break;
+                 case format_lisp:
+                   table = &flag_table_lisp;
+                   break;
+                 case format_elisp:
+                   table = &flag_table_elisp;
+                   break;
+                 case format_librep:
+                   table = &flag_table_librep;
+                   break;
+                 case format_smalltalk:
+                   return;
+                 case format_java:
+                   table = &flag_table_java;
+                   break;
+                 case format_awk:
+                   table = &flag_table_awk;
+                   break;
+                 case format_pascal:
+                   return;
+                 case format_ycp:
+                   table = &flag_table_ycp;
+                   break;
+                 case format_tcl:
+                   table = &flag_table_tcl;
+                   break;
+                 case format_perl:
+                   table = &flag_table_perl;
+                   break;
+                 case format_perl_brace:
+                   index = 1;
+                   table = &flag_table_perl;
+                   break;
+                 case format_php:
+                   table = &flag_table_php;
+                   break;
+                 case format_gcc_internal:
+                   table = &flag_table_gcc_internal;
+                   break;
+                 default:
+                   abort ();
+                 }
+
+               if (table == &flag_table_lisp)
+                 {
+                   /* Convert NAME to upper case.  */
+                   size_t name_len = name_end - name_start;
+                   char *name = (char *) alloca (name_len);
+                   size_t i;
+
+                   for (i = 0; i < name_len; i++)
+                     name[i] = (name_start[i] >= 'a' && name_start[i] <= 'z'
+                                ? name_start[i] - 'a' + 'A'
+                                : name_start[i]);
+                   name_start = name;
+                   name_end = name + name_len;
+                 }
+               else if (table == &flag_table_tcl)
+                 {
+                   /* Remove redundant "::" prefix.  */
+                   if (name_end - name_start > 2
+                       && name_start[0] == ':' && name_start[1] == ':')
+                     name_start += 2;
+                 }
+
+               /* Insert the pair (VALUE, PASS) at INDEX in the element
+                  numbered ARGNUM of the list corresponding to NAME in the
+                  TABLE.  */
+               if (table->table == NULL)
+                 init_hash (table, 100);
+               {
+                 void *entry;
+
+                 if (find_entry (table, name_start, name_end - name_start,
+                                 &entry) != 0)
+                   {
+                     /* Create new hash table entry.  */
+                     flag_context_list_ty *list =
+                       (flag_context_list_ty *)
+                       xmalloc (sizeof (flag_context_list_ty));
+                     list->argnum = argnum;
+                     memset (&list->flags, '\0', sizeof (list->flags));
+                     switch (index)
+                       {
+                       case 0:
+                         list->flags.is_format1 = value;
+                         list->flags.pass_format1 = pass;
+                         break;
+                       case 1:
+                         list->flags.is_format2 = value;
+                         list->flags.pass_format2 = pass;
+                         break;
+                       default:
+                         abort ();
+                       }
+                     list->next = NULL;
+                     insert_entry (table, name_start, name_end - name_start,
+                                   list);
+                   }
+                 else
+                   {
+                     flag_context_list_ty *list =
+                       (flag_context_list_ty *)entry;
+                     flag_context_list_ty **lastp = NULL;
+
+                     while (list != NULL && list->argnum < argnum)
+                       {
+                         lastp = &list->next;
+                         list = *lastp;
+                       }
+                     if (list != NULL && list->argnum == argnum)
+                       {
+                         /* Add this flag to the current argument number.  */
+                         switch (index)
+                           {
+                           case 0:
+                             list->flags.is_format1 = value;
+                             list->flags.pass_format1 = pass;
+                             break;
+                           case 1:
+                             list->flags.is_format2 = value;
+                             list->flags.pass_format2 = pass;
+                             break;
+                           default:
+                             abort ();
+                           }
+                       }
+                     else if (lastp != NULL)
+                       {
+                         /* Add a new list entry for this argument number.  */
+                         list =
+                           (flag_context_list_ty *)
+                           xmalloc (sizeof (flag_context_list_ty));
+                         list->argnum = argnum;
+                         memset (&list->flags, '\0', sizeof (list->flags));
+                         switch (index)
+                           {
+                           case 0:
+                             list->flags.is_format1 = value;
+                             list->flags.pass_format1 = pass;
+                             break;
+                           case 1:
+                             list->flags.is_format2 = value;
+                             list->flags.pass_format2 = pass;
+                             break;
+                           default:
+                             abort ();
+                           }
+                         list->next = *lastp;
+                         *lastp = list;
+                       }
+                     else
+                       {
+                         /* Add a new list entry for this argument number,
+                            at the beginning of the list.  Since we don't
+                            have an API for replacing the value of a key
+                            in the hash table, we have to copy the first
+                            list element.  */
+                         flag_context_list_ty *copy =
+                           (flag_context_list_ty *)
+                           xmalloc (sizeof (flag_context_list_ty));
+                         *copy = *list;
+
+                         list->argnum = argnum;
+                         memset (&list->flags, '\0', sizeof (list->flags));
+                         switch (index)
+                           {
+                           case 0:
+                             list->flags.is_format1 = value;
+                             list->flags.pass_format1 = pass;
+                             break;
+                           case 1:
+                             list->flags.is_format2 = value;
+                             list->flags.pass_format2 = pass;
+                             break;
+                           default:
+                             abort ();
+                           }
+                         list->next = copy;
+                       }
+                   }
+               }
+               return;
+             }
+         /* If the flag is not among the valid values, the optionstring is
+            invalid.  */
+       }
+    }
+  }
+
+err:
+  error (EXIT_FAILURE, 0, _("\
+A --flag argument doesn't have the <keyword>:<argnum>:[pass-]<flag> syntax: %s"),
+        optionstring);
+}
+
+
 static string_list_ty *comment;
 
 void
@@ -994,8 +1454,14 @@ error while opening \"%s\" for reading"), new_name);
 }
 
 
+/* Language dependent format string parser.
+   NULL if the language has no notion of format strings.  */
+static struct formatstring_parser *current_formatstring_parser1;
+static struct formatstring_parser *current_formatstring_parser2;
+
+
 static void
-extract_from_file (const char *file_name, extractor_func extractor,
+extract_from_file (const char *file_name, extractor_ty extractor,
                   msgdomain_list_ty *mdlp)
 {
   char *logical_file_name;
@@ -1009,7 +1475,10 @@ extract_from_file (const char *file_name, extractor_func extractor,
   xgettext_current_source_iconv = xgettext_global_source_iconv;
 #endif
 
-  extractor (fp, real_file_name, logical_file_name, mdlp);
+  current_formatstring_parser1 = extractor.formatstring_parser1;
+  current_formatstring_parser2 = extractor.formatstring_parser2;
+  extractor.func (fp, real_file_name, logical_file_name, extractor.flag_table,
+                 mdlp);
 
   if (fp != stdin)
     fclose (fp);
@@ -1019,12 +1488,6 @@ extract_from_file (const char *file_name, extractor_func extractor,
 
 
 
-/* Language dependent format string parser.
-   NULL if the language has no notion of format strings.  */
-static struct formatstring_parser *current_formatstring_parser1;
-static struct formatstring_parser *current_formatstring_parser2;
-
-
 #if !HAVE_ICONV
 /* If we don't have iconv(), the only supported values for
    xgettext_global_source_encoding and thus also for
@@ -1070,8 +1533,67 @@ Please specify the source encoding through --from-code.\n"),
                                         pos->line_number);
 
 
+/* Update the is_format[] flags depending on the information given in the
+   context.  */
+static void
+set_format_flags_from_context (enum is_format is_format[NFORMATS],
+                              flag_context_ty context, const char *string,
+                              lex_pos_ty *pos, const char *pretty_msgstr)
+{
+  size_t i;
+
+  if (context.is_format1 != undecided || context.is_format2 != undecided)
+    for (i = 0; i < NFORMATS; i++)
+      {
+       if (is_format[i] == undecided)
+         {
+           if (formatstring_parsers[i] == current_formatstring_parser1
+               && context.is_format1 != undecided)
+             is_format[i] = context.is_format1;
+           if (formatstring_parsers[i] == current_formatstring_parser2
+               && context.is_format2 != undecided)
+             is_format[i] = context.is_format2;
+         }
+       if (possible_format_p (is_format[i]))
+         {
+           struct formatstring_parser *parser = formatstring_parsers[i];
+           char *invalid_reason = NULL;
+           void *descr = parser->parse (string, &invalid_reason);
+
+           if (descr != NULL)
+             parser->free (descr);
+           else
+             {
+               /* The string is not a valid format string.  */
+               if (is_format[i] != possible)
+                 {
+                   char buffer[21];
+
+                   error_with_progname = false;
+                   if (pos->line_number == (size_t)(-1))
+                     buffer[0] = '\0';
+                   else
+                     sprintf (buffer, ":%ld", (long) pos->line_number);
+                   multiline_warning (xasprintf (_("%s%s: warning: "),
+                                                 pos->file_name, buffer),
+                                      xasprintf (is_format[i] == yes_according_to_context ? _("Although being used in a format string position, the %s is not a valid %s format string. Reason: %s\n") : _("Although declared as such, the %s is not a valid %s format string. Reason: %s\n"),
+                                                 pretty_msgstr,
+                                                 format_language_pretty[i],
+                                                 invalid_reason));
+                   error_with_progname = true;
+                 }
+
+               is_format[i] = impossible;
+               free (invalid_reason);
+             }
+         }
+      }
+}
+
+
 message_ty *
-remember_a_message (message_list_ty *mlp, char *string, lex_pos_ty *pos)
+remember_a_message (message_list_ty *mlp, char *string,
+                   flag_context_ty context, lex_pos_ty *pos)
 {
   enum is_format is_format[NFORMATS];
   enum is_wrap do_wrap;
@@ -1148,6 +1670,10 @@ meta information, not the empty string.\n")));
       message_list_append (mlp, mp);
     }
 
+  /* Determine whether the context specifies that the msgid is a format
+     string.  */
+  set_format_flags_from_context (is_format, context, mp->msgid, pos, "msgid");
+
   /* Ask the lexer for the comments it has seen.  Only do this for the
      first instance, otherwise there could be problems; especially if
      the same comment appears before each.  */
@@ -1261,7 +1787,8 @@ meta information, not the empty string.\n")));
 
 
 void
-remember_a_message_plural (message_ty *mp, char *string, lex_pos_ty *pos)
+remember_a_message_plural (message_ty *mp, char *string,
+                          flag_context_ty context, lex_pos_ty *pos)
 {
   char *msgid_plural;
   char *msgstr1;
@@ -1298,6 +1825,11 @@ remember_a_message_plural (message_ty *mp, char *string, lex_pos_ty *pos)
       mp->msgstr = msgstr;
       mp->msgstr_len = mp->msgstr_len + msgstr1_len;
 
+      /* Determine whether the context specifies that the msgid_plural is a
+        format string.  */
+      set_format_flags_from_context (mp->is_format, context, mp->msgid_plural,
+                                    pos, "msgid_plural");
+
       /* If it is not already decided, through programmer comments or
         the msgid, whether the msgid is a format string, examine the
         msgid_plural.  This is a heuristic.  */
@@ -1471,7 +2003,7 @@ finalize_header (msgdomain_list_ty *mdlp)
 #define ENDOF(a) ((a) + SIZEOF(a))
 
 
-static extractor_func
+static extractor_ty
 language_to_extractor (const char *name)
 {
   typedef struct table_ty table_ty;
@@ -1479,6 +2011,7 @@ language_to_extractor (const char *name)
   {
     const char *name;
     extractor_func func;
+    flag_context_list_table_ty *flag_table;
     struct formatstring_parser *formatstring_parser1;
     struct formatstring_parser *formatstring_parser2;
   };
@@ -1511,16 +2044,22 @@ language_to_extractor (const char *name)
   for (tp = table; tp < ENDOF(table); ++tp)
     if (strcasecmp (name, tp->name) == 0)
       {
-       /* XXX Ugly side effect.  */
-       current_formatstring_parser1 = tp->formatstring_parser1;
-       current_formatstring_parser2 = tp->formatstring_parser2;
+       extractor_ty result =
+         {
+           tp->func,
+           tp->flag_table,
+           tp->formatstring_parser1, tp->formatstring_parser2
+         };
 
-       return tp->func;
+       return result;
       }
 
   error (EXIT_FAILURE, 0, _("language `%s' unknown"), name);
   /* NOTREACHED */
-  return NULL;
+  {
+    extractor_ty result = { NULL, NULL, NULL, NULL };
+    return result;
+  }
 }
 
 
index b209405309eafd75ab94d08912fdd858c5593b7b..426af68dde2047f6c215999bccc80fda5148dc29 100644 (file)
@@ -44,10 +44,69 @@ extern int xgettext_omit_header;
 
 extern bool substring_match;
 
+
 /* Split keyword spec into keyword, argnum1, argnum2.  */
 extern void split_keywordspec (const char *spec, const char **endp,
                               int *argnum1p, int *argnum2p);
 
+
+/* Context representing some flags.  */
+typedef struct flag_context_ty flag_context_ty;
+struct flag_context_ty
+{
+  /* Regarding the primary formatstring type.  */
+  enum is_format is_format1 : 3;
+  bool pass_format1         : 1;
+  /* Regarding the secondary formatstring type.  */
+  enum is_format is_format2 : 3;
+  bool pass_format2         : 1;
+};
+/* Null context.  */
+extern flag_context_ty null_context;
+/* Transparent context.  */
+extern flag_context_ty passthrough_context;
+/* Compute an inherited context.
+   The outer_context is assumed to have all pass_format* flags = false.
+   The result will then also have all pass_format* flags = false.  */
+extern flag_context_ty
+       inherited_context (flag_context_ty outer_context,
+                         flag_context_ty modifier_context);
+
+/* Context representing some flags, for each possible argument number.
+   This is a linked list, sorted according to the argument number.  */
+typedef struct flag_context_list_ty flag_context_list_ty;
+struct flag_context_list_ty
+{
+  int argnum;                  /* current argument number, > 0 */
+  flag_context_ty flags;       /* flags for current argument */
+  flag_context_list_ty *next;
+};
+
+/* Iterator through a flag_context_list_ty.  */
+typedef struct flag_context_list_iterator_ty flag_context_list_iterator_ty;
+struct flag_context_list_iterator_ty
+{
+  int argnum;                          /* current argument number, > 0 */
+  const flag_context_list_ty* head;    /* tail of list */
+};
+extern flag_context_list_iterator_ty null_context_list_iterator;
+extern flag_context_list_iterator_ty passthrough_context_list_iterator;
+extern flag_context_list_iterator_ty
+       flag_context_list_iterator (flag_context_list_ty *list);
+extern flag_context_ty
+       flag_context_list_iterator_advance (flag_context_list_iterator_ty *iter);
+
+/* For nearly each backend, we have a separate table mapping a keyword to
+   a flag_context_list_ty *.  */
+typedef hash_table /* char[] -> flag_context_list_ty * */
+        flag_context_list_table_ty;
+extern flag_context_list_ty *
+       flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
+                                      const void *key, size_t keylen);
+/* Record a flag in the appropriate backend's table.  */
+extern void xgettext_record_flag (const char *optionstring);
+
+
 /* Canonicalized encoding name for all input files.  */
 extern const char *xgettext_global_source_encoding;
 
@@ -74,27 +133,34 @@ extern char *from_current_source_encoding (const char *string,
                                           const char *file_name,
                                           size_t line_number);
 
+
 /* List of messages whose msgids must not be extracted, or NULL.
    Used by remember_a_message().  */
 extern message_list_ty *exclude;
 
+
 /* Comment handling: There is a list of automatic comments that may be appended
    to the next message.  Used by remember_a_message().  */
 extern void xgettext_comment_add (const char *str);
 extern const char *xgettext_comment (size_t n);
 extern void xgettext_comment_reset (void);
 
+
 /* Add a message to the list of extracted messages.
    string must be malloc()ed string; its ownership is passed to the callee.
    pos->file_name must be allocated with indefinite extent.  */
 extern message_ty *remember_a_message (message_list_ty *mlp,
-                                      char *string, lex_pos_ty *pos);
+                                      char *string,
+                                      flag_context_ty context,
+                                      lex_pos_ty *pos);
 /* Add an msgid_plural to a message previously returned by
    remember_a_message.
    string must be malloc()ed string; its ownership is passed to the callee.
    pos->file_name must be allocated with indefinite extent.  */
 extern void remember_a_message_plural (message_ty *mp,
-                                      char *string, lex_pos_ty *pos);
+                                      char *string,
+                                      flag_context_ty context,
+                                      lex_pos_ty *pos);
 
 
 #ifdef __cplusplus
index 5f20369e59950965795290afed1175da2777b4e3..8e1f52a1a3356910e93e042384956a11d316f55e 100644 (file)
@@ -1,3 +1,18 @@
+2003-10-05  Bruno Haible  <bruno@clisp.org>
+
+       * xgettext-4: Update expected test result.
+       * xgettext-5: Likewise.
+       * xgettext-6: Likewise.
+       * xgettext-8: Likewise.
+       * xgettext-24: Likewise.
+       * xgettext-26: Pass --flag options to xgettext. Update expected test
+       result.
+       * lang-perl-1: Pass --flag options to xgettext.
+       * lang-perl-2: Likewise.
+
+       * xgettext-31: New file.
+       * Makefile.am (TESTS): Add it.
+
 2003-10-04  Bruno Haible  <bruno@clisp.org>
 
        * xgettext-11: Test details of the new Java backend, instead of the
index 8d8ab06200dda8094cd3d4aa7b02ebaa37036f5b..fa7e3986dbc4f041b55cabb20406952b32a7ea5c 100644 (file)
@@ -50,7 +50,7 @@ TESTS = gettext-1 gettext-2 \
        xgettext-13 xgettext-14 xgettext-15 xgettext-16 xgettext-17 \
        xgettext-18 xgettext-19 xgettext-20 xgettext-21 xgettext-22 \
        xgettext-23 xgettext-24 xgettext-25 xgettext-26 xgettext-27 \
-       xgettext-28 xgettext-29 xgettext-30 \
+       xgettext-28 xgettext-29 xgettext-30 xgettext-31 \
        format-awk-1 format-awk-2 \
        format-c-1 format-c-2 format-c-3 format-c-4 \
        format-elisp-1 format-elisp-2 \
index 7adc35d5f311be809d126c59a3a37f2120fdaef7..8bdbd0448563d572eb57c83c8c054a782113dafc 100755 (executable)
@@ -26,7 +26,9 @@ EOF
 
 tmpfiles="$tmpfiles prog.pot"
 : ${XGETTEXT=xgettext}
-${XGETTEXT} -k__ -o prog.pot --omit-header --no-location program.pl
+${XGETTEXT} \
+  -k__ --flag=__:1:pass-perl-format --flag=__:1:pass-perl-brace-format \
+  -o prog.pot --omit-header --no-location program.pl
 
 tmpfiles="$tmpfiles prog.ok"
 cat <<EOF > prog.ok
@@ -55,7 +57,7 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
 msgid "'Your command, please?', asked the waiter."
-msgstr "«Votre commande, s'il vous plait», dit le garçon."
+msgstr "Votre commande, s'il vous plait, dit le gar�n."
 
 # Les gateaux allemands sont les meilleurs du monde.
 #, perl-format
@@ -87,7 +89,7 @@ ${MSGFMT} -o fr/LC_MESSAGES/prog.mo fr.po
 tmpfiles="$tmpfiles prog.ok prog.out"
 : ${DIFF=diff}
 cat <<\EOF > prog.ok
-«Votre commande, s'il vous plait», dit le garçon.
+Votre commande, s'il vous plait, dit le gar�n.
 2 morceaux de gateau
 EUR remplace FF.
 EOF
index 845b5a0b0188709db4aa3c72e44017a677482e14..f9868b20e7330c2e6a5552223f2467b9b469b491 100755 (executable)
@@ -22,7 +22,12 @@ EOF
 
 tmpfiles="$tmpfiles prog.pot"
 : ${XGETTEXT=xgettext}
-${XGETTEXT} -k__ -k__n:1,2 -k__x -o prog.pot --omit-header --no-location program.pl
+${XGETTEXT} \
+  -k__ --flag=__:1:pass-perl-format --flag=__:1:pass-perl-brace-format \
+  -k__n:1,2 --flag=__n:1:pass-perl-format --flag=__n:1:pass-perl-brace-format \
+            --flag=__n:2:pass-perl-format --flag=__n:2:pass-perl-brace-format \
+  -k__x --flag=__x:1:perl-brace-format \
+  -o prog.pot --omit-header --no-location program.pl
 
 tmpfiles="$tmpfiles prog.ok"
 cat <<EOF > prog.ok
index eb82a66e5c503ba8ca48757bb33c707aee7c57d4..8ebb2b27336de1d96987ae9f2d7db03ecb4601a1 100755 (executable)
@@ -65,6 +65,7 @@ msgid "hello"
 msgstr "Again some text for fuzzy"
 
 #: xg-test24.c:6
+#, c-format
 msgid "Hello, world."
 msgstr ""
 
index f17b5fcdd2669ce5e7393d3781dbfef477087cfe..8491be414a404cee09086acdac2a32402f4b359d 100755 (executable)
@@ -150,7 +150,11 @@ EOF
 
 tmpfiles="$tmpfiles xg-test26.po"
 : ${XGETTEXT=xgettext}
-${XGETTEXT} --omit-header -n -k_ -k%__ -k\$__ xg-test26.pl -d xg-test26
+${XGETTEXT} --omit-header -n \
+  -k_ --flag=_:1:pass-perl-format --flag=_:1:pass-perl-brace-format \
+  -k%__ --flag=%__:1:pass-perl-format --flag=%__:1:pass-perl-brace-format \
+  -k\$__ --flag=\$__:1:pass-perl-format --flag=\$__:1:pass-perl-brace-format \
+  xg-test26.pl -d xg-test26
 test $? = 0 || { rm -fr $tmpfiles; exit 1; }
 
 tmpfiles="$tmpfiles xg-test26.ok"
@@ -179,6 +183,7 @@ msgstr[0] ""
 msgstr[1] ""
 
 #: xg-test26.pl:22
+#, perl-format
 msgid "Singular\n"
 msgid_plural "Plural\n"
 msgstr[0] ""
diff --git a/gettext-tools/tests/xgettext-31 b/gettext-tools/tests/xgettext-31
new file mode 100755 (executable)
index 0000000..0b6f11b
--- /dev/null
@@ -0,0 +1,259 @@
+#!/bin/sh
+
+# Test of position dependent recognition of format strings.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles xg-test31.c"
+cat <<\EOF > xg-test31.c
+fprintf (fp, gettext ("c-format positive1"), gettext ("c-format negative1"));
+printk (gettext ("c-format negative2"));
+EOF
+
+tmpfiles="$tmpfiles xg-test31.sh"
+cat <<\EOF > xg-test31.sh
+eval_gettext "sh-format positive1" "`gettext \"sh-format negative1\"`"
+echo "`gettext \"sh-format negative2\"`"
+EOF
+
+tmpfiles="$tmpfiles xg-test31.py"
+cat <<\EOF > xg-test31.py
+my_printf (gettext ("python-format positive1"),
+           gettext ("python-format negative1"));
+printk (gettext ("python-format negative2"));
+EOF
+
+tmpfiles="$tmpfiles xg-test31.lisp"
+cat <<\EOF > xg-test31.lisp
+(format t (gettext "lisp-format positive1") (gettext "lisp-format negative1"))
+(prin1 (gettext "lisp-format negative2"))
+EOF
+
+tmpfiles="$tmpfiles xg-test31.el"
+cat <<\EOF > xg-test31.el
+(format (_ "elisp-format positive1") (_ "elisp-format negative1"))
+(printk (_ "elisp-format negative2"))
+EOF
+
+tmpfiles="$tmpfiles xg-test31.jl"
+cat <<\EOF > xg-test31.jl
+(format stream (_ "librep-format positive1") (_ "librep-format negative1"))
+(printk (_ "librep-format negative2"))
+EOF
+
+tmpfiles="$tmpfiles xg-test31.java"
+cat <<\EOF > xg-test31.java
+MessageFormat.format(gettext("java-format positive1"),
+                     gettext("java-format negative1"));
+System.err.println(gettext("java-format negative2"));
+EOF
+
+tmpfiles="$tmpfiles xg-test31.awk"
+cat <<\EOF > xg-test31.awk
+printf dcgettext ("awk-format positive1"), dcgettext ("awk-format negative1");
+printf (dcgettext ("awk-format positive2"), dcgettext ("awk-format negative2"));
+printf dcgettext ("awk-format positive3"); dcgettext ("awk-format negative3");
+printk dcgettext ("awk-format negative4");
+EOF
+
+tmpfiles="$tmpfiles xg-test31.ycp"
+cat <<\EOF > xg-test31.ycp
+sformat (_("ycp-format positive1"), _("ycp-format negative1"));
+printk (_("ycp-format negative2"));
+EOF
+
+tmpfiles="$tmpfiles xg-test31.tcl"
+cat <<\EOF > xg-test31.tcl
+[format [::msgcat::mc "tcl-format positive1"]
+        [::msgcat::mc "tcl-format negative1"]]
+[print [::msgcat::mc "tcl-format negative2"]]
+EOF
+
+tmpfiles="$tmpfiles xg-test31.pl"
+cat <<\EOF > xg-test31.pl
+printf gettext "perl-format positive1", gettext ("perl-format negative1");
+gettext ("perl-format negative2");
+printf gettext "perl-format positive2"; gettext ("perl-format negative3");
+gettext ("perl-format negative4");
+print sprintf gettext "perl-format positive3";
+print kprintf gettext "perl-format negative5";
+EOF
+
+tmpfiles="$tmpfiles xg-test31.php"
+cat <<\EOF > xg-test31.php
+<? php
+printf (_ ("php-format positive1"), _ ("php-format negative1"));
+printk (_ ("php-format negative2"));
+EOF
+
+tmpfiles="$tmpfiles xg-test31.po"
+: ${XGETTEXT=xgettext}
+${XGETTEXT} --omit-header --no-location -d xg-test31 \
+  --flag=my_printf:1:python-format \
+  xg-test31.c xg-test31.sh xg-test31.py xg-test31.lisp xg-test31.el \
+  xg-test31.jl xg-test31.java xg-test31.awk xg-test31.ycp xg-test31.tcl \
+  xg-test31.pl xg-test31.php 
+test $? = 0 || { rm -fr $tmpfiles; exit 1; }
+
+tmpfiles="$tmpfiles xg-test31.ok"
+cat <<\EOF > xg-test31.ok
+#, c-format
+msgid "c-format positive1"
+msgstr ""
+
+msgid "c-format negative1"
+msgstr ""
+
+msgid "c-format negative2"
+msgstr ""
+
+#, sh-format
+msgid "sh-format positive1"
+msgstr ""
+
+msgid "sh-format negative1"
+msgstr ""
+
+msgid "sh-format negative2"
+msgstr ""
+
+#, python-format
+msgid "python-format positive1"
+msgstr ""
+
+msgid "python-format negative1"
+msgstr ""
+
+msgid "python-format negative2"
+msgstr ""
+
+#, lisp-format
+msgid "lisp-format positive1"
+msgstr ""
+
+msgid "lisp-format negative1"
+msgstr ""
+
+msgid "lisp-format negative2"
+msgstr ""
+
+#, elisp-format
+msgid "elisp-format positive1"
+msgstr ""
+
+msgid "elisp-format negative1"
+msgstr ""
+
+msgid "elisp-format negative2"
+msgstr ""
+
+#, librep-format
+msgid "librep-format positive1"
+msgstr ""
+
+msgid "librep-format negative1"
+msgstr ""
+
+msgid "librep-format negative2"
+msgstr ""
+
+#, java-format
+msgid "java-format positive1"
+msgstr ""
+
+msgid "java-format negative1"
+msgstr ""
+
+msgid "java-format negative2"
+msgstr ""
+
+#, awk-format
+msgid "awk-format positive1"
+msgstr ""
+
+msgid "awk-format negative1"
+msgstr ""
+
+#, awk-format
+msgid "awk-format positive2"
+msgstr ""
+
+msgid "awk-format negative2"
+msgstr ""
+
+#, awk-format
+msgid "awk-format positive3"
+msgstr ""
+
+msgid "awk-format negative3"
+msgstr ""
+
+msgid "awk-format negative4"
+msgstr ""
+
+#, ycp-format
+msgid "ycp-format positive1"
+msgstr ""
+
+msgid "ycp-format negative1"
+msgstr ""
+
+msgid "ycp-format negative2"
+msgstr ""
+
+#, tcl-format
+msgid "tcl-format positive1"
+msgstr ""
+
+msgid "tcl-format negative1"
+msgstr ""
+
+msgid "tcl-format negative2"
+msgstr ""
+
+#, perl-format
+msgid "perl-format positive1"
+msgstr ""
+
+msgid "perl-format negative1"
+msgstr ""
+
+msgid "perl-format negative2"
+msgstr ""
+
+#, perl-format
+msgid "perl-format positive2"
+msgstr ""
+
+msgid "perl-format negative3"
+msgstr ""
+
+msgid "perl-format negative4"
+msgstr ""
+
+#, perl-format
+msgid "perl-format positive3"
+msgstr ""
+
+msgid "perl-format negative5"
+msgstr ""
+
+#, php-format
+msgid "php-format positive1"
+msgstr ""
+
+msgid "php-format negative1"
+msgstr ""
+
+msgid "php-format negative2"
+msgstr ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-test31.ok xg-test31.po
+result=$?
+
+rm -fr $tmpfiles
+
+exit $result
index 80cfb2ca4b58a3c1ed6fbe6fc80a5f61f0f6e247..42fe8416431fa9ddc2c5fabca775138cae9893f4 100755 (executable)
@@ -21,6 +21,7 @@ test $? = 0 || { rm -fr $tmpfiles; exit 1; }
 tmpfiles="$tmpfiles xg-test4.ok"
 cat <<EOF > xg-test4.ok
 #: bozo:42
+#, c-format
 msgid "Hello, World!\n"
 msgstr ""
 
index 36f6dc64c6759a9c1487944377f44794aca4236f..ce100a4c58f4133e38a8548a1597243344881d65 100755 (executable)
@@ -17,6 +17,7 @@ test $? = 0 || { rm -fr $tmpfiles; exit 1; }
 
 tmpfiles="$tmpfiles xg-test5.ok"
 cat <<EOF > xg-test5.ok
+#, c-format
 msgid "Hello, World!\n"
 msgstr ""
 EOF
index 16a7a3a3f46a4f1cbb5550679fe084f8303bb346..c9a411935c7a1cbccb2a3dd2ae2f5ff03c170593 100755 (executable)
@@ -19,6 +19,7 @@ tmpfiles="$tmpfiles xg-test6.ok"
 cat <<EOF > xg-test6.ok
 #. puke
 #. barf
+#, c-format
 msgid "Hello, World!\n"
 msgstr ""
 EOF
index 837832a1c1efa7f4f1cfac9c6ad5f4c9737933c9..0c784ffc5ec68528044e6e0342b79f09f6d98232 100755 (executable)
@@ -68,6 +68,7 @@ msgid "hello"
 msgstr "Again some text for fuzzy"
 
 #: xg-test8.c:6
+#, c-format
 msgid "Hello, world."
 msgstr ""