]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Support for gcc-internal format strings.
authorBruno Haible <bruno@clisp.org>
Fri, 8 Aug 2003 17:51:04 +0000 (17:51 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:10:48 +0000 (12:10 +0200)
16 files changed:
gettext-tools/doc/ChangeLog
gettext-tools/doc/gettext.texi
gettext-tools/doc/xgettext.texi
gettext-tools/src/ChangeLog
gettext-tools/src/Makefile.am
gettext-tools/src/format-gcc-internal.c [new file with mode: 0644]
gettext-tools/src/format.c
gettext-tools/src/format.h
gettext-tools/src/message.c
gettext-tools/src/message.h
gettext-tools/src/x-c.h
gettext-tools/src/xgettext.c
gettext-tools/tests/ChangeLog
gettext-tools/tests/Makefile.am
gettext-tools/tests/format-gcc-internal-1 [new file with mode: 0755]
gettext-tools/tests/format-gcc-internal-2 [new file with mode: 0755]

index 9cac878cb5e6ef4e738bd85b17aeaa8ff894a030..0b22322d0199d12eff4aa3e2e58b042e3dc049a9 100644 (file)
@@ -1,3 +1,10 @@
+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
index 9e0fa748a74c21a38bbf774fb5f7f7544595bc49..0bed79d45fb082be887a0eda61e089ed2e108b0a 100644 (file)
@@ -339,6 +339,7 @@ The Translator's View
 * 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
 
@@ -360,6 +361,7 @@ Individual Programming Languages
 * Perl::                        Perl
 * PHP::                         PHP Hypertext Preprocessor
 * Pike::                        Pike
+* GCC-source::                  GNU Compiler Collection sources
 
 Internationalizable Data
 
@@ -1207,6 +1209,12 @@ Likewise for Tcl, see @ref{tcl-format}.
 @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
@@ -7217,6 +7225,7 @@ strings.
 * 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
@@ -7346,13 +7355,31 @@ libintl-perl.  In brief, Perl format uses placeholders put between
 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
 
@@ -7453,6 +7480,7 @@ that language, and to combine the resulting files using @code{msgcat}.
 * 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
@@ -9116,7 +9144,7 @@ On platforms without gettext, the functions are not available.
 ---
 @end table
 
-@node Pike,  , PHP, List of Programming Languages
+@node Pike, GCC-source, PHP, List of Programming Languages
 @subsection Pike
 @cindex Pike
 
@@ -9164,6 +9192,55 @@ On platforms without gettext, the functions are not available.
 ---
 @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
 
index f29a5a662630d847f94eeff3c2f2a23e58d5118a..7e4593fd39bfce5ce7ab3894a7f49be5b84362d5 100644 (file)
@@ -72,7 +72,7 @@ Specifies the language of the input files.  The supported languages
 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++
index 50c9043afc17052a023147859e8cf902d1e2d95d..6a082a3b64f615bc0f39a4cbd117e6e5bff69bea 100644 (file)
@@ -1,3 +1,15 @@
+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.
index 305ab8c7a75295ea8adf732ca3b855842e2a5809..9c747090a22f4f7eb0154882c457356e077a9029 100644 (file)
@@ -93,7 +93,7 @@ read-properties.c open-po.c dir-list.c str-list.c
 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 = \
diff --git a/gettext-tools/src/format-gcc-internal.c b/gettext-tools/src/format-gcc-internal.c
new file mode 100644 (file)
index 0000000..5441af3
--- /dev/null
@@ -0,0 +1,431 @@
+/* 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 */
index 17423f340cfd9025c7fd3f1f397304e304c5ddb8..b89185b1506c284446dede430f3bf3d4594173c9 100644 (file)
@@ -39,5 +39,6 @@ struct formatstring_parser *formatstring_parsers[NFORMATS] =
   /* 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
 };
index 6cd241be1185ea62ba2d6bad263621e5b2594e79..b62ec2ccf417d80f82938fa07343d1e0d98b05a2 100644 (file)
@@ -69,6 +69,7 @@ extern struct formatstring_parser formatstring_tcl;
 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];
index 294506303985314c2138e833ece822908b42ae67..f8c32e964447290b74f0c2a73744279696a950b3 100644 (file)
@@ -47,7 +47,8 @@ const char *const format_language[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] =
@@ -65,7 +66,8 @@ 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"
 };
 
 
index a64c86ce2602b1f53bf79807d3dc71e319cbb93b..482198744cd2ca3702d3ebb012bb630f4d2e594b 100644 (file)
@@ -47,9 +47,10 @@ enum format_type
   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];
 
index ed1fd3058c20cf92a9385334f8df42403a210de3..f79e7964642db1beb96aeca697f95ee288714188 100644 (file)
@@ -34,6 +34,7 @@
   { "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,
index 81d085d940e7f8cadd30fab08ae4b83f4aa58326..0c73607f17451581e318fbbbe9088aa4ca832fd8 100644 (file)
@@ -658,7 +658,7 @@ Choice of input file language:\n"));
                                 (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 (_("\
index 0956d26bd5c69acba92b7c0936d7ea661b409e17..eb5ae4fb679b0de6dd69a3856865b362596cb6b5 100644 (file)
@@ -1,3 +1,9 @@
+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.
index ad29fc3295b887a0537effbf3d06f4a1fcce99ae..205d0147f8bba3de1d9074e955257f48fbcf91ce 100644 (file)
@@ -54,6 +54,7 @@ TESTS = gettext-1 gettext-2 \
        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 \
diff --git a/gettext-tools/tests/format-gcc-internal-1 b/gettext-tools/tests/format-gcc-internal-1
new file mode 100755 (executable)
index 0000000..e47626e
--- /dev/null
@@ -0,0 +1,107 @@
+#! /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
diff --git a/gettext-tools/tests/format-gcc-internal-2 b/gettext-tools/tests/format-gcc-internal-2
new file mode 100755 (executable)
index 0000000..a4b7d5d
--- /dev/null
@@ -0,0 +1,439 @@
+#! /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