Portable mini-vfprintf?
Jef Poskanzer
jef at well.sf.ca.us
Sun Jun 30 13:11:46 AEST 1991
In the referenced message, torek at 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 at 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*/
More information about the Comp.lang.c
mailing list