home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume29
/
parseargs
/
part03
/
vprintf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-19
|
8KB
|
353 lines
/* Portable vsprintf by Robert A. Larson <blarson@skat.usc.edu> */
/* Copyright 1989 Robert A. Larson.
* Distribution in any form is allowed as long as the author
* retains credit, changes are noted by their author and the
* copyright message remains intact. This program comes as-is
* with no warentee of fitness for any purpose.
*
* Thanks to Doug Gwyn, Chris Torek, and others who helped clarify
* the ansi printf specs.
*
* Please send any bug fixes and improvements to blarson@skat.usc.edu .
* The use of goto is NOT a bug.
*/
/* Feb 7, 1989 blarson First usenet release */
/* Oct 20, 1990 Brad Appleton -- enclosed in #ifdef BSD for parseargs */
/* Oct 21, 1990 Brad Appleton -- added test in #ifdef VPRINTF_TEST */
/* Feb 25, 1990 Brad Appleton -- #included "useful.h" and added #ifdefs
* to compile for ANSI-C as well as K&R
*/
/* This code implements the vsprintf function, without relying on
* the existance of _doprint or other system specific code.
*
* Define NOVOID if void * is not a supported type.
*
* Two compile options are available for efficency:
* INTSPRINTF should be defined if sprintf is int and returns
* the number of chacters formated.
* LONGINT should be defined if sizeof(long) == sizeof(int)
*
* They only make the code smaller and faster, they need not be
* defined.
*
* UNSIGNEDSPECIAL should be defined if unsigned is treated differently
* than int in argument passing. If this is definded, and LONGINT is not,
* the compiler must support the type unsingned long.
*
* Most quirks and bugs of the available sprintf fuction are duplicated,
* however * in the width and precision fields will work correctly
* even if sprintf does not support this, as will the n format.
*
* Bad format strings, or those with very long width and precision
* fields (including expanded * fields) will cause undesired results.
*/
/* Parseargs only needs this stuff for BSD Unix -- Brad Appleton */
#include <useful.h>
#ifdef BSD
#include <stdio.h>
#include <ctype.h>
#ifdef OSK /* os9/68k can take advantage of both */
# define LONGINT
# define INTSPRINTF
#endif
/* This must be a typedef not a #define! */
#ifdef NOVOID
typedef char *pointer;
#else
typedef void *pointer;
#endif
#ifdef INTSPRINTF
# define Sprintf(string,format,arg) (sprintf((string),(format),(arg)))
#else
# define Sprintf(string,format,arg) (\
sprintf((string),(format),(arg)),\
strlen(string)\
)
#endif
typedef int *intp;
#ifdef __ANSI_C__
int vsprintf(char *dest, register const char *format, va_list args)
#else
int vsprintf(dest, format, args)
char *dest;
register char *format;
va_list args;
#endif
{
register char *dp = dest;
register char c;
register char *tp;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
tempfmt[0] = '%';
while( (c = *format++) != 0) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch(c = *format++) {
case 's':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, VA_ARG(args, char *));
break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned long));
else
#endif
dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, VA_ARG(args, long));
else
#endif
dp += Sprintf(dp, tempfmt, VA_ARG(args, int));
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, VA_ARG(args, double));
break;
case 'p':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, VA_ARG(args, pointer));
break;
case '-':
case '+':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ' ':
case '#':
case 'h':
*tp++ = c;
goto continue_format;
case 'l':
#ifndef LONGINT
longflag = 1;
*tp++ = c;
#endif
goto continue_format;
case '*':
tp += Sprintf(tp, "%d", VA_ARG(args, int));
goto continue_format;
case 'n':
*VA_ARG(args, intp) = dp - dest;
break;
case '%':
default:
*dp++ = c;
break;
}
} else *dp++ = c;
}
*dp = '\0';
return dp - dest;
}
#ifdef __ANSI_C__
int vfprintf(FILE *dest, register const char *format, va_list args)
#else
int vfprintf(dest, format, args)
FILE *dest;
register char *format;
va_list args;
#endif
{
register char c;
register char *tp;
register int count = 0;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
tempfmt[0] = '%';
while(c = *format++) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch(c = *format++) {
case 's':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, VA_ARG(args, char *));
break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, VA_ARG(args, unsigned long));
else
#endif
count += fprintf(dest, tempfmt, VA_ARG(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, VA_ARG(args, long));
else
#endif
count += fprintf(dest, tempfmt, VA_ARG(args, int));
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, VA_ARG(args, double));
break;
case 'p':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, VA_ARG(args, pointer));
break;
case '-':
case '+':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ' ':
case '#':
case 'h':
*tp++ = c;
goto continue_format;
case 'l':
#ifndef LONGINT
longflag = 1;
*tp++ = c;
#endif
goto continue_format;
case '*':
tp += Sprintf(tp, "%d", VA_ARG(args, int));
goto continue_format;
case 'n':
*VA_ARG(args, intp) = count;
break;
case '%':
default:
putc(c, dest);
count++;
break;
}
} else {
putc(c, dest);
count++;
}
}
return count;
}
#ifdef __ANSI_C__
int vprintf(const char *format, va_list args)
#else
int vprintf(format, args)
char *format;
va_list args;
#endif
{
return vfprintf(stdout, format, args);
}
#endif /* BSD Unix ONLY */
/* use a VERY SIMPLE test case to test this out -- Brad Appleton */
#ifdef VPRINTF_TEST
/*VARARGS1*/
#ifdef __ANSI_C__
int vtest( char *fmt, ... )
#else
int vtest( fmt, va_alist )
char *fmt;
va_dcl
#endif
{
va_list ap;
int rc;
VA_START(ap, fmt);
rc = vprintf( fmt, ap );
VA_END(ap);
return rc;
}
void main()
{
printf( "its a %s %% day in the %d neighborhood for %*s\n",
"pitiful", 4, 8, "fun" );
vtest( "its a %s %% day in the %d neighborhood for %*s\n",
"pitiful", 4, 8, "fun" );
}
#endif /* VPRINTF_TEST */