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


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

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


Gabriel Dos Reis wrote:
> 
> "Joseph S. Myers" <jsm@polyomino.org.uk> writes:
> 
> | On Thu, 31 Jul 2003, Ishikawa wrote:
> |
> | > Ok, while I am waiting for the patch to support positional format
> | > specifiers in diagnostic (and formated output) routines being merged
> | > into mainline tree (hint, hint), I looked at
> |
> | For the detailed review process to start, please submit a version of the
> | patch formatted according to the GNU Coding Standards.  (There may then
> | need to be several rounds of technical review of the patch following
> | that.)
> 
> I have been looking at his code -- no I didn't reach the conclusion
> I'm satisfied yet.  For future resubmission I would suggest he avoid
> _[a-z]* and instead use the "pp_" prefix instead (or better).

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

(There's dupliate part in the summary, etc. below with
the previous post, but I wanted to make this post as self-contained
as possible. In any case, we have uncovered the pitfalls and
special cautions necessary for supporting postional parameters
in GCC diagnostic routines. Future enhancements can certainly
use the gleaned info.)

Please note that my patch tried to preserve the behavior of the code
when there is no positional parameter.  Also, after testing on local
PC (with a small test program and also by make -k check), I am fairly
certain that the mechanism works without problems for current PO file
disregarding the potential errors in PO files themselves.  [the
Japanese PO file that is installed in my Debian GNU/Linux, that is.  I
have not yet gotten around to install the current GCC CVS po files
under the system directory where running GCC would pick it up. Please
be careful about this distincition of message files.]

So I would like to see others in different locale to test this out if
they are brave, er, forward-looking types.  But do not be afraid. If
there is a problem, my patch is quite likely to print the problematic
format string to stderr, and so we will see immediately what format
string caused a problem. 

We now probably need to move on to clean up external PO files once the
support code is in the mainline.  (It is a chicken and egg situtation:
PO file translators, I am sure, will use positional parameters, but
unless the support is in the code, it will be useless. Worse, it might
stop the compilation.  I think it does. Without my patch a digit
following a '%' as in "%2$d" will result in abort(). )

Posting the patch now is to urge the review and
adoption of the positional parameter support.

One problem of testing the patch is that most of the error/warning
messages that use extended format characters are for printing
semantical problems in the source code and not with syntactic
errors. So, in order to invoke the error/warning processing with
interesting format strings, we need source files that exhibit such
semantical problems.

I won't be able to write exhaustive list of test files alone. So the
separate check of PO files, and the format argument check proposed
(and implemented?)  in this mailing list is in order.
Modified msgfmt would do this to a certain extent.

(make -k check invokes only a subset of such error/warning, it seems.)

Basic support mechanism has been checked with a codelet attached
and it seems to work just fine.

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.)

The attached patch can certainly use some clean up, but the cleanup
can wait until the basic scheme is studied/reviewed and approved.

Again, comments/feedback welcome.

I modified the following summary document for a few spelling mistakes,
and better exposition, etc..

---

I attach the edited summary document first 
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)
============================================================

Background:

%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.

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.

[] %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 permit ALL or NONE usage.


[] 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 a 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.

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

   I looked at the original source of pretty-print.c ( and
   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.

[] 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.
   This new macro takes the index to the argument array.

[] 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.

[] Caution to PO writers.

   Extracted and edited as a separate file.

	diagnostic-caution-to-PO.txt

[] 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.

   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.

[] Implementation Strategy.

    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.


[] 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.
    (The following output is obtained after my local patch.)

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

    [... output omitted ...]


[] 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.
    
[]  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.


[] Current implementation overview.

   I have written a preliminary code/patch, which works
   more or less.

   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.

[..] Scan Stage

    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.

[..] 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.)

[..] 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.

[] 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.

[..]  What to do for each arg_decode_action value?

    I take care of the simplest one first.

[...]    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.

[...]  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.


[...]    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.)

[...]    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.

[] 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 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, 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.  

   But the larger problem is to let the translator 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
   or something.  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.

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

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

[] LIMITATION/FEATURES:

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

    %1$... %9$...

[] A thought about Format checker.

   My current thinking: 

   We should not allow positional parameter in source code as much as
   possible. Or prohibit it altogether.
   
   Use them only in PO files  initially (and forever, maybe).

   So 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, msgfmt from GNU gettext() leaves much room
   for improvement.

   GNU gettext suite's msgfmt comes very close, but it doesn't
   understand the extended format characters used by GCC's internal
   diagnostic routines.  
   Another thing is that the latest version didn't print
   out a problem in msgid string and silently skips it, it seems.
   (By the way, it turns out msgfmt checks the positional
   parameres very well, too. I am working on a patch to let msgfmt
   understand the extended character set, but it is tricky.)

   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 are in place.

Comments/feedback welcome.

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

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.

        PO files need separate sweep somehow since
        it is not untenable to switch the LANG/LC_MESSAGE/LC_ALL
        setting, etc. for all supported language environment.
	(A patch to msgfmt would check the files statically,
	 but we need the help from translation community very much to
	 enable the checking of many fuzzy and untranslated messages.)

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.
	  
The code snipet tests the operation of positional parameters.

#if 0  <--- change this to 1 for testing. cc1, for example, run
            the code snipet and quits.

{
#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=0x%08x\n", (unsigned int) &t);*/
  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


OUTPUT from the above:

cc1: warning: Test diagnostic.

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

pointer=0xbfffdf7c
cc1: warning: 1st: pointer=0xbfffdf7c, char=c, integer=1234
cc1: warning: 2nd: pointer=0xbfffdf7c, char=c, integer=1234
cc1: warning: 3rd: pointer=0xbfffdf7c, char=c, integer=1234
cc1: warning: pointer=0xbfffdf7c, char=c, integer=1234
cc1: warning: 
   One argument
cc1: warning: integer=1234
cc1: warning: char   =c
cc1: warning: pointer=0xbfffdf7c
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=0xbfffdf7c
cc1: warning: char=c, integer=1234, pointer=0xbfffdf7c
cc1: warning: pointer=0xbfffdf7c, char=c, integer=1234
cc1: warning: char=c, integer=1234, pointer=0xbfffdf7c
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=0xbfffdf7c, 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=0xbfffdf7c, 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.)


2003-07-29    <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-07-26    <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.

	                

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


[] 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.

   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/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/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/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/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/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/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/bin/msgfmt --statistics -o po/ja.gmo /u2/tools/gcc-mainline-cvs/gcc/gcc/po/ja.po
    2350 translated messages, 1280 fuzzy translations, 919 untranslated messages.
    test -d po || mkdir po
    /usr/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/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/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.
    TARGET_CPU_DEFAULT="" \

Patch itself.

Index: gcc/c-objc-common.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.30
diff -c -3 -p -r1.30 c-objc-common.c
*** gcc/c-objc-common.c	25 Jul 2003 09:52:23 -0000	1.30
--- gcc/c-objc-common.c	31 Jul 2003 09:30:59 -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 inline_forbidden_p (tree *, int *, void *);
  static void expand_deferred_fns (void);
  static tree start_cdtor (int);
--- 39,45 ----
  #include "target.h"
  #include "cgraph.h"
  
! static bool c_tree_printer (pretty_printer *, text_info *, arg_decode_action);
  static tree inline_forbidden_p (tree *, int *, void *);
  static void expand_deferred_fns (void);
  static tree start_cdtor (int);
*************** c_objc_common_finish_file (void)
*** 414,449 ****
     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;
      }
  }
  
  #include "gt-c-objc-common.h"
--- 414,558 ----
     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.  
! 
! 
!    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;
! 
!   /* fprintf(stderr,"c_tree_printer: a =%d\n", a);*/
  
!   if(a == PRINT_ARG_VALUE_AS_BEFORE /* good old printing as before. */
!      || a == PRINT_ARG_VALUE )	/* positional parameter support. */
      {
!       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)
+     {
+ 
+       /* fprintf(stderr,"c_tree_printer: a =%d, c=%c\n", a,
+        *text->format_after_percent_or_dollar); */
+ 
+       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;
+ 	}
+     }
+ #if 0
+   else if (a == PRINT_ARG_VALUE )
+     {
+ 
+       t = (tree) text->arg_array[text->index_num].v.ptr;
+       text->bump_format = 1;	/* we know it is 1 at most. */
+       switch (*text->format_after_percent_or_dollar)
+ 	{
+ 	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;
+ 	}
+     }
+ #endif
+   else 
+     abort();
+ 
+   return false;
  }
  
  #include "gt-c-objc-common.h"
Index: gcc/diagnostic.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/diagnostic.c,v
retrieving revision 1.127
diff -c -3 -p -r1.127 diagnostic.c
*** gcc/diagnostic.c	25 Jul 2003 09:52:24 -0000	1.127
--- gcc/diagnostic.c	31 Jul 2003 09:31:00 -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 so that the subsequent call
!    to pp_text_format() can access %H (or %1$H).
!    and  we no longer remove the %H reference.
!    Now pp_format_text() no longer 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,162 ----
    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.
!   */
! 
!   /*fprintf(stderr,"text_specifies_location p=<<%s>>\n", p);*/
! 
!   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 *);
!       /*DONT SKIP: text->format_spec = p + 1;*/
!       /* fprintf(stderr,"saved_ptr =%p, *text->args_ptr=%p\n",
! 	 saved_ptr, *text->args_ptr); 
!       */
!       *text->args_ptr = saved_ptr; /* restore */
        return true;
      }
  
Index: gcc/pretty-print.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.c,v
retrieving revision 2.1
diff -c -3 -p -r2.1 pretty-print.c
*** gcc/pretty-print.c	25 Jul 2003 09:52:25 -0000	2.1
--- gcc/pretty-print.c	31 Jul 2003 09:31:01 -0000
*************** Software Foundation, 59 Temple Place - S
*** 26,31 ****
--- 26,34 ----
  #include "coretypes.h"
  #include "pretty-print.h"
  
+ /* for isdigit */
+ #include <ctype.h>
+ 
  #define obstack_chunk_alloc xmalloc
  #define obstack_chunk_free  free
  
*************** pp_append_r (pretty_printer *pp, const c
*** 164,169 ****
--- 167,812 ----
    pp->buffer->line_length += length;
  }
  
+ /* 
+  ========================================
+   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.
+ */
+ 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();
+ 
+   /*   fprintf(stderr,"set_argument_type_with_precision: %d, prec=%d\n",
+        i, precision); 
+   */
+ 
+   /* First definition/reference */
+   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)
+ 
+ 
+ /*
+   Building 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. */
+ 
+   /* TODO/FIXME: this is somewhat redundant now that arg_array is made 
+      part of text_info. Or we can still use this value as the unmodified
+      format string. 
+   */
+   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.  */
+       /* CI mods. We now 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];
+ 
+ 	      /* We may be handling non-ASCII like EBCDIC where
+ 		 digit character codes are not consecutive.
+ 		 Let atoi() take care of that. */
+ 
+ 	      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 */
+ 	  /* arg_index --; */
+ 	  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 '.':  /* Original %.*s, 
+ 	              but could be %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 but `%.*s'.  */
+ 	    /* This pp_build_argument_array() is called when %n$
+ 	       specifier 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.
+ 	   * c_tree_printer in c-objc-common.c
+ 	   * cp_print in cp/error.c
+ 	   * default_tree_printer in toplev.c
+ 	   */
+ 
+ 	  /* set up for GET_ARG_TYPE */
+ 
+ 	  text->index_num = arg_index;
+ 	  text->format_after_percent_or_dollar = format;
+ 
+ 	  /* save previously seen format, if any, for checking
+ 	     incompatible double references. */
+ 	  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')
+ 	    ; 			/* It was first reference. OK */
+ 	  else 
+ 	    {
+ 	      /*
+ 		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 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 */
+ 	  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. */
+   /* fprintf(stderr, "arg_max=%d\n", arg_max); */
+ 
+   /* NOTE: we start at 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' /* HOST_WIDE_INT */ : 
+ 	  text->arg_array[i].v.hwi = va_arg (*text->args_ptr, HOST_WIDE_INT);
+ 	  break;
+ 
+ 	case 'U' /*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);
+ 	}
+ 
+     }
+ 
+   /* Now we know the type/value of arguments */
+   
+   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_append_r (pretty_printer *pp, const c
*** 179,194 ****
     %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_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 != '%')
--- 822,853 ----
     %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.
!    %[0-9]${d,i,u,o,x,...,H}
! 
! */
  void
  pp_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. */
+ 
+   /* fprintf(stderr,"pp_format_text:text->format_spec=<<%s>>\n", 
+      text->format_spec);
+   */
+ 
    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_format_text (pretty_printer *pp, text
*** 197,206 ****
--- 856,916 ----
          text->format_spec = p;
        }
  
+       /* assert:    text->format_spec == '\0'
+ 	 || text->format_spec == '%'
+       */
        if (*text->format_spec == '\0')
  	break;
  
+       /*fprintf(stderr,"loop:<<%c>>\n", *text->format_spec);*/
+ 
        /* We got a '%'.  Parse precision modifiers, if any.  */
+       /* We now need to handle [0-9] as in %1$d */
+ 
+       if(isdigit(text->format_spec[1]))
+ 	{
+ 	  if(text->format_spec[2] == '$')
+ 	    {
+ 	      char tmp[2];
+ 
+ 	      /* How about EBCDIC? */
+ 	      /* Let atoi handle the digit positions in  character set. */
+ 
+ 	      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$ as of now.\n", text);
+ 	      else 
+ 		pp_helper_abort("we have seen %d, 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_format_text (pretty_printer *pp, text
*** 217,319 ****
          default:
            break;
          }
!       /* We don't support precision behond 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 ();
  	    }
  	}
      }
  }
  
--- 927,1171 ----
          default:
            break;
          }
!       /* 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);
! 
! 
!       /*fprintf(stderr,"loop2:<<%c>>\n", *text->format_spec);*/
  
        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;
! 
! 	    if(has_processed_one <= 0)
! 	      ; /* Don't format %H if it is the first specifier. */
! 	    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 but `%.*s'.  */
! 	      /* Like this.  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 only %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 */
+ 	  /*fprintf(stderr,"text->bump_format=%d\n", text->bump_format);*/
+ 
+ 	  if(use_pos_specifier && text->bump_format > 1)
+ 	    text->format_spec += (text->bump_format - 1);
  	}
+       has_processed_one ++;
      }
  }
  
Index: gcc/pretty-print.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/pretty-print.h,v
retrieving revision 1.6
diff -c -3 -p -r1.6 pretty-print.h
*** gcc/pretty-print.h	25 Jul 2003 09:52:25 -0000	1.6
--- gcc/pretty-print.h	31 Jul 2003 09:31:02 -0000
*************** Software Foundation, 59 Temple Place - S
*** 25,30 ****
--- 25,81 ----
  #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 {
+     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;			/* assuming one pointer type */
+     char *cptr;
+     int  *iptr;
+     long *lptr;
+     long long *llptr;
+     location_t l_ptr;
+   } v;
+ }  argtype_t;
+ 
+ 
+ /* Instruct 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 ****
--- 83,100 ----
    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*/
+   int arg_max;
+   const char *format_after_percent_or_dollar;   /* for GET_ARG_TYPE, COPY_ARG_VALUE */
+   int index_num;		/* used input for arg_decode_action */
+   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
--- 139,145 ----
     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/toplev.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.814
diff -c -3 -p -r1.814 toplev.c
*** gcc/toplev.c	25 Jul 2003 09:52:26 -0000	1.814
--- gcc/toplev.c	31 Jul 2003 09:31:07 -0000
*************** init_asm_output (const char *name)
*** 4101,4125 ****
  
  /* 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
--- 4101,4210 ----
  
  /* Default tree printer.   Handles declarations only.  */
  static bool
! default_tree_printer (pretty_printer * pp, text_info *text, arg_decode_action a)
  {
! 
!   /* fprintf(stderr,"default_tree_printer: a = %d\n", a); */
! 
!   if(a == PRINT_ARG_VALUE_AS_BEFORE  /* good ole format printing. */
!      || a == PRINT_ARG_VALUE )	/* positional format specifier */
!     {
!       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 )
      {
!       if(text->index_num > 9 || text->index_num <= 0)
! 	abort();
!       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 )
!     {
!       if(text->index_num > 9 || text->index_num <= 0)
! 	abort();
!       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;
! 	}
! 
  
      }
+ #if 0
+   else if ( a == PRINT_ARG_VALUE )
+     {
+       tree t;
+ 
+ 
+       t = (tree) text->arg_array[text->index_num].v.ptr ;
+ 
+       switch (*text->format_after_percent_or_dollar)
+ 	{
+ 	case 'D':
+ 	case 'F':
+ 	case 'T':
+ 	  {
+ 	    const char *n = DECL_NAME (t)
+ 	      ? (*lang_hooks.decl_printable_name) (t, 2)
+ 	      : "<anonymous>";
+ 	    pp_string (pp, n);
+ 	    text->bump_format = 1;
+ 	  }
+ 	  return true;
+ 	default:
+ 	  return false;
+ 	}
+     }
+ #endif
+   else
+     abort();
+ 
  }
  
  /* Initialization of the front end environment, before command line
*************** toplev_main (unsigned int argc, const ch
*** 4589,4594 ****
--- 4674,4824 ----
  
    /* Initialization of GCC's environment, and diagnostics.  */
    general_init (argv[0]);
+ 
+ #if 0
+ 
+ {
+ #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=0x%08x\n", (unsigned int) &t);*/
+   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/cp/error.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.227
diff -c -3 -p -r1.227 error.c
*** gcc/cp/error.c	28 Jul 2003 11:06:28 -0000	1.227
--- gcc/cp/error.c	31 Jul 2003 09:31:11 -0000
*************** static void print_instantiation_partial_
*** 97,104 ****
  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 (pretty_printer *, int);
  static tree locate_error (const char *, va_list);
  static location_t location_of (tree);
--- 97,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 *, arg_decode_action );
  static void pp_non_consecutive_character (pretty_printer *, int);
  static tree locate_error (const char *, va_list);
  static location_t location_of (tree);
*************** print_instantiation_context (void)
*** 2424,2432 ****
     %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;
--- 2423,2434 ----
     %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
*** 2435,2472 ****
  #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_string (pp, result);
-   return true;
  #undef next_tree
  #undef next_tcode
  #undef next_lang
  #undef next_int
  }
  
  static void
--- 2437,2619 ----
  #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)
! 
! 
!   /* fprintf(stderr,"cp_printer: a =%d\n", a); */
! 
! 
!   if(a == PRINT_ARG_VALUE_AS_BEFORE /* good old printing unmodified. */
!      || 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 (next_tree, verbose);	break;
! 	case 'V': result = cv_to_string (next_tree, verbose);	break;
   
! 	default:
! 	  return false;
! 	}
! 
!       pp_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;
!     }
! #if 0
!   else if ( a == PRINT_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_after_percent_or_dollar == '#')
! 	{
! 	  verbose = 1;
! 	  ++text->format_after_percent_or_dollar;
! 	  ++text->bump_format;
! 	}
! 
!       switch (*text->format_after_percent_or_dollar)
! 	{
! 	case 'A': result = args_to_string (pos_next_tree, verbose);	break;
! 	case 'C': result = code_to_string (pos_next_tcode);	        break;
! 	case 'D': result = decl_to_string (pos_next_tree, verbose);	break;
! 	case 'E': result = expr_to_string (pos_next_tree);      	break;
! 	case 'F': result = fndecl_to_string (pos_next_tree, verbose);	break;
! 	case 'L': result = language_to_string (pos_next_lang);          break;
! 	case 'O': result = op_to_string (pos_next_tcode);       	break;
! 	case 'P': result = parm_to_string (pos_next_int);	        break;
! 	case 'Q': result = assop_to_string (pos_next_tcode);	        break;
! 	case 'T': result = type_to_string (pos_next_tree, verbose);	break;
! 	case 'V': result = cv_to_string (pos_next_tree, verbose);	break;
!  
! 	default:
! 	  return false;
! 	}
! 
!       pp_string (pp, result);
!       return true;
      }
+ #endif
+   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





-- 
int main(void){int j=2003;/*(c)2003 cishikawa. */
char t[] ="<CI> @abcdefghijklmnopqrstuvwxyz.,\n\"";
char *i ="g>qtCIuqivb,gCwe\np@.ietCIuqi\"tqkvv is>dnamz";
while(*i)((j+=strchr(t,*i++)-(int)t),(j%=sizeof t-1),
(putchar(t[j])));return 0;}/* under GPL */


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