egcs, REVIEW FOR SUBMISSION, vfprintf.c ...
Kaveh R. Ghazi
ghazi@caip.rutgers.edu
Thu Apr 2 11:32:00 GMT 1998
Here is my first cut at a vfprintf.c for platforms with
stdarg/varargs but no vfprintf() function. It fakes things by parsing
the format specifier string, pulling args and printing using fprintf.
I hacked it up using parts of libiberty/vasprintf.c and some RTFM.
Its currently meant to live in the gcc directory of egcs since
I'm not ready to tackle libiberty. But it could easily live in the
libiberty directory with only a couple of changes in whcih include
files it gets.
I'd like it if people more familiar with the exact conformant
behavior of vfprintf() would look at it to make sure I got it right.
I'm especially unsure of the 'h' flag's meaning.
You can use -DTEST to do build a runnable self testing
program. I compiled it like this out of the gcc dir:
> stage2/xgcc -DTEST -Bstage2/ -DMAIN -DIN_GCC -DSVR4 -W -Wall -O2 -g
> -DHAVE_CONFIG_H -I. -I. -I./config vfprintf.c
--Kaveh
-----cut-here-----
/* Provide a version vfprintf in terms of fprintf.
By Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98
Copyright (C) 1998 Free Software Foundation, Inc.
*/
#include "config.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "system.h"
#include "gansidecl.h"
#ifdef TEST /* Make sure to use the internal one. */
#define vfprintf my_vfprintf
#endif
#define COPY_VA_INT \
do { \
const int value = abs (va_arg (ap, int)); \
char buf[32]; \
ptr++; /* Go past the asterisk. */ \
*sptr = '\0'; /* NULL terminate sptr. */ \
sprintf(buf, "%d", value); \
strcat(sptr, buf); \
while (*sptr) sptr++; \
} while (0)
#define PRINT_CHAR(CHAR) \
do { \
putc(CHAR, stream); \
ptr++; \
total_printed++; \
continue; \
} while (0)
#define PRINT_TYPE(TYPE) \
do { \
int result; \
TYPE value = va_arg (ap, TYPE); \
*sptr++ = *ptr++; /* Copy the type specifier. */ \
*sptr = '\0'; /* NULL terminate sptr. */ \
result = fprintf(stream, specifier, value); \
if (result == -1) \
return -1; \
else \
{ \
total_printed += result; \
continue; \
} \
} while (0)
int
vfprintf (stream, format, ap)
FILE * stream;
const char * format;
va_list ap;
{
#ifdef HAVE_DOPRNT
return _doprnt (format, ap, stream);
#else /* ! HAVE_DOPRNT */
const char * ptr = format;
char specifier[128];
int total_printed = 0;
while (*ptr != '\0')
{
if (*ptr != '%') /* While we have regular characters, print them. */
PRINT_CHAR(*ptr);
else /* We got a format specifier! */
{
char * sptr = specifier;
int long_width = 0, short_width = 0, double_width = 0;
*sptr++ = *ptr++; /* Copy the % and move forward. */
while (strchr ("-+ #0", *ptr)) /* Move past flags. */
*sptr++ = *ptr++;
if (*ptr == '*')
COPY_VA_INT;
else
while (isdigit(*ptr)) /* Handle explicit numeric value. */
*sptr++ = *ptr++;
if (*ptr == '.')
{
*sptr++ = *ptr++; /* Copy and go past the period. */
if (*ptr == '*')
COPY_VA_INT;
else
while (isdigit(*ptr)) /* Handle explicit numeric value. */
*sptr++ = *ptr++;
}
while (strchr ("hlL", *ptr))
{
switch (*ptr)
{
case 'h':
short_width = 1;
break;
case 'l':
long_width++;
break;
case 'L':
double_width = 1;
break;
default:
abort();
}
*sptr++ = *ptr++;
}
switch (*ptr)
{
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
case 'c':
{
if (short_width)
PRINT_TYPE(short);
else
{
switch (long_width)
{
case 0:
PRINT_TYPE(int);
break;
case 1:
PRINT_TYPE(long);
break;
case 2:
#if defined(__GNUC__) || defined(HAVE_LONG_LONG)
PRINT_TYPE(long long);
#else
PRINT_TYPE(long); /* Fake it and hope for the best. */
#endif
break;
default:
abort();
} /* End of switch (int_width) */
} /* End of else statement */
} /* End of integer case */
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
{
if (double_width == 0)
PRINT_TYPE(double);
else
{
#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
PRINT_TYPE(long double);
#else
PRINT_TYPE(double); /* Fake it and hope for the best. */
#endif
}
}
break;
case 's':
PRINT_TYPE(char *);
break;
case 'p':
PRINT_TYPE(void *);
break;
case '%':
PRINT_CHAR('%');
break;
default:
abort();
} /* End of switch (*ptr) */
} /* End of else statement */
}
return total_printed;
#endif /* HAVE_DOPRNT */
}
#ifdef TEST
#include <math.h>
#ifndef M_PI
#define M_PI (3.1415926535897932385)
#endif
#define RESULT(x) printf ("printed %d characters\n", (x));
#ifndef PRINTF_ATTRIBUTE
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define PRINTF_ATTRIBUTE(m, n)
# else
# define PRINTF_ATTRIBUTE(m, n) __attribute__ ((format (__printf__, m, n)))
# endif
#endif
#define PRINTF_ATTRIBUTE_1 PRINTF_ATTRIBUTE(1, 2)
#define PRINTF_ATTRIBUTE_2 PRINTF_ATTRIBUTE(2, 3)
#define PRINTF_ATTRIBUTE_3 PRINTF_ATTRIBUTE(3, 4)
static int checkit PVPROTO ((const char * format, ...)) PRINTF_ATTRIBUTE_1;
static int
checkit VPROTO ((const char* format, ...))
{
va_list args;
int result;
#ifndef __STDC__
char *format;
#endif
VA_START (args, format);
#ifndef __STDC__
format = va_arg (args, char *);
#endif
result = vfprintf(stdout, format, args);
va_end(args);
return result;
}
int
main ()
{
RESULT(checkit ("<%d>\n", 0x12345678));
RESULT(printf ("<%d>\n", 0x12345678));
RESULT(checkit ("<%200d>\n", 5));
RESULT(printf ("<%200d>\n", 5));
RESULT(checkit ("<%.300d>\n", 6));
RESULT(printf ("<%.300d>\n", 6));
RESULT(checkit ("<%100.150d>\n", 7));
RESULT(printf ("<%100.150d>\n", 7));
RESULT(checkit ("<%s>\n",
"jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
777777777777777777333333333333366666666666622222222222777777777777733333"));
RESULT(printf ("<%s>\n",
"jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
777777777777777777333333333333366666666666622222222222777777777777733333"));
RESULT(checkit ("<%f%s%d%s>\n",
1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
RESULT(printf ("<%f%s%d%s>\n",
1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
75, 75, 75, 75, 75, 75, 75));
RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
75, 75, 75, 75, 75, 75, 75));
RESULT(checkit ("<%d><%ld><%hd><%d>\n", 123, (long)234, (short)345, 456));
RESULT(printf ("<%d><%ld><%hd><%d>\n", 123, (long)234, (short)345, 456));
#if defined(__GNUC__) || defined (HAVE_LONG_LONG)
RESULT(checkit ("<%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
RESULT(printf ("<%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
#endif
#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
RESULT(checkit ("<%.20f><%.20Lf><%.20f>\n",
1.23456, 1.234567890123456789L, 1.23456));
RESULT(printf ("<%.20f><%.20Lf><%.20f>\n",
1.23456, 1.234567890123456789L, 1.23456));
#endif
return 0;
}
#endif /* TEST */
More information about the Gcc
mailing list