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

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.

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