+2003-08-08 Bruno Haible <bruno@clisp.org>
+
+ * gettext.texi (PO Files): Mention gcc-internal-format.
+ (gcc-internal-format): New subsection.
+ (GCC-source): New subsection.
+ * xgettext.texi: Mention GCC-source language.
+
2003-07-05 Bruno Haible <bruno@clisp.org>
* gettext.texi (perl-format): Use braces, not brackets, in format
* tcl-format:: Tcl Format Strings
* perl-format:: Perl Format Strings
* php-format:: PHP Format Strings
+* gcc-internal-format:: GCC internal Format Strings
Individual Programming Languages
* Perl:: Perl
* PHP:: PHP Hypertext Preprocessor
* Pike:: Pike
+* GCC-source:: GNU Compiler Collection sources
Internationalizable Data
@kwindex no-php-format@r{ flag}
Likewise for PHP, see @ref{php-format}.
+@item gcc-internal-format
+@kwindex gcc-internal-format@r{ flag}
+@itemx no-gcc-internal-format
+@kwindex no-gcc-internal-format@r{ flag}
+Likewise for the GCC sources, see @ref{gcc-internal-format}.
+
@end table
@kwindex msgid_plural
* tcl-format:: Tcl Format Strings
* perl-format:: Perl Format Strings
* php-format:: PHP Format Strings
+* gcc-internal-format:: GCC internal Format Strings
@end menu
@node c-format, python-format, Translators for other Languages, Translators for other Languages
braces (@samp{@{} and @samp{@}}). The placeholder must have the syntax
of simple identifiers.
-@node php-format, , perl-format, Translators for other Languages
+@node php-format, gcc-internal-format, perl-format, Translators for other Languages
@subsection PHP Format Strings
PHP format strings are described in the documentation of the PHP function
@code{sprintf}, in @file{phpdoc/manual/function.sprintf.html} or
@uref{http://www.php.net/manual/en/function.sprintf.php}.
+@node gcc-internal-format, , php-format, Translators for other Languages
+@subsection GCC internal Format Strings
+
+These format strings are used inside the GCC sources. In such a format
+string, a directive starts with @samp{%}, is optionally followed by a
+size specifier @samp{l}, an optional flag @samp{+}, another optional flag
+@samp{#}, and is finished by a specifier: @samp{%} denotes a literal
+percent sign, @samp{c} denotes a character, @samp{s} denotes a string,
+@samp{i} and @samp{d} denote an integer, @samp{o}, @samp{u}, @samp{x}
+denote an unsigned integer, @samp{.*s} denotes a string preceded by a
+width specification, @samp{H} denotes a @samp{location_t *} pointer,
+@samp{D} denotes a general declaration, @samp{F} denotes a function
+declaration, @samp{T} denotes a type, @samp{A} denotes a function argument,
+@samp{C} denotes a tree code, @samp{E} denotes an expression, @samp{L}
+denotes a programming language, @samp{O} denotes a binary operator,
+@samp{P} denotes a function parameter, @samp{Q} denotes an assignment
+operator, @samp{V} denotes a const/volatile qualifier.
+
@node Maintainers for other Languages, List of Programming Languages, Translators for other Languages, Programming Languages
@section The Maintainer's View
* Perl:: Perl
* PHP:: PHP Hypertext Preprocessor
* Pike:: Pike
+* GCC-source:: GNU Compiler Collection sources
@end menu
@node C, sh, List of Programming Languages, List of Programming Languages
---
@end table
-@node Pike, , PHP, List of Programming Languages
+@node Pike, GCC-source, PHP, List of Programming Languages
@subsection Pike
@cindex Pike
---
@end table
+@node GCC-source, , Pike, List of Programming Languages
+@subsection GNU Compiler Collection sources
+@cindex GCC-source
+
+@table @asis
+@item RPMs
+gcc
+
+@item File extension
+@code{c}, @code{h}.
+
+@item String syntax
+@code{"abc"}
+
+@item gettext shorthand
+@code{_("abc")}
+
+@item gettext/ngettext functions
+@code{gettext}, @code{dgettext}, @code{dcgettext}, @code{ngettext},
+@code{dngettext}, @code{dcngettext}
+
+@item textdomain
+@code{textdomain} function
+
+@item bindtextdomain
+@code{bindtextdomain} function
+
+@item setlocale
+Programmer must call @code{setlocale (LC_ALL, "")}
+
+@item Prerequisite
+@code{#include "intl.h"}
+
+@item Use or emulate GNU gettext
+Use
+
+@item Extractor
+@code{xgettext -k_}
+
+@item Formatting with positions
+---
+
+@item Portability
+Uses autoconf macros
+
+@item po-mode marking
+yes
+@end table
+
@c This is the template for new languages.
@ignore
are @code{C}, @code{C++}, @code{ObjectiveC}, @code{PO}, @code{Python},
@code{Lisp}, @code{EmacsLisp}, @code{librep}, @code{Smalltalk}, @code{Java},
@code{JavaProperties}, @code{awk}, @code{YCP}, @code{Tcl}, @code{Perl},
-@code{PHP}, @code{RST}, @code{Glade}.
+@code{PHP}, @code{GCC-source}, @code{RST}, @code{Glade}.
@item -C
@itemx --c++
+2003-08-08 Bruno Haible <bruno@clisp.org>
+
+ * format-gcc-internal.c: New file.
+ * message.h (format_gcc_internal): New enum value.
+ (NFORMATS): Increment.
+ * format.h (formatstring_gcc_internal): New declaration.
+ * format.c (formatstring_parsers): Add entry for gcc_internal.
+ * message.c (format_language, format_language_pretty): Likewise.
+ * x-c.h (SCANNERS_C): Add an entry for GCC-source.
+ * xgettext.c (usage): Mention GCC-source language.
+ * Makefile.am (FORMAT_SOURCE): Add format-gcc-internal.c.
+
2003-08-04 Bruno Haible <bruno@clisp.org>
* x-perl.c (extract_quotelike_pass3): Fix \x handling.
FORMAT_SOURCE = format.c format-invalid.h \
format-c.c format-python.c format-lisp.c format-elisp.c format-librep.c \
format-java.c format-awk.c format-pascal.c format-ycp.c format-tcl.c \
-format-perl.c format-perl-brace.c format-php.c
+format-perl.c format-perl-brace.c format-php.c format-gcc-internal.c
# libgettextsrc contains all code that is needed by at least two programs.
libgettextsrc_la_SOURCES = \
--- /dev/null
+/* GCC internal format strings.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "format.h"
+#include "c-ctype.h"
+#include "xmalloc.h"
+#include "xerror.h"
+#include "format-invalid.h"
+#include "error.h"
+#include "progname.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+/* GCC internal format strings consist of language frontend independent
+ format directives, implemented in gcc-3.3/gcc/diagnostic.c (function
+ output_format), plus some frontend dependent extensions:
+ - for the C/ObjC frontend in gcc-3.3/gcc/c-objc-common.c
+ - for the C++ frontend in gcc-3.3/gcc/cp/error.c
+ Taking these together, GCC internal format strings are specified as follows.
+ A directive
+ - starts with '%',
+ - is optionally followed by a size specifier 'l',
+ - is optionally followed by '+' (only the specifiers of gcc/cp/error.c),
+ - is optionally followed by '#' (only the specifiers of gcc/cp/error.c),
+ - is finished by a specifier
+
+ - '%', that needs no argument,
+ - 'c', that needs a character argument,
+ - 's', that needs a string argument,
+ - 'i', 'd', that need a signed integer argument,
+ - 'o', 'u', 'x', that need an unsigned integer argument,
+ - '.*s', that needs a signed integer argument and a string argument,
+ - 'H', that needs a 'location_t *' argument,
+ [see gcc/diagnostic.c]
+
+ - 'D', that needs a general declaration argument,
+ - 'F', that needs a function declaration argument,
+ - 'T', that needs a type argument,
+ [see gcc/c-objc-common.c and gcc/cp/error.c]
+
+ - 'A', that needs a function argument list argument,
+ - 'C', that needs a tree code argument,
+ - 'E', that needs an expression argument,
+ - 'L', that needs a language argument,
+ - 'O', that needs a binary operator argument,
+ - 'P', that needs a function parameter argument,
+ - 'Q', that needs an assignment operator argument,
+ - 'V', that needs a const/volatile qualifier argument.
+ [see gcc/cp/error.c]
+ */
+
+enum format_arg_type
+{
+ FAT_NONE = 0,
+ /* Basic types */
+ FAT_INTEGER = 1,
+ FAT_CHAR = 2,
+ FAT_STRING = 3,
+ FAT_LOCATION = 4,
+ FAT_TREE = 5,
+ FAT_TREE_CODE = 6,
+ FAT_LANGUAGES = 7,
+ /* Flags */
+ FAT_UNSIGNED = 1 << 3,
+ FAT_SIZE_LONG = 1 << 4,
+ FAT_TREE_DECL = 1 << 5,
+ FAT_TREE_FUNCDECL = 2 << 5,
+ FAT_TREE_TYPE = 3 << 5,
+ FAT_TREE_ARGUMENT = 4 << 5,
+ FAT_TREE_EXPRESSION = 5 << 5,
+ FAT_TREE_CV = 6 << 5,
+ FAT_TREE_CODE_BINOP = 1 << 8,
+ FAT_TREE_CODE_ASSOP = 2 << 8,
+ FAT_FUNCPARAM = 1 << 10
+};
+
+struct unnumbered_arg
+{
+ enum format_arg_type type;
+};
+
+struct spec
+{
+ unsigned int directives;
+ unsigned int unnumbered_arg_count;
+ unsigned int allocated;
+ struct unnumbered_arg *unnumbered;
+};
+
+/* Locale independent test for a decimal digit.
+ Argument can be 'char' or 'unsigned char'. (Whereas the argument of
+ <ctype.h> isdigit must be an 'unsigned char'.) */
+#undef isdigit
+#define isdigit(c) ((unsigned int) ((c) - '0') < 10)
+
+
+static void *
+format_parse (const char *format, char **invalid_reason)
+{
+ struct spec spec;
+ struct spec *result;
+
+ spec.directives = 0;
+ spec.unnumbered_arg_count = 0;
+ spec.allocated = 0;
+ spec.unnumbered = NULL;
+
+ for (; *format != '\0';)
+ if (*format++ == '%')
+ {
+ /* A directive. */
+ enum format_arg_type size;
+
+ spec.directives++;
+
+ /* Parse size. */
+ size = 0;
+ if (*format == 'l')
+ {
+ format++;
+ size = FAT_SIZE_LONG;
+ }
+
+ if (*format != '%')
+ {
+ enum format_arg_type type;
+
+ if (*format == 'c')
+ type = FAT_CHAR;
+ else if (*format == 's')
+ type = FAT_STRING;
+ else if (*format == 'i' || *format == 'd')
+ type = FAT_INTEGER | size;
+ else if (*format == 'o' || *format == 'u' || *format == 'x')
+ type = FAT_INTEGER | FAT_UNSIGNED | size;
+ else if (*format == '.' && format[1] == '*' && format[2] == 's')
+ {
+ if (spec.allocated == spec.unnumbered_arg_count)
+ {
+ spec.allocated = 2 * spec.allocated + 1;
+ spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
+ }
+ spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER;
+ spec.unnumbered_arg_count++;
+ type = FAT_STRING;
+ }
+ else if (*format == 'H')
+ type = FAT_LOCATION;
+ else
+ {
+ if (*format == '+')
+ format++;
+ if (*format == '#')
+ format++;
+ if (*format == 'D')
+ type = FAT_TREE | FAT_TREE_DECL;
+ else if (*format == 'F')
+ type = FAT_TREE | FAT_TREE_FUNCDECL;
+ else if (*format == 'T')
+ type = FAT_TREE | FAT_TREE_TYPE;
+ else if (*format == 'A')
+ type = FAT_TREE | FAT_TREE_ARGUMENT;
+ else if (*format == 'C')
+ type = FAT_TREE_CODE;
+ else if (*format == 'E')
+ type = FAT_TREE | FAT_TREE_EXPRESSION;
+ else if (*format == 'L')
+ type = FAT_LANGUAGES;
+ else if (*format == 'O')
+ type = FAT_TREE_CODE | FAT_TREE_CODE_BINOP;
+ else if (*format == 'P')
+ type = FAT_INTEGER | FAT_FUNCPARAM;
+ else if (*format == 'Q')
+ type = FAT_TREE_CODE | FAT_TREE_CODE_ASSOP;
+ else if (*format == 'V')
+ type = FAT_TREE | FAT_TREE_CV;
+ else
+ {
+ *invalid_reason =
+ (*format == '\0'
+ ? INVALID_UNTERMINATED_DIRECTIVE ()
+ : (*format == 'c'
+ || *format == 's'
+ || *format == 'i' || *format == 'd'
+ || *format == 'o' || *format == 'u' || *format == 'x'
+ || *format == 'H'
+ ? xasprintf (_("In the directive number %u, flags are not allowed before '%c'."), spec.directives, *format)
+ : INVALID_CONVERSION_SPECIFIER (spec.directives,
+ *format)));
+ goto bad_format;
+ }
+ }
+
+ if (spec.allocated == spec.unnumbered_arg_count)
+ {
+ spec.allocated = 2 * spec.allocated + 1;
+ spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
+ }
+ spec.unnumbered[spec.unnumbered_arg_count].type = type;
+ spec.unnumbered_arg_count++;
+ }
+
+ format++;
+ }
+
+ result = (struct spec *) xmalloc (sizeof (struct spec));
+ *result = spec;
+ return result;
+
+ bad_format:
+ if (spec.unnumbered != NULL)
+ free (spec.unnumbered);
+ return NULL;
+}
+
+static void
+format_free (void *descr)
+{
+ struct spec *spec = (struct spec *) descr;
+
+ if (spec->unnumbered != NULL)
+ free (spec->unnumbered);
+ free (spec);
+}
+
+static int
+format_get_number_of_directives (void *descr)
+{
+ struct spec *spec = (struct spec *) descr;
+
+ return spec->directives;
+}
+
+static bool
+format_check (const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr,
+ bool equality, bool noisy, const char *pretty_msgstr)
+{
+ struct spec *spec1 = (struct spec *) msgid_descr;
+ struct spec *spec2 = (struct spec *) msgstr_descr;
+ bool err = false;
+ unsigned int i;
+
+ /* Check the argument types are the same. */
+ if (equality
+ ? spec1->unnumbered_arg_count != spec2->unnumbered_arg_count
+ : spec1->unnumbered_arg_count < spec2->unnumbered_arg_count)
+ {
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("number of format specifications in 'msgid' and '%s' does not match"),
+ pretty_msgstr);
+ error_with_progname = true;
+ }
+ err = true;
+ }
+ else
+ for (i = 0; i < spec2->unnumbered_arg_count; i++)
+ if (spec1->unnumbered[i].type != spec2->unnumbered[i].type)
+ {
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and '%s' for argument %u are not the same"),
+ pretty_msgstr, i + 1);
+ error_with_progname = true;
+ }
+ err = true;
+ }
+
+ return err;
+}
+
+
+struct formatstring_parser formatstring_gcc_internal =
+{
+ format_parse,
+ format_free,
+ format_get_number_of_directives,
+ format_check
+};
+
+
+#ifdef TEST
+
+/* Test program: Print the argument list specification returned by
+ format_parse for strings read from standard input. */
+
+#include <stdio.h>
+#include "getline.h"
+
+static void
+format_print (void *descr)
+{
+ struct spec *spec = (struct spec *) descr;
+ unsigned int i;
+
+ if (spec == NULL)
+ {
+ printf ("INVALID");
+ return;
+ }
+
+ printf ("(");
+ for (i = 0; i < spec->unnumbered_arg_count; i++)
+ {
+ if (i > 0)
+ printf (" ");
+ if (spec->unnumbered[i].type & FAT_UNSIGNED)
+ printf ("[unsigned]");
+ if (spec->unnumbered[i].type & FAT_SIZE_LONG)
+ printf ("[long]");
+ switch (spec->unnumbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_LONG))
+ {
+ case FAT_INTEGER:
+ printf ("i");
+ break;
+ case FAT_INTEGER | FAT_FUNCPARAM:
+ printf ("P");
+ break;
+ case FAT_CHAR:
+ printf ("c");
+ break;
+ case FAT_STRING:
+ printf ("s");
+ break;
+ case FAT_LOCATION:
+ printf ("H");
+ break;
+ case FAT_TREE | FAT_TREE_DECL:
+ printf ("D");
+ break;
+ case FAT_TREE | FAT_TREE_FUNCDECL:
+ printf ("F");
+ break;
+ case FAT_TREE | FAT_TREE_TYPE:
+ printf ("T");
+ break;
+ case FAT_TREE | FAT_TREE_ARGUMENT:
+ printf ("A");
+ break;
+ case FAT_TREE | FAT_TREE_EXPRESSION:
+ printf ("E");
+ break;
+ case FAT_TREE | FAT_TREE_CV:
+ printf ("V");
+ break;
+ case FAT_TREE_CODE:
+ printf ("C");
+ break;
+ case FAT_TREE_CODE | FAT_TREE_CODE_BINOP:
+ printf ("O");
+ break;
+ case FAT_TREE_CODE | FAT_TREE_CODE_ASSOP:
+ printf ("Q");
+ break;
+ case FAT_LANGUAGES:
+ printf ("L");
+ break;
+ default:
+ abort ();
+ }
+ }
+ printf (")");
+}
+
+int
+main ()
+{
+ for (;;)
+ {
+ char *line = NULL;
+ size_t line_size = 0;
+ int line_len;
+ char *invalid_reason;
+ void *descr;
+
+ line_len = getline (&line, &line_size, stdin);
+ if (line_len < 0)
+ break;
+ if (line_len > 0 && line[line_len - 1] == '\n')
+ line[--line_len] = '\0';
+
+ invalid_reason = NULL;
+ descr = format_parse (line, &invalid_reason);
+
+ format_print (descr);
+ printf ("\n");
+ if (descr == NULL)
+ printf ("%s\n", invalid_reason);
+
+ free (invalid_reason);
+ free (line);
+ }
+
+ return 0;
+}
+
+/*
+ * For Emacs M-x compile
+ * Local Variables:
+ * compile-command: "/bin/sh ../libtool --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../lib -I../intl -DHAVE_CONFIG_H -DTEST format-gcc-internal.c ../lib/libgettextlib.la"
+ * End:
+ */
+
+#endif /* TEST */
/* format_tcl */ &formatstring_tcl,
/* format_perl */ &formatstring_perl,
/* format_perl_brace */ &formatstring_perl_brace,
- /* format_php */ &formatstring_php
+ /* format_php */ &formatstring_php,
+ /* format_gcc_internal */ &formatstring_gcc_internal
};
extern struct formatstring_parser formatstring_perl;
extern struct formatstring_parser formatstring_perl_brace;
extern struct formatstring_parser formatstring_php;
+extern struct formatstring_parser formatstring_gcc_internal;
/* Table of all format string parsers. */
extern struct formatstring_parser *formatstring_parsers[NFORMATS];
/* format_tcl */ "tcl",
/* format_perl */ "perl",
/* format_perl_brace */ "perl-brace",
- /* format_php */ "php"
+ /* format_php */ "php",
+ /* format_gcc_internal */ "gcc-internal"
};
const char *const format_language_pretty[NFORMATS] =
/* format_tcl */ "Tcl",
/* format_perl */ "Perl",
/* format_perl_brace */ "Perl brace",
- /* format_php */ "PHP"
+ /* format_php */ "PHP",
+ /* format_gcc_internal */ "GCC internal"
};
format_tcl,
format_perl,
format_perl_brace,
- format_php
+ format_php,
+ format_gcc_internal
};
-#define NFORMATS 14 /* Number of format_type enum values. */
+#define NFORMATS 15 /* Number of format_type enum values. */
extern const char *const format_language[NFORMATS];
extern const char *const format_language_pretty[NFORMATS];
{ "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 }, \
/* Scan a C/C++/ObjectiveC file and add its translatable strings to mdlp. */
extern void extract_c (FILE *fp, const char *real_filename,
(C, C++, ObjectiveC, PO, Python, Lisp,\n\
EmacsLisp, librep, Smalltalk, Java,\n\
JavaProperties, awk, YCP, Tcl, Perl, PHP,\n\
- RST, Glade)\n"));
+ GCC-source, RST, Glade)\n"));
printf (_("\
-C, --c++ shorthand for --language=C++\n"));
printf (_("\
+2003-08-08 Bruno Haible <bruno@clisp.org>
+
+ * format-gcc-internal-1: New file.
+ * format-gcc-internal-2: New file.
+ * Makefile.am (TESTS): Add them.
+
2003-08-04 Bruno Haible <bruno@clisp.org>
* lang-perl-1: Small tweaks.
format-awk-1 format-awk-2 \
format-c-1 format-c-2 format-c-3 format-c-4 \
format-elisp-1 format-elisp-2 \
+ format-gcc-internal-1 format-gcc-internal-2 \
format-java-1 format-java-2 \
format-librep-1 format-librep-2 \
format-lisp-1 format-lisp-2 \
--- /dev/null
+#! /bin/sh
+
+# Test recognition of GCC internal format strings.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles f-gi-1.data"
+cat <<\EOF > f-gi-1.data
+# Valid: no argument
+"abc%%"
+# Valid: one character argument
+"abc%c"
+# Valid: one string argument
+"abc%s"
+# Valid: one integer argument
+"abc%i"
+# Valid: one integer argument
+"abc%d"
+# Valid: one integer argument
+"abc%o"
+# Valid: one integer argument
+"abc%u"
+# Valid: one integer argument
+"abc%x"
+# Valid: one integer and one string argument
+"abc%.*s"
+# Valid: one pointer argument
+"abc%H"
+# Valid: one pointer argument
+"abc%D"
+# Valid: one pointer argument
+"abc%F"
+# Valid: one pointer argument
+"abc%T"
+# Valid: one pointer argument
+"abc%A"
+# Valid: one pointer argument
+"abc%C"
+# Valid: one pointer argument
+"abc%E"
+# Valid: one pointer argument
+"abc%L"
+# Valid: one pointer argument
+"abc%O"
+# Valid: one pointer argument
+"abc%P"
+# Valid: one pointer argument
+"abc%Q"
+# Valid: one pointer argument
+"abc%V"
+# Valid: one argument with flags
+"abc%+#Ag"
+# Valid: one argument with size specifier
+"abc%li"
+# Invalid: unterminated
+"abc%"
+# Invalid: unknown format specifier
+"abc%y"
+# Invalid: precision with non-string
+"abc%.*c"
+# Invalid: twice precision
+"abc%.*.*s"
+# Valid: three arguments
+"abc%d%u%u"
+# Invalid: a numbered argument
+"abc%1$d"
+EOF
+
+: ${XGETTEXT=xgettext}
+n=0
+while read comment; do
+ read string
+ n=`expr $n + 1`
+ tmpfiles="$tmpfiles f-gi-1-$n.in f-gi-1-$n.po"
+ cat <<EOF > f-gi-1-$n.in
+gettext(${string});
+EOF
+ ${XGETTEXT} -L GCC-source -o f-gi-1-$n.po f-gi-1-$n.in || exit 1
+ test -f f-gi-1-$n.po || exit 1
+ fail=
+ if echo "$comment" | grep 'Valid:' > /dev/null; then
+ if grep gcc-internal-format f-gi-1-$n.po > /dev/null; then
+ :
+ else
+ fail=yes
+ fi
+ else
+ if grep gcc-internal-format f-gi-1-$n.po > /dev/null; then
+ fail=yes
+ else
+ :
+ fi
+ fi
+ if test -n "$fail"; then
+ echo "Format string recognition error:" 1>&2
+ cat f-gi-1-$n.in 1>&2
+ echo "Got:" 1>&2
+ cat f-gi-1-$n.po 1>&2
+ exit 1
+ fi
+ rm -f f-gi-1-$n.in f-gi-1-$n.po
+done < f-gi-1.data
+
+rm -fr $tmpfiles
+
+exit 0
--- /dev/null
+#! /bin/sh
+
+# Test checking of C format strings.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles f-gi-2.data"
+cat <<\EOF > f-gi-2.data
+# Valid: %% doesn't count
+msgid "abc%%def"
+msgstr "xyz"
+# Invalid: invalid msgstr
+msgid "abc%%def"
+msgstr "xyz%"
+# Valid: same arguments
+msgid "abc%s%Hdef"
+msgstr "xyz%s%H"
+# Valid: same arguments, with different widths
+msgid "abc%.*sdef"
+msgstr "xyz%i%s"
+# Invalid: too few arguments
+msgid "abc%sdef%u"
+msgstr "xyz%s"
+# Invalid: too many arguments
+msgid "abc%udef"
+msgstr "xyz%uvw%c"
+# Valid: type compatibility
+msgid "abc%i"
+msgstr "xyz%d"
+# Valid: type compatibility
+msgid "abc%o"
+msgstr "xyz%u"
+# Valid: type compatibility
+msgid "abc%u"
+msgstr "xyz%x"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%s"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%i"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%u"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%H"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%D"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%F"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%c"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%i"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%u"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%H"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%D"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%F"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%s"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%u"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%H"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%D"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%F"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%i"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%H"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%D"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%F"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%u"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%D"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%F"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%H"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%F"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%D"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%T"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%F"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%A"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%T"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%C"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%A"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%C"
+msgstr "xyz%E"
+# Invalid: type incompatibility
+msgid "abc%C"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%C"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%C"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%C"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%C"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%E"
+msgstr "xyz%L"
+# Invalid: type incompatibility
+msgid "abc%E"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%E"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%E"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%E"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%L"
+msgstr "xyz%O"
+# Invalid: type incompatibility
+msgid "abc%L"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%L"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%L"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%O"
+msgstr "xyz%P"
+# Invalid: type incompatibility
+msgid "abc%O"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%O"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%P"
+msgstr "xyz%Q"
+# Invalid: type incompatibility
+msgid "abc%P"
+msgstr "xyz%V"
+# Invalid: type incompatibility
+msgid "abc%Q"
+msgstr "xyz%V"
+# Invalid: type incompatibility for width
+msgid "abc%.*s"
+msgstr "xyz%u%s"
+EOF
+
+: ${MSGFMT=msgfmt}
+n=0
+while read comment; do
+ read msgid_line
+ read msgstr_line
+ n=`expr $n + 1`
+ tmpfiles="$tmpfiles f-gi-2-$n.po f-gi-2-$n.mo"
+ cat <<EOF > f-gi-2-$n.po
+#, gcc-internal-format
+${msgid_line}
+${msgstr_line}
+EOF
+ fail=
+ if echo "$comment" | grep 'Valid:' > /dev/null; then
+ if ${MSGFMT} --check-format -o f-gi-2-$n.mo f-gi-2-$n.po; then
+ :
+ else
+ fail=yes
+ fi
+ else
+ ${MSGFMT} --check-format -o f-gi-2-$n.mo f-gi-2-$n.po 2> /dev/null
+ if test $? = 1; then
+ :
+ else
+ fail=yes
+ fi
+ fi
+ if test -n "$fail"; then
+ echo "Format string checking error:" 1>&2
+ cat f-gi-2-$n.po 1>&2
+ exit 1
+ fi
+ rm -f f-gi-2-$n.po f-gi-2-$n.mo
+done < f-gi-2.data
+
+rm -fr $tmpfiles
+
+exit 0