barb@hpfcms.UUCP (06/14/84)
There are two different source files shipped for printf with System III. One version of printf() uses doprnt. doprnt is written in vax assembly language. The second version of printf() uses _print. _print is written in C. Thus, the HP9000 series 500 and series 200 used the source for _print. The arguments to _print are _print(format, args). format is a char pointer to the format string and args is a char pointer to the list of arguments to be printed. A global variable _pfile (FILE *) must be set to the stream pointer associated with the file to be written on before calling _print. System V.2 now uses only doprnt for printf(). They ship both a vax assembly language version and a C version. The 4.0 release of the Series 500 and 2.1 release of the Series 200 (both to be released late this summer) will use System V.2 doprnt. _print and doprint are not valid user entry points and are explicitly undocumented both by HP9000 and by Bell because their interface is subject to change in future releases. Barbara Flahive, Technical Support Hewlett-Packard - Ft.Collins, CO {hplabs,ihnp4}!hpfcla!barb
toby@gargoyle.UChicago.UUCP (Toby Harness) (06/15/84)
I am moving some code from a VAX/750 (4.2bsd) to a HP9000 (mostly(!) sys III), and have discovered that in /lib/libc.a _doprnt has been replaced with _print. Is this a HP mod or standard sys III? Does anyone (hplabs??) know how _print is supposed to work (e.g. type and ordering of arguments)? We have only binary from HP on this, and of course _print isn`t documented anywhere. We do have source for 4.2bsd and v7. The problem first came up in curses, but _doprnt is also used in csh and a couple of other places I can`t recall right now. The piece of curses code in question is (from _sprintw in printw.c): ... char *fmt; int *args; { FILE junk; char buf[512]; junk._flag = _IOWRT + _IOSTRG; junk._prt = buf; junk._cnt = 32767; _doprnt(fmt, arg, &junk); ... I don`t know, but doesn`t this strike some of you as UGLY? (comments?) With a work-around that can`t handle varargs (and that I have too much self respect to post here) I have curses working just fine on the HP9000 (incl. Mark Davoren`s recent scroll fixes). If anyone (with 4.2bsd source, alas) is interrest in a "#ifdef SYSIII" version of curses, I will be happy to send it to him/her, but only *after* I get an answer about _print. Toby Harness Ogburn/Stouffer Center, University of Chicago ...inhp4!gargoyle!sam!toby
geoff@utcsstat.UUCP (Geoff Collyer) (06/16/84)
Any program that calls _doprnt (or _print or whatever) directly is *broken*. The internals of a given stdio implementation are the business of no one but its author(s) and maintainer(s). If you think you need to call _doprnt or whatever, try sprintf'ing into a buffer and passing the buffer. Many people, especially those at Berkeley, seem to think that there is only one stdio implementation, Dennis Ritchie's. It ain't so, folks. I know of one stdio implementation in progress in which *all* the internal names, including names in stdio.h that aren't documented, are different or static so as to forcibly break programs that use the internal names. Some people may think that deliberately changing the names hurts portability; on the contrary, demonstrating that broken programs really are broken is a favour to their authors. The authors can fix their programs before they reach a wider audience and are a greater embarrassment than they are today.
dave@utcsrgv.UUCP (Dave Sherman) (06/17/84)
In article <1973@utcsstat.UUCP> geoff@utcsstat.UUCP (Geoff Collyer) writes:
~| Any program that calls _doprnt (or _print or whatever) directly is
~| *broken*. The internals of a given stdio implementation are the
~| business of no one but its author(s) and maintainer(s). If you think
~| you need to call _doprnt or whatever, try sprintf'ing into a buffer and
~| passing the buffer.
~|
Geoff, you would be correct to call such programs "non-portable".
I think "broken" is going a little too far. I have some implementations
which "work" just fine.
sprintf'ing into a buffer isn't always the answer. For one, it
requires two or more lines of code for what is conceptually one
action. Secondly, it may not work for the particular need. In
my code which interposes termcap interpretation at the output
level, for example, "putc" is redefined. For this to work, _strout
(called by _doprnt which is called by printf) has to be recompiled
with "putc" #undef'ed from being a macro.
Sure it's non-portable, when I next hit a system which uses some
other stdio. When the time comes I'll make whatever trivial changes
are needed to make it run on such a system. So far I've ported it
from PDP-11 (v7) to a Perkin-Elmer 3220 and an IBM-PC running
Venix/86, and it runs like a charm. So don't tell me it's "broken".
(If you persist, I will define my programs as "written for v7 UNIX"
rather than "written for UNIX". So there.)
Dave Sherman
Toronto
--
{allegra,cornell,decvax,ihnp4,linus,utzoo}!utcsrgv!dave
stan@RICE.ARPA (06/17/84)
From: Stan Hanks <stan@RICE.ARPA> Toby, It is standard System III. AT&T finally wised up to how much software broke when they took _doprnt away, and made it come back in System V. Not that this helps you any, but..... Anyway, here's how you work this: 1) the FILE * that you are printing to is not in the arguments to _print. Instead, this goes in the external variable "_pfile". 2) the first argument to _print is the format, followed by the various arguments Therefore the "_doprnt(fmt, args, file)" becomes "_pfile = file; _print(fmt, args)" No sweat. Stan Hanks Department of Computer Science Rice University Houston TX stan@rice.ARPA (arpanet) stan@rice (csnet) ...!lbl-csam!rice!stan (uucp)
ksbszabo@wateng.UUCP (Kevin S. B. Szabo) (06/18/84)
In article <1973@utcsstat.UUCP> geoff@utcsstat.UUCP (Geoff Collyer) writes:
~| Any program that calls _doprnt (or _print or whatever) directly is
~| *broken*. The internals of a given stdio implementation are the
~| business of no one but its author(s) and maintainer(s).
And Dave Sherman replies:
~|Geoff, you would be correct to call such programs "non-portable".
~|I think "broken" is going a little too far. I have some implementations
~|which "work" just fine.
~|sprintf'ing into a buffer isn't always the answer. For one, it
~|requires two or more lines of code for what is conceptually one
~|action.
Dave, I'm sorry but I and many others (I hope), don't agree. The program
implementation is worse that unportable, it is unmaintainable. Sure,
the author can maintain it and will probably continue to keep it humming
perfectly on many systems. But if he/she ever leaves and someone has to
a) fix the code because of an internal, supposedly transparent change to stdio;
or b) port the code to a machine with a totally reworked stdio; the
maintainer will have to spend many unecessary hours trying to find all the
hidden dependancies on an undocumented internal system routine. Besides, two
lines of code is a small price to pay for clarity, portability and
*maintainability*.
All this from someone who wrote in SP-1 ESS* assembler for a year. Yuck, talk
about un-maintainable.
*SP-1 ESS (Stored Program One, Electronic Switching System. Designed by
Bell-Northern Research circa 1967. All programs in assembler, at least
100-200 thousand lines per version).
--
Kevin Szabo watmath!wateng!ksbszabo (Elec Eng, U of Waterloo)
dave@utcsrgv.UUCP (Dave Sherman) (06/18/84)
In article <1101@wateng.UUCP> ksbszabo@wateng.UUCP (Kevin S. B. Szabo) writes:
~| Dave, I'm sorry but I and many others (I hope), don't agree. The program
~| implementation is worse that unportable, it is unmaintainable. Sure,
~| the author can maintain it and will probably continue to keep it humming
~| perfectly on many systems. But if he/she ever leaves and someone has to
~| a) fix the code because of an internal, supposedly transparent change to stdio;
~| or b) port the code to a machine with a totally reworked stdio; the
~| maintainer will have to spend many unecessary hours trying to find all the
~| hidden dependancies on an undocumented internal system routine. Besides, two
~| lines of code is a small price to pay for clarity, portability and
~| *maintainability*.
Two points:
1. Good documentation will avoid the portability problems. I am clearly
documenting in my code exactly what the v7-stdio dependency is.
2. "two lines of code is a small price to pay..."? Not when two lines
would have to be used for every printf in a source file which has a
lot of printfs, escpecially during the development phase.
Dave Sherman
--
{allegra,cornell,decvax,ihnp4,linus,utzoo}!utcsrgv!dave
bob@SU-SHASTA.ARPA (06/18/84)
SHAME ON Ken Arnold and Bill Joy for making assumptions about printf's implementation. Yes, System III and System V have done away with _doprnt. I have re-written printw and wprintw to not have implementation dependencies and reproduce them here for your use. -------------------------------------------------------------------------- /* * This routine implements a printf on the standard screen. */ printw(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char *fmt; int *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10; { return wprintw(stdscr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } /* * This routine actually executes the printf and adds it to the window * This is really a modified version of "sprintf". * */ int wprintw(win, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) WINDOW *win; char *fmt; int *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10; { int rc; char buf[512]; rc = sprintf(buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); return waddstr(win, buf); } -------------------------------------------------------------------------- Bob Toxen Silicon Graphics ucbvax!Shasta!olympus!bob
geoff@utcsstat.UUCP (Geoff Collyer) (06/18/84)
Programs that rely on the internals of a given stdio implementation are certainly grossly non-portable, but more importantly they are *BROKEN*. By using _doprnt, you are assuming that there exists a function in every stdio implementation similar to _doprnt in Dennis Ritchie's implementation. If such a function exists, it may be static and thus inaccessible, but it may not even exist. Defending existing programs on the grounds that they seem to work doesn't stand up to a moment's reflection; plenty of buggy programs have appeared to work due to flukes: the v7 mv called strcat to append to an uninitialised auto char array. Such behaviour was clearly a bug and deserved to be fixed; mv was broken, not just unportable. Sometimes correct code (using sprintf) is a bit longer than incorrect code (using stdio internals). Redeclaration of putc is ``perilous'' (stdio(3S)). I fail to see why putc needs to be redefined.
toby@gargoyle.UChicago.UUCP (Toby Harness) (06/19/84)
Geoff Collyer: > Any program that calls _doprnt (or _print or whatever) directly is > *broken*. The internals of a given stdio implementation are the > business of no one but its author(s) and maintainer(s). If you think > you need to call _doprnt or whatever, try sprintf'ing into a buffer and > passing the buffer. I agree, avoiding INTERNALS (gee, what is that name supposed to imply?) like "_print or whatever" is a good thing, and I use sprintf whenever I need to print to a buffer. In fact, until I started poking through some of the unix source, it never occurred to me to make direct calls to _doprnt/_print (somehow I got it into my head that that was a no-no). But there is a difference between writting a program and maintaining it, especially when it is not your code to begin with. > Some people may think that deliberately changing the names hurts > portability; on the contrary, demonstrating that broken programs really > are broken is a favour to their authors. The authors can fix their > programs before they reach a wider audience and are a greater > embarrassment than they are today. Embarrassment? yes. My opinion of Ken Arnold (for what it`s worth) went down a notch when I uncovered that crud in _sprintw. But I doubt that "deliberately changing the names ... is a favour (sic) to their authors". Dave Sherman: > Sure it's non-portable, when I next hit a system which uses some > other stdio. When the time comes I'll make whatever trivial changes > are needed to make it run on such a system. So far I've ported it > from PDP-11 (v7) to a Perkin-Elmer 3220 and an IBM-PC running > Venix/86, and it runs like a charm. So don't tell me it's "broken". > > (If you persist, I will define my programs as "written for v7 UNIX" > rather than "written for UNIX". So there.) Dennis Ritchie (_The Standard I/O Library_): The standard I/O library was designed with the following goals in mind.... 2. It must be simple to use, and also free of the magic numbers and mysterious calls whose use mars the understandability and portability of many programs using older packages. 3. The interface provided should be applicable on all machines, whether or not the programs which implement it are directly portable to other systems, or to machines other than the PDP-11 running a version of UNIX. Toby Harness Ogburn/Stouffer Center, University of Chicago ...inhp4!gargoyle!toby
smk@axiom.UUCP (Steven M. Kramer) (06/20/84)
When I was porting some programs/packages, I ran again the _doprnt() problem in curses and other things. I wasn't lucky enough to 1) have it work OK, or 2) have it exist. What had happened was that 2 arguments in _doprnt (which was defined in both UNIX systems I was working with) were reversed. Since I never expected this and had other porting problems at the time, it took a long time to find this gem. Now, the authors of each _doprnt had every right to do their own implementation of what is essentially a part of printf. There were no standards on _doprnt, nor were there even any man pages on it or references to it (except this has changed in 4.2). ... and since there were no standards, it shouldn't have been used except as a way to implement printf. Maybe it's time in the next releases of UNIX to declare all support routines in the UNIX support libraries as static so that external references like that won't happen. -- --steve kramer {allegra,genrad,ihnp4,utzoo,philabs,uw-beaver}!linus!axiom!smk (UUCP) linus!axiom!smk@mitre-bedford (MIL)
dhb@rayssd.UUCP (06/20/84)
If you think that trying to bring up curses (or similar program which use _doprnt) is a problem on sys III, you should try bringing it up on VMS using the VAX11C compiler from DEC. Not only did they change the internals of the 'stdio' package, but they don't tell you what they are. Since we don't have source for VMS (does anybody?), I was forced to rewrite the printw routines in order to get them to work. I think that anyone who is writing code that will end up in the public domain should be careful to avoid any system dependencies. Given the fact that VMS now has a reasonably good implementation of the C compiler, more and more packages are going to start popping up on VMS machines. Most commercial outfits are already aware of this and take care to make sure their code is not system dependent (if possible). -- Dave Brierley Raytheon Co.; Portsmouth RI; (401)-847-8000 x4073 ...!decvax!brunix!rayssd!dhb ...!allegra!rayssd!dhb ...!linus!rayssd!dhb
rcc@imsvax.UUCP (06/21/84)
If you're adamant about speed, efficiency, etc., then do what ex does, don't use stdio. However, if you're going to use stdio, then you should *not* use any undocumented/internal routines and claim that the program is portable, even if you document the fact that you used them. Documenting that your program is dependent on multiplexed files doesn't make it portable if a system doesn't have multiplexed files (at least, not without some work). Either include your own stdio in the program that works, or play by the rules. Doing otherwise guarantees that your program will break. The only question is when. -- The preceding message was brought to you by -- Ray Chen UUCP: umcp-cs!eneevax!imsvax!rcc (NEW ADDRESS) Voice: (301) 984-8343 USnail: Integrated Microcomputer Systems, Inc. Suite 400 6100 Executive Blvd. Rockville, MD 20852
henry@utzoo.UUCP (Henry Spencer) (06/21/84)
Alas, Bob Toxen's rewrites of printw and wprintw continue to have implementation dependencies: the declare-lots-of-arguments trick depends on the stack frame being organized a certain way. Before we get started on a big discussion about varargs functions, let me point out that this was discussed at excruciating length a few months ago (possibly in another newsgroup, I forget), and the conclusion was quite simple: There is *no* fully machine-independent way to write a function which takes a variable number of arguments, even if all the function is trying to do is to pass its argument list on to another function. Not even the varargs.h machinery is workable on all machines, and the various more simplistic schemes are much less portable. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
hansen@pegasus.UUCP (Tony L. Hansen) (06/22/84)
> > It is standard System III. AT&T finally wised up to how much software > > broke when they took _doprnt away, and made it come back in System V. > Well, I looked, and "_doprnt" is back; in S5R2, they also provide the > "vprintf", "vfprintf", and "vsprintf" interfaces that were in S3 as > distributed (and which can be used instead of "_doprnt"), but were > ripped out of S5. "_doprnt" is, alas, not in every implementation of > standard I/O, so software which uses it will still break under some > implementations. Still wrong! _doprnt() is only in SOME versions of System V. I have worked with at least three different System V machines that did NOT have _doprnt() in their libc. Nor did they have _print(). The Vax version of System V DOES have _doprnt() in it for System V, but don't count on it being there forever. How to get around it? We've made extensive use of a C version of _doprnt(), as well as the v*printf() family. There is a version of v*printf() which works with _doprnt(). (Our curses uses vsprintf().) In System Vr2, v*printf() is implemented as a supported part of the stdio package and uses whatever underlying mechanism the rest of stdio uses. I wish BSD had picked up the v*printf() functions rather than documenting the _doprnt() routine. Re-implementing v*printf() would be a 15 minute job for someone who knows _doprnt() well. Tony Hansen pegasus!hansen
guy@rlgvax.UUCP (Guy Harris) (06/23/84)
> Gee guys ... I wouild like to see you implement something > like printw *correctly* without calling _doprnt. I do NOT > consider limiting the number of format items to 10 (or any > other upper limit) a correct implementation. Unfortunately, on some systems you can't implement "printw" correctly by calling "_doprnt", because it doesn't exist; on other systems, I believe "_doprnt" may have a different calling sequence than the "standard" one. True, the other implementations don't work in the general case, but it's a choice between one that works with *most* C implementations (there probably isn't one that works on *all* implementations) but has limitations, vs. one that works only on some C/"stdio" implementations but doesn't have those limitations. > However (and here's the kicker), _doprnt IS documented > in 4.2BSD!!! Look at the manual page for printf(3S) if you > doubt me. ... I don't have Sys III documentation in front of me, > but, is _print documented in Sys III? I suspect that it is. "_print" isn't documented in System III. "vprintf", "vfprintf", and "vsprintf", unfortunately, aren't documented either; they were intended to be the "visible" hook for routines that need things like "_doprnt". System V doesn't document them, but that's because they were removed. System V Release 2 put them back in, *and* put "_doprnt" back in, and documented the "vprintf" family (although *not* "_doprnt"): NAME vprintf, vfprintf, vsprintf - print formatted output of a varargs argument list SYNOPSIS #include <stdio.h> #include <varargs.h> int vprintf (format, ap) char *format; va_list ap; int vfprintf (stream, format, ap) FILE *stream; char *format; va_list ap; int vsprintf (s, format, ap) char *s, *format; va_list ap; DESCRIPTION vprintf, vfprintf, and vsprintf are the same as printf, fprintf, and sprintf respectively, except that instead of being called with a variable number of arguments, they are called with an argument list as defined by varargs(5). EXAMPLE The following demonstrates how vfprintf could be used to write an error routine. #include <stdio.h> #include <varargs.h> . . . /* * error should be called like * error(function_name, format, arg1, arg2...); */ /*VARARGS0*/ void error(va_alist) /* Note that the function_name and format arguments cannot be * separately declared because of the definition of varargs. */ va_dcl { va_list args; char *fmt; va_start(args); /* print out name of function causing error */ (void)fprintf(stderr, "ERROR in %s: ", va_arg(args, char *)); fmt = va_arg(args, char *); /* print out remainder of message */ (void)vfprintf(fmt, args); va_end(args); (void)abort( ); } Unfortunately, this still doesn't give a portable way (even between "similar" C implementations) for doing "printw"-like functions. You have: PDP-11 V7 - use "_doprnt". Other V7 - try using "_doprnt", and hope that it exists and has the same implementation. 4.xBSD - use "_doprnt". System III (PDP-11, VAX-11, and other ones that adopted one or the other of those implementations) - use "v*printf". System V - suffer, unless they revived "_doprnt". System V Release 2 (VAX-11 and other ones that adopted that implementation, and possibly PDP-11 as well) - use "v*printf" (the preferred, clean way; it's compatible with System III) or "_doprnt" (if you want to be compatible with one using a compatible "_doprnt" which doesn't provide "v*printf". Guy Harris {seismo,ihnp4,allegra}!rlgvax!guy
guy@rlgvax.UUCP (Guy Harris) (06/26/84)
> It is standard System III. AT&T finally wised up to how much software > broke when they took _doprnt away, and made it come back in System V. > Not that this helps you any, but..... Well, I looked, and "_doprnt" is back; in S5R2, they also provide the "vprintf", "vfprintf", and "vsprintf" interfaces that were in S3 as distributed (and which can be used instead of "_doprnt"), but were ripped out of S5. "_doprnt" is, alas, not in every implementation of standard I/O, so software which uses it will still break under some implementations. Alas, there is no portable way to write routines which take "printf"-like call interfaces; neither "v*printf" nor "_doprnt" are guaranteed to be there ("v*printf" were in the distributed S3, but not documented). Guy Harris {seismo,ihnp4,allegra}!rlgvax!guy
rcd@opus.UUCP (Dick Dunn) (06/27/84)
Dave Sherman is defending his use of the internal functions _print/_doprint in his code: >1. Good documentation will avoid the portability problems. I am clearly >documenting in my code exactly what the v7-stdio dependency is. How many times have I overheard someone discussing a disastrous bug when some gadfly comes up, cackles "So document it and call it a feature!" and goes laughing off into the distance. Documentation doesn't avoid the portability problems, it only points out where they are. Well-documented bad practice is still bad practice. >2. "two lines of code is a small price to pay..."? Not when two lines >would have to be used for every printf in a source file which has a >lot of printfs, escpecially during the development phase. So use a procedure or a macro to encapsulate the two lines. That should be obvious - performance, to the tune of an extra procedure call or so, is hardly an issue when printf is at the business end. I think (hope) that the effect of this discussion will be to convince Dave that what he's doing is "bad practice" such as the collective conscience of the net might define it. -- Dick Dunn {hao,ucbvax,allegra}!nbires!rcd (303)444-5710 x3086 ...Cerebus for dictator!
hansen@pegasus.UUCP (Tony L. Hansen) (07/06/84)
Golly, no one bit after two weeks. > Gee guys ... I wouild like to see you implement something > like printw *correctly* without calling _doprnt. I do NOT > consider limiting the number of format items to 10 (or any > other upper limit) a correct implementation. I'd be glad to, using the v*printf() facility now fully documented and supported as part of System Vr2: #include <stdio.h> #include <varargs.h> printw (va_alist) va_dcl { va_list ap; WINDOW *win; char *fmt; char buffer[BUFSIZ]; va_start(ap); win = va_arg(ap, WINDOW *); fmt = va_arg(ap,char *); vsprintf(buffer, fmt, ap); va_end(ap); return waddstr(win,buffer); } I think that that's as portable an implementation as you're going to get, assuming that you have varargs.h on your system, modulo Henry Spencer's comments on varargs.h: > Not even the varargs.h machinery is workable on all machines, and > the various more simplistic schemes are much less portable. The REAL kicker is that you need vsprintf(). In System Vr2, it is implemented using _doprnt on the Vaxen, using an assembly language routine (not called _doprnt) on the AT&T 3b20, and I don't know what else on the other machines that System Vr2 is available on. The point is that is to be implemented using whatever underlying mechanism is available for the rest of your stdio implementation. So, if you don't have v*printf() on your system, here is a version of vsprintf() that should work with the _doprnt() that comes with 4.xBSD, V7 and System V, rewritten from some public domain software that I had lying around: #include <stdio.h> #ifdef BSD # define MAXINT 32767 #else # include <values.h> #endif BSD #include <varargs.h> vsprintf(buffer, fmt, ap) char *buffer, *fmt; va_list ap; { FILE temp; int count; extern int _doprnt(); temp._cnt = MAXINT; #ifdef BSD temp._flag = _IOSTRG | _IOWRT; temp._ptr = buffer; #else temp._base = temp._ptr = (unsigned char *) buffer; temp._flag = _IOWRT; #endif BSD temp._file = _NFILE; count = _doprnt(fmt, ap, &temp); *temp._ptr = '\0'; return count; } It shouldn't be too hard to rewrite the above to use _print() or whatever other internal mechanism your stdio happens to use. Vprintf() and vfprintf() are left as an exercize for the reader. (Does anyone want to do a completely public domain version for the record?) There is now no excuse for anyone to have to reinvent the wheel as long as people start providing the v*printf() facilities along with the rest of their stdio implementations. Tony Hansen pegasus!hansen