Package: gettext
Version: 0.15-2
Severity: important

Hello,

dpkg currently fails to update its POTs which contain strings extracted
from Perl scripts.

The attached Perl script is a minimal example to reproduce this bug.
It also gives some ideas on how to fix the perl scripts to bypass the bug.

    xgettext -k_ test.pl
    test.pl:10: invalid variable interpolation at "$"

It seems xgettext considers some strings out of _(...) as being part of the
msgid, and thus refuses dollars in the parameters following the format of
printf.

I think the bug is caused by extract_balanced in gettext-tools/src/x-perl.c
This function uses a state and is recusive, but the state is not
propagated back to the caller. I made a test, which uses the following
prototype (state is now a pointer):
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, struct arglist_parser *argparser);

It works with the attached example, but I did not test it on something
more complicated. Also, I was a little bit lost in the parser, so it may
be completely wrong.

Kind Regards,
-- 
Nekral
#!/usr/bin/perl

my $a="a";

# These are parsed OK
printf _("%s\n"), $a;
printf (_("%s\n")), "$a";
printf _("%s\n")."", "$a";

# Parsing error
printf _("%s\n"), "$a";
diff -rauN ../orig/gettext-0.15/gettext-tools/src/x-perl.c 
./gettext-0.15/gettext-tools/src/x-perl.c
--- ../orig/gettext-0.15/gettext-tools/src/x-perl.c     2006-05-08 
15:31:37.000000000 +0200
+++ ./gettext-0.15/gettext-tools/src/x-perl.c   2006-09-11 01:56:16.000000000 
+0200
@@ -759,7 +759,7 @@
                                  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 state,
+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,
@@ -1282,6 +1282,7 @@
   size_t varbody_length = 0;
   bool maybe_hash_deref = false;
   bool maybe_hash_value = false;
+  int state = 0;
 
   tp->type = token_type_variable;
 
@@ -1369,7 +1370,8 @@
               real_file_name, line_number);
 #endif
 
-      if (extract_balanced (mlp, 0, token_type_rbrace,
+      state = 0;
+      if (extract_balanced (mlp, &state, token_type_rbrace,
                            null_context, null_context_list_iterator,
                            1, arglist_parser_alloc (mlp, NULL)))
        return;
@@ -1560,7 +1562,8 @@
                else
                  {
                    x_perl_unlex (t1);
-                   if (extract_balanced (mlp, 1, token_type_rbrace,
+                   state = 1;
+                   if (extract_balanced (mlp, &state, token_type_rbrace,
                                          null_context, context_iter,
                                          1, arglist_parser_alloc (mlp, 
&shapes)))
                      return;
@@ -1591,7 +1594,8 @@
          fprintf (stderr, "%s:%d: extracting balanced '{' after varname\n",
                   real_file_name, line_number);
 #endif
-         extract_balanced (mlp, 0, token_type_rbrace,
+         state = 0;
+         extract_balanced (mlp, &state, token_type_rbrace,
                            null_context, null_context_list_iterator,
                            1, arglist_parser_alloc (mlp, NULL));
          break;
@@ -1601,7 +1605,8 @@
          fprintf (stderr, "%s:%d: extracting balanced '[' after varname\n",
                   real_file_name, line_number);
 #endif
-         extract_balanced (mlp, 0, token_type_rbracket,
+         state = 0;
+         extract_balanced (mlp, &state, token_type_rbracket,
                            null_context, null_context_list_iterator,
                            1, arglist_parser_alloc (mlp, NULL));
          break;
@@ -2821,7 +2826,7 @@
    tokens will cause a warning.  */
 
 static bool
-extract_balanced (message_list_ty *mlp, 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, struct arglist_parser *argparser)
@@ -2910,7 +2915,7 @@
 
                last_token = token_type_keyword_symbol;
 
-               state = 2;
+               *state = 2;
              }
          }
          next_is_argument = true;
@@ -3015,7 +3020,7 @@
              remember_a_message (mlp, NULL, string, inner_context, &pos, 
savable_comment);
              xgettext_current_source_encoding = 
xgettext_global_source_encoding;
            }
-         else if (state)
+         else if (*state)
            {
              char *string = collect_message (mlp, tp, EXIT_FAILURE);
 
@@ -3033,7 +3038,7 @@
              arglist_parser_done (argparser, arg);
              xgettext_current_source_encoding = 
xgettext_global_source_encoding;
              argparser = arglist_parser_alloc (mlp, NULL);
-             state = 0;
+             *state = 0;
            }
 
          next_is_argument = false;
@@ -3056,7 +3061,8 @@
          fprintf (stderr, "%s:%d: type lbrace (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
-         if (extract_balanced (mlp, 0, token_type_rbrace,
+         *state = 0;
+         if (extract_balanced (mlp, state, token_type_rbrace,
                                null_context, null_context_list_iterator,
                                1, arglist_parser_alloc (mlp, NULL)))
            {
@@ -3077,7 +3083,7 @@
 #endif
          next_is_argument = false;
          next_context_iter = null_context_list_iterator;
-         state = 0;
+         *state = 0;
          break;
 
        case token_type_lbracket:
@@ -3085,7 +3091,8 @@
          fprintf (stderr, "%s:%d: type lbracket (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
-         if (extract_balanced (mlp, 0, token_type_rbracket,
+         *state = 0;
+         if (extract_balanced (mlp, state, token_type_rbracket,
                                null_context, null_context_list_iterator,
                                1, arglist_parser_alloc (mlp, NULL)))
            {
@@ -3106,7 +3113,7 @@
 #endif
          next_is_argument = false;
          next_context_iter = null_context_list_iterator;
-         state = 0;
+         *state = 0;
          break;
 
        case token_type_semicolon:
@@ -3114,7 +3121,7 @@
          fprintf (stderr, "%s:%d: type semicolon (%d)\n",
                   logical_file_name, tp->line_number, nesting_level);
 #endif
-         state = 0;
+         *state = 0;
 
          /* The ultimate sign.  */
          xgettext_current_source_encoding = po_charset_utf8;
@@ -3151,7 +3158,7 @@
 #endif
          next_is_argument = false;
          next_context_iter = null_context_list_iterator;
-         state = 0;
+         *state = 0;
          break;
 
        case token_type_named_op:
@@ -3162,7 +3169,7 @@
 #endif
          next_is_argument = false;
          next_context_iter = null_context_list_iterator;
-         state = 0;
+         *state = 0;
          break;
 
        case token_type_regex_op:
@@ -3181,7 +3188,7 @@
 #endif
          next_is_argument = false;
          next_context_iter = null_context_list_iterator;
-         state = 0;
+         *state = 0;
          break;
 
        default:
@@ -3200,6 +3207,7 @@
              msgdomain_list_ty *mdlp)
 {
   message_list_ty *mlp = mdlp->item[0]->messages;
+  int state = 0;
 
   fp = f;
   real_file_name = real_filename;
@@ -3223,7 +3231,8 @@
 
   /* Eat tokens until eof is seen.  When extract_balanced returns
      due to an unbalanced closing brace, just restart it.  */
-  while (!extract_balanced (mlp, 0, token_type_rbrace,
+  state = 0;
+  while (!extract_balanced (mlp, &state, token_type_rbrace,
                            null_context, null_context_list_iterator,
                            1, arglist_parser_alloc (mlp, NULL)))
     ;

Reply via email to