]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Update to GCC 4.1 internal format strings.
authorBruno Haible <bruno@clisp.org>
Wed, 21 Jun 2006 12:10:01 +0000 (12:10 +0000)
committerBruno Haible <bruno@clisp.org>
Sun, 28 Jun 2009 17:23:45 +0000 (19:23 +0200)
NEWS
gettext-tools/src/ChangeLog
gettext-tools/src/format-gcc-internal.c
gettext-tools/tests/ChangeLog
gettext-tools/tests/format-gcc-internal-1
gettext-tools/tests/format-gcc-internal-2

diff --git a/NEWS b/NEWS
index 55d881ea7fcafa014af6cd2efbbb6cdb27924a7c..e2b41a3a0717511cc68c897d38d886806444253f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.14.6 - June 2006
+
+* Updated the meaning of 'gcc-internal-format' to match GCC 4.1.
+\f
 Version 0.14.5 - May 2005
 
 * Updated the meaning of 'gcc-internal-format' to match GCC 4.0.
index 15f0a1a2fb6af26b49e36a99aa92eb8681971bbf..0a2b272012ea30f80d5c5228913a7f65433b738b 100644 (file)
@@ -1,3 +1,14 @@
+2006-06-20  Bruno Haible  <bruno@clisp.org>
+
+       * format-gcc-internal.c (struct unnumbered_arg): Remove type.
+       (struct numbered_arg): New type.
+       (struct spec): Use it.
+       (isdigit): New macro.
+       (numbered_arg_compare): New function.
+       (format_parse, format_free, format_check, format_print): Update to
+       GCC 4.1 internal format strings.
+       Reported by Göran Uddeborg <goeran@uddeborg.se>.
+
 2005-05-23  Bruno Haible  <bruno@clisp.org>
 
        * gettext-0.14.5 released.
index 7d3be080fb6887344e58fabc02cd221245055bd8..98b4550e1498b25200c8fa9605428c5433402053 100644 (file)
@@ -1,5 +1,5 @@
 /* GCC internal format strings.
-   Copyright (C) 2003-2005 Free Software Foundation, Inc.
+   Copyright (C) 2003-2006 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2003.
 
    This program is free software; you can redistribute it and/or modify
 #define _(str) gettext (str)
 
 /* GCC internal format strings consist of language frontend independent
-   format directives, implemented in gcc-4.0.0/gcc/pretty-print.c (function
-   pp_base_format_text), plus some frontend dependent extensions:
+   format directives, implemented in gcc-4.1.0/gcc/pretty-print.c (function
+   pp_base_format), plus some frontend dependent extensions:
      - for the C/ObjC frontend
-       in gcc-4.0.0/gcc/c-objc-common.c (function c_tree_printer)
+       in gcc-4.1.0/gcc/c-objc-common.c (function c_tree_printer)
      - for the C++ frontend
-       in gcc-4.0.0/gcc/cp/error.c (function cp_printer)
+       in gcc-4.1.0/gcc/cp/error.c (function cp_printer)
    Taking these together, GCC internal format strings are specified as follows.
 
    A directive
    - starts with '%',
-   - is optionally followed by 'q',
-   - is optionally followed by a size specifier 'l', 'll' or 'w',
-   - 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
-
+   - either is finished by one of these:
        - '%', '<', '>', "'", that need no argument,
        - 'm', that needs no argument but looks at an err_no variable,
-       - 'c', that needs a character argument,
-       - 's', that needs a string argument,
-       - 'i', 'd', that need a signed integer argument of the specified size,
-       - 'o', 'u', 'x', that need an unsigned integer argument of the specified
-         size,
-       - '.*s', that needs a signed integer argument and a string argument,
-       - 'p', that needs a 'void *' argument,
-       - 'H', that needs a 'location_t *' argument,
-         [see gcc/pretty-print.c]
-
-       - 'D', that needs a general declaration argument,
-       - 'F', that needs a function declaration argument,
-       - 'T', that needs a type argument,
-       - 'E', that needs an expression 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,
-       - '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]
-
-   Furthermore, some extra directives can occur only at the beginning of a
-   format string. Such a directive
-   - starts with '%',
-   - is finished by a specifier
-       - 'J', that needs a general declaration argument.
-   [see gcc/pretty-print.c (function pp_base_prepare_to_format)]
- */
+   - or is continued like this:
+       - optionally 'm$' where m is a positive integer,
+       - optionally any number of flags:
+         'q' (once only),
+         'l' (up to twice) or 'w' (once only) (exclusive),
+         '+' (once only),
+         '#' (once only),
+       - finished by a specifier
+
+           - 'c', that needs a character argument,
+           - 's', that needs a string argument,
+           - '.NNNs', where NNN is a nonempty digit sequence, that needs a
+             string argument,
+           - '.*NNN$s' where NNN is a positive integer and NNN = m - 1, that
+             needs a signed integer argument at position NNN and a string
+             argument,
+           - '.*s', that needs a signed integer argument and a string argument,
+           - 'i', 'd', that need a signed integer argument of the specified
+             size,
+           - 'o', 'u', 'x', that need an unsigned integer argument of the
+             specified size,
+           - 'p', that needs a 'void *' argument,
+           - 'H', that needs a 'location_t *' argument,
+           - 'J', that needs a general declaration argument,
+             [see gcc/pretty-print.c]
+
+           - 'D', that needs a general declaration argument,
+           - 'F', that needs a function declaration argument,
+           - 'T', that needs a type argument,
+           - 'E', that needs an expression 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,
+           - '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]
+
+   Numbered ('%m$' or '*m$') and unnumbered argument specifications cannot
+   be used in the same string.  */
 
 enum format_arg_type
 {
@@ -114,65 +120,57 @@ enum format_arg_type
   FAT_SIZE_MASK                = (FAT_SIZE_LONG | FAT_SIZE_LONGLONG | FAT_SIZE_WIDE)
 };
 
-struct unnumbered_arg
+struct numbered_arg
 {
+  unsigned int number;
   enum format_arg_type type;
 };
 
 struct spec
 {
   unsigned int directives;
-  unsigned int unnumbered_arg_count;
+  unsigned int numbered_arg_count;
   unsigned int allocated;
-  struct unnumbered_arg *unnumbered;
+  struct numbered_arg *numbered;
   bool uses_err_no;
 };
 
+/* 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 int
+numbered_arg_compare (const void *p1, const void *p2)
+{
+  unsigned int n1 = ((const struct numbered_arg *) p1)->number;
+  unsigned int n2 = ((const struct numbered_arg *) p2)->number;
+
+  return (n1 > n2 ? 1 : n1 < n2 ? -1 : 0);
+}
 
 static void *
 format_parse (const char *format, bool translated, char **invalid_reason)
 {
-  const char *format_start;
   struct spec spec;
+  unsigned int unnumbered_arg_count;
   struct spec *result;
 
-  format_start = format;
-
   spec.directives = 0;
-  spec.unnumbered_arg_count = 0;
+  spec.numbered_arg_count = 0;
   spec.allocated = 0;
-  spec.unnumbered = NULL;
+  spec.numbered = NULL;
   spec.uses_err_no = false;
+  unnumbered_arg_count = 0;
 
   for (; *format != '\0';)
     if (*format++ == '%')
       {
        /* A directive.  */
-       enum format_arg_type size;
-
        spec.directives++;
 
-       if (*format == 'q')
-         format++;
-
-       /* Parse size.  */
-       size = 0;
-       if (*format == 'l')
-         {
-           format++;
-           size = FAT_SIZE_LONG;
-           if (*format == 'l')
-             {
-               format++;
-               size = FAT_SIZE_LONGLONG;
-             }
-         }
-       else if (*format == 'w')
-         {
-           format++;
-           size = FAT_SIZE_WIDE;
-         }
-
        if (*format == '%' || *format == '<' || *format == '>'
            || *format == '\'')
          ;
@@ -180,50 +178,217 @@ format_parse (const char *format, bool translated, char **invalid_reason)
          spec.uses_err_no = true;
        else
          {
+           unsigned int number = 0;
+           unsigned int flag_q = 0;
+           unsigned int flag_l = 0;
+           unsigned int flag_w = 0;
+           unsigned int flag_plus = 0;
+           unsigned int flag_sharp = 0;
+           enum format_arg_type size;
            enum format_arg_type type;
 
+           if (isdigit (*format))
+             {
+               const char *f = format;
+               unsigned int m = 0;
+
+               do
+                 {
+                   m = 10 * m + (*f - '0');
+                   f++;
+                 }
+               while (isdigit (*f));
+
+               if (*f == '$')
+                 {
+                   if (m == 0)
+                     {
+                       *invalid_reason = INVALID_ARGNO_0 (spec.directives);
+                       goto bad_format;
+                     }
+                   number = m;
+                   format = ++f;
+                 }
+             }
+
+           /* Parse flags and size.  */
+           for (;; format++)
+             {
+               switch (*format)
+                 {
+                 case 'q':
+                   if (flag_q > 0)
+                     goto invalid_flags;
+                   flag_q = 1;
+                   continue;
+                 case 'l':
+                   if (flag_l > 1 || flag_w)
+                     goto invalid_flags;
+                   flag_l++;
+                   continue;
+                 case 'w':
+                   if (flag_w > 0 || flag_l)
+                     goto invalid_flags;
+                   flag_w = 1;
+                   continue;
+                 case '+':
+                   if (flag_plus > 0)
+                     goto invalid_flags;
+                   flag_plus = 1;
+                   continue;
+                 case '#':
+                   if (flag_sharp > 0)
+                     goto invalid_flags;
+                   flag_sharp = 1;
+                   continue;
+                 invalid_flags:
+                   *invalid_reason = xasprintf (_("In the directive number %u, the flags combination is invalid."), spec.directives);
+                   goto bad_format;
+                 default:
+                   break;
+                 }
+               break;
+             }
+           size = (flag_l == 2 ? FAT_SIZE_LONGLONG :
+                   flag_l == 1 ? FAT_SIZE_LONG :
+                   flag_w ? FAT_SIZE_WIDE :
+                   0);
+
            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')
+           else if (*format == '.')
              {
-               if (spec.allocated == spec.unnumbered_arg_count)
+               format++;
+
+               if (isdigit (*format))
                  {
-                   spec.allocated = 2 * spec.allocated + 1;
-                   spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
+                   do
+                     format++;
+                   while (isdigit (*format));
+
+                   if (*format != 's')
+                     {
+                       *invalid_reason =
+                         (*format == '\0'
+                          ? INVALID_UNTERMINATED_DIRECTIVE ()
+                          : xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format));
+                       goto bad_format;
+                     }
+
+                   type = FAT_STRING;
+                 }
+               else if (*format == '*')
+                 {
+                   unsigned int precision_number = 0;
+
+                   format++;
+
+                   if (isdigit (*format))
+                     {
+                       const char *f = format;
+                       unsigned int m = 0;
+
+                       do
+                         {
+                           m = 10 * m + (*f - '0');
+                           f++;
+                         }
+                       while (isdigit (*f));
+
+                       if (*f == '$')
+                         {
+                           if (m == 0)
+                             {
+                               *invalid_reason = INVALID_WIDTH_ARGNO_0 (spec.directives);
+                               goto bad_format;
+                             }
+                           if (unnumbered_arg_count > 0 || number == 0)
+                             {
+                               *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+                               goto bad_format;
+                             }
+                           if (m != number - 1)
+                             {
+                               *invalid_reason = xasprintf (_("In the directive number %u, the argument number for the precision must be equal to %u."), spec.directives, number - 1);
+                               goto bad_format;
+                             }
+                           precision_number = m;
+                           format = ++f;
+                         }
+                     }
+
+                   if (precision_number)
+                     {
+                       /* Numbered argument.  */
+
+                       /* Numbered and unnumbered specifications are exclusive.  */
+                       if (unnumbered_arg_count > 0)
+                         {
+                           *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+                           goto bad_format;
+                         }
+
+                       if (spec.allocated == spec.numbered_arg_count)
+                         {
+                           spec.allocated = 2 * spec.allocated + 1;
+                           spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
+                         }
+                       spec.numbered[spec.numbered_arg_count].number = precision_number;
+                       spec.numbered[spec.numbered_arg_count].type = FAT_INTEGER;
+                       spec.numbered_arg_count++;
+                     }
+                   else
+                     {
+                       /* Unnumbered argument.  */
+
+                       /* Numbered and unnumbered specifications are exclusive.  */
+                       if (spec.numbered_arg_count > 0)
+                         {
+                           *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+                           goto bad_format;
+                         }
+
+                       if (spec.allocated == unnumbered_arg_count)
+                         {
+                           spec.allocated = 2 * spec.allocated + 1;
+                           spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
+                         }
+                       spec.numbered[unnumbered_arg_count].number = unnumbered_arg_count + 1;
+                       spec.numbered[unnumbered_arg_count].type = FAT_INTEGER;
+                       unnumbered_arg_count++;
+                     }
+
+                   if (*format == 's')
+                     type = FAT_STRING;
+                   else
+                     {
+                       *invalid_reason =
+                         (*format == '\0'
+                          ? INVALID_UNTERMINATED_DIRECTIVE ()
+                          : xasprintf (_("In the directive number %u, a precision is not allowed before '%c'."), spec.directives, *format));
+                       goto bad_format;
+                     }
+                 }
+               else
+                 {
+                   *invalid_reason = xasprintf (_("In the directive number %u, the precision specification is invalid."), spec.directives);
+                   goto bad_format;
                  }
-               spec.unnumbered[spec.unnumbered_arg_count].type = FAT_INTEGER;
-               spec.unnumbered_arg_count++;
-               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 == 'p')
              type = FAT_POINTER;
            else if (*format == 'H')
              type = FAT_LOCATION;
            else if (*format == 'J')
-             {
-               if (format - format_start == 1)
-                 type = FAT_TREE | FAT_TREE_DECL;
-               else
-                 {
-                   *invalid_reason =
-                     (format[-1] == '%'
-                      ? xasprintf (_("The %%J directive is only allowed at the beginning of the string."))
-                      : xasprintf (_("The %%J directive does not support flags.")));
-                   goto bad_format;
-                 }
-             }
+             type = FAT_TREE | FAT_TREE_DECL;
            else
              {
-               if (*format == '+')
-                 format++;
-               if (*format == '#')
-                 format++;
                if (*format == 'D')
                  type = FAT_TREE | FAT_TREE_DECL;
                else if (*format == 'F')
@@ -263,25 +428,108 @@ format_parse (const char *format, bool translated, char **invalid_reason)
                  }
              }
 
-           if (spec.allocated == spec.unnumbered_arg_count)
+           if (number)
+             {
+               /* Numbered argument.  */
+
+               /* Numbered and unnumbered specifications are exclusive.  */
+               if (unnumbered_arg_count > 0)
+                 {
+                   *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+                   goto bad_format;
+                 }
+
+               if (spec.allocated == spec.numbered_arg_count)
+                 {
+                   spec.allocated = 2 * spec.allocated + 1;
+                   spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
+                 }
+               spec.numbered[spec.numbered_arg_count].number = number;
+               spec.numbered[spec.numbered_arg_count].type = type;
+               spec.numbered_arg_count++;
+             }
+           else
              {
-               spec.allocated = 2 * spec.allocated + 1;
-               spec.unnumbered = (struct unnumbered_arg *) xrealloc (spec.unnumbered, spec.allocated * sizeof (struct unnumbered_arg));
+               /* Unnumbered argument.  */
+
+               /* Numbered and unnumbered specifications are exclusive.  */
+               if (spec.numbered_arg_count > 0)
+                 {
+                   *invalid_reason = INVALID_MIXES_NUMBERED_UNNUMBERED ();
+                   goto bad_format;
+                 }
+
+               if (spec.allocated == unnumbered_arg_count)
+                 {
+                   spec.allocated = 2 * spec.allocated + 1;
+                   spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
+                 }
+               spec.numbered[unnumbered_arg_count].number = unnumbered_arg_count + 1;
+               spec.numbered[unnumbered_arg_count].type = type;
+               unnumbered_arg_count++;
              }
-           spec.unnumbered[spec.unnumbered_arg_count].type = type;
-           spec.unnumbered_arg_count++;
          }
 
        format++;
       }
 
+  /* Convert the unnumbered argument array to numbered arguments.  */
+  if (unnumbered_arg_count > 0)
+    spec.numbered_arg_count = unnumbered_arg_count;
+  /* Sort the numbered argument array, and eliminate duplicates.  */
+  else if (spec.numbered_arg_count > 1)
+    {
+      unsigned int i, j;
+      bool err;
+
+      qsort (spec.numbered, spec.numbered_arg_count,
+            sizeof (struct numbered_arg), numbered_arg_compare);
+
+      /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
+      err = false;
+      for (i = j = 0; i < spec.numbered_arg_count; i++)
+       if (j > 0 && spec.numbered[i].number == spec.numbered[j-1].number)
+         {
+           enum format_arg_type type1 = spec.numbered[i].type;
+           enum format_arg_type type2 = spec.numbered[j-1].type;
+           enum format_arg_type type_both;
+
+           if (type1 == type2)
+             type_both = type1;
+           else
+             {
+               /* Incompatible types.  */
+               type_both = FAT_NONE;
+               if (!err)
+                 *invalid_reason =
+                   INVALID_INCOMPATIBLE_ARG_TYPES (spec.numbered[i].number);
+               err = true;
+             }
+
+           spec.numbered[j-1].type = type_both;
+         }
+       else
+         {
+           if (j < i)
+             {
+               spec.numbered[j].number = spec.numbered[i].number;
+               spec.numbered[j].type = spec.numbered[i].type;
+             }
+           j++;
+         }
+      spec.numbered_arg_count = j;
+      if (err)
+       /* *invalid_reason has already been set above.  */
+       goto bad_format;
+    }
+
   result = (struct spec *) xmalloc (sizeof (struct spec));
   *result = spec;
   return result;
 
  bad_format:
-  if (spec.unnumbered != NULL)
-    free (spec.unnumbered);
+  if (spec.numbered != NULL)
+    free (spec.numbered);
   return NULL;
 }
 
@@ -290,8 +538,8 @@ format_free (void *descr)
 {
   struct spec *spec = (struct spec *) descr;
 
-  if (spec->unnumbered != NULL)
-    free (spec->unnumbered);
+  if (spec->numbered != NULL)
+    free (spec->numbered);
   free (spec);
 }
 
@@ -311,27 +559,67 @@ format_check (void *msgid_descr, void *msgstr_descr, bool equality,
   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 (spec1->numbered_arg_count + spec2->numbered_arg_count > 0)
     {
-      if (error_logger)
-       error_logger (_("number of format specifications in 'msgid' and '%s' does not match"),
-                     pretty_msgstr);
-      err = true;
-    }
-  else
-    for (i = 0; i < spec2->unnumbered_arg_count; i++)
-      if (spec1->unnumbered[i].type != spec2->unnumbered[i].type)
+      unsigned int i, j;
+      unsigned int n1 = spec1->numbered_arg_count;
+      unsigned int n2 = spec2->numbered_arg_count;
+
+      /* Check the argument names are the same.
+        Both arrays are sorted.  We search for the first difference.  */
+      for (i = 0, j = 0; i < n1 || j < n2; )
        {
-         if (error_logger)
-           error_logger (_("format specifications in 'msgid' and '%s' for argument %u are not the same"),
-                         pretty_msgstr, i + 1);
-         err = true;
+         int cmp = (i >= n1 ? 1 :
+                    j >= n2 ? -1 :
+                    spec1->numbered[i].number > spec2->numbered[j].number ? 1 :
+                    spec1->numbered[i].number < spec2->numbered[j].number ? -1 :
+                    0);
+
+         if (cmp > 0)
+           {
+             if (error_logger)
+               error_logger (_("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"),
+                             spec2->numbered[j].number, pretty_msgstr);
+             err = true;
+             break;
+           }
+         else if (cmp < 0)
+           {
+             if (equality)
+               {
+                 if (error_logger)
+                   error_logger (_("a format specification for argument %u doesn't exist in '%s'"),
+                                 spec1->numbered[i].number, pretty_msgstr);
+                 err = true;
+                 break;
+               }
+             else
+               i++;
+           }
+         else
+           j++, i++;
        }
+      /* Check the argument types are the same.  */
+      if (!err)
+       for (i = 0, j = 0; j < n2; )
+         {
+           if (spec1->numbered[i].number == spec2->numbered[j].number)
+             {
+               if (spec1->numbered[i].type != spec2->numbered[j].type)
+                 {
+                   if (error_logger)
+                     error_logger (_("format specifications in 'msgid' and '%s' for argument %u are not the same"),
+                                   pretty_msgstr, spec2->numbered[j].number);
+                   err = true;
+                   break;
+                 }
+               j++, i++;
+             }
+           else
+             i++;
+         }
+    }
 
   /* Check that the use of err_no is the same.  */
   if (spec1->uses_err_no != spec2->uses_err_no)
@@ -373,6 +661,7 @@ static void
 format_print (void *descr)
 {
   struct spec *spec = (struct spec *) descr;
+  unsigned int last;
   unsigned int i;
 
   if (spec == NULL)
@@ -382,13 +671,20 @@ format_print (void *descr)
     }
 
   printf ("(");
-  for (i = 0; i < spec->unnumbered_arg_count; i++)
+  last = 1;
+  for (i = 0; i < spec->numbered_arg_count; i++)
     {
+      unsigned int number = spec->numbered[i].number;
+
       if (i > 0)
        printf (" ");
-      if (spec->unnumbered[i].type & FAT_UNSIGNED)
+      if (number < last)
+       abort ();
+      for (; last < number; last++)
+       printf ("_ ");
+      if (spec->numbered[i].type & FAT_UNSIGNED)
        printf ("[unsigned]");
-      switch (spec->unnumbered[i].type & FAT_SIZE_MASK)
+      switch (spec->numbered[i].type & FAT_SIZE_MASK)
        {
        case 0:
          break;
@@ -404,7 +700,7 @@ format_print (void *descr)
        default:
          abort ();
        }
-      switch (spec->unnumbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_MASK))
+      switch (spec->numbered[i].type & ~(FAT_UNSIGNED | FAT_SIZE_MASK))
        {
        case FAT_INTEGER:
          printf ("i");
@@ -457,6 +753,7 @@ format_print (void *descr)
        default:
          abort ();
        }
+      last = number + 1;
     }
   printf (")");
   if (spec->uses_err_no)
index e8fcd27f07076a952eab93d927b9858637eb59c2..d9d0e482cd2472efd06c9afcde017e00383d5d2d 100644 (file)
@@ -1,3 +1,8 @@
+2006-06-20  Bruno Haible  <bruno@clisp.org>
+
+       * format-gcc-internal-1: Update to GCC 4.1 internal format strings.
+       * format-gcc-internal-2: Likewise.
+
 2005-05-23  Bruno Haible  <bruno@clisp.org>
 
        * gettext-0.14.5 released.
index a64074c87b8a81f8d1894c9ba268e3609d4169a4..da055e496a4d75bec0bb63b3daba6734d67c40db 100755 (executable)
@@ -39,9 +39,9 @@ cat <<\EOF > f-gi-1.data
 "abc%H"
 # Valid: one pointer argument
 "%J"
-# Invalid: %J not at start
+# Valid: %J not at start
 "abc%J"
-# Invalid: %J with flags
+# Valid: %J with flags
 "%qJ"
 # Valid: one pointer argument
 "abc%D"
@@ -87,8 +87,44 @@ cat <<\EOF > f-gi-1.data
 "abc%.*.*s"
 # Valid: three arguments
 "abc%d%u%u"
-# Invalid: a numbered argument
+# Valid: a numbered argument
 "abc%1$d"
+# Invalid: zero
+"abc%0$d"
+# Valid: two-digit numbered arguments
+"abc%11$def%10$dgh%9$dij%8$dkl%7$dmn%6$dop%5$dqr%4$dst%3$duv%2$dwx%1$dyz"
+# Invalid: unterminated number
+"abc%1"
+# Invalid: flags before number
+"abc%+1$d"
+# Valid: three arguments, two with same number
+"abc%1$x,%2$c,%1$u"
+# Invalid: argument with conflicting types
+"abc%1$x,%2$c,%1$s"
+# Valid: no conflict
+"abc%1$x,%2$c,%1$u"
+# Invalid: mixing of numbered and unnumbered arguments
+"abc%d%2$x"
+# Valid: numbered argument with constant precision
+"abc%1$.9s"
+# Invalid: mixing of numbered and unnumbered arguments
+"abc%1$.*s"
+# Valid: missing non-final argument
+"abc%2$x%3$s"
+# Valid: permutation
+"abc%2$ddef%1$d"
+# Valid: multiple uses of same argument
+"abc%2$xdef%1$sghi%2$x"
+# Valid: one argument with precision
+"abc%2$#.*1$s"
+# Invalid: non-string argument with precision
+"abc%2$#.*1$d"
+# Invalid: one argument with width
+"abc%2$#*1$s"
+# Invalid: one argument with width and precision
+"abc%3$*2$.*1$s"
+# Invalid: zero
+"abc%1$#.*0$s"
 EOF
 
 : ${XGETTEXT=xgettext}
index bf0a2d2030d24cb32e5f7840608ba63e3bf292bd..55725d135b5a832cb157a8e3e06feb5152a65913 100755 (executable)
@@ -37,12 +37,33 @@ msgstr "xyz%qs%qH"
 # Valid: same arguments, with different widths
 msgid  "abc%.*sdef"
 msgstr "xyz%i%s"
+# Valid: same arguments but in numbered syntax
+msgid  "abc%s%ddef"
+msgstr "xyz%1$s%2$d"
+# Valid: permutation
+msgid  "abc%s%d%cdef"
+msgstr "xyz%3$c%2$d%1$s"
+# Valid: permutation with width
+msgid  "abc%c%.*sdef"
+msgstr "xyz%3$.*2$s%1$c"
 # Invalid: too few arguments
 msgid  "abc%sdef%u"
 msgstr "xyz%s"
 # Invalid: too many arguments
 msgid  "abc%udef"
 msgstr "xyz%uvw%c"
+# Valid: same numbered arguments, with different widths
+msgid  "abc%2$5s%1$4s"
+msgstr "xyz%2$4s%1$5s"
+# Invalid: missing argument
+msgid  "abc%2$sdef%1$u"
+msgstr "xyz%1$u"
+# Invalid: missing argument
+msgid  "abc%1$sdef%2$u"
+msgstr "xyz%2$u"
+# Invalid: added argument
+msgid  "abc%1$udef"
+msgstr "xyz%1$uvw%2$c"
 # Valid: type compatibility
 msgid  "abc%i"
 msgstr "xyz%d"