From: Bruno Haible Date: Thu, 30 Nov 2023 16:16:36 +0000 (+0100) Subject: xgettext: Vala: Flag strings on which the method 'printf' is used as c-format. X-Git-Tag: v0.23~284 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e55e5495222fb561be3ac3f7aa36e1f88eac1de;p=thirdparty%2Fgettext.git xgettext: Vala: Flag strings on which the method 'printf' is used as c-format. * gettext-tools/src/x-vala.c (token_type_semicolon): New enum item. (phase3_get): Recognize semicolon tokens. (phase4_pushback, phase4_pushback_length): New variables. (phase4_get): Renamed from x_vala_lex. Handle pushback. (phase4_unget, x_vala_lex, x_vala_unlex): New functions. (extract_balanced): Handle method invocations .printf and .vprintf. Return when a semicolon was seen. (extract_vala): Initialize phase4_pushback_length. * gettext-tools/tests/xgettext-vala-6: Add tests for printf used as method. * gettext-tools/tests/xgettext-vala-7: New file. * gettext-tools/tests/Makefile.am (TESTS): Add it. * NEWS: Mention the change. --- diff --git a/NEWS b/NEWS index 0af9d0439..f9e7ae073 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ Version 0.23 - December 2023 * Programming languages support: + - Vala: Improved recognition of format strings when the string.printf method + is used. - Glade: xgettext has improved support for GtkBuilder 4. * Runtime behaviour: diff --git a/gettext-tools/src/x-vala.c b/gettext-tools/src/x-vala.c index 0b58d929a..ac41aa233 100644 --- a/gettext-tools/src/x-vala.c +++ b/gettext-tools/src/x-vala.c @@ -403,6 +403,7 @@ enum token_type_ty token_type_string_literal, /* "abc" */ token_type_string_template, /* @"abc" */ token_type_regex_literal, /* /.../ */ + token_type_semicolon, /* ; */ token_type_symbol, /* if else etc. */ token_type_other }; @@ -1206,6 +1207,10 @@ phase3_get (token_ty *tp) return; } + case ';': + tp->type = last_token_type = token_type_semicolon; + return; + default: tp->type = last_token_type = token_type_other; return; @@ -1226,11 +1231,20 @@ phase3_unget (token_ty *tp) } -/* String concatenation with '+'. */ +/* 4. String concatenation with '+'. */ + +static token_ty phase4_pushback[2]; +static int phase4_pushback_length; static void -x_vala_lex (token_ty *tp) +phase4_get (token_ty *tp) { + if (phase4_pushback_length) + { + *tp = phase4_pushback[--phase4_pushback_length]; + return; + } + phase3_get (tp); if (tp->type == token_type_string_literal) { @@ -1263,6 +1277,31 @@ x_vala_lex (token_ty *tp) } } +static void +phase4_unget (token_ty *tp) +{ + if (tp->type != token_type_eof) + { + if (phase4_pushback_length == SIZEOF (phase4_pushback)) + abort (); + phase4_pushback[phase4_pushback_length++] = *tp; + } +} + + +static void +x_vala_lex (token_ty *tp) +{ + phase4_get (tp); +} + +/* Supports 2 tokens of pushback. */ +static void +x_vala_unlex (token_ty *tp) +{ + phase4_unget (tp); +} + /* ========================= Extracting strings. ========================== */ @@ -1293,7 +1332,8 @@ static int nesting_depth; We use recursion because the arguments before msgid or between msgid and msgid_plural can contain subexpressions of the same form. */ -/* Extract messages until the next balanced closing parenthesis or bracket. +/* Extract messages until the next balanced closing parenthesis or bracket + or the next semicolon. Extracted messages are added to MLP. DELIM can be either token_type_rparen or token_type_rbracket, or token_type_eof to accept both. @@ -1366,6 +1406,36 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim, return true; } nesting_depth--; + /* Test whether the next tokens are '.' and 'printf' or 'vprintf'. */ + { + token_ty token2; + x_vala_lex (&token2); + if (token2.type == token_type_symbol + && strcmp (token2.string, ".") == 0) + { + token_ty token3; + x_vala_lex (&token3); + if (token3.type == token_type_symbol + && (strcmp (token3.string, "printf") == 0 + || strcmp (token3.string, "vprintf") == 0)) + { + /* Mark the messages found in the region as c-format + a posteriori. */ + inner_region->for_formatstring[XFORMAT_PRIMARY].is_format = yes_according_to_context; + struct remembered_message_list_ty *rmlp = + inner_region->for_formatstring[XFORMAT_PRIMARY].remembered; + size_t i; + for (i = 0; i < rmlp->nitems; i++) + { + struct remembered_message_ty *rmp = &rmlp->item[i]; + set_format_flag_from_context (rmp->mp, rmp->plural, &rmp->pos, + XFORMAT_PRIMARY, inner_region); + } + } + x_vala_unlex (&token3); + } + x_vala_unlex (&token2); + } next_context_iter = null_context_list_iterator; state = 0; break; @@ -1393,6 +1463,11 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim, state = 0; continue; + case token_type_semicolon: + arglist_parser_done (argparser, arg); + unref_region (inner_region); + return false; + case token_type_eof: arglist_parser_done (argparser, arg); unref_region (inner_region); @@ -1485,6 +1560,8 @@ extract_vala (FILE *f, phase3_pushback_length = 0; last_token_type = token_type_other; + phase4_pushback_length = 0; + flag_context_list_table = flag_table; nesting_depth = 0; diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index e6e6b040d..4e432e63a 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -165,7 +165,7 @@ TESTS = gettext-1 gettext-2 \ xgettext-tcl-stackovfl-1 xgettext-tcl-stackovfl-2 \ xgettext-tcl-stackovfl-3 xgettext-tcl-stackovfl-4 \ xgettext-vala-1 xgettext-vala-2 xgettext-vala-3 xgettext-vala-4 \ - xgettext-vala-5 xgettext-vala-6 \ + xgettext-vala-5 xgettext-vala-6 xgettext-vala-7 \ xgettext-vala-stackovfl-1 xgettext-vala-stackovfl-2 \ xgettext-ycp-1 xgettext-ycp-2 xgettext-ycp-3 xgettext-ycp-4 \ xgettext-ycp-stackovfl-1 xgettext-ycp-stackovfl-2 \ diff --git a/gettext-tools/tests/xgettext-vala-6 b/gettext-tools/tests/xgettext-vala-6 index afd78e9e4..f215f8218 100755 --- a/gettext-tools/tests/xgettext-vala-6 +++ b/gettext-tools/tests/xgettext-vala-6 @@ -8,6 +8,10 @@ cat <<\EOF > xg-vala-6.vala "%s".printf(_("Hello 1")); _("Explanation: %s").printf(_("Hello 2")); +_("No error 1"); +_("No error 2").printf(); +(_("No error 3")).printf(); +foo(_("No error 4")).printf(); Posix.printf(_("Hello 3")); Posix.printf(_("Hello 4 %s!"), _("Sir")); EOF @@ -26,6 +30,20 @@ msgstr "" msgid "Hello 2" msgstr "" +msgid "No error 1" +msgstr "" + +#, c-format +msgid "No error 2" +msgstr "" + +#, c-format +msgid "No error 3" +msgstr "" + +msgid "No error 4" +msgstr "" + msgid "Hello 3" msgstr "" diff --git a/gettext-tools/tests/xgettext-vala-7 b/gettext-tools/tests/xgettext-vala-7 new file mode 100755 index 000000000..b68074750 --- /dev/null +++ b/gettext-tools/tests/xgettext-vala-7 @@ -0,0 +1,26 @@ +#! /bin/sh +. "${srcdir=.}/init.sh"; path_prepend_ . ../src + +# Test Vala support: diagnostics for invalid format strings. + +: ${XGETTEXT=xgettext} + +cat <<\EOF > xg-vala-7.vala +_("Invalid C format %z").printf(); +EOF + +LANGUAGE= LC_ALL=C ${XGETTEXT} --omit-header --no-location -o xg-vala-7.tmp xg-vala-7.vala 2>xg-vala-7.err || Exit 1 +cat xg-vala-7.err +grep 'warning: Although being used in a format string position, the msgid is not a valid C format string.' xg-vala-7.err >/dev/null || Exit 1 +func_filter_POT_Creation_Date xg-vala-7.tmp xg-vala-7.po + +cat <<\EOF > xg-vala-7.ok +msgid "Invalid C format %z" +msgstr "" +EOF + +: ${DIFF=diff} +${DIFF} xg-vala-7.ok xg-vala-7.po +result=$? + +exit $result