jef@well.sf.ca.us (Jef Poskanzer) (06/29/91)
I have this large software package, pbmplus, which I would like to be
as portable as possible. It has a unified message and error routine
called pm_message, which really ought to be a varargs routine. The
problem is doing this portably. I can deal with varargs.h vs. stdarg.h
easily enough, but what about the substantial minority of systems out
there which don't have vfprintf?
The proposed skeleton of the portable version is appended. If you can
think of a way to do this without needing to supply a vfprintf, I'd
love to hear about it. Otherwise, do you have a vfprintf lying around?
---
Jef
Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef
"Swell."
#if __STDC__
static void
pm_message( char* fmt, ... )
{
va_list ap;
va_start( ap, fmt );
#else /*__STDC__*/
/*VARARGS1*/
static void
pm_message( va_alist )
va_dcl
{
va_list ap;
char* fmt;
va_start(ap);
fmt = va_arg( ap, char* );
#endif /*__STDC__*/
(void) vfprintf( stderr, fmt, ap );
va_end( ap );
}
#ifdef NEED_VFPRINTF
/* portable mini-vfprintf goes here */
#endif /*NEED_VFPRINTF*/
jef@well.sf.ca.us (Jef Poskanzer) (06/29/91)
In the referenced message, jef@well.sf.ca.us (Jef Poskanzer) wrote:
}do you have a vfprintf lying around?
Thanks to a prompt mail responder, I found a mini-printf in the version
of tcsh on uunet. I'm still interested in opinions on whether this is
the right solution.
---
Jef
Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef
"The great tragedy of Science - the slaying of a beautiful hypothesis
by an ugly fact." -- Thomas Henry Huxley
jef@well.sf.ca.us (Jef Poskanzer) (06/30/91)
To support floating-point output in the mini-vfprintf, I added a call to gcvt. How portable is this? Chris Torek suggested I just call _doprnt instead of vfprintf - same args, different order. How portable is this? People have gotten the current version of pbmplus working under VMS and MS-DOS, and I don't want to lose that. --- Jef Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef
torek@elf.ee.lbl.gov (Chris Torek) (06/30/91)
In article <25777@well.sf.ca.us> Jef Poskanzer <jef@well.sf.ca.us> writes: >To support floating-point output in the mini-vfprintf, I added a call >to gcvt. How portable is this? Not. >Chris Torek suggested I just call _doprnt instead of vfprintf - same >args, different order. How portable is this? Also not. Let me clarify a bit: I suggested using vfprintf where it exists, and where it does not, falling back on _doprnt. Most `supported' systems have at least the ANSI C libraries (if not the syntaxes), and most `unsupported' C systems seem to be aging Unix systems. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
jef@well.sf.ca.us (Jef Poskanzer) (06/30/91)
In the referenced message, torek@elf.ee.lbl.gov (Chris Torek) wrote: }Let me clarify a bit: I suggested using vfprintf where it }exists, and where it does not, falling back on _doprnt. Yeah, my current version has two fallbacks. If you get a link error on vfprintf, you define NEED_VFPRINTF1, which gives you a vfprintf that just calls _doprnt. If you then get a link error on _doprnt, you define NEED_VFPRINTF2 and you get the portable mini-vfprintf. To avoid using gcvt, how about writing vfprintf in terms of fprintf? Have it parse the format string into individual format specifiers, do the appropriate va_arg call, and then fprintf each arg individually. It would be silly to organize a general-purpose stdio that way, but it's also silly to not have vfprintf. Fight silly with silly! Code appended. --- Jef Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef WCBG: All Elvis, All The Time #ifdef NEED_VFPRINTF1 /* Micro-vfprintf, for systems that don't have vfprintf but do have _doprnt. */ int vfprintf( stream, format, args ) FILE* stream; char* format; va_list args; { return _doprnt( format, args, stream ); } #endif /*NEED_VFPRINTF1*/ #ifndef NEED_VFPRINTF2 /* Portable mini-vfprintf, for systems that don't have either vfprintf or ** _doprnt. This depends only on fprintf. If you don't have fprintf, ** you might consider getting a new stdio library. */ int vfprintf( stream, format, args ) FILE* stream; char* format; va_list args; { char* ep; char fchar; char tformat[512]; int do_long; int i; long l; unsigned long ul; char* s; double d; while ( *format != '\0' ) { if ( *format != '%' ) { /* Not special, just write out the char. */ putc( *format, stream ); ++format; } else { do_long = 0; ep = format + 1; /* Skip over all the field width and precision junk. */ if ( *ep == '-' ) ++ep; if ( *ep == '0' ) ++ep; while ( isdigit( *ep ) ) ++ep; if ( *ep == '.' ) { ++ep; while ( isdigit( *ep ) ) ++ep; } if ( *ep == '#' ) ++ep; if ( *ep == 'l' ) { do_long = 1; ++ep; } /* Here's the field type. Extract it, and copy this format ** specifier to a temp string so we can add an end-of-string. */ fchar = *ep; (void) strncpy( tformat, format, ep - format + 1 ); tformat[ep - format + 1] = '\0'; /* Now do a one-argument fprintf with the format string we have ** isolated. */ switch ( fchar ) { case 'd': if ( do_long ) l = va_arg( args, long ); else l = (long) ( va_arg( args, int ) ); (void) fprintf( stream, tformat, l ); break; case 'o': case 'x': case 'u': if ( do_long ) ul = va_arg( args, unsigned long ); else ul = (unsigned long) ( va_arg( args, unsigned ) ); (void) fprintf( stream, tformat, ul ); break; case 'c': i = (char) va_arg( args, int ); (void) fprintf( stream, tformat, i ); break; case 's': s = va_arg( args, char* ); (void) fprintf( stream, tformat, s ); break; case 'e': case 'f': case 'g': d = va_arg( args, double ); (void) fprintf( stream, tformat, d ); break; case '%': putc( '%', stream ); break; default: return -1; } /* Resume formatting on the next character. */ format = ep + 1; } } return 0; } #endif /*NEED_VFPRINTF2*/
jef@well.sf.ca.us (Jef Poskanzer) (06/30/91)
In the referenced message, Jef Poskanzer <jef@well.sf.ca.us> wrote:
}#ifndef NEED_VFPRINTF2
Obviously this should be ifdef. I had it set the opposite way for testing.
---
Jef
Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef
"Lots of women. All Romulan women." -- William Shatner
jef@well.sf.ca.us (Jef Poskanzer) (06/30/91)
Also, this:
} return _doprnt( format, args, stream );
should, I am informed, be more like this:
#ifdef BSD
return _doprnt( format, &args, stream );
#else /*BSD*/
return _doprnt( format, args, stream );
#endif /*BSD*/
Hmm, I didn't realize there were alternate versions of _doprnt kicking around.
Maybe I shouldn't bother with the _doprnt version at all.
---
Jef
Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef
Speak softly and carry a terawatt laser.
mycroft@kropotki.gnu.ai.mit.edu (Charles Hannum) (07/01/91)
In article <25767@well.sf.ca.us> jef@well.sf.ca.us (Jef Poskanzer) writes: > I have this large software package, pbmplus, which I would like to be > as portable as possible. It has a unified message and error routine > called pm_message, which really ought to be a varargs routine. The > problem is doing this portably. I can deal with varargs.h vs. stdarg.h > easily enough, but what about the substantial minority of systems out > there which don't have vfprintf? This is one of my arguments for varargs in macros. Wouldn't it be so nice to: #define pm_message(f,x,...) fprintf( stderr, f, ...) Opinions welcome, flames ignored.