[net.unix-wizards] need info: %r in printf

jr@fortune.UUCP (John A. Rogers) (10/12/83)

I need to port some code (from DECUS C on the RT11), which uses the "%r"
format in printf.  Of course, I've never heard of "%r", and I can't find it
in K&R, or the documentation for V7 or Sys III.  Does anyone know what it is,
and (even better) how I can simulate it using standard printf formats?
				Thanks in advance...
-- 
				John Rogers
				CompuServe: 70140,213
				Usenet: ...decvax!decwrl!amd70!fortune!jr

leichter@yale-com.UUCP (Jerry Leichter) (10/12/83)

"%r" is "Remote Format" in DECUS C; I don't know whether any other C's support
it.  Here is the relevant documentation from the DECUS C manual:

	Remote Format.  The next printf() argument is the format.  Note that
	this is not a subroutine.  The current format is not processed
	further.  For example:

		bug(args)
		{
			error("Error at %r",&args);
		}

	This routine might be called as follows:

		bug("Error %d at %s\n",val,name);

Note:  error() in DECUS C takes a printf-like argument, prints it to stderr,
then exits.  The use of "&args" is a standard hack for passing on multiple
arguments.

There is no general equivalent for %r that I know of.  You can probably get
some of the effect using the variable-number-of-arguments package.  In some
cases, you'll have to re-organize the code, perhaps to do multiple sprintf's.

BTW, the example above is rather silly, since the "bug" call shown will produce
a message of the form "Error at Error xxx at yyy".  However, the idea should
be clear...The only examples of %r I know of, as it happens, are in error
printers of this general form; in fact, I think error() itself may use %r
to call fprintf.
							-- Jerry
					decvax!yale-comix!leichter leichter@yale

guido@mcvax.UUCP (Guido van Rossum) (10/13/83)

Since %r is - as far as I know - not standard, and the stated most common
use (in general error message printers) is as easily programmed as follows:

/* VARARGS 1 */	bug(fmt, a1, a2, ..., a10) char *fmt; {
	fprintf(stderr, "Error: ");
	fprintf(stderr, fmt, a1, a2, ..., a10);
	abort();
}

it seems better if DECUS had never introduced it in the first place.
The same is true for the "well-known hack" to pass a variable number
of arguments!!!-- 
Guido van Rossum, Mathematical Centre, Amsterdam, {philabs,decvax}!mcvax!guido

eric@washu.UUCP (10/13/83)

The C-compiler at BBN allowed the %R or %r construction, but I believe
it was a local hack.  You can get the same results as follows (although
it is a bit less beautiful):

	char *ProgramName;
	warning(fmt,args)
	char *fmt;
	{

	  fprintf(stderr,"%s: (warning) ",ProgramName);
	  _doprnt(fmt, &args, stderr);		/* this is the good line */
	  return(ferror(stderr)? EOF : 0);
	
	}

On 4.1 at least, no special libs need be included.

eric
..!ihnp4!washu!eric-- 
eric
..!ihnp4!washu!eric

henry@utzoo.UUCP (Henry Spencer) (10/13/83)

The reason (well, I think the major reason) why %r has gone away in
recent years is that it is not really portable.  The trick of calling
a routine with a variable number of parameters, while the routine
declares only one parameter and invokes printf %r with the address
of that parameter, is nifty and neat but absolutely requires some
highly machine-dependent assumptions about calling sequences.  There
is no truly machine-independent way to do this trick without help from
the language, help which C does not provide.  The only thing you can
really do about it is to sprintf into a string and then pass that.
(Yes, I know, it's not as convenient.)

Please, no questions about why a machine-dependent construct like this
is in DECUS C.  Either they didn't know what they were doing, or they
didn't care (anyone using a DEC operating system obviously isn't worried
about portability anyway, right?).
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

gwyn%brl-vld@sri-unix.UUCP (10/14/83)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

printf %r was removed in UNIX System III.  If I remember right, it was
a means of embedding a format spec ((char *) corresponding to the %r
in the main format spec) within the main format spec.  One way to
do this would be to assemble the "real" format spec with sprintf into
a char buffer (maybe strcats would be easier), then use that buffer as
the printf main format spec.

If you have code that is using printf %r, you should also be alert for
use of sprintf return value as a (char *); this was also changed in
System III.

leichter@yale-com.UUCP (Jerry Leichter) (10/14/83)

"it seems better if DECUS had never introduced it in the first place."
What a remarkable statement!  According to various replies to the original
article, %r was certainly in V6, probably in V7, and may have been in System II.
The "well-known hack" is the technique used to IMPLEMENT VARARGS, so is as
current as anything.  VARARGS is also fairly recent in itself.

DECUS C goes back a ways.  At the time its printf was done, it is quite probable
that %r was "current".  Just because Unix has historically been quite cavalier
about ignoring problems of upward compatibility, do you think everyone should
be?  Hey, you commit something to a public interface and you are COMMITTED to
it; you are introducing major costs on your users if you decide you no longer
want it.

In any case, DECUS C never claimed to be 100% Unix compatible.  The compiler is
quite close to C AS DESCRIBED IN K&R - the ONLY widely available language
reference.  The library emulates a variety of Unix functions and provides
much the same functionality as the Unix library, but it is by no means identi-
cal.  MOST Unix programs move to DECUS C with little or no trouble.  MOST
DECUS C programs move to Unix in the same way.  If you want to eliminate the
"most", run on Unix.  DECUS C runs under 4 different operating systems, none
of which is particularly similar to Unix.  When these operating systems have
required some non-Unix-compatible feature to make C more useful on them, it
has found its way into DECUS C.  For example, in DECUS C the compiler allows
you to manipulate PSECT's, a concept that doesn't even exist in Unix in the
same form.  Also, when Unix's approach was just plain wrong, or when Unix
was missing something that was obviously useful, DECUS C has been willing to
say:  We will do it right - often by implementing things in a way similar to
that discussed in this very newsgroup.  (Actually, there are very few of the
former - Unix "errors" - but a good number of the latter - Unix "lacks".
For example, DECUS C's library has a function, msize(), which tells you the
size of a block returned by malloc() - after all, free() can find out, why
shouldn't the user be able to?  I wrote that one myself; you don't like it, it's
"not portable"? - fix your own system.  After all, everyone claims one of Unix'x
\\\Unix's big advantages is that if you don't like something you can change it!)
							-- Jerry
					decvax!yale-comix!leichter leichter@yale

mark@cbosgd.UUCP (Mark Horton) (10/14/83)

I think %r was in UNIX/32V (undocumented) and possibly V7.
It went away in 4BSD and was never in System III or its
precursors.

Calling _doprnt is very unportable.  In particular, System III
and V don't have _doprnt, they have _print, with slightly
different conventions.  There are also slight differences
between V7 and 32V.

The next release of System V has something called vsprintf:
	vsprintf(string, format, ap)
	char *string, *fmt;
	va_list ap;
(see varargs(3)).  This is like sprintf, except that ap is
something that can be passed through more than one layer of
function (e.g. it's normally a pointer to the first argument
in the list.) Assuming you consider System V "standard",
this will be the first documented way to do this in "standard UNIX".

In general, this is useful when you want to provide a printf-style
routine for other routines to use.  It's great for debugging and
error messages.  It's also useful when you want to provide a
subroutine package - e.g. printw in curses.

lwa%mit-csr@sri-unix.UUCP (10/15/83)

The %r format item is "recursive format".  It causes the next argument
in the argument list (which should be a string) to be interpreted as
a format string; the remainder of the arguments in the argument list
are printed according to the new format string.  Note that this isn't
really "recursive" in that the format strings aren't nested; when
the end of the new format string is reached the printf terminates.

Fortunately, this means it's pretty easy to simulate %r: just
concatenate (strcat) the original format string and the "recursive"
string and use the result as the format string to printf.
					-Larry Allen
-------

guy@rlgvax.UUCP (Guy Harris) (10/15/83)

To be precise:

	%r was in V6, and if I remember my ancient history was documented.
	%r is in PDP-11 V7 but is NOT documented.
	%r is not in PDP-11 nor VAX-11 System III nor VAX-11 4.?BSD, nor,
	   I suspect, 32V (i.e., VAX-11 V7).

I have no idea whether %r is in other V7, 4.?BSD, or System III/V
implementations, but I wouldn't count on it.  (The (mostly)-portable C
implementation of "printf" that comes with System III uses the "varargs"
include file, by the way.  If you want "varargs" *documentation*, however,
the only place I've seen it is in the 4.?BSD documentation.)

	Guy Harris
	{seismo,mcnc,we13,brl-bmd,allegra}!rlgvax!guy

henry@utzoo.UUCP (Henry Spencer) (10/16/83)

Unfortunately, Guido van Rossum's solution to the lack of %r (declaring
a whole bunch of arguments) isn't portable either.  If you call a function
declared with m arguments and pass it n arguments, m != n, the resulting
behavior is machine-dependent.  In particular, you are *not* guaranteed
that the first passed argument will show up as the first declared one.
/* VARARGS 1 */ doesn't help -- it just shuts lint up, without affecting
how the compiler deals with the situation.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

henry@utzoo.UUCP (Henry Spencer) (10/16/83)

washu!eric says:

	 "_doprnt(fmt, &args, stderr);		/* this is the good line */"

On the contrary, this is the bad, unportable, implementation-dependent
line.  If you search chapter 3 of the Unix manual, you will not find
an entry for _doprnt.  This is because it is a detail of the implementation,
not a guaranteed feature of the library.  There are Unixes that don't have
such a function.  Incidentally, the technique of passing _doprnt a whole
argument list by passing it the address of one argument is also machine-
dependent and unportable.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

gwyn%brl-vld@sri-unix.UUCP (10/22/83)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

Just for the record, you CAN get a more recent definition of C; just
buy the appropriate UNIX System V manuals.  You don't need a license.
The language is much nicer these days than it was at the time of 7th
Edition UNIX.

I obtained the DECUS C compiler and was not at all impressed with it.
To give the audience an idea of how its developers viewed C, the DECUS
compiler was WRITTEN IN MACRO-11!  Most of the emphasis in its library
support was on ways of accessing the baroque DECisms, especially bad
in the RSX-11M version.  You would think that "Software Tools" would
have had a larger impact..

gwyn%brl-vld@sri-unix.UUCP (10/23/83)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

_doprnt() came back in (at least the VAX version of) UNIX System V.
vsprintf() and friends were in UNIX System III (with one bug) but
went away in UNIX System V.  What is the "next release of UNIX System V"?
Any relation to USG 6.0?  Why can't the WECo developers make up their
mind about these things??