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
notes@fortune.UUCP (10/12/83)
#R:fortune:-158700:fortune:16200007:000:412 fortune!olson Oct 11 19:57:00 1983 John, you are out of luck on this one. %r was a beautiful kludge which was undocumented, and went away with post V7 releases. What it did was allow you to pass a char ** to printf. printf then took the rest of the format and arguments from that pointer. This was wonderful for doing a common debug/error function. It went away ..... By the way, anything following the %r in the format was totally ignored
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