Redux. Support for positional format parameter in diagnostic output

ishikawa@duron.erephon ishikawa@duron.erephon
Fri Sep 19 19:26:00 GMT 2003


(This is a recreation of the patch produced in August against
the latest CVS tree. Sorry I was away for late summer holidays and
other engagements for a couple of weeks and now have a time to
work on GCC again.)

[Below, the comment is repeated with the slight editing
for the latecomer to see what
is positional format specifier support, etc..]

CAVEAT: For the past few days, virus infected PCs (or mailiciously
controlled PCs) have sent me tons of virus-infected e-mails each of
which about 150KB.  If I receive a couple of hundred such e-mails, my
slow internet connection takes a long time before I can download
essential e-mail correspondents from my ISP mail server.  So the
postings to gcc-patch mailing list, which is archived at
http://gcc.gnu.org is actually easier for me to read the responses. I
hope not everyone is suffering from this latest surge of virus spams.

Here the main text goes.

---

This is the latest cut for the patch to support positional format
specifiers for study/review.

Joseph Myers wrote:

|Please take care to follow the GNU Coding Standards.  I'll point out some
|of the issues below, but only point out a particular issue once although
|it may appear elsewhere in the code as well; for each issue you should go
|through the code and fix it everywhere it occurs.

I followed Joseph Myers's comment and
cleaned up the patch.
 
There are a couple of questions and a comment, though.

      ... my question about potential EBICDIC message file is
      ... removed.

|And remember the
|spaces before the open parenthesis, and after the comma.

In re-creating this patch, I noticed a few other places
where the "space before the openparenthesis" is not
followed in existing code, but decided not to touch them.
A few were modified, though, during my editing to
follow this rule.


|For this sort of consistency check, I think you should simply use
|internal_error () rather than attempting to continue.  And remember the
|spaces before the open parenthesis, and after the comma.

For general error cases, I agree that internal_error() is
probably better. 

But I decided to keep fprintf(stderr, ...) in my code, in a few places,
since the problems are detected INSIDE A ROUTINE CALLED BY
ERROR/DIAGNOSTIC ROUTINE. Using  internal_error() probably
won't print anything useful and decided to die immediately.

E.g., (this is a real example taken from a test run during debugging.)
   Internal compiler error: Error reporting routines re-entered.
   Please submit a full bug report,

At least, with my code using fprintf (stderr, ...) we get
useful output for debugging.

[] RE: pp_base_string () vs pp_string ().

Now, another question:

While re-creating the patch, I noticed that
a call to pp_string () in cp_printer() in  cp/error.c
is now modified to pp_base_string ().

I suppose this is intentional.

However, if so, should we not modify the call to pp_string() in

 - default_printer () in toplev.c,
 - c_tree_printer () in c-objc-common.c 

to pp_base_string() as well?


BTW, I wrote earlier:

>I will be happy to work on an external PO file checker once the
>positional parameter support in mainline CVS. (I have already worked
>on a premiliminary modification to GNU gettext msgfmt since this
>support positional parameter to begin with.)

After I wrote to the translation project and gnu-gettext-bug address
with my kludgy patch,
I heard from Bruno Haible. After reading the
problems my e-mail explained, he has modified gettext suite.
(So I don't need to work on external PO file checker!)

He has written a special handler for the format specifiers used by
GCC's internal diagnostic routine in version 3.3 (which is
the publicly released working version) and intends to
incoporate it to the next release of gettext.  He noted that the
format character set is not quite an "extension" of the standard C
printf format character set and so devised a new format recognition
routine solely for GCC internal diagnostic formating routine.

With his patch, the PO file can be checked in a more
satisfactory manner for GCC messages in the future.  (We need to
update gettext() when GCC 3.4 appears, though since there seem
to have been a few additions to the format specifier
characters in the latest CVS in comparison 
with the GCC 3.3. Such a modification should not be hard.)

The attached patch for positional parameter handling
can probably still use some clean up, but the
final cleanup can wait until the basic scheme is studied/reviewed and
approved.

Again, comments/feedback welcome.

---

I attach the edited summary document first (this part
is again slightly edited to reflect the latest patch
and Bruno's patch and is included here to make this
post as self-contained as possible.)
and then the ChangeLog and patch, etc..

============================================================
Support for %d$c postional format specifier in pp_text_format()  in 
pretty-print.c 
(formerly  output_format() in diagnostic.c)
============================================================



[1] Background:

In the discussion below, 
%d$c here stand for positional specifier such as %1$d, and %2$p.
This is specified in SUS printf format specifier spec.

http://www.opengroup.org/onlinepubs/007904975/functions/printf.html

In gcc mailing list, Zack Weinberg suggested the implementation of
this feature in diagnostic output routines, and I have hacked
pretty-print.c (formely diagnostic.c) to support this.

[2] Rationale:

Why is such positional parameter desirable?  

This is mainly for helping I18N/L10N translation work.  There are
cases where the English diagnostic messages that refer to parameters
in certain order may not translate well (or only in unnatural fashion)
in other languages.

Say, original English format string refers to int value, i, character
value, c, and still another integer value, i2.

warning ("formatstring with %d, %c, %d in this order)"  , i, c, i2)
 
There are cases when a Spanish/German/French/insert-your-language-here/Japanese
translator for the said diagnostic message finds that a translated
message would be more natural if we can refer the arguments in
different order, say, i2, i, c.  However, we can't do that in the
current framework.  In such cases, a rather unnatural rearranging of
words/pharases is done to accommodate the original argument order.

For example, I have seen a few contorted Japanese messages myself both
in GCC (current) and in an old Sun Solaris 4 (SunOS 5.4) localized
messages used by its ksh. 
The messages will be understandable, if we get lucky, after a few
second thoughts. However, I had to think twice or three times before I
was sure if I understood the meaning of such messages correctly.  We
really ought to issue easy to understand messages: the user is already
struggling with the errors/problems in the source code itself, and we
should not burden them with the extra weight of dubious messages.

Please recall that the gettext() I18N/L10N framework replaces the said
format string at run time, but at this level of I18N/L10N
transformation, we can't change the ORDER of the arguments passed to
the original diagnostic message function calls.

This is where positional format specifier to the rescue!

If we want to refer to i2, i, and c in this order in the
above example, we can now use the following:

warning ("translated string with %3$d, %1$d, %2$c in this order)"  , i, c, i2)

This meets the desire of the translators very well.

[3] %d$n format specifier usage rule: 

    Initially, I was not entirely sure of the usage rule of %n$c
    format specifier.

    For example, can we mix the old form and positional form?

    Standard turns out to be clear. My reading was insufficient.  We
    must either use %n$ form specifiers for ALL the specifiers, or
    NONE at all.  (Thanks to Zack and Joseph Myers for pointing this
    out.)

	========================================
	standard-wise 
	----------------------------------------
	OK	           %1$d %3$c %2$s %6$d %5$s %4$c

	NOT OK             %d %s %c %6$d %5$s %4$c

	NOT OK ambiguous   %d %s %c %6$d %s %4$c
			   1  2  3   4   5  6
	In the last example, against which argument is the format specifier
	above (the fifth one) should be used?  
	----------------------------------------

    So my patch only permits ALL or NONE usage.


[4] GCC's warning/diagnostic message handling.

   See the gcc/gcc/ABOUT-GCC-NLS for general philosophy of handling
   I18N/L10N in GCC.

   The translation is done by routines in diagnostic.c.
  (printf-like formatting itself is done now in pretty-print.c)

   From an early post by Zack Weinberg.

   --- begin quote ---
    > I am not sure if there are entry points in diagnostic.c which
    > do  NOT use the translation and end up with output_format() with
    > the original format string intact.
    > But I guess there must be such entry points.

    There are not supposed to be any such entry points.  All of the
    strings that are deliberately not translated, do not go through
    diagnostic.c.  Everything that diagnostic.c prints is supposed to
    be subject to translation.

    > Such usage of output_format() won't need positional parameters.
    > I have a feeling that tree dump and RTL dump(?) won't need
    > such translation either.

    You're correct that debugging dumps do not need translation, but
    they use their own printers, so you needn't worry about it.

    Tracing through diagnostic.c can be confusing.  There is a convention
    that may help: A function with an argument 'const char *msgid' has
    responsibility for getting the string translated.  This may happen
    either by a direct call to gettext (which may be written using a
    shorthand macro: _(msgid)), or by passing the string to another
    function which will take responsibility.

    In diagnostic.c, the buck stops (mostly) with diagnostic_set_info.

    Another convention which is much less widely used: a function with
    an argument 'const char *msgstr' expects to receive a string that
    has already been translated.

    More generally, string variables named 'msgid' are intended to be
    translated, but haven't yet, and string variables named 'msgstr' have
    already been translated.
  --- end quote ---
  (See comment about the file re-organization near the beginning.
   function names and file names were retained as in the original
   post and no longer reflect the used names.).

  So by modifying pp_format_text() in pretty-print.c (formerly 
  output_format() in diagnostic.c) to support positional format specifier,
  we are done (!).
  
  Aha, not quite.  It turns out the custom decoder function to support
  extended format characters need to be modified a little bit. This is
  a price we must pay.

[5] Given Conditions/Limitation: Preserving the existing infrastructure.

   I looked at the original source of pretty-print.c ( formely part of
   diagnostic.c ) code and noted the following.

   GCC's diagnostic formating uses only a subset of format
   specifiers of standard C. For example, it doesn't handle
   floating point data output.
   However, it adds its own format characters and
   has a mechanism to install custom format decoder that extends
   the recongnized characters more such as %H, %T, %D, etc..

   Field width specification via passed argument is supported for only
   string 's' specifier in pretty-print.c.  I didn't change this. (and
   this simplifies the handling of %n$c format specifier a little
   bit.)

   However, it turns out when the positional specifier (i.e., %n$c
   format) is used, then the argument specifying for string width must
   be given by the %n$ form as well. (This complicates the processing
   a little bit.)

   The initial patch was not thread-safe.  However, afterward, I put
   the statically allocated argument array, and arg_max into text_info
   struct.  Now the modification works and pp_format_text is thread
   safe to the extent that the functions it calls are thread safe.

[6] Implemenatation CAUTION/CAVEAT, etc.: 
	
   I found out that precision for integer print defines the
   width by specifiying the 
   used type (%d, %ld, %lld, ... ).

   output_integer_with_precision() macro uses the following
   precision/types.

	%d   %u
	%ld  %lu
	%lld %llu

	%w, %lw, and %llw, too. 

   This must be observed by my patch also.

   A new output_integer_with_precision_NEW() macro was introduced to
   handle positional specifier situation.
   This new macro takes the index to the argument array.

[7] Usage Example of Positional parameters:

   Firstly, words of caution.  We should not allow/use positional
   parameter in source code as much as possible.
   
   Use them only in PO files initially.

   Usage Example: in the source code we may have the following call to
   print an integer, a character, and a string:

   warning("A warning message that refers to %d %c %s in this order", 
        intvalue, 
	charvalue, 
	"string");

   Now, during the I18N/L10N processing,  this warning is translated
   into, say, non-English langauge message.
   (Such translation itself is done in diagnostic.c, I think using
   gettxt().)
   Suppose that message is better written if we refer the
   arguments in a certain different order, say, the charvalue, "string" and
   intvalue.
   In this case, the translation for the warning message should be
   written using the positional format specifier :

   "A translation that refers to %2$c, %3$s, and %1$d in this order.".

   This will be put into corresponding PO file and will be subsituted
   when the warning() is called with the original warning format string.

[8] Caution to PO writers.

   Extracted and edited as a separate file.

	diagnostic-caution-to-PO.txt

	( I will post this if anyone so desires.)

[9] Difficulty of creating standalone test programs.

   I wish I could create an example test program.

   However, I found it difficult to write a standalone short test
   program to check calls, say, warning().  For example, routines in
   diagnostic.c requires prior envrionment initialization and I was
   not quite sure how to do that.

   I also found out that diagnostic.o requires linking of
   various modules. Without that, unresolved symbols appear.
   So I hacked up toplev.c to insert a test call to
   warning() with various combinations of format string and arguments.
   Now, the hacked gcc calls these functions and quits.  The function
   seem to work well and also catches errors in the format
   specification strings rather well.

   I have learned the inter module dependency of diagnostic.c will
   be lessened in the future. Now output_format() has been
   taken out from the file and renamed as pp_text_format() and
   put into pretty-print.c. (July 25, 2003.) So a standalone test program
   would be easier to make now. But I have not still figured out how
   to do this. (Sept, 2003).

   The test code snipet and the output from it is given below
   in the testcase section.

   "make -k check" is also invoked to make sure the compiler doesn't segfault.

[10] Implementation Strategy for positional parameter support.

    To support the above, we need to scan the whole format string to find
    out the type of each i-th value passed to pp_format_text.

    So when we see ONE format specifier in the form of %1$d format (1
    could be 2, 3, 4...), we scan the whole format string and we build an
    internal array that defines the type of i-th argument.  Afterward we
    scan the argument list and record the value of argument themselves.

    (UNLESS one such reference to a format specifier in the form of
    %n$c is done, we won't have the overhead of the array construction.)

    Requirements/Caution:

    The size of paramaters pushed on the stack can vary (say, int vs long
    long, and/or 64 bits pointer vs 32 bit int, etc.), so we must KNOW the
    size of each argument before constructing the argument value
    list.  (This is why we use a two pass algorithm below.  one for the
    format string to look for the type of each argument, 
    and then the scan of the argument list itself for the value.)

    Passing the correct types in the format string is and has always been
    the responsibility of the caller.


[11] Surprise: custom decoder used a lot.

    About Custom Format Decoders. (Three is not too many...) 

    My current ptach handles custom format decoder as of
    now even IF positional parameter is used. (If we don't use it, the
    support remains as is and there is no overhead.)

    I initially wondered if anyone uses the format_decoder function.
    It turns out it is used a lot by c++, and objc front end.

    So I checked where the custom decoder is installed in current GCC
    source.
    This is how I used it.

    find . -type f -name "*.[cChHjJaA]*" -print |   xargs egrep -i format_decoder 

    [... output omitted ...]


[12] Summary of my finding regarding custom format decoder 

    There are basically only three custom decoders in use now.
 
    They are
    - c_tree_printer in c-objc-common.c
    - cp_printer in cp/error.c
    - default_tree_printer in toplev.c

    I needed to study how the custom decoders extended the recognized
    format character set and how they are used in practice.

    My initial observation was as follows.
    c_tree_printer is easy to handle.
    default_tree_printer is easy to handle, also.
    cp_printer is a little complicated, but still manageable.
    
[12-a]  Complication of cp/error.c:

    cp/error.c contains the following code of cp_printer(). Namely,
    it handles '+', and '#' which can prefix the extended format characters.

    if (*text->format_spec == '+')
      ++text->format_spec;
    if (*text->format_spec == '#')
      {
        verbose = 1;
        ++text->format_spec;
      }

    switch (*text->format_spec)
      {
      ...

    So we must take care of multiple format specifier character
    as well. 

   (This complicates the skipping of substring used by custom format
    decoder. It also complicates the consistency checking, i.e.,
    "match"ing of two positional
    references to the same i-th argument in format string.  We need to
    be sure that they refer to the same type.  

    In the above case of cp_printer(), the use of "#" doesn't change
    meaning of the following format character as far as the type is
    concerned. It simply change the output verboseness.  But since we
    use strncmp() for simplicity now, the use of "#" can change
    the result of "match"ing of type. Not serious problem for now.)

    For skipping the substring properly, we also need to extract the
    length of the format specifier string used up by the custom
    decoder as well.


[13] Current implementation overview.

   I have written a preliminary code/patch, which works now.

   My current algorithm is as follows.

   If there is NO positional format specifier, my
   modification works exactly as the original unmodified program.
   It scans the format string and as it encounters a format
   specifier, it obtains the corresponding value from argument list
   and formats it.

   Only if there is a positional format specifier (i.e., %1$c, etc.),
   the following algorithm is entered and executed.

   Basically, it is as follows.
   - scan the whole format string, and builds an array of expected
     types of arguments.
   - Scan the argument list and based on the type found in the above
     step, copy the argument value to the array of argument values.
   - Finally, rescan the format string and as we encounter the
     positional format specifier, use the value stored in the second
     step and format (output, that is) the value into suitable string form.
   

[13-a] Scan Stage

   Now the details.

    First we scan the format specifier list and records the type
    AND the PRECISION IF APPROPRIATE  of i-th argument.

    Before recording, we should check the double reference 
    and if we are making incompatible double usage, etc..
    We don't want to see an argument used once as
    integer, and then as pointer, etc..
    (Double reference is OK as long as the previous reference is
    compatible [check is done to make sure the data width is the
    same], etc.)

    The current patch uses the following algorithm to catch
    inconsitent usage even when custom decoder is invoked.

    Algorithm to check for type-consistent double (or more) references. 

      - check if custom_format field of i-th arg_value[] is empty or
        not. If empty, this is the first reference and we don't have
	to worry about type consistency. 

      - if it is NOT empty, then copy the 
        text->arg_value[i].custom_format member to
        text->arg_value[0].custom_format member. (temporary value holder.)

	(Actually we check this at a later stage in the current patch,
	and so the copying takes place always.)

      - call custom decoder 
        (after setting arg_index, and format string pointer into
        text_info variable, namely text.)
        as in
        format_decoder(buffer, text, GET_ARG_TYPE)

      - custom decoder returns the used (understood) format string
        in  text->arg_value[i].custom_format. So let us
        compare it against text->arg_value[0].custom_format.
        (These are the used format character(s) for processing argument
         by the custom decoder. if text->arg_value[0].custom_format[0]
         is NUL ('\0'), then there was no prior reference to the argument.)

        If it `matches', 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 strncmp()
	against	the two format strings. This seems practical and works.
	We don't want to complicated decoder very much.

[13-b] Value Copy stage.

    Secondly, using the freshly built array of the type of
    i-th argument, we scan the real argument list and record the
    value of each argument one by one.  If we find undefined type for used
    arg, then we abort();

    Custom Format Decoder case: Invoke GET_ARG_VALUE action.
	If the arg_value]i].type is UNDEFINED_FORMAT
	then we need to check the custom_format field and
	if it is set (the first element is not NUL), then we need to call
	  (after setting the arg_index)
	  format_decoder(buffer, text, GET_ARG_VALUE);
	If NOT, then the type for ith-argument was never
	recorded (-> error.).

    We should abort if we find syntax error during scan.  (Someone
    can provide an off-line tool to check the PO strings for such
    static problems.)

[13-c] PRINT_VALUE stage.

     Now we are back to the original algorithm.
     But we set a flag use_pos_specifier to signal the
     processing of positional specifier. This essentially means
     we use the linear array of argument value instead of
     the argument list to obtain the to-be-formated value.
     We now continue to scan the format string, and using the value
     stored in the argument array, print the value
     according to the format specification.
     Custom decoder is invoked if necessary.

[14] Protocol between pretty-print.c and custom decoder.

    In pretty-print.h, I defined an enum type to enumerate the
    actions we want the custom decoders to perform.

    /* Instruct custom defined format decoder to
       return information for 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;


    Now the  format_decoder takes an extra argument at the end 
    and is called as follows:

    To get the argument type:
    format_decoder(buffer, text, GET_ARG_TYPE)

    To record the argument value:
    format_decoder(buffer, text, COPY_ARG_VALUE)

    To print the arugment value thus recorded:
    format_decoder(buffer, text, PRINT_ARG_VALUE)

    To print as in the original,i.e., no positional parameter case. 
    format_decoder(buffer, text, PRINT_ARG_VALUE_AS_BEFORE)

    text_info data type is exteneded to hold
    temporay values for positional parameter handling.

[14']  What to do for each arg_decode_action value?

    I take care of the simplest one first.

[14'-1]    PRINT_ARG_VALUE_AS_BEFORE.

    format_decoder is called:
    format_decoder(buffer, text, PRINT_ARG_VALUE_AS_BEFORE)

    The fouth  call with PRINT_ARG_VALUE_AS_BEFORE
    is a request to print argument as has been the case without the
    positional parameter. So the action should preserve the
    current (pre-postional parameter ) behavior.

[14'-2]  GET_ARG_TYPE:

    format_decoder is called:
    format_decoder(buffer, text, GET_ARG_TYPE)

    Input: format string and its current postion immedaitely AFTER '%'
           or immediately after '$' as in %1$.
	   argument index position in format positional spec. (e.g., 2
           for %2$)

	   passed as text_info struct member:
	   text->index_num = arg_index;
	   text->format_after_percent_or_dollar = text->format_spec;

    Return value:
       true if the format is understood.
       false if not understood.	   

    Output returned in text (text_info *).

    (a) int text->bump_format:
        How many format characters it will be consumed (cp/error.c can use
        a few characters.)

	This is necessary so that we can skip over the
	non-standard format character before continuing with
	the rest of the format spcification.

	If the skip amount is one (1), then
	the pp_format_text loop in pretty-print.c handles it automatically, but
	there are cases where multiple characters needs to be skipped.
	In that case, we need to bump format string pointer additionally.

	(This part could be optimized. The original printing 
	by custom format decoders modifies the format string pointer
	directly, but we don't want it to modify it now
	during positional parameter processing. I will see if I can
	simplify this.)

    (b)	The format substring understood by custom decoder
        is stored in text->custom_format[];

        Basically we want to know the type/size of the second argument
	used in the  va_arg
	as in the "#define next_tree    va_arg (*text->args_ptr,
        tree)" or "#define next_int     va_arg (*text->args_ptr, int)".
        as well as  type information.

	There is no easy way to pass the type information itself, so
	we let the custom decoder stores the format string 
	itself which it groks.

	As a general comment, we have to admit that

	- C's variable argument handling is a kludge and
	  works well only when the stack is a linear array
	  and all the argumets are passed in the stack (and
	  not in registers).

	So I admit that my current quick/hack/implementation may not
	be perfect.

        From a post by Joseph Myers:

|    >    (We essentially need the width of the argument to bump the pointer
|    > for
|    >    variable argument processing  is necessary. So all we need is
|    >    the # of bytes for the argument type. The value itself can be opaque,
|    >    and will be stored in an appropriate argumet array cell.)

|    We need the actual type, not the width.  Passing the wrong type to va_arg
|    will lead to (a) aliasing issues (generating wrong code), (b) problems
|    with ABIs that handle integer/floating point/pointer arguments differently
|    in variable arguments (if such ABIs aren't currently in use, someone will
|    one day invent one), (c) problems when someone implements a safer ABI that
|    stores information about argument types and actually checks at runtime
|    that they are correct.  So you should always store information about the 
|    actual type (distinguishing "int" and "long" even if the same size, for 
|    example).
|
|    For the format decoders, I'd guess that just the character 'D', 'T', etc.,
|    is sufficient to determine what the type is, and so can be stored as an
|    opaque identifier itself.  So you need (a) a list of valid characters for
|    the front end (needn't be a function, though using a function would keep
|    more generality), (b) a function to extract and store the relevant value,
|    (c) a function to print the saved value.  Trying to call va_arg to extract
|    the value from within diagnostic.c, using some substitute type because
|    diagnostic.c shouldn't know about "tree" etc., would I think end up being
|    a mistake.


	- An attractive and type-safe architecture mentioned in 
	  Joseph Myers's post (quoted above)  is nowhere in sight at least
	  commercially. 
	  I am afraid that the popularity of ISO-C
	  is hindering the adoption of such user-friendly architecture
	  due to the difficulty of some ISO-C construct such as
	  the variable argument list handling.!

	  I propose we might as well postpone the "perfect" implementation
	  until such architecture finally arrives and we are given
	  the variable argument handling implementation on such
	  architecture. Then, we can hack it to support our scheme.


[14'-3]    COPY_ARG_VALUE action:

    Custom format_decoder is called:
    format_decoder(buffer, text, COPY_ARG_VALUE)

    This is called within a loop in pretty-print.c
    So the arg_ptr is bumped per argument as we visit it.
    for(arg_index = 1; arg_index <= arg_max; arg_index++)
    {
        ...
        ....format_decoder(buffer, text, COPY_ARG_VALUE)  
    }       

    Input: text->custom_format[];
	   arg index position.

    passed as part of text_info struct member:
	   text->index_num = arg_index;
	   text->format_after_percent_or_dollar = text->custom_format;

    Return value:
       true if the format is understood.
       false if not understood.	   

    Action: Use text->text->format_after_percent_or_dollar
            string and copy the value into 
	    text->arg_array[text->index_num].v.xxx 

	    (Custom decoder is requested to use appropriate union
	    member for the value. This union member is used
	    later during PRINT_ARG_VALUE processing.
	    We can possibly add another union member, but
	    be advised to use an existing one. See cp/error.c
	    modification.)

[14'-4]    PRINT_ARG_VALUE

    Custom format_decoder is called:
    format_decoder(buffer, text, PRINT_ARG_VALUE)

    Input: format string and its current postion immedaitely AFTER '%'
           or immediately after '$' as in %1$.
	   arg index position.

	   passed as text_info struct member:
	   text->index_num = arg_index;
	   text->format_spec.
	   ( text->format_spec_after_percent_or_dollar is now not used
	   for PRINT_ARG_VALUE so that the code can share much
	   with PRINT_ARG_VALUE_AS_BEFORE action.)

     Action:
     print, i.e., insert the string image of the value of
     text->arg_array[text->index_num].v.xxx into string buffer.


cp/error.c, c-objc-common.c, toplev.c have been modified according to
the above scheme.

[15] Is there a simpler way to handle custom decoders?

   After a lot of experimenting, I found
   out a half-hearted kludge doesn't work.

   By the way, Zack Weinberg suggested an interesting alternative
   approach which might lessen the number of interactions from
   pp_format_text() to the custom decoders.  This is attractive. But
   his algorithm assumes that we need to scan the format string once
   prior to the processing even if there is no positional argument
   specifier.  In contrast, my patch was written so that the
   processing remains unchanged if the postional notation is not used
   at all.

   I left my current algorithm as is so that the change is easier to
   understand in comparison to the current existing implementation.

   After the mail exchanges of the last several weeks in June and
   July, I think the larger problem is now not whether we use a better
   algorithm for the support of positional paramter. My patch works
   and supports the custom format decoder. So I regard my current
   algorithm and implementation as sufficient for the current needs.

   The larger problem is to let the translator community catch up with the
   latest GCC messages and clean up PO files to let the messages with
   the extended format character set be checked using modified msgfmt
   in modified gettext suite.

   The translators have not let the format strings be checked since
   the unmodified msgfmt doesn't check theset properly.  It is/would
   be a problem for some time to come. But Bruno's new patch to
   gettext should get things moving forward.

   This is a larger problem that exists now whether we handle
   positional parameter or not.

   I hope modified Bruno's msgfmt helps us in cleaning up the mess and
   gradually persuade the translators to check these throughly.

[16] LIMITATION/FEATURES:

    My current implementation handles only 1-9 range.  
    This should suffice for GCC usage.

[17] A thought about Format checker.

   My current thinking: 

   Use positional parameter only in PO files initially (and forever, maybe).

   We should not allow positional parameter in source code as much as
   possible. Or prohibit it altogether. 
   
   A separate PO file checker is in order.
   Such a tool makes sure that the extracted messages and the
   translated messages agree to the use of arguments.

   Although it is powerful, the old version of
   msgfmt from GNU gettext() left much room for improvement.

   msgfmt from the newer GNU gettext should work for
   this purpose.
   Bruno Haible's new gettext suite will 
   understand the set of format characters used by GCC's internal
   diagnostic routines (GCC version 3.3, that is). 
   The option to check GCC message would be  something
   like  "--language=gcc-internal".

   Now xgettext() would mark likely format strings with
   "#, gcc-internal-format" rather than with "#, c-format" with
   Bruno's patch.

   The old version of msgfmt didn't print out a problem in the
   original msgid string and silently skipped it, it seems.  (I am not
   sure if Bruno fixed this problem or not.)

[17-1] format checking messages in the source file.

   As for the messages in the source file, is there a mechanism to
   check if the messages in the source code use the passed argument
   properly including the checking for extended format characters?
   
   There is.

   Quote from a post by Joseph Myers			

  |> Yes, for the format checker, 
  |> I will use the data definitions, etc. as implemented in your patch, but
  |> I am not quite sure how to accommodate the 
  |> positional parameter in the checker framework.
  |
  |There is full support for such formats in the checking code - you'd need
  |to set the flag FMT_FLAG_USE_DOLLAR and possibly FMT_FLAG_DOLLAR_MULTIPLE.   
  |That doesn't mean there would be any purpose other than obfuscation for
  |actually using them directly in source files.

  |Although the support for checking such formats is probably little used -
  |as they are generally used in translations only - at least one person must
  |have used that support (and so $ formats in the source file) in the past,
  |because there was once a bug report about it (6547).

  I would study this mechanism to see how we can
  possibly enhance the checking scheme, but this can wait until the
  rest of the pieces (positional parameter support,
  new gettext release, and new GCC release, etc.) are in place.

  (Sorry I have not gotten around to doing this yet. Sept, 2003).

----------------------------------------

[18] 
TestCase:
	Below I explain the quick test I inserted into toplev.c.

	But I wonder how to test extensively?

        make -k check is NOT a satisfactory test since
        the error / warning messages must be
        generated by running program source code that
        triggers such error/warning message output.

        Newer version of gettext will help us in checking PO files.
	(We need the help from translation community very much to
	enable the checking of many fuzzy and untranslated messages.)

[18-1] Quick testcase: 

  For preliminary testing, I embedded the following into toplev.c 
  immediately after

	  >    /* Initialization of GCC's environment, and diagnostics.  */
	  >     general_init (argv[0]);

	  and before
	  
	  >  /* Parse the options and do minimal processing; basically just
	  >     enough to default flags appropriately.  */
	  >  decode_options (argc, argv);

	  The routines worked as expected, I think, from the
	  test output I obtained (and shown below).
	  
[18-2] Code snipet

I inserted the following code snipet in toplev.c tests the operation
of positional parameters.

#if 0  <--- change this to 1 for testing. cc1, for example, run
            the code snipet and quits.
 {
   /* This is a test code for diagnostic routines. 
      I wonder where we should keep this code. */

#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 fprintf(): %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: 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 


========================================
[18-3] OUTPUT from the [18-2] above:

cc1: warning: Test diagnostic.

cc1: warning: integer=1234, pointer=0xbfffdf1c, char=c
cc1: warning: 
   Pointer value print

pointer=0xbfffdf1c
cc1: warning: 1st: pointer=0xbfffdf1c, char=c, integer=1234
cc1: warning: 2nd: pointer=0xbfffdf1c, char=c, integer=1234
cc1: warning: 3rd: pointer=0xbfffdf1c, char=c, integer=1234
cc1: warning: pointer=0xbfffdf1c, char=c, integer=1234
cc1: warning: 
   One argument
cc1: warning: integer=1234
cc1: warning: char   =c
cc1: warning: pointer=0xbfffdf1c
cc1: warning: long=16777215
cc1: warning: long=ffffff
cc1: warning: long=(x) ffffff
 ordinary printf: ffffff
cc1: warning: long=(o) 77777777
 ordinary printf: 77777777
cc1: warning: long=(d) 16777215
 ordinary printf: 16777215
cc1: warning: long long=(d) 281474943156225
ordinary fprintf(): 281474943156225
cc1: warning: long long=(x) 123456789abcdef
 ordinary printf: 123456789abcdef
cc1: warning: long long=(o) 4432126361152746757
 ordinary printf: 4432126361152746757
cc1: warning: long long=(d) 81985529216486895
 ordinary printf: 81985529216486895
cc1: warning: Wide

cc1: warning: wide=(wd) 16777215
cc1: warning: wide=(wx) 0xffffff
cc1: warning: wide=(wo) 77777777
cc1: warning: 
   Two arguments
cc1: warning: integer=1234, char=c
cc1: warning: char   =c, integer=1234
cc1: warning: 
   Three Arguments

cc1: warning: char=c, integer=1234, pointer=0xbfffdf1c
cc1: warning: char=c, integer=1234, pointer=0xbfffdf1c
cc1: warning: pointer=0xbfffdf1c, char=c, integer=1234
cc1: warning: char=c, integer=1234, pointer=0xbfffdf1c
cc1: warning: integer=1234, long=16777215, long long=281474943156225
cc1: warning: long=16777215, long long=281474943156225, int=1234
cc1: warning: long long=281474943156225, int=1234, long=16777215
cc1: warning: pointer=0xbfffdf1c, char=c, integer=1234
cc1: warning: long long=281474943156225, long=16777215, int=1234
cc1: warning: long=16777215, int=1234, long long=281474943156225
cc1: warning: int=1234, long long=281474943156225, long=16777215
cc1: warning: 
   String
cc1: warning: String =123456789A123456789A123456789A
cc1: warning: String =123456789A123456789A123456789A
ordinary fprintf(): 123456789A123456789A123456789A
cc1: warning: String = 123456789A, extra=1234
cc1: warning: String = 123456789A, extra=1234
cc1: warning: String = 123456789A, extra=1234
ordinary fprintf(): 123456789A
cc1: warning: String = Hello!
cc1: warning: 
   H
   He
   Hel
   Hell
   Hello
   Hello!
cc1: warning: 
   H
   He
   Hel
   Hell
   Hello
   Hello!
cc1: warning: This is one % (percent sign)  and error code message: could be random <<No such file or directory>>
cc1: warning: int=1234, long long=281474943156225,  % (percent sign) and error message should be for EPIPE <<Broken pipe>>
Problem with output formatting: We can't mix %d and %n$d form

format=<<Should abort: integer=%d, pointer=%p, char=%3$c
>>
cc1: warning: Should abort: integer=1234, pointer=0xbfffdf1c, char=
Internal compiler error: Error reporting routines re-entered.
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.


(CI's comment: the abort is due to the fact that
the abort is done within an error handling routine
and some function tries to invoke another diagnostic instance.)


========================================
[19] ChangeLog

2003-09-18    <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 (pp_helper_abort): print the problematic format string
	  and abort.
	  (pp_type_width): returns the argument width based
	  on format specifier type.
	  (pp_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.
	  (pp_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.

	* toplev.c (default_tree_printer): ditto.
	
	* cp/error.c (cp_printer) : ditto
	
	* diagnostic.c (text_specifies_location): 
	  check for "%1$H" as well as for "%H". Restores the pointer.
	  '%H' is now retained by text_specifies_location. 
	

cp/ChangeLog
2003-09-18    <ishikawa@yk.rim.or.jp>

	Positional format specifier support for 
	pp_format_text().	
	
        * error.c (cp_printer):  takes extra argument of type
	  arg_decode_action. Modified to support four actions.

	                

========================================
[20] Bootstrapping and Testing

      compiled and tested within the GCC object directory
      configured as
      i686-pc-linux-gnu

      It was tested using the aforementioned codelet as well
      as "make -k check" to see if there was any ill-effect.
      None was found. 
      
cf. Since the custom format decoders were installed
    for c, c++, objc only, I configured the GCC using
    the following. (I wonder if I should check for java, g77, and
    ada.)

    env CC=gcc /u2/tools/gcc-mainline-cvs/gcc/configure  \
	    --enable-languages=c,c++,objc	\
	    --program-suffix=-mainline-cvs --enable-nls
    ++ env CC=gcc /u2/tools/gcc-mainline-cvs/gcc/configure --enable-languages=c,c++,objc --program-suffix=-mainline-cvs --enable-nls


========================================
[21] current checking using msfgmt

   I noted that the following msgfmt checking occurs during make bootstrap.
   In the future, these would need to take
   an extra option to check the internally extended format characters
   for GCC diagnostic functions.

   Once Bruno's patch is in the new gettext suite, we need to call
   msgfmt with the option below.
   msgfmt --language=gcc-internal  

   The translators of da.po, es.po, fr.po, and tr.po are ahead
   of the rest in terms of messages translated, it seems.

    msgfmt check during make bootstrap


    make[2]: Entering directory `/u2/tools/gcc-mainline-obj-dir/gcc'
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/be.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/be.po
    312 translated messages, 386 fuzzy translations, 3851 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/da.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/da.po
    4070 translated messages, 325 fuzzy translations, 154 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/de.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/de.po
    84 translated messages, 7 fuzzy translations, 4458 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/el.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/el.po
    165 translated messages, 916 fuzzy translations, 3468 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/es.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/es.po
    4549 translated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/fr.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/fr.po
    4070 translated messages, 332 fuzzy translations, 147 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/ja.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/ja.po
    2380 translated messages, 1252 fuzzy translations, 917 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/nl.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/nl.po
    655 translated messages, 1165 fuzzy translations, 2729 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/sv.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/sv.po
    931 translated messages, 939 fuzzy translations, 2679 untranslated messages.
    test -d po || mkdir po
    /usr/local/bin/msgfmt --statistics -o po/tr.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/tr.po
    4070 translated messages, 331 fuzzy translations, 148 untranslated messages.

========================================
[22] Patch itself.
----------------------------------------


Index: gcc/gcc/c-objc-common.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.34
diff -c -3 -p -r1.34 c-objc-common.c
*** gcc/gcc/c-objc-common.c	10 Sep 2003 23:45:05 -0000	1.34
--- gcc/gcc/c-objc-common.c	19 Sep 2003 18:45:47 -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)
*** 293,326 ****
     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);
  
!   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;
  
!     case 'E':
!        if (TREE_CODE (t) == IDENTIFIER_NODE)
!          {
!            pp_string (pp, IDENTIFIER_POINTER (t));
!            return true;
!          }
!        return false;
  
!     default:
!       return false;
      }
  }
--- 293,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;
! 
  
!   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':
! 	case 'T':
! 	  {
! 	    const char *n = DECL_NAME (t)
! 	      ? (*lang_hooks.decl_printable_name) (t, 2)
! 	      : "({anonymous})";
! 	    pp_string (pp, n);
! 	  }
! 	  return true;
! 
! 	case 'E':
! 	  if (TREE_CODE (t) == IDENTIFIER_NODE)
! 	    {
! 	      pp_string (pp, IDENTIFIER_POINTER (t));
! 	      return true;
! 	    }
! 	  return false;
! 
! 	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':
! 	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->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. */
!       switch (*text->format_after_percent_or_dollar)
! 	{
! 	case 'D':
! 	case 'F':
! 	case 'T':
! 	  return true;
! 
! 	case 'E':
! 	  return true;
! 	default:
! 	  return false;
! 	}
      }
+   else 
+     abort ();
+ 
+   return false;
  }
Index: gcc/gcc/diagnostic.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/diagnostic.c,v
retrieving revision 1.130
diff -c -3 -p -r1.130 diagnostic.c
*** gcc/gcc/diagnostic.c	7 Sep 2003 11:59:52 -0000	1.130
--- gcc/gcc/diagnostic.c	19 Sep 2003 18:45:48 -0000
*************** diagnostic_initialize (diagnostic_contex
*** 120,126 ****
  
  /* 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)
  {
--- 120,134 ----
  
  /* 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,139 ****
    for (p = text->format_spec; *p && *p != '%'; ++p)
      ;
  
!   /* Extract the location information if any.  */
!   if (*p == '%' && *++p == 'H')
      {
        *locus = *va_arg (*text->args_ptr, location_t *);
!       text->format_spec = p + 1;
        return true;
      }
  
--- 137,155 ----
    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;
      }
  
Index: gcc/gcc/pretty-print.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.c,v
retrieving revision 2.6
diff -c -3 -p -r2.6 pretty-print.c
*** gcc/gcc/pretty-print.c	12 Sep 2003 23:47:01 -0000	2.6
--- gcc/gcc/pretty-print.c	19 Sep 2003 18:45:49 -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
  
*************** Software Foundation, 59 Temple Place - S
*** 58,63 ****
--- 60,67 ----
    while (0)
  
  
+ 
+ 
  /* Subroutine of pp_set_maximum_length.  Set up PRETTY-PRINTER's
     internal maximum characters per line.  */
  static void
*************** pp_base_indent (pretty_printer *pp)
*** 164,169 ****
--- 168,776 ----
      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
+ 
+ /* Aborting with error message and the format string that caused it. */
+ 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_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 '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_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 != '%')
--- 783,812 ----
     %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':
--- 815,872 ----
          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,325 ****
          }
        /* 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 ();
  	    }
  	}
      }
  }
  
  /* Helper subroutine of output_verbatim and verbatim. Do the appropriate
     settings needed by BUFFER for a verbatim formatting.  */
! void
  pp_base_format_verbatim (pretty_printer *pp, text_info *text)
  {
    diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp);
--- 885,1135 ----
          }
        /* 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;
  
          case 'H':
            {
!             const location_t *locus;
! 
! 	    if (!use_pos_specifier)
! 	      locus = va_arg (*text->args_ptr, location_t *);
! 	    else
! 	      locus = (location_t *) text->arg_array[arg_index].v.ptr;
! 
! 	    /* We dont format 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 ++;
      }
  }
  
  /* Helper subroutine of output_verbatim and verbatim. Do the appropriate
     settings needed by BUFFER for a verbatim formatting.  */
! void 
  pp_base_format_verbatim (pretty_printer *pp, text_info *text)
  {
    diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp);
Index: gcc/gcc/pretty-print.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.h,v
retrieving revision 1.10
diff -c -3 -p -r1.10 pretty-print.h
*** gcc/gcc/pretty-print.h	25 Aug 2003 19:10:48 -0000	1.10
--- gcc/gcc/pretty-print.h	19 Sep 2003 18:45:49 -0000
*************** Software Foundation, 59 Temple Place - S
*** 25,30 ****
--- 25,78 ----
  #include "obstack.h"
  #include "input.h"
  
+ /*  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;
+ 
+ 
+ /* 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,98 ----
    const char *format_spec;
    va_list *args_ptr;
    int err_no;  /* for %m */
+ 
+   /* Below is for positional argument support */
+ 
+   const char *original_format_spec; /* this remains unchanged.  */
+   argtype_t arg_array[10 + 1];	/* arg_array[0].v.cptr holds 
+ 				   the original format pointer. 
+                                    Argument is counted from postion no. 1. */
+   int arg_max;
+   const char *format_after_percent_or_dollar;   /* for GET_ARG_TYPE, COPY_ARG_VALUE */
+   int index_num;		/* argument index for custom decoder. */
+   int bump_format ;		/* GET_ARG_TYPE: returns
+ 				   how many bytes of format chars will 
+ 				   be eaten by  custom decoder. */
  } 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
--- 137,143 ----
     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
Index: gcc/gcc/toplev.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.826
diff -c -3 -p -r1.826 toplev.c
*** gcc/gcc/toplev.c	17 Sep 2003 07:10:59 -0000	1.826
--- gcc/gcc/toplev.c	19 Sep 2003 18:45:55 -0000
*************** crash_signal (int signo)
*** 1331,1337 ****
  }
  
  /* 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)
--- 1331,1337 ----
  }
  
  /* 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)
*************** init_asm_output (const char *name)
*** 4017,4041 ****
  
  /* 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
--- 4017,4097 ----
  
  /* 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
*** 4513,4518 ****
--- 4569,4725 ----
  
    /* 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 fprintf(): %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: 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/gcc/cp/error.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.236
diff -c -3 -p -r1.236 error.c
*** gcc/gcc/cp/error.c	18 Sep 2003 08:25:12 -0000	1.236
--- gcc/gcc/cp/error.c	19 Sep 2003 18:45:59 -0000
*************** static void print_instantiation_partial_
*** 96,103 ****
  static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
  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);
--- 96,102 ----
  static void cp_diagnostic_starter (diagnostic_context *, diagnostic_info *);
  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);
--- 1549,1555 ----
  	}
        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;
--- 2267,2277 ----
     %P   function parameter whose position is indicated by an integer.
     %Q	assignment operator.
     %T   type.
!    %V   cv-qualifier.  
! 
!    Modified to support postional 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
--- 2280,2430 ----
  #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



More information about the Gcc-patches mailing list