From: Bruno Haible Date: Sun, 1 Jun 2025 22:32:14 +0000 (+0200) Subject: xgettext: D: Improve heuristic for format strings. X-Git-Tag: v0.26~135 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=99529c200daba583c92701d35c473b9e664d6da3;p=thirdparty%2Fgettext.git xgettext: D: Improve heuristic for format strings. * gettext-tools/src/format-d.c (struct spec): Add field 'likely_intentional_directives'. (parse_upto): Increment it for each directive that don't contain a space. (format_parse): Initialize it. (format_is_unlikely_intentional): New function. (formatstring_d): Use it. * gettext-tools/tests/format-d-3: New file. * gettext-tools/tests/Makefile.am (TESTS): Add it. --- diff --git a/gettext-tools/src/format-d.c b/gettext-tools/src/format-d.c index 0b1bd1790..52107641d 100644 --- a/gettext-tools/src/format-d.c +++ b/gettext-tools/src/format-d.c @@ -153,6 +153,11 @@ struct format_arg_list struct spec { unsigned int directives; + /* We consider a directive as "likely intentional" if it does not contain a + space. This prevents xgettext from flagging strings like "100% complete" + as 'd-format' if they don't occur in a context that requires a format + string. */ + unsigned int likely_intentional_directives; struct format_arg_list *list; }; @@ -1701,6 +1706,8 @@ parse_upto (struct spec *spec, if (c == '%') { + bool likely_intentional = true; + FDI_SET (format - 1, FMTDIR_START); /* Count number of directives. */ @@ -1797,7 +1804,11 @@ parse_upto (struct spec *spec, /* Parse flags. */ while (*format == ' ' || *format == '+' || *format == '-' || *format == '#' || *format == '0' || *format == '=') - format++; + { + if (*format == ' ') + likely_intentional = false; + format++; + } /* Parse width. */ if (c_isdigit (*format)) @@ -2125,6 +2136,8 @@ parse_upto (struct spec *spec, free_list (elementwise_list); } + if (likely_intentional) + spec->likely_intentional_directives++; FDI_SET (format, FMTDIR_END); format++; @@ -2162,6 +2175,7 @@ format_parse (const char *format, bool translated, char *fdi, struct spec *result; spec.directives = 0; + spec.likely_intentional_directives = 0; spec.list = make_unconstrained_list (); if (!parse_upto (&spec, &format, false, @@ -2200,6 +2214,14 @@ format_get_number_of_directives (void *descr) return spec->directives; } +static bool +format_is_unlikely_intentional (void *descr) +{ + struct spec *spec = (struct spec *) descr; + + return spec->likely_intentional_directives == 0; +} + static bool format_check (void *msgid_descr, void *msgstr_descr, bool equality, formatstring_error_logger_t error_logger, void *error_logger_data, @@ -2262,7 +2284,7 @@ struct formatstring_parser formatstring_d = format_parse, format_free, format_get_number_of_directives, - NULL, + format_is_unlikely_intentional, format_check }; diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index eff5a313d..602482c48 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -200,7 +200,7 @@ TESTS = gettext-1 gettext-2 \ format-c-1 format-c-2 format-c-3 format-c-4 format-c-5 format-c-6 \ format-c++-brace-1 format-c++-brace-2 \ format-csharp-1 format-csharp-2 \ - format-d-1 format-d-2 \ + format-d-1 format-d-2 format-d-3 \ format-elisp-1 format-elisp-2 \ format-gcc-internal-1 format-gcc-internal-2 \ format-gfc-internal-1 format-gfc-internal-2 \ diff --git a/gettext-tools/tests/format-d-3 b/gettext-tools/tests/format-d-3 new file mode 100755 index 000000000..94c78bb28 --- /dev/null +++ b/gettext-tools/tests/format-d-3 @@ -0,0 +1,49 @@ +#! /bin/sh +. "${srcdir=.}/init.sh"; path_prepend_ . ../src + +# Test heuristic recognition of D format strings like "100% complete". + +cat <<\EOF > f-d-3.d +void func () { + gettext("Test 1a is 100% complete"); + format(gettext("Test 1b is 100% complete"), 120); + gettext("Test 2a from 0% complete to 100% complete"); + format(gettext("Test 2b from 0% complete to 100% complete"), 120, 121); + gettext("Test 3a of %s is 100% complete"); + format(gettext("Test 3b of %s is 100% complete"), "foo", 120); +} +EOF + +: ${XGETTEXT=xgettext} +${XGETTEXT} --omit-header --no-location -d f-d-3.tmp f-d-3.d || Exit 1 +LC_ALL=C tr -d '\r' < f-d-3.tmp.po > f-d-3.po || Exit 1 + +cat <<\EOF > f-d-3.ok +msgid "Test 1a is 100% complete" +msgstr "" + +#, d-format +msgid "Test 1b is 100% complete" +msgstr "" + +msgid "Test 2a from 0% complete to 100% complete" +msgstr "" + +#, d-format +msgid "Test 2b from 0% complete to 100% complete" +msgstr "" + +#, c-format, d-format +msgid "Test 3a of %s is 100% complete" +msgstr "" + +#, d-format +msgid "Test 3b of %s is 100% complete" +msgstr "" +EOF + +: ${DIFF=diff} +${DIFF} f-d-3.ok f-d-3.po +result=$? + +exit $result