This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Special handling of "%H" (Re: Support for %d$c format specifier in diagnostics.c)


Hi

Here is the latest patch to support positional format specifiers
in GCC's diagnostics output.

This patch has been discussed on this mailing list previously
(starting early summer to September then I waited for the FSF
paperwork to finish, which took time due to mail misdelivery).
I have signed the copyright assignment form with FSF and paperwork
is finished.

So I am sending out the patch against the CVS for peer review.

Basically, the modification does the following.

When a positional format specifier is seen inside a format string,

 - (GET_ARG_TYPE): the argument list is scanned to record the type/size of the passed
   arguments.

 - (COPY_ARG_VALUE): the arguments based on the type/size obtained during the first scan
   are copied to a linear array one by one.

 - (PRINT_ARG_VALUE):
   finally the printing takes place and
   positional specifiers are now handled smoothly by using the
   linear array of argumet values.

The label used above are taken from  the values for enum arg_decode_action.

When there is no positional format specifier, we use the old-fashioned
action as is. (PRINT_ARG_VALUE_AS_BEFORE)

The modification tries to preserve the old behavior as much as
possible to show the approach as well as avoiding introducing bugs.

bootstrapped under i686-pc-linux-gnu, and tested using
make -k check. 
(Strange thing is that for about a week, the
copy of CVS source generates many errors for
make -k check. This started when c++ headers were modified/renamed in
CVS tree. bitset.h, -> std_bitset.h, etc..
I must have missed something. Or the tests need to be changed?)


Here is the ChangeLog and the patch itself.

2003-11-20    <ishikawa@yk.rim.or.jp>

	Positional format specifier support for pp_format_text().	
	
	* pretty-print.h (struct): struct argtype_t, enum  arg_decode_action, struct text_info.
	  printer_fn takes extra argument of type  arg_decode_action.
	
	* pretty-print.c (_helper_abort): print the problematic format string
	  and abort.
	  (_type_width): returns the argument width based
	  on format specifier type.
	  (compatible_and_has_same_width): check if the double use of
	  an argument uses the same type and width.
	  (set_argument_type_with_precision): store the argument type in 
	  a static array.
	  (set_argument_type): store the argument type without precision.
	  (pp_integer_with_precision_NEW): Macro based on the
	  original pp_integer_with_precision. Uses the created argument
	  array to fetch the value.
	  (build_argument_array): build an array of argument to support
	  positional format specifier.
	  (pp_format_text): modified to work with the positional format
	  specifier support. %H no longer prints output.
	
	* c-objc-common.c (c_tree_printer): takes extra argument of type
	  arg_decode_action. Modified to support four actions.

	* cp/error.c (cp_printer) : ditto
	
	* toplev.c (default_tree_printer): ditto.
	  Also a dummy (ifdef'ed out using #if 0) resting place 
	  for test code for the lack of better place.
	
	* diagnostic.c (diagnostic_J_tree2locus): 
          This function is here so that pretty-print.c itself is
          free of tree-related typedefs, etc. necessary for
	  DECL_SOURCE_LOCATION macro, which is now used for %J support.
	
	  (text_specifies_location): 
	  check for "%1$H" as well as for "%H". Restores the pointer.
	  '%H' is now retained by text_specifies_location. 
	  Similar handling for "%J" and "%1$J" as well.


Index: gcc/c-objc-common.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.36
diff -p -3 -c -r1.36 c-objc-common.c
*** gcc/c-objc-common.c	31 Oct 2003 07:14:43 -0000	1.36
--- gcc/c-objc-common.c	19 Nov 2003 10:28:32 -0000
*************** Software Foundation, 59 Temple Place - S
*** 39,45 ****
  #include "target.h"
  #include "cgraph.h"
  
! static bool c_tree_printer (pretty_printer *, text_info *);
  static tree start_cdtor (int);
  static void finish_cdtor (tree);
  
--- 39,45 ----
  #include "target.h"
  #include "cgraph.h"
  
! static bool c_tree_printer (pretty_printer *, text_info *, arg_decode_action);
  static tree start_cdtor (int);
  static void finish_cdtor (tree);
  
*************** c_objc_common_finish_file (void)
*** 288,333 ****
     These format specifiers form a subset of the format specifiers set used
     by the C++ front-end.
     Please notice when called, the `%' part was already skipped by the
!    diagnostic machinery.  */
  static bool
! c_tree_printer (pretty_printer *pp, text_info *text)
  {
!   tree t = va_arg (*text->args_ptr, tree);
    const char *n = "({anonymous})";
  
!   switch (*text->format_spec)
      {
!     case 'D':
!     case 'F':
!       if (DECL_NAME (t))
! 	n = (*lang_hooks.decl_printable_name) (t, 2);
!       break;
  
!     case 'T':
!       if (TREE_CODE (t) == TYPE_DECL)
  	{
  	  if (DECL_NAME (t))
  	    n = (*lang_hooks.decl_printable_name) (t, 2);
  	}
!       else
  	{
! 	  t = TYPE_NAME (t);
! 	  if (t)
! 	    n = IDENTIFIER_POINTER (t);
  	}
-       break;
- 
-     case 'E':
-       if (TREE_CODE (t) == IDENTIFIER_NODE)
- 	n = IDENTIFIER_POINTER (t);
-       else
-         return false;
-       break;
- 
-     default:
-       return false;
      }
  
!   pp_string (pp, n);
!   return true;
  }
--- 288,401 ----
     These format specifiers form a subset of the format specifiers set used
     by the C++ front-end.
     Please notice when called, the `%' part was already skipped by the
!    diagnostic machinery.  
! 
! 
!    Additional comment about support for positional parameters.
! 
!    Modifying c_tree_printer to support positional parameters was
!    relatively easy.
!    Reasons why.
! 
!    (1) Only a single format character is used as opposed to 
!        multi-character sequence.
! 
!    (2) Value fetched from the argument list is of only ONE type, namely
!        "tree".
! 
!    Below, I play fast and loose in handling of 'E' format.
!    I don't return "false" to indicate error until
!    PRINT_ARG_VALUE is requested, and the TREE value is not
!    found to be IDENTIFIER_NODE.
!    This is because I know for certain that the any error is
!    eventually caught during the processing of PRINT_ARG_VALUE.
!    No need to complicate processing during
!      - GET_ARG_TYPE, and 
!      - COPY_ARG_VALUE. */
! 
  static bool
! c_tree_printer (pretty_printer *pp, text_info *text, arg_decode_action a)
  {
!   tree t ;
    const char *n = "({anonymous})";
  
!   if (a == PRINT_ARG_VALUE_AS_BEFORE || a == PRINT_ARG_VALUE)	
      {
!       if (a == PRINT_ARG_VALUE)
! 	t = (tree) text->arg_array[text->index_num].v.ptr;
!       else
! 	t = va_arg (*text->args_ptr, tree);
  
!       switch (*text->format_spec)
  	{
+ 	case 'D':
+ 	case 'F':
  	  if (DECL_NAME (t))
  	    n = (*lang_hooks.decl_printable_name) (t, 2);
+ 	  break;
+ 
+ 	case 'T':
+ 	  if (TREE_CODE (t) == TYPE_DECL)
+ 	    {
+ 	      if (DECL_NAME (t))
+ 		n = (*lang_hooks.decl_printable_name) (t, 2);
+ 	    }
+ 	  else
+ 	    {
+ 	      t = TYPE_NAME (t);
+ 	      if (t)
+ 		n = IDENTIFIER_POINTER (t);
+ 	    }
+ 
+ 
+ 	case 'E':
+ 	  if (TREE_CODE (t) == IDENTIFIER_NODE)
+ 	    n = IDENTIFIER_POINTER (t);
+ 	  else
+ 	    return false;
+ 	  break;
+ 	default:
+ 	  return false;
  	}
!       pp_string (pp, n);
!       return true;
!     }
!   else if (a == GET_ARG_TYPE)
!     {
!       text->bump_format = 0;
!       switch (*text->format_after_percent_or_dollar)
  	{
! 	case 'D':
! 	case 'F':
! 	case 'T':
! 	case 'E':
! 	  text->bump_format = 1;
! 	  text->arg_array[text->index_num].custom_format[0]
! 	    = *text->format_after_percent_or_dollar;
! 	  return true;
! 	default:
! 	  return false;
  	}
      }
+   else if (a == COPY_ARG_VALUE)
+     {
+       text->bump_format = 0;
+       switch (*text->format_after_percent_or_dollar)
+ 	{
+ 	case 'D':
+ 	case 'F':
+ 	case 'T':
+ 	case 'E':
+ 	  text->arg_array[text->index_num].v.ptr 
+ 	    = (void *) va_arg (*text->args_ptr, tree);
+ 	  text->bump_format = 1;	/* we know it is 1 at most. */
+ 	  return true;
+ 	default:
+ 	  return false;
+ 	}
+     }
+   else 
+     abort ();
  
!   return false;
  }
Index: gcc/diagnostic.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/diagnostic.c,v
retrieving revision 1.133
diff -p -3 -c -r1.133 diagnostic.c
*** gcc/diagnostic.c	22 Sep 2003 05:09:12 -0000	1.133
--- gcc/diagnostic.c	19 Nov 2003 10:28:33 -0000
*************** diagnostic_initialize (diagnostic_contex
*** 118,126 ****
    context->x_data = NULL;
  }
  
  /* Returns true if the next format specifier in TEXT is a format specifier
     for a location_t.  If so, update the object pointed by LOCUS to reflect
!    the specified location in *TEXT->args_ptr.  */
  static bool
  text_specifies_location (text_info *text, location_t *locus)
  {
--- 118,144 ----
    context->x_data = NULL;
  }
  
+ /* Returns location_t struct from a tree node for a
+    declaration. Called from within pretty-print.c.
+    This function is here so that pretty-print.c itself is
+    free of tree-related typedefs, etc. necessary for DECL_SOURCE_LOCATION. */
+ location_t 
+ diagnostic_J_tree2locus (tree t)
+ {
+   return DECL_SOURCE_LOCATION (t);
+ }
+ 
  /* Returns true if the next format specifier in TEXT is a format specifier
     for a location_t.  If so, update the object pointed by LOCUS to reflect
!    the specified location in *TEXT->args_ptr.  
! 
!    To bring consistency to positional format specifier support,
!    we restore the original args_ptr before returning
!    so that the subsequent call to pp_text_format() can access %H (or %1$H).
!    and  we don't remove the %H reference.
! 
!    pp_format_text() doesn't formats/prints the first %H reference.
!    It merely bumps the arg pointer. */
  static bool
  text_specifies_location (text_info *text, location_t *locus)
  {
*************** text_specifies_location (text_info *text
*** 129,151 ****
    for (p = text->format_spec; *p && *p != '%'; ++p)
      ;
  
!   /* Extract the location information if any.  */
!   if (p[0] == '%' && p[1] == 'H')
      {
        *locus = *va_arg (*text->args_ptr, location_t *);
!       text->format_spec = p + 2;
        return true;
      }
!   else if (p[0] == '%' && p[1] == 'J')
      {
        tree t = va_arg (*text->args_ptr, tree);
        *locus = DECL_SOURCE_LOCATION (t);
!       text->format_spec = p + 2;
        return true;
      }
  
    return false;
  }
  
  void
  diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid,
--- 147,180 ----
    for (p = text->format_spec; *p && *p != '%'; ++p)
      ;
  
!   /* assert *p == NUL 
!      || *p == '%' */
! 
!   /* Extract the location information if any.  
!      We now match either %H or %1$H, and
!      don't skip in the format_spec either. */
! 
!   if (strncmp (p, "%H", 2) == 0
!       || strncmp (p, "%1$H", 4) == 0)
      {
+       va_list saved_ptr =  *text->args_ptr; /* save */
        *locus = *va_arg (*text->args_ptr, location_t *);
!       *text->args_ptr = saved_ptr; /* restore */
        return true;
      }
!   else if (    strncmp (p, "%J",   2)   == 0
! 	    || strncmp (p, "%1$J", 4) == 0 )
      {
+       va_list saved_ptr =  *text->args_ptr; /* save */
        tree t = va_arg (*text->args_ptr, tree);
        *locus = DECL_SOURCE_LOCATION (t);
!       *text->args_ptr = saved_ptr; /* restore */
        return true;
      }
  
    return false;
  }
+ 
  
  void
  diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid,
Index: gcc/diagnostic.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/diagnostic.h,v
retrieving revision 1.66
diff -p -3 -c -r1.66 diagnostic.h
*** gcc/diagnostic.h	22 Aug 2003 06:25:08 -0000	1.66
--- gcc/diagnostic.h	19 Nov 2003 10:28:33 -0000
*************** extern char *diagnostic_build_prefix (di
*** 182,185 ****
--- 182,189 ----
  extern void verbatim (const char *, ...);
  extern char *file_name_as_prefix (const char *);
  
+ extern location_t diagnostic_J_tree2locus (tree t);
+ 
+ 
+ 
  #endif /* ! GCC_DIAGNOSTIC_H */
Index: gcc/pretty-print.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.c,v
retrieving revision 2.6
diff -p -3 -c -r2.6 pretty-print.c
*** gcc/pretty-print.c	12 Sep 2003 23:47:01 -0000	2.6
--- gcc/pretty-print.c	19 Nov 2003 10:28:34 -0000
*************** Software Foundation, 59 Temple Place - S
*** 26,31 ****
--- 26,33 ----
  #include "coretypes.h"
  #include "pretty-print.h"
  
+ #include <ctype.h>
+ 
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free  free
  
*************** pp_base_indent (pretty_printer *pp)
*** 164,169 ****
--- 166,787 ----
      pp_space (pp);
  }
  
+ 
+ /*  ========================================
+     Supporting positional format specifiers a la 
+     %2$d, %1$d, %3$c, etc..
+     ======================================== */
+ #define UNDEFINED_FORMAT 0
+ #define LOCATION_T_TYPE 1001
+ #define LOCATION_D_TYPE 1002	/* for DECL_SOURCE_LOCATION,  %J */
+ 
+ /* Aborting with error message and the format string that caused it.
+    This intentionally prints out format string so that we can save
+    a few e-mail exchanges with the bug reporter(s). */
+ static void pp_helper_abort (const char *a, text_info *text)
+ {
+   fprintf (stderr, "Problem with output formatting: %s\n", a);
+   fprintf (stderr, "format=<<%s>>\n", text->original_format_spec);
+ #ifdef ENABLE_CHECKING
+   abort ();
+ #endif
+ }
+ 
+ /*   type compatibility info for %d$c processing.
+    Check is based only on the width, i.e., sizeof (t).
+ 
+    The whole scheme does not feel quit right in that 
+    it is not quite clear whether %lld, %ld, and/or %d  should
+    be compatible with HOST_WIDE_INT. 
+    But it works. */
+ static int pp_type_width (int t)
+ {
+   switch (t)
+     {
+     default:
+       fprintf (stderr, "pp_type_width: unknown type spec. %d\n", t);
+       abort ();
+       break;
+ 
+     case 's': return sizeof (char *); 
+ 
+     case 'c': return sizeof (int);
+ 
+     case 'i':
+     case 'd': return sizeof (int);
+ 
+       /* HOST_WIDE_INT may be blank "" on some systems such as x86 
+          So we use 'W' to stand for it. */
+     case 'W' /* for HOST_WIDE_INT */ : return  sizeof (long); 
+ 
+     case 'U' /* UNSIGNED_HOST_WIDE_INT */ : return sizeof (unsigned long int);
+ 
+     case 'x':
+     case 'u': 
+     case 'o': return sizeof (unsigned int) ;
+ 
+     case 'p': return sizeof (void *);
+ 
+     case LOCATION_D_TYPE: return sizeof (void *);
+ 
+     case LOCATION_T_TYPE: return sizeof (void *);
+     }
+ 
+   /* NOTREACHED */
+   abort ();
+ }
+ 
+ /* if an argument is referenced twice, we
+   say, the references are compatible if the type (width)
+  is the same, and its precisions are the same.
+ 
+  E.g. %1$d and %1$lld is not considered compatible. */
+ static int
+ pp_compatible_and_has_same_width (int t, int prec1, int u, int prec2)
+ {
+   return pp_type_width (t) == pp_type_width (u)
+     && prec1 == prec2 ;
+ }
+ 
+ 
+ /* store argument tye with precision. */
+ static void 
+ set_argument_type_with_precision (int i, int type, 
+ 				  int precision, text_info *text)
+ {
+   if (i <= 0 || i >= 10)
+     abort ();
+ 
+   if (precision < 0 || precision > 2)
+     abort ();
+ 
+   if (type == UNDEFINED_FORMAT)
+     abort ();
+ 
+   /* First definition/reference is OK. */
+   if (text->arg_array[i].typespec == UNDEFINED_FORMAT)
+     {
+       text->arg_array[i].typespec = type;
+       text->arg_array[i].precision = precision;
+ 
+       switch (precision)
+ 	{
+ 	default: abort ();
+ 
+ 	case 0:
+ 	  text->arg_array[i].format[0] = '%';
+ 	  text->arg_array[i].format[1] = type;
+ 	  break;
+ 
+ 	case 1:
+ 	  text->arg_array[i].format[0] = '%';
+ 	  text->arg_array[i].format[1] = 'l';
+ 	  text->arg_array[i].format[2] = type;
+ 	  break;
+ 
+ 	case 2:
+ 	  text->arg_array[i].format[0] = '%';
+ 	  text->arg_array[i].format[1] = 'l';
+ 	  text->arg_array[i].format[2] = 'l';
+ 	  text->arg_array[i].format[3] = type;
+ 	  break;
+ 	}
+ 
+       return;
+     }
+ 
+   /* Check the double definition */
+   if (pp_compatible_and_has_same_width
+        (text->arg_array[i].typespec, text->arg_array[i].precision, 
+ 	 type, precision))
+     return;
+   else
+     {
+       fprintf (stderr, "pretty-print.c: Specifying incompatible types for argument (at %d) twice\n", i);
+       fprintf (stderr, "format : <<%s>>\n", text->arg_array[0].v.cptr);
+ #ifdef ENABLE_CHECKING
+       abort ();      	
+ #endif
+     }
+ } 
+ 
+ /* store argument type (without precision.) */
+ static void 
+ set_argument_type (int i, int type, text_info *text)
+ {
+   /* precision is 0 */
+   set_argument_type_with_precision (i, type, 0, text);
+ }
+ 
+ 
+ /* we define the format string to be used
+    at the time of first scan (for types) 
+    by calling set_argument_type_with_precision, 
+    and do away with the dynamic construction of "%" F, "%l", F, "%ll", F
+    in pp_integer_with_precision. 
+ 
+    Assumption. This is used ONLY for
+    'd', 'i', 'x', 'o', 'u', that is for value meant to be numbers.
+    So I use i, li, and lli fields.
+    CAVEAT: I am making an assumption that
+    long long int, and long long unsigned uses a same size
+    memory cell. This seems reasonable.
+ 
+    arg_array[ind] holds the value, format, and precision. */ 
+ 
+ 
+ #define pp_integer_with_precision_NEW(PP, ind, text)  		\
+   do                                                            \
+     switch (text->arg_array[ind].precision)                     \
+       {                                                         \
+       case 0:                                                   \
+         pp_scalar                                 		\
+           (PP, text->arg_array[ind].format, text->arg_array[ind].v.i);  \
+         break;                                                  \
+                                                                 \
+       case 1:                                                   \
+         pp_scalar                                 		\
+           (PP, text->arg_array[ind].format, text->arg_array[ind].v.l);  \
+         break;                                                  \
+                                                                 \
+       case 2:                                                   \
+         pp_scalar                                 		\
+           (PP, text->arg_array[ind].format, text->arg_array[ind].v.ll); \
+         break;                                                  \
+                                                                 \
+       default:                                                  \
+         abort (); break;                                         \
+       }                                                         \
+   while (0)
+ 
+ 
+ /* Build argument array to support format specifiers in the form 
+  of %1$s, %2$d %3$d, etc. */
+ static void 
+ pp_build_argument_array (const char * format, 
+ 			 pretty_printer *pp, text_info *text)
+ {
+   int arg_index = 0;
+   int i;
+   int has_seen_number = 0;	/* have we seen "n$" in %n$d? */
+   
+   text->arg_max = 0;
+ 
+   memset (text->arg_array, 
+ 	 0, sizeof (text->arg_array)); /* fill in zero. UNDEFINED_FORMAT. */
+ 
+   text->arg_array[0].v.cptr = (char *) format; /* record for error message. */
+ 
+   /* loop through the string just looking for the type
+      Note that the variable, format, changes its value in this loop. */
+   for (; *format; ++format)
+     {
+       int precision = 0;
+       bool wide = false;
+ 
+       has_seen_number = 0;
+ 
+       /*  "Ignore text." while we build the array.  */
+       {
+ 	const char *p = format;
+ 	while (*p && *p != '%')
+ 	  ++p;
+         format = p;
+       }
+ 
+       /* assert:    format == '\0'
+ 	 || format == '%'
+       */
+ 
+       if (*format == '\0') /* we are at the end. Finish */
+ 	break;
+ 
+       /* We got a '%'.  Parse precision modifiers, if any.  
+          We also need to handle [0-9] as in %1$d */
+ 
+       /* assert:    
+ 	 we have  % [non-digit]
+ 	 || we have  % [digit] $    */
+ 
+       if (isdigit (format[1]))
+ 	{
+ 	  /* %1$ ... */
+ 	  if (format[2] == '$')
+ 	    {
+ 	      char tmp[2];
+ 
+ 	      tmp[1] = '\0';
+ 	      tmp[0] = format[1];
+ 	      arg_index = atoi (tmp);
+ 
+ 	      if (arg_index == 0)
+ 		{
+ 		  pp_helper_abort ("The digit that comes after % must be non-zero.",  text);
+ 		}
+ 
+ 	      if (text->arg_max < arg_index)
+ 		text->arg_max = arg_index;
+ 
+ 	      has_seen_number = 1;
+ 
+ 	      format += 2;
+ 	    }
+ 	  else  /* We expected '$' after "%1" */
+ 	    {
+ 	      if (isdigit (format[2]))
+ 		pp_helper_abort ("we handle only 1-9 in %%d$ as of now.\n", text);
+ 	      else
+ 		pp_helper_abort ("We expected '$' after %% and digit as in '%%1$'", text);
+ 	    }
+ 	}
+ 
+       /* assert:    
+ 	 format points at the % in   % [non-digit]
+ 	 || format points at the $ in   % [digit] $    */
+ 
+       switch (*++format)
+         {
+         case 'w':
+           wide = true;
+           ++format;
+           break;
+ 
+         case 'l':
+           do
+             ++precision;
+           while (*++format == 'l');
+           break;
+ 
+ 
+         default:
+           break;
+         }
+ 
+       /* We don't support precision behond that of "long long".  */
+       if (precision > 2)
+ 	pp_helper_abort ("We don't support precision behond that of \"long long\" ", text);
+ 
+       if (arg_index >= 10 || arg_index < 0)
+ 	abort ();
+ 
+       if (!has_seen_number && ! (*format == '%' || *format == 'm'))
+ 	{
+ 	  pp_helper_abort ("Use %n$c form specifier in ALL places except for % (percent sign) and %m.", text);
+ 	}
+ 
+       switch (*format)
+ 	{
+ 	case 'c':
+ 	  set_argument_type (arg_index, 'c', text);
+ 	  break;
+ 
+ 	case 'd':
+ 	case 'i':
+           if (wide)
+ 	    set_argument_type (arg_index, 'W' /* HOST_WIDE_INT*/, text);
+           else
+ 	    set_argument_type_with_precision (arg_index, 'd',  precision, text);
+ 	  break;
+ 
+ 	  /* TODO/FIXME long 'U', and long long 'U' can be
+ 	     used as in %lw %llw ?  */
+ 	case 'o':
+           if (wide)
+ 	    set_argument_type (arg_index, 'U' /*UNSIGNED_HOST_WIDE_INT*/, text) ;
+           else
+ 	    set_argument_type_with_precision (arg_index, 'o', precision, text);
+ 	  break;
+ 
+ 	case 's':
+ 	  set_argument_type (arg_index, 's', text); /* char *ptr */
+ 	  break;
+ 
+         case 'p':
+ 	  set_argument_type (arg_index, 'p', text); /* void *p */
+           break;
+ 
+ 	case 'u': /* now we must split this from 'x' to handle
+                      precision string processing. */
+           if (wide)
+ 	    set_argument_type (arg_index, 'U' /*UNSIGNED_HOST_WIDE_INT*/, text);
+           else
+ 	    set_argument_type_with_precision (arg_index,  'u', precision, text);
+ 	  break;
+ 
+ 
+ 	case 'x':
+           if (wide)
+ 	    set_argument_type (arg_index, 'U' /*UNSIGNED_HOST_WIDE_INT*/, text);
+           else
+ 	    set_argument_type_with_precision (arg_index,  'x', precision, text);
+ 	  break;
+ 
+ 	case 'm': /* error code: handles separately. */
+ 	  break;
+ 
+ 	case '%': /* % character */
+ 
+ 	  if (format[-1] != '%')
+ 	    {
+ 	      /* Before we catch this, we saw subtle Error as in:
+ 		argument at 1 not specified in format string. <<pointer=%3$p, char=%1$%c, integer=%4$d
+ 		
+ 		%1$%c is handled as if it were %%c and thus 
+ 		no information about argument was recorded. */
+ 
+ 	      fprintf (stderr, "cf. char=%%1$%%c is handled as if it were char %%%%c\n");
+ 	      fprintf (stderr, "That is, 1$ is ignored when the second %% is seen.\n");
+ 
+ 	      pp_helper_abort ("We should have a consecutive % s ", text);
+ 
+ 	    }
+ 
+ 	  break;
+ 
+ 	case 'J': 
+ 	  set_argument_type (arg_index, LOCATION_D_TYPE, text);
+ 	  break;
+ 
+         case 'H':
+ 	  set_argument_type (arg_index, LOCATION_T_TYPE, text);
+           break;
+ 
+ 	case '.':  /* Either  %.*s, orpositional paraeter as in
+ 		      %1$.*3$s ... 1st argument with the
+ 	              width given by the third argument. */
+ 	  {
+ 	    /* From SUS.
+ 	    The precision takes the form of a period ( '.' ) followed
+ 	    either by an asterisk ( '*' ), described below, or an
+ 	    optional decimal digit string, where a null digit string is
+ 	    treated as zero.  
+ 
+ 	    [...]  
+ 
+ 	    In format strings containing the "%n$" form of a
+ 	    conversion specification, a field width or precision may
+ 	    be indicated by the sequence "*m$", where m is a decimal
+ 	    integer in the range [1,{NL_ARGMAX}] giving the position
+ 	    in the argument list (after the format argument) of an
+ 	    integer argument containing the field width or
+ 	    precision,  */
+ 
+ 
+ 	    /* We handle no precision specifier except for string type
+ 	       as in `%.*s'.  
+ 	       pp_build_argument_array () is called when positional
+ 	       specifier of the form %n$ is used and 
+ 	       so the width also needs to be specified as *m$ ! */
+ 	    
+ 	    if (*++format != '*')
+ 	      pp_helper_abort ("We expected '*' after '.'", text);
+ 	    else 
+ 	      { /* we handle only %d$.*m$s : we have seen "*". */ 
+ 		int a;
+ 		char tmp[2];
+ 		int c;
+ 		c = *++format;
+ 		if (!isdigit (c))
+  		  pp_helper_abort ("We expected a digit after '*'", text);
+ 		tmp[0] = c; 
+ 		tmp[1] = '\0';
+ 		a = atoi (tmp);
+ 		if (a == 0)
+ 		  pp_helper_abort ("The digit that comes after % must be non-zero.\n",  text);
+ 		if (text->arg_max < a) 
+ 		  text->arg_max = a;
+ 		if (text->arg_max < arg_index)
+ 		  text->arg_max = arg_index;
+ 
+ 		set_argument_type (a, 'd', text); /* host int */
+ 		set_argument_type (arg_index, 's', text);
+ 	      }
+ 	  }
+ 	  break;
+ 
+ 	default:
+ 
+ 	  /* Let us see if custom decoder installed can understand the
+ 	   format character. Custom format_decoder examples are as
+ 	   follows.  
+ 	   c_tree_printer in c-objc-common.c 
+ 	   cp_print in  cp/error.c 
+ 	   default_tree_printer in toplev.c */
+ 
+ 
+ 	  /* Set up for calling custom format decoder 
+ 	   with GET_ARG_TYPE action. */
+ 
+ 	  text->index_num = arg_index;
+ 	  text->format_after_percent_or_dollar = format;
+ 
+ 	  /* Save previously seen format, if any, for checking
+ 	     incompatible double references later. */
+ 	  memcpy (text->arg_array[0].custom_format,
+ 		 text->arg_array[arg_index].custom_format,
+ 		 sizeof (text->arg_array[0].custom_format));
+ 
+ 	  if (arg_index <= 0 || arg_index > 9)
+ 	    pp_helper_abort ("arg_index out of range.", text);
+ 
+ 	  if (!pp_format_decoder (pp)
+               || !(*pp_format_decoder (pp)) (pp, text, GET_ARG_TYPE))
+ 	    {
+ 	      /* Ugh. Error. */
+ 
+ 	      /* Hmmm.  The front-end failed to install a format translator
+                  but called us with an unrecognized format.  Or, maybe, the
+                  translated string just contains an invalid format, or
+                  has formats in the wrong order.  Sorry.  */
+ 	      pp_helper_abort ("Unrecognized format.", text);
+ 	    }
+ 
+ 	  /* Check for double definition for custom-extended format
+ 	     argument */
+ 	  
+ 	  if (text->arg_array[0].custom_format[0] == '\0')
+ 	    ; 			/* OK. It was the first reference. */
+ 	  else 
+ 	    {
+ 	      /* If the previously used type information `matches' with
+ 		 the latest type information, then the double usage is OK.
+  		 Otherwise, it is an error.
+ 
+ 		 Now the semantics of `match' is a little tricky to get right.
+ 		 We probably need to ask the format decoder to decide
+ 		 the compatibility of two different format strings.
+ 		
+ 		 As an initial implementation, we simply use the strncmp ()
+ 		 against the two format strings. */
+ 
+ 	      if (strncmp (text->arg_array[0].custom_format, 
+ 			 text->arg_array[arg_index].custom_format, 
+ 			 sizeof (text->arg_array[0].custom_format)) == 0)
+ 		;		/* OK */
+ 	      else 
+ 		{
+ 		  fprintf (stderr, "Specifying incompatible types for argument (at %d)\n", arg_index);
+ 		  fprintf (stderr, "format:<<%s>>\n", text->arg_array[0].v.cptr);
+ 		  abort ();      	
+ 		}
+ 
+ 	    }
+ 
+ 	  /* adjust the format pointer by the number of
+ 	     bytes understood by the custom decoder. */
+ 	  if (text->bump_format > 1)
+ 	    format += (text->bump_format - 1);
+ 		 
+ 	}
+ 	  
+     }
+ 
+ 
+   /* Now let us scan the argumet and fetch the value as specified by the type. 
+     NOTE: we start at position 1. */
+ 
+   for (i = 1; i <= text->arg_max; i++)
+     {
+       switch (text->arg_array[i].typespec)
+ 	{
+ 	case UNDEFINED_FORMAT:
+ 	  if (text->arg_array[i].custom_format[0] == '\0')
+ 	    {
+ 	      fprintf (stderr, "argument at %d not specified in format string. <<%s>>\n", i, text->arg_array[0].v.cptr);
+ 	      abort ();
+ 	    }
+ 	  else 	  /* handling custom extended format character */
+ 	    {
+ 	      /* setup for COPY_ARG_VALUE. */
+ 	      text->index_num = i;
+ 	      text->format_after_percent_or_dollar 
+ 		= text->arg_array[i].custom_format;
+ 
+ 	      if (!pp_format_decoder (pp) 
+ 		  || !(*pp_format_decoder (pp)) (pp, text,
+ 						 COPY_ARG_VALUE))
+ 		{
+ 		  pp_helper_abort ("Unrecognized format.", text);
+ 		}
+ 	    }
+ 
+ 	  break;
+ 
+ 	case 's': text->arg_array[i].v.cptr = (char *) va_arg (*text->args_ptr, const char *);
+ 	  break;
+ 
+ 	case 'i':
+ 	case 'd': 
+ 	  switch (text->arg_array[i].precision)
+ 	    {
+ 	    case 0:
+ 	      text->arg_array[i].v.i = va_arg (*text->args_ptr, int);
+ 	      break;
+ 	    case 1:	    
+ 	      text->arg_array[i].v.l = va_arg (*text->args_ptr, long int);
+ 	      break;
+ 	    case 2:
+ 	      text->arg_array[i].v.ll = va_arg (*text->args_ptr, long  long int);
+ 	      break;
+ 		    
+ 	    default: abort ();
+ 	    }
+ 	  break;
+ 
+ 	case 'c': text->arg_array[i].v.i = va_arg (*text->args_ptr, int);
+ 	  break;
+ 
+ 
+ 	case 'W'   /* We use 'W' for HOST_WIDE_INT */ : 
+ 	  text->arg_array[i].v.hwi = va_arg (*text->args_ptr, HOST_WIDE_INT);
+ 	  break;
+ 
+ 	case 'U' : /* We use 'U' for UNSIGNED_HOST_WIDE_INT*/
+ 	  text->arg_array[i].v.uhwi = va_arg (*text->args_ptr, unsigned HOST_WIDE_INT);
+ 	  break;
+ 
+ 	case 'x':
+ 	case 'u': 
+ 	case 'o': 
+ 	  switch (text->arg_array[i].precision)
+ 	    {
+ 	    case 0:	
+ 	      text->arg_array[i].v.ui = va_arg (*text->args_ptr, unsigned);
+ 	      break;
+ 	    case 1:	    
+ 	      text->arg_array[i].v.ul = va_arg (*text->args_ptr, long unsigned);
+ 	      break;
+ 	    case 2:
+ 	      text->arg_array[i].v.ull = va_arg (*text->args_ptr, long  long unsigned);
+ 	      break;
+ 	    default: abort ();
+ 
+ 	    }
+ 	  break;
+ 
+ 	case 'p': 
+ 	  text->arg_array[i].v.ptr = va_arg (*text->args_ptr, void *);
+ 	  break;
+ 
+ 	case LOCATION_D_TYPE: 
+ 	  text->arg_array[i].v.ptr = va_arg (*text->args_ptr, tree);
+ 	  break;
+ 
+ 	case LOCATION_T_TYPE: 
+ 	  text->arg_array[i].v.ptr = va_arg (*text->args_ptr, location_t *);
+ 	  break;
+ 
+ 	default:
+ 	  pp_helper_abort ("Unknown output specifier during value copy.", text);
+ 	}
+ 
+     }
+ 
+   /* We have established the type/value of arguments when we return. */
+   
+   return;
+ }
+ 
  /* Format a message pointed to by TEXT.  The following format specifiers are
     recognized as being client independent:
     %d, %i: (signed) integer in base ten.
*************** pp_base_indent (pretty_printer *pp)
*** 176,194 ****
     %c: character.
     %s: string.
     %p: pointer.
!    %m: strerror(text->err_no) - does not consume a value from args_ptr.
     %%: `%'.
     %*.s: a substring the length of which is specified by an integer.
!    %H: location_t.  */
! void
  pp_base_format_text (pretty_printer *pp, text_info *text)
  {
    for (; *text->format_spec; ++text->format_spec)
      {
        int precision = 0;
        bool wide = false;
  
!       /* Ignore text.  */
        {
  	const char *p = text->format_spec;
  	while (*p && *p != '%')
--- 794,823 ----
     %c: character.
     %s: string.
     %p: pointer.
!    %m: strerror (text->err_no) - does not consume a value from args_ptr.
     %%: `%'.
     %*.s: a substring the length of which is specified by an integer.
!    %H: location_t.  
! 
!    Addition: positional parameter.
!    %[0-9]${d,i,u,o,x,...,H}  */
! 
! void 
  pp_base_format_text (pretty_printer *pp, text_info *text)
  {
+   int arg_index = -1; 		/* for positional format specifier. */
+   int has_processed_one = 0;	/* has processed specifiers. (counter) */
+   int use_pos_specifier = 0;	/* %d$c form positional specifier was found. */
+ 
+   text->original_format_spec = text->format_spec; /* save the original. */
+ 
    for (; *text->format_spec; ++text->format_spec)
      {
        int precision = 0;
        bool wide = false;
  
!       /* Misleading old comment "Ignore text."  */
!       /* Rather We output text as is (!) */
        {
  	const char *p = text->format_spec;
  	while (*p && *p != '%')
*************** pp_base_format_text (pretty_printer *pp,
*** 197,206 ****
          text->format_spec = p;
        }
  
        if (*text->format_spec == '\0')
  	break;
  
!       /* We got a '%'.  Parse precision modifiers, if any.  */
        switch (*++text->format_spec)
          {
          case 'w':
--- 826,883 ----
          text->format_spec = p;
        }
  
+       /* assert:    text->format_spec == '\0'
+ 	 || text->format_spec == '%' */
+ 
        if (*text->format_spec == '\0')
  	break;
  
!       /* We got a '%'.  Parse precision modifiers, if any.  
! 	 We also need to handle [0-9] as in %1$d */
! 
!       if (isdigit (text->format_spec[1]))
! 	{
! 	  if (text->format_spec[2] == '$')
! 	    {
! 	      char tmp[2];
! 
! 	      tmp[1] = '\0';
! 	      tmp[0] = (text->format_spec)[1];
! 	      arg_index = atoi (tmp);
! 
! 	      if (arg_index == 0)
! 		pp_helper_abort ("The digit that comes after % must be non-zero.\n", text);
! 
! 	      if (!use_pos_specifier)
! 		{
! 		  if (has_processed_one > 1)
! 		    pp_helper_abort ("We can't mix %d and %n$d form\n", text);
! 		  pp_build_argument_array (text->original_format_spec, pp, text);
! 		}
! 	      use_pos_specifier = 1;
! 
! 	      /* after the above call to pp_build_argument_array (),
! 		 we know the value (and type) for each argument. */
! 
! 	      text->format_spec += 2;
! 
! 	    }
! 	  else 
! 	    {
! 	      /* we have seen % and digit as in '%1', 
! 		 but it is not followed by '$' */
! 
! 	      if (isdigit ((text->format_spec)[2]))
! 		pp_helper_abort ("We handle only 1-9 in %d$ style positional parameter.\n", text);
! 	      else 
! 		pp_helper_abort ("We have seen a percent sign followed by a digit, but it is not followed by '$'\n", text);
! 	    }
! 	}
! 
!       /* assert:
! 	 text->format_spec points at % as in % [non-digit]
! 	 || text->format_spec points at $ as in % [digit] $    */
! 
        switch (*++text->format_spec)
          {
          case 'w':
*************** pp_base_format_text (pretty_printer *pp,
*** 219,319 ****
          }
        /* We don't support precision beyond that of "long long".  */
        if (precision > 2)
!         abort();
  
        switch (*text->format_spec)
  	{
  	case 'c':
! 	  pp_character (pp, va_arg (*text->args_ptr, int));
  	  break;
  
  	case 'd':
  	case 'i':
            if (wide)
!             pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT));
            else
!             pp_integer_with_precision
!               (pp, *text->args_ptr, precision, int, "d");
  	  break;
  
  	case 'o':
!           if (wide)
!             pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
!                        va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
!           else
!             pp_integer_with_precision
!               (pp, *text->args_ptr, precision, unsigned, "u");
  	  break;
  
  	case 's':
! 	  pp_string (pp, va_arg (*text->args_ptr, const char *));
  	  break;
  
          case 'p':
!           pp_pointer (pp, va_arg (*text->args_ptr, void *));
            break;
  
  	case 'u':
            if (wide)
!             pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
!                        va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
            else
!             pp_integer_with_precision
!               (pp, *text->args_ptr, precision, unsigned, "u");
  	  break;
  
  	case 'x':
            if (wide)
!             pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
!                        va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
            else
!             pp_integer_with_precision
!               (pp, *text->args_ptr, precision, unsigned, "x");
  	  break;
  
  	case 'm':
  	  pp_string (pp, xstrerror (text->err_no));
  	  break;
  
  	case '%':
  	  pp_character (pp, '%');
  	  break;
  
          case 'H':
            {
!             const location_t *locus = va_arg (*text->args_ptr, location_t *);
!             pp_string (pp, "file '");
!             pp_string (pp, locus->file);
!             pp_string (pp, "', line ");
!             pp_decimal_int (pp, locus->line);
            }
            break;
  
  	case '.':
! 	  {
! 	    int n;
! 	    const char *s;
! 	    /* We handle no precision specifier but `%.*s'.  */
! 	    if (*++text->format_spec != '*')
! 	      abort ();
! 	    else if (*++text->format_spec != 's')
! 	      abort ();
! 	    n = va_arg (*text->args_ptr, int);
! 	    s = va_arg (*text->args_ptr, const char *);
! 	    pp_append_text (pp, s, s + n);
! 	  }
  	  break;
  
  	default:
!           if (!pp_format_decoder (pp) || !(*pp_format_decoder (pp)) (pp, text))
  	    {
  	      /* Hmmm.  The client failed to install a format translator
                   but called us with an unrecognized format.  Or, maybe, the
                   translated string just contains an invalid format, or
                   has formats in the wrong order.  Sorry.  */
! 	      abort ();
  	    }
  	}
      }
  }
  
--- 896,1164 ----
          }
        /* We don't support precision beyond that of "long long".  */
        if (precision > 2)
!         pp_helper_abort ("Too many precision 'l' specfied.", text);
! 
!       if (use_pos_specifier
! 	  && (arg_index <= 0 || arg_index > 9))
! 	pp_helper_abort ("Argument index out of range.\n", text);
! 
  
        switch (*text->format_spec)
  	{
  	case 'c':
! 	  if (!use_pos_specifier) 
! 	    pp_character (pp, va_arg (*text->args_ptr, int)) ;
! 	  else
! 	    pp_character (pp, text->arg_array[arg_index].v.i);
  	  break;
  
  	case 'd':
  	case 'i':
            if (wide)
! 	    {
! 	      if (!use_pos_specifier)
! 		pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT)); 
! 	      else
! 		pp_wide_integer (pp, text->arg_array[arg_index].v.hwi);
! 	    }
            else
! 	    {
! 	      if (use_pos_specifier)
! 		pp_integer_with_precision_NEW (pp, arg_index, text);
! 	      else
! 		pp_integer_with_precision
! 		  (pp, *text->args_ptr, precision, int, "d");
! 	    }
  	  break;
  
  	case 'o':
! 	  if (!use_pos_specifier)
! 	    {
! 	      if (wide)
! 		pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
! 			   va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! 	      else
! 		pp_integer_with_precision
! 		  (pp, *text->args_ptr, precision, unsigned, "u");
! 	    }
! 	  else 
! 	    {
! 	      if (wide)
! 		pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
! 			   text->arg_array[arg_index].v.uhwi);
! 	      else
! 		pp_integer_with_precision_NEW
! 		  (pp, arg_index, text);
! 
! 	    }
  	  break;
  
  	case 's':
! 	  if (!use_pos_specifier)
! 	    pp_string (pp, va_arg (*text->args_ptr, const char *));
! 	  else
! 	    pp_string (pp, text->arg_array[arg_index].v.cptr);
  	  break;
  
          case 'p':
! 	  if (!use_pos_specifier)
! 	    pp_pointer (pp, va_arg (*text->args_ptr, void *));
! 	  else
! 	    pp_pointer (pp, text->arg_array[arg_index].v.ptr);
            break;
  
  	case 'u':
            if (wide)
! 	    {
! 	      if (!use_pos_specifier) 
! 		pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
! 			   va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! 	      else
! 		pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
! 			   text->arg_array[arg_index].v.uhwi);
! 	    }
            else
! 	    {
! 	      if (!use_pos_specifier)
! 		pp_integer_with_precision
! 		  (pp, *text->args_ptr, precision, unsigned, "u");
! 	      else
! 		pp_integer_with_precision_NEW
! 		  (pp, arg_index, text);
! 	    }
  	  break;
  
  	case 'x':
            if (wide)
! 	    {
! 	      if (!use_pos_specifier) 
! 		pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
! 			   va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
! 	      else
! 		pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
! 			   text->arg_array[arg_index].v.uhwi);
! 	    }
            else
! 	    {
! 	      if (!use_pos_specifier)
! 		pp_integer_with_precision
! 		  (pp, *text->args_ptr, precision, unsigned, "x");
! 	      else
! 		pp_integer_with_precision_NEW
! 		  (pp, arg_index, text);
! 	    }
  	  break;
  
  	case 'm':
  	  pp_string (pp, xstrerror (text->err_no));
+ 	  has_processed_one --;	/* Adjust. we don't want to count this.   */
  	  break;
  
  	case '%':
  	  pp_character (pp, '%');
+ 	  has_processed_one --;	/* Adjust. we don't want to count this.   */
  	  break;
  
+ 	  /* In the following, the reference to %H should be taken to
+ 	     include the reference to "%J" as well. */
+ 	case 'J':
          case 'H':
            {
!             const location_t *locus;
! 	    static location_t l_locus;
! 
! 	    if (*text->format_spec == 'H')
! 	      {
! 		if (!use_pos_specifier)
! 		  locus = va_arg (*text->args_ptr, location_t *);
! 		else
! 		  locus = (location_t *) text->arg_array[arg_index].v.ptr;
! 	      }
! 	    else if (*text->format_spec == 'J')
! 	      {
! 		tree np;
! 		if (!use_pos_specifier)
! 		  {
! 		    np =  va_arg (*text->args_ptr, tree);
! 		    l_locus = diagnostic_J_tree2locus (np);
! 		    locus = &l_locus;
! 		  }
! 		else
! 		  {
! 		    np = (tree) text->arg_array[arg_index].v.ptr;
! 		    l_locus = diagnostic_J_tree2locus (np);
! 		    locus = &l_locus;
! 		  }
! 	      }
! 	    else
! 	      abort ();
! 	    /* We dont format %H if it is the first specifier. 
! 	       This is necessary to work with text_specifies_location ()
! 	       in diagnostic.c */
! 	    if (has_processed_one <= 0)
! 	      ; 
! 	    else
! 	      {
! 		pp_string (pp, "file '");
! 		pp_string (pp, locus->file);
! 		pp_string (pp, "', line ");
! 		pp_decimal_int (pp, locus->line);
! 	      }
            }
            break;
  
  	case '.':
! 
! 	  if (!use_pos_specifier)
! 	    {
! 	      int n;
! 	      const char *s;
! 	      /* We handle no precision specifier except for string type
! 		 as in `%.*s'.  
! 	         E.g.,  warning ("String = %.*s, extra=%d\n", 10, str, i);  */
! 
! 	      if (*++text->format_spec != '*')
! 		pp_helper_abort ("We expected '*' after '.'", text);
! 	      else if (*++text->format_spec != 's')
! 		pp_helper_abort ("We expected 's' after '*'", text);
! 	      n = va_arg (*text->args_ptr, int);
! 	      if (n <= 0)	/* we may want to check this. */
! 		{
! 		  fprintf (stderr, "diagnostic: string width %d given is not positive.\n", n);
! 		  n = 0;
! 		}
! 	      s = va_arg (*text->args_ptr, const char *);
! 	      pp_append_text (pp, s, s + n);
! 	    }
! 	  else
! 	    {
! 	      /* we handle %d$.*m$s : we have seen "period". */ 
! 
! 	      int a;
! 	      char tmp[2];
! 	      int c;
! 	      int n;
! 	      char *s;
! 
! 	      if (*++text->format_spec != '*')
! 		pp_helper_abort ("We expected '*' afer '.'", text);
! 
! 	      c = *++text->format_spec;
! 	      if (!isdigit (c))
! 		pp_helper_abort ("We expected a digit after '*'", text);
! 	      tmp[0] = c; tmp[1] = '\0';
! 	      a = atoi (tmp);
! 	      c = *++text->format_spec;
! 	      if (c != '$')
! 		pp_helper_abort ("We expected a '$' after a digit", text);
! 	      c = *++text->format_spec;
! 	      if (c != 's')
! 		pp_helper_abort ("We expected an 's' after '$'", text);
! 	      n = text->arg_array[a].v.i;
! 	      if (n <= 0)
! 		{
! 		  fprintf (stderr, "diagnostic: string width %d at %d is not positive.\n", n, a);
! 		  n = 0;
! 		}
! 	      s = text->arg_array[arg_index].v.cptr;
! 	      pp_append_text (pp, s, s + n);
! 
! 	    }
  	  break;
  
  	default:
! 
! 	  text->index_num = arg_index;
! 
! 	  /* We decided to use text->format_spec even
! 	     in the case of PRINT_ARG_VALUE case (positional
! 	     parameter support), but still set this just in case. */
! 	  text->format_after_percent_or_dollar = text->format_spec;
! 	  text->bump_format = 0;
! 
! 	  if (use_pos_specifier 
! 	      && (arg_index <= 0 || arg_index > 9))
! 	    pp_helper_abort ("arg_index out of range.", text);
! 
!           if (!pp_format_decoder (pp) 
! 	      || !(*pp_format_decoder (pp)) (pp, text,
! 					     use_pos_specifier ?
! 					     PRINT_ARG_VALUE :
! 					     PRINT_ARG_VALUE_AS_BEFORE))
  	    {
  	      /* Hmmm.  The client failed to install a format translator
                   but called us with an unrecognized format.  Or, maybe, the
                   translated string just contains an invalid format, or
                   has formats in the wrong order.  Sorry.  */
! 	      pp_helper_abort ("unrecognized format.", text);
  	    }
+ 
+ 	  /* adjust the pointer by the bytes understood by the
+ 	     custom format decoder. */
+ 	  if (use_pos_specifier && text->bump_format > 1)
+ 	    text->format_spec += (text->bump_format - 1);
  	}
+       has_processed_one ++;
      }
  }
  
Index: gcc/pretty-print.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.h,v
retrieving revision 1.10
diff -p -3 -c -r1.10 pretty-print.h
*** gcc/pretty-print.h	25 Aug 2003 19:10:48 -0000	1.10
--- gcc/pretty-print.h	19 Nov 2003 10:28:35 -0000
*************** Software Foundation, 59 Temple Place - S
*** 25,30 ****
--- 25,78 ----
  #include "obstack.h"
  #include "input.h"
  
+ /*  argtype_t: The type of variable argument arg_array[] (part of
+     text_info) to store type and the value.  This is to support
+     positional format specifiers in the form of %1$s, %2$d %3$d, etc.
+ 
+     Note that we use the arg_array[0].v.cptr to store the format
+     string.  The whole array is set to zero before each construction. */
+ 
+ typedef struct 
+ {
+   int typespec ;		/* type 'd', etc. */
+   int precision ;		/* to handle %d, %ld, %lld */
+   char format [5];		/* %lld at the longest. */
+   char custom_format[4]; /* CUSTOM decoder format. May contain #+, etc. */
+   union {			/* holding the value of argument */
+     int i;
+     unsigned int ui;
+     short s;
+     unsigned short us;
+     char c;
+     unsigned char uc;
+     long l;
+     unsigned long ul;
+     long long ll;
+     unsigned long long ull;
+     HOST_WIDE_INT hwi;
+     unsigned HOST_WIDE_INT uhwi;
+     void *ptr;			
+     char *cptr;
+     int  *iptr;
+     long *lptr;
+     long long *llptr;
+     location_t l_ptr;
+   } v;
+ }  argtype_t;
+ 
+ 
+ /* arg_decode_action: The type of an action to custom defined format
+    decoder: to return information or perform copy/print action for
+    positional parameter processing. */
+ typedef enum 
+ {
+   GET_ARG_TYPE = 2,
+   COPY_ARG_VALUE = 3,
+   PRINT_ARG_VALUE = 4,
+   PRINT_ARG_VALUE_AS_BEFORE = 5 /* as before: no positional support */
+ } arg_decode_action;
+ 
+ 
  /* The type of a text to be formatted according a format specification
     along with a list of things.  */
  typedef struct
*************** typedef struct
*** 32,37 ****
--- 80,107 ----
    const char *format_spec;
    va_list *args_ptr;
    int err_no;  /* for %m */
+ 
+   /* Items below are for positional argument support */
+ 
+   /* once set, this remains unmodified.  */
+   const char *original_format_spec;
+ 
+   /* arg_array[0].v.cptr holds the original format pointer.  Argument
+    is counted from position no. 1. */
+   argtype_t arg_array[10 + 1];	
+ 
+   /* argument count. */
+   int arg_max;
+ 
+   /* used for GET_ARG_TYPE, COPY_ARG_VALUE */
+   const char *format_after_percent_or_dollar;   
+ 
+   /* argument index for custom decoder. */
+   int index_num;		
+ 
+   /* used in GET_ARG_TYPE: returns how many bytes of format chars will be
+      eaten by custom decoder. */
+   int bump_format ;		
  } text_info;
  
  /* How often diagnostics are prefixed by their locations:
*************** typedef enum
*** 76,82 ****
     A client-supplied formatter returns true if everything goes well,
     otherwise it returns false.  */
  typedef struct pretty_print_info pretty_printer;
! typedef bool (*printer_fn) (pretty_printer *, text_info *);
  
  /* Client supplied function used to decode formats.  */
  #define pp_format_decoder(PP) pp_base (PP)->format_decoder
--- 146,152 ----
     A client-supplied formatter returns true if everything goes well,
     otherwise it returns false.  */
  typedef struct pretty_print_info pretty_printer;
! typedef bool (*printer_fn) (pretty_printer *, text_info *, arg_decode_action);
  
  /* Client supplied function used to decode formats.  */
  #define pp_format_decoder(PP) pp_base (PP)->format_decoder
*************** extern void pp_base_indent (pretty_print
*** 257,261 ****
--- 327,335 ----
  extern void pp_base_newline (pretty_printer *);
  extern void pp_base_character (pretty_printer *, int);
  extern void pp_base_string (pretty_printer *, const char *);
+ 
+ /* in diagnostic.c */
+ extern location_t diagnostic_J_tree2locus (tree t);
+ 
  
  #endif /* GCC_PRETTY_PRINT_H */
Index: gcc/toplev.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.844
diff -p -3 -c -r1.844 toplev.c
*** gcc/toplev.c	13 Nov 2003 19:40:13 -0000	1.844
--- gcc/toplev.c	19 Nov 2003 10:28:40 -0000
*************** crash_signal (int signo)
*** 1372,1378 ****
  }
  
  /* Arrange to dump core on error.  (The regular error message is still
!    printed first, except in the case of abort().)  */
  
  static void
  setup_core_dumping (void)
--- 1372,1378 ----
  }
  
  /* Arrange to dump core on error.  (The regular error message is still
!    printed first, except in the case of abort ().)  */
  
  static void
  setup_core_dumping (void)
*************** default_pch_valid_p (const void *data_p,
*** 4222,4246 ****
  
  /* Default tree printer.   Handles declarations only.  */
  static bool
! default_tree_printer (pretty_printer * pp, text_info *text)
  {
!   switch (*text->format_spec)
      {
!     case 'D':
!     case 'F':
!     case 'T':
!       {
!         tree t = va_arg (*text->args_ptr, tree);
!         const char *n = DECL_NAME (t)
!           ? (*lang_hooks.decl_printable_name) (t, 2)
!           : "<anonymous>";
!         pp_string (pp, n);
!       }
!       return true;
  
-     default:
-       return false;
      }
  }
  
  /* Initialization of the front end environment, before command line
--- 4222,4302 ----
  
  /* Default tree printer.   Handles declarations only.  */
  static bool
! default_tree_printer (pretty_printer * pp, text_info *text, arg_decode_action a)
  {
! 
!   /* We share the code for printing between
!      positional and non-positional specifier cases */
! 
!   if (a == PRINT_ARG_VALUE_AS_BEFORE  
!      || a == PRINT_ARG_VALUE)	
      {
!       tree t;
!       if (a == PRINT_ARG_VALUE)
! 	t = (tree) text->arg_array[text->index_num].v.ptr ;
!       else
! 	t = va_arg (*text->args_ptr, tree);
! 
!       switch (*text->format_spec)
! 	{
! 	case 'D':
! 	case 'F':
! 	case 'T':
! 	  {
! 	    const char *n = DECL_NAME (t)
! 	      ? (*lang_hooks.decl_printable_name) (t, 2)
! 	      : "<anonymous>";
! 	    pp_string (pp, n);
! 	  }
! 	  return true;
! 
! 	default:
! 	  return false;
! 	}
!     }
!   else if (a == GET_ARG_TYPE)
!     {
!       text->bump_format = 0;
!       
!       switch (*text->format_after_percent_or_dollar)
! 	{
! 	case 'D':
! 	case 'F':
! 	case 'T':
! 	  {
! 	    text->bump_format = 1;
! 	    text->arg_array[text->index_num].custom_format[0]
! 	      = *text->format_after_percent_or_dollar;
! 	  }
! 	  return true;
! 	default:
! 	  return false;
! 	}
!     }
!   else if (a == COPY_ARG_VALUE)
!     {
!       text->bump_format = 0;
!       
!       switch (*text->format_after_percent_or_dollar)
! 	{
! 	case 'D':
! 	case 'F':
! 	case 'T':
! 	  {
! 	    text->bump_format = 1;
! 	    text->arg_array[text->index_num].v.ptr 
! 	      = (void *) va_arg (*text->args_ptr, tree);
! 	  }
! 	  return true;
! 	default:
! 	  return false;
! 	}
! 
  
      }
+   else
+     abort ();
+ 
  }
  
  /* Initialization of the front end environment, before command line
*************** toplev_main (unsigned int argc, const ch
*** 4723,4728 ****
--- 4779,4935 ----
  
    /* Initialization of GCC's environment, and diagnostics.  */
    general_init (argv[0]);
+ 
+ #if 0
+  {
+    /* This is a test code for checking the
+       positional parameter support in diagnostic routines. 
+       I wonder where we should keep this code. 
+       As I explained in my post to gcc-patches , there is no easy way to
+       test the positional parameter support without
+       using an existing program and inserting this test code
+       somewhere. */
+ 
+ #include <errno.h>
+    int i;
+    long t;
+    long long ill;
+    long long xll;
+    extern void warning (const char *msgid, ...);
+ 
+    static char str [] = "123456789A123456789A123456789A";
+ 
+    i = 1234;
+    t = 0x0FFFFFFl;
+    ill = (long long) t * t;
+    xll = 0x0123456789ABCDEFull;
+ 
+ 
+    warning ("Test diagnostic.\n");
+ 
+    warning ("integer=%d, pointer=%p, char=%c", i, &t, 'c');
+ 
+    warning ("\nPointer value print\n");
+ 
+    fprintf (stderr, "pointer=%p\n",  (void *) &t);
+    warning ("1st: pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+    warning ("2nd: pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+    warning ("3rd: pointer=%1$p, char=%3$c, integer=%2$d", &t, i, 'c');
+    warning ("pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+ 
+ 
+    warning ("\nOne argument");
+    warning ("integer=%1$d", i);
+    warning ("char   =%1$c", 'c');
+    warning ("pointer=%1$p", &t);
+    warning ("long=%1$ld", t);
+    warning ("long=%1$lx", t);
+ 
+ 
+    /* long */
+    warning ("long=(x) %1$lx", t);
+    fprintf (stderr, " ordinary printf:      %lx\n", t);
+    warning ("long=(o) %1$lo", t);
+    fprintf (stderr, " ordinary printf:      %lo\n", t);
+    warning ("long=(d) %1$ld", t);
+    fprintf (stderr, " ordinary printf:      %ld\n", t);
+ 
+ 
+    /* long long */
+ 
+    warning ("long long=(d) %1$lld", ill);
+    fprintf (stderr, "ordinary printf():          %lld\n", ill);
+ 
+ 
+    warning ("long long=(x) %1$llx", xll);
+    fprintf (stderr, " ordinary printf:           %llx\n", xll);
+ 
+ 
+    warning ("long long=(o) %1$llo", xll);
+    fprintf (stderr, " ordinary printf:           %llo\n", xll);
+ 
+ 
+    warning ("long long=(d) %1$lld", xll);
+    fprintf (stderr, " ordinary printf:           %lld\n", xll);
+ 
+    /* wide ? */
+ 
+    warning ("Wide\n");
+    warning ("wide=(wd) %1$wd", t);
+    warning ("wide=(wx) %1$wx", t);
+    warning ("wide=(wo) %1$wo", t);
+ 
+    warning ("\nTwo arguments");
+    warning ("integer=%1$d, char=%2$c", i, 'c');
+    warning ("char   =%2$c, integer=%1$d", i, 'c');
+ 
+    warning ("\nThree Arguments\n");
+    warning ("char=%3$c, integer=%1$d, pointer=%2$p", i, &t, 'c');
+ 
+    warning ("char=%c, integer=%d, pointer=%p", 'c', i, &t);
+    warning ("pointer=%3$p, char=%1$c, integer=%2$d", 'c', i, &t);
+    warning ("char=%1$c, integer=%2$d, pointer=%3$p", 'c', i, &t);
+ 
+    warning ("integer=%d, long=%ld, long long=%lld", i, t, ill);
+    warning ("long=%2$ld, long long=%3$lld, int=%1$d", i, t, ill);
+    warning ("long long=%3$lld, int=%1$d, long=%2$ld", i, t, ill);
+ 
+    warning ("pointer=%2$p, char=%3$c, integer=%1$d", i, &t, 'c');
+ 
+    warning ("long long=%lld, long=%ld, int=%d", ill, t, i);
+    warning ("long=%2$ld, int=%3$d, long long=%1$lld", ill, t, i);
+    warning ("int=%3$d, long long=%1$lld, long=%2$ld", ill, t, i);
+ 
+ 
+    /* String and its width*/
+    warning ("\nString");
+ 
+    warning ("String =%s", str);
+    warning ("String =%1$s", str);  
+    fprintf (stderr, "ordinary fprintf():   %s\n", str);
+ 
+    warning ("String = %.*s, extra=%d",           10, str, i);
+    warning ("String = %3$.*1$s, extra=%2$d",     10, i, str);
+    warning ("String = %2$.*1$s, extra=%3$d",     10, str, i);
+    fprintf (stderr, "ordinary fprintf():    %.*s\n", 10, str);
+ 
+    /* modified test from a post by Jonathan Lennox */
+    {
+      const char *str = "Hello!";
+      warning ("String = %2$.*1$s, extra=%3$d",     10, str, i);
+      warning ("\n%.*s\n%.*s\n%.*s\n%.*s\n%.*s\n%.*s",
+ 	     1, str, 2, str,  3, str, 4, str, 5, str, 6, str);
+      warning ("\n%1$.*2$s\n%1$.*3$s\n%1$.*4$s\n%1$.*5$s\n%1$.*6$s\n%1$.*7$s",
+ 	     str, 1, 2, 3, 4, 5, 6);
+    }
+ 
+ 
+    /* %% and %m */
+ 
+    warning ("This is one %% (percent sign)  and error code message: could be random <<%m>>");
+ 
+ 
+    errno = EPIPE;
+    warning ("int=%1$d, long long=%2$lld,  %% (percent sign) and error message should be for EPIPE <<%m>>", i, ill);
+ 
+ 
+    /* should abort: we can't mix two forms. */
+    warning ("Should abort. We can't mix two forms: integer=%d, pointer=%p, char=%3$c\n", i, &t, 'c');
+ 
+    /* should abort because %3$whatever is missing. */
+    warning ("Should abort: char=%4$p, integer=%1$d, pointer=%2$p\n", i, &t, 'c');
+ 
+    /* should abort: we can't mix two forms */
+    warning ("Should abort: integer=%1$d, pointer=%2$p, char=%c\n", i, &t, 'c');
+ 
+    /* should abort: 0 after %. */
+    warning ("Should abort: integer=%0$d, pointer=%2$p, char=%3c\n", i, &t, 'c'); 
+ 
+  }
+ 
+ #endif 
+ 
+ 
  
    /* Parse the options and do minimal processing; basically just
       enough to default flags appropriately.  */
Index: gcc/cp/error.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.239
diff -p -3 -c -r1.239 error.c
*** gcc/cp/error.c	8 Oct 2003 00:42:55 -0000	1.239
--- gcc/cp/error.c	19 Nov 2003 10:28:45 -0000
*************** static void cp_diagnostic_starter (diagn
*** 97,103 ****
  static void cp_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
  static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
  
! static bool cp_printer (pretty_printer *, text_info *);
  static void pp_non_consecutive_character (cxx_pretty_printer *, int);
  static tree locate_error (const char *, va_list);
  static location_t location_of (tree);
--- 97,103 ----
  static void cp_diagnostic_finalizer (diagnostic_context *, diagnostic_info *);
  static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
  
! static bool cp_printer (pretty_printer *, text_info *, arg_decode_action);
  static void pp_non_consecutive_character (cxx_pretty_printer *, int);
  static tree locate_error (const char *, va_list);
  static location_t location_of (tree);
*************** dump_expr (tree t, int flags)
*** 1550,1556 ****
  	}
        else
  	{
! 	  if (TREE_OPERAND (t,0) != NULL_TREE
  	      && TREE_TYPE (TREE_OPERAND (t, 0))
  	      && NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
  	    dump_expr (TREE_OPERAND (t, 0), flags);
--- 1550,1556 ----
  	}
        else
  	{
! 	  if (TREE_OPERAND (t, 0) != NULL_TREE
  	      && TREE_TYPE (TREE_OPERAND (t, 0))
  	      && NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
  	    dump_expr (TREE_OPERAND (t, 0), flags);
*************** print_instantiation_context (void)
*** 2268,2276 ****
     %P   function parameter whose position is indicated by an integer.
     %Q	assignment operator.
     %T   type.
!    %V   cv-qualifier.  */
  static bool
! cp_printer (pretty_printer *pp, text_info *text)
  {
    int verbose = 0;
    const char *result;
--- 2268,2278 ----
     %P   function parameter whose position is indicated by an integer.
     %Q	assignment operator.
     %T   type.
!    %V   cv-qualifier.  
! 
!    Modified to support positional format parameter. */
  static bool
! cp_printer (pretty_printer *pp, text_info *text, arg_decode_action a)
  {
    int verbose = 0;
    const char *result;
*************** cp_printer (pretty_printer *pp, text_inf
*** 2279,2316 ****
  #define next_lang    va_arg (*text->args_ptr, enum languages)
  #define next_int     va_arg (*text->args_ptr, int)
  
!   if (*text->format_spec == '+')
!     ++text->format_spec;
!   if (*text->format_spec == '#')
!     {
!       verbose = 1;
!       ++text->format_spec;
!     }
! 
!   switch (*text->format_spec)
!     {
!     case 'A': result = args_to_string (next_tree, verbose);	break;
!     case 'C': result = code_to_string (next_tcode);	        break;
!     case 'D': result = decl_to_string (next_tree, verbose);	break;
!     case 'E': result = expr_to_string (next_tree);      	break;
!     case 'F': result = fndecl_to_string (next_tree, verbose);	break;
!     case 'L': result = language_to_string (next_lang);          break;
!     case 'O': result = op_to_string (next_tcode);       	break;
!     case 'P': result = parm_to_string (next_int);	        break;
!     case 'Q': result = assop_to_string (next_tcode);	        break;
!     case 'T': result = type_to_string (next_tree, verbose);	break;
!     case 'V': result = cv_to_string (next_tree, verbose);	break;
   
!     default:
!       return false;
      }
  
-   pp_base_string (pp, result);
-   return true;
  #undef next_tree
  #undef next_tcode
  #undef next_lang
  #undef next_int
  }
  
  static void
--- 2281,2424 ----
  #define next_lang    va_arg (*text->args_ptr, enum languages)
  #define next_int     va_arg (*text->args_ptr, int)
  
! #define pos_next_tree    ((tree) text->arg_array[i].v.ptr)
! #define pos_next_tcode   ((enum tree_code) text->arg_array[i].v.i)
! #define pos_next_lang    ((enum languages) text->arg_array[i].v.i)
! #define pos_next_int     (text->arg_array[i].v.i)
! 
! 
! #define x_next_tree    ((a == PRINT_ARG_VALUE) ? pos_next_tree  : next_tree)
! #define x_next_tcode   ((a == PRINT_ARG_VALUE) ? pos_next_tcode : next_tcode)
! #define x_next_lang    ((a == PRINT_ARG_VALUE) ? pos_next_lang  : next_lang)
! #define x_next_int     ((a == PRINT_ARG_VALUE) ? pos_next_int   : next_int)
! 
! 
!   /* We share the code for printing between
!      positional and non-positional specifier cases */
! 
!   if (a == PRINT_ARG_VALUE_AS_BEFORE 
!      || a == PRINT_ARG_VALUE)
!     {
!       int i = text->index_num;
! 
!       text->bump_format = 0;
!       
!       if (*text->format_spec == '+')
! 	++text->format_spec;
!       if (*text->format_spec == '#')
! 	{
! 	  verbose = 1;
! 	  ++text->format_spec;
! 	}
! 
!       switch (*text->format_spec)
! 	{
! 	case 'A': result = args_to_string (x_next_tree, verbose);	break;
! 	case 'C': result = code_to_string (x_next_tcode);	        break;
! 	case 'D': result = decl_to_string (x_next_tree, verbose);	break;
! 	case 'E': result = expr_to_string (x_next_tree);      	break;
! 	case 'F': result = fndecl_to_string (x_next_tree, verbose);	break;
! 	case 'L': result = language_to_string (x_next_lang);          break;
! 	case 'O': result = op_to_string (x_next_tcode);       	break;
! 	case 'P': result = parm_to_string (x_next_int);	        break;
! 	case 'Q': result = assop_to_string (x_next_tcode);	        break;
! 	case 'T': result = type_to_string (x_next_tree, verbose);	break;
! 	case 'V': result = cv_to_string (x_next_tree, verbose);	break;
   
! 	default:
! 	  return false;
! 	}
! 
!       pp_base_string (pp, result);
!       return true;
!     }
!   else if (a == GET_ARG_TYPE)
!     {
!       text->bump_format = 0;
!       if (*text->format_after_percent_or_dollar == '+')
! 	text->arg_array[text->index_num].custom_format[text->bump_format++] =
! 	  *text->format_after_percent_or_dollar++;
!       if (*text->format_spec == '#')
! 	{
! 	  verbose = 1;
! 	  text->arg_array[text->index_num].custom_format[text->bump_format++] =
! 	    *text->format_after_percent_or_dollar++;
! 	}
! 
!       switch (*text->format_after_percent_or_dollar)
! 	{
! 	case 'A': 
! 	case 'C': 
! 	case 'D': 
! 	case 'E': 
! 	case 'F': 
! 	case 'L': 
! 	case 'O': 
! 	case 'P': 
! 	case 'Q': 
! 	case 'T': 
! 	case 'V': 
! 	  text->arg_array[text->index_num].custom_format[text->bump_format++] =
! 	    *text->format_after_percent_or_dollar;
! 	  break;
! 
! 	default:
! 	  return false;
! 	}
!       return true;
!     }
!   else if (a == COPY_ARG_VALUE)
!     {
!       int i = text->index_num;
! 
!       text->bump_format = 0;
! 
!       if (*text->format_after_percent_or_dollar == '+')
! 	++text->format_after_percent_or_dollar,  ++text->bump_format;
!       if (*text->format_spec == '#')
! 	{
! 	  verbose = 1;
! 	  ++text->format_after_percent_or_dollar;
! 	  ++text->bump_format;
! 	}
! 
!       switch (*text->format_after_percent_or_dollar)
! 	{
! 	case 'A': text->arg_array[i].v.ptr = (void *) next_tree ; break;
! 	case 'C': text->arg_array[i].v.ptr = (void *) next_tcode;        break;
! 	case 'D': text->arg_array[i].v.ptr = (void *) next_tree;	break;
! 	case 'E': text->arg_array[i].v.ptr = (void *) next_tree;      	break;
! 	case 'F': text->arg_array[i].v.ptr = (void *) next_tree;	break;
! 	case 'L': text->arg_array[i].v.i = next_lang;          break;
! 	case 'O': text->arg_array[i].v.i = next_tcode;       	break;
! 	case 'P': text->arg_array[i].v.i = next_int;	        break;
! 	case 'Q': text->arg_array[i].v.i = next_tcode;	        break;
! 	case 'T': text->arg_array[i].v.ptr = next_tree; 	break;
! 	case 'V': text->arg_array[i].v.ptr = next_tree;	break;
!  
! 	default:
! 	  return false;
! 	}
!       return true;
      }
+   else
+     abort ();
  
  #undef next_tree
  #undef next_tcode
  #undef next_lang
  #undef next_int
+ 
+ #undef pos_next_tree
+ #undef pos_next_tcode
+ #undef pos_next_lang
+ #undef pos_next_int
+ 
+ #undef x_next_tree
+ #undef x_next_tcode
+ #undef x_next_lang
+ #undef x_next_int
+ 
  }
  
  static void
*************** pp_non_consecutive_character (cxx_pretty
*** 2324,2330 ****
  }
  
  /* These are temporary wrapper functions which handle the historic
!    behavior of cp_*_at.  */
  
  static tree
  locate_error (const char *msgid, va_list ap)
--- 2432,2442 ----
  }
  
  /* These are temporary wrapper functions which handle the historic
!    behavior of cp_*_at.  
! 
!   We don't have to worry about positional format specifier
!   in this function since this receives msgid, i.e., the original format string
!   before translation that should NOT contain such positional specifiers. */
  
  static tree
  locate_error (const char *msgid, va_list ap)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]