I found that it would be a real easement to have the "%r" conversion for
printf() in the POSIX standard.
This is something that exists for a long time:
- DECUS C implemented this via 'goto' (so it has been non-return
recursive) - the old format string behind %r was ignored.
- UNOS a UNIX clone implemented this in 1981
- I implemented this in my own portable printf() in the mid 1980s
from the idea found on UNOS.
I don't know where this really belongs to, so I just send it to you for a
private discussion about it's future.
/*--------------------------------------------------------------------------*/
PROPOSAL for a new printf format conversion specifier '%r':
%r Recursive or remote format.
This format conversion takes two arguments: a format string and
a va_list type argument. The first parameter is the format string
and may contain any valid format conversions defined with printf().
The second argument is of type va_list and obtained via va_start().
The new format string is formatted and put out in place of the %r.
The field width and precision specification is ignored for the %r
format. The recursive format makes it possible to write variable arg
printing routines without using v*printf(3) directly. This allows to
amongst others to write layered error printing routines.
USAGE EXAMPLE:
#include <stdio.h>
#include <stdarg.h>
int
my_error(const char *fmt, ...)
{
va_list args;
int ret;
va_start(args, fmt);
ret = fprintf(stderr, "The following error orrured: '%r'.",
fmt, args);
va_end(args);
return (ret);
}
Internal implementation example:
char *rfmt;
case 'r': /* recursive printf */
rfmt = va_arg(args, char *);
/*
* I don't know any portable way to get an arbitrary
* C object from a var arg list so I use a
* system-specific routine __va_arg_list() that knows
* if 'va_list' is an array. You will not be able to
* assign the value of __va_arg_list() but it works
* to be used as an argument of a function.
* It is a requirement for recursive printf to be able
* to use this function argument. If your system
* defines va_list to be an array you need to know this
* via autoconf or another mechanism.
* It would be nice to have something like
* __va_arg_list() in stdarg.h
*/
count += format(fun, farg, rfmt, __va_arg_list(args));
continue;
You need:
#ifdef VA_LIST_IS_ARRAY
# define __va_arg_list(list) va_arg(list, void *)
#else
# define __va_arg_list(list) va_arg(list, va_list)
#endif
RATIONALE:
The %r format has been successfully implemented and used on the following
platforms:
Alpha, MP-PA, MC-68xxx, Sparc, Intel-x86, Intel-IA64, MIPS, IBM-S390,
StrongARM
The problem is that the official Power PC standard for var arg lists defines an
"array"
type for va_list and you cannot assign objects of type "array".
I implemented it the way shown above by defining a macro that fetches the
apropriate
object from the var arg list. My macro only allows to fetch the argument from
the list
and use it as function argument.
If the printf() implementation needs to implement the '%n$' type conversion,
then
a macro is needed that allows to fetch an va_list type arg and assign it to a
variable
of type "va_list". As both, my va_arg_list() macro and the C-99 macro va_copy()
have
been prooved to work for all platforms, it would be possible to also write a
macro that
fetches a va_list and assigns it.
It could be called va_arg_list_copy(to, list). An implementation for the
non-array
case could look this way:
#define va_arg_list_copy(to, list) ((to) = va_arg(list, va_list))
an implementation for the array case for the PPC could look similar to this:
#define va_arg_list_copy(to, list) ((to)[0] = ((va_list)va_arg(list, void
*))[0])
Best regards
Jörg
--
EMail:yyyyy@xxxxxxxxxxxxxxxxxxxxxxxxxxx (home) Jörg Schilling D-13353 Berlin
yy@xxxxxxxxxxxxxxx (uni) If you don't have iso-8859-1
yyyyyyyyy@xxxxxxxxxxxxxxxxxxx (work) chars I am J"org Schilling
URL: http://www.fokus.fraunhofer.de/usr/schilling
ftp://ftp.berlios.de/pub/schily
|