Xref: utzoo comp.sources.wanted:17326 alt.sources.wanted:1400 comp.lang.c:40616 Path: utzoo!utgpu!cs.utexas.edu!qt.cs.utexas.edu!zaphod.mps.ohio-state.edu!usc!apple!well!jef From: jef@well.sf.ca.us (Jef Poskanzer) Newsgroups: comp.sources.wanted,alt.sources.wanted,comp.lang.c Subject: Re: Portable mini-vfprintf? Message-ID: <25787@well.sf.ca.us> Date: 30 Jun 91 03:11:46 GMT References: <14814@dog.ee.lbl.gov> Reply-To: Jef Poskanzer Organization: Acme Software Lines: 154 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*/