The following patch to lib/libc/stdio implements positional arguments in
a manner consistent with other implementations. Its done in a way that adds only a tiny amount of overhead when positional arguments are not used. I also have a test program to go with this, but don't know where it belongs in the tree. Submitted-By: Bill Fenner <fenner@FreeBSD.ORG>
This commit is contained in:
parent
9c0cd3f9df
commit
8c1ecf7d88
@ -176,6 +176,16 @@ After the
|
|||||||
the following appear in sequence:
|
the following appear in sequence:
|
||||||
.Bl -bullet
|
.Bl -bullet
|
||||||
.It
|
.It
|
||||||
|
An optional field, consisting of a decimal digit string followed by a
|
||||||
|
.Cm $ ,
|
||||||
|
specifying the next argument to access .
|
||||||
|
If this field is not provided, the argument following the last
|
||||||
|
argument accessed will be used.
|
||||||
|
Arguments are numbered starting at
|
||||||
|
.Cm 1 .
|
||||||
|
If unaccessed arguments in the format string are interspersed with ones that
|
||||||
|
are accessed the results will be indeterminate.
|
||||||
|
.It
|
||||||
Zero or more of the following flags:
|
Zero or more of the following flags:
|
||||||
.Bl -hyphen
|
.Bl -hyphen
|
||||||
.It
|
.It
|
||||||
@ -394,6 +404,8 @@ A character that specifies the type of conversion to be applied.
|
|||||||
A field width or precision, or both, may be indicated by
|
A field width or precision, or both, may be indicated by
|
||||||
an asterisk
|
an asterisk
|
||||||
.Ql *
|
.Ql *
|
||||||
|
or an asterisk followed by one or more decimal digits and a
|
||||||
|
.Ql $
|
||||||
instead of a
|
instead of a
|
||||||
digit string.
|
digit string.
|
||||||
In this case, an
|
In this case, an
|
||||||
@ -402,6 +414,8 @@ argument supplies the field width or precision.
|
|||||||
A negative field width is treated as a left adjustment flag followed by a
|
A negative field width is treated as a left adjustment flag followed by a
|
||||||
positive field width; a negative precision is treated as though it were
|
positive field width; a negative precision is treated as though it were
|
||||||
missing.
|
missing.
|
||||||
|
If a single format directive mixes positional (nn$)
|
||||||
|
and non-positional arguments, the results are undefined.
|
||||||
.Pp
|
.Pp
|
||||||
The conversion specifiers and their meanings are:
|
The conversion specifiers and their meanings are:
|
||||||
.Bl -tag -width "diouxX"
|
.Bl -tag -width "diouxX"
|
||||||
|
@ -75,6 +75,8 @@ static int __sprint __P((FILE *, struct __suio *));
|
|||||||
static int __sbprintf __P((FILE *, const char *, va_list));
|
static int __sbprintf __P((FILE *, const char *, va_list));
|
||||||
static char * __ultoa __P((u_long, char *, int, int, char *));
|
static char * __ultoa __P((u_long, char *, int, int, char *));
|
||||||
static char * __uqtoa __P((u_quad_t, char *, int, int, char *));
|
static char * __uqtoa __P((u_quad_t, char *, int, int, char *));
|
||||||
|
static void __find_arguments __P((const char *, va_list, void ***));
|
||||||
|
static void __grow_type_table __P((int, unsigned char **, int *));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush out all the vectors defined by the given uio,
|
* Flush out all the vectors defined by the given uio,
|
||||||
@ -274,6 +276,7 @@ static int exponent __P((char *, int, int));
|
|||||||
|
|
||||||
#endif /* FLOATING_POINT */
|
#endif /* FLOATING_POINT */
|
||||||
|
|
||||||
|
#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags used during conversion.
|
* Flags used during conversion.
|
||||||
@ -295,7 +298,7 @@ vfprintf(fp, fmt0, ap)
|
|||||||
{
|
{
|
||||||
register char *fmt; /* format string */
|
register char *fmt; /* format string */
|
||||||
register int ch; /* character from fmt */
|
register int ch; /* character from fmt */
|
||||||
register int n; /* handy integer (short term usage) */
|
register int n, n2; /* handy integer (short term usage) */
|
||||||
register char *cp; /* handy char pointer (short term usage) */
|
register char *cp; /* handy char pointer (short term usage) */
|
||||||
register struct __siov *iovp;/* for PRINT macro */
|
register struct __siov *iovp;/* for PRINT macro */
|
||||||
register int flags; /* flags as above */
|
register int flags; /* flags as above */
|
||||||
@ -323,6 +326,10 @@ vfprintf(fp, fmt0, ap)
|
|||||||
struct __siov iov[NIOV];/* ... and individual io vectors */
|
struct __siov iov[NIOV];/* ... and individual io vectors */
|
||||||
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
|
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
|
||||||
char ox[2]; /* space for 0x hex-prefix */
|
char ox[2]; /* space for 0x hex-prefix */
|
||||||
|
void **argtable; /* args, built due to positional arg */
|
||||||
|
void *statargtable [STATIC_ARG_TBL_SIZE];
|
||||||
|
int nextarg; /* 1-based argument index */
|
||||||
|
va_list orgap; /* original argument pointer */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Choose PADSIZE to trade efficiency vs. size. If larger printf
|
* Choose PADSIZE to trade efficiency vs. size. If larger printf
|
||||||
@ -365,18 +372,53 @@ vfprintf(fp, fmt0, ap)
|
|||||||
iovp = iov; \
|
iovp = iov; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the argument indexed by nextarg. If the argument table is
|
||||||
|
* built, use it to get the argument. If its not, get the next
|
||||||
|
* argument (and arguments must be gotten sequentially).
|
||||||
|
*/
|
||||||
|
#define GETARG(type) \
|
||||||
|
((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \
|
||||||
|
(nextarg++, va_arg(ap, type)))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To extend shorts properly, we need both signed and unsigned
|
* To extend shorts properly, we need both signed and unsigned
|
||||||
* argument extraction methods.
|
* argument extraction methods.
|
||||||
*/
|
*/
|
||||||
#define SARG() \
|
#define SARG() \
|
||||||
(flags&LONGINT ? va_arg(ap, long) : \
|
(flags&LONGINT ? GETARG(long) : \
|
||||||
flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
|
flags&SHORTINT ? (long)(short)GETARG(int) : \
|
||||||
(long)va_arg(ap, int))
|
(long)GETARG(int))
|
||||||
#define UARG() \
|
#define UARG() \
|
||||||
(flags&LONGINT ? va_arg(ap, u_long) : \
|
(flags&LONGINT ? GETARG(u_long) : \
|
||||||
flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
|
flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
|
||||||
(u_long)va_arg(ap, u_int))
|
(u_long)GETARG(u_int))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get * arguments, including the form *nn$. Preserve the nextarg
|
||||||
|
* that the argument can be gotten once the type is determined.
|
||||||
|
*/
|
||||||
|
#define GETASTER(val) \
|
||||||
|
n2 = 0; \
|
||||||
|
cp = fmt; \
|
||||||
|
while (is_digit(*cp)) { \
|
||||||
|
n2 = 10 * n2 + to_digit(*cp); \
|
||||||
|
cp++; \
|
||||||
|
} \
|
||||||
|
if (*cp == '$') { \
|
||||||
|
int hold = nextarg; \
|
||||||
|
if (argtable == NULL) { \
|
||||||
|
argtable = statargtable; \
|
||||||
|
__find_arguments (fmt0, orgap, &argtable); \
|
||||||
|
} \
|
||||||
|
nextarg = n2; \
|
||||||
|
val = GETARG (int); \
|
||||||
|
nextarg = hold; \
|
||||||
|
fmt = ++cp; \
|
||||||
|
} else { \
|
||||||
|
val = GETARG (int); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef _THREAD_SAFE
|
#ifdef _THREAD_SAFE
|
||||||
_thread_flockfile(fp,__FILE__,__LINE__);
|
_thread_flockfile(fp,__FILE__,__LINE__);
|
||||||
@ -399,6 +441,9 @@ vfprintf(fp, fmt0, ap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt = (char *)fmt0;
|
fmt = (char *)fmt0;
|
||||||
|
argtable = NULL;
|
||||||
|
nextarg = 1;
|
||||||
|
orgap = ap;
|
||||||
uio.uio_iov = iovp = iov;
|
uio.uio_iov = iovp = iov;
|
||||||
uio.uio_resid = 0;
|
uio.uio_resid = 0;
|
||||||
uio.uio_iovcnt = 0;
|
uio.uio_iovcnt = 0;
|
||||||
@ -445,7 +490,8 @@ reswitch: switch (ch) {
|
|||||||
* -- ANSI X3J11
|
* -- ANSI X3J11
|
||||||
* They don't exclude field widths read from args.
|
* They don't exclude field widths read from args.
|
||||||
*/
|
*/
|
||||||
if ((width = va_arg(ap, int)) >= 0)
|
GETASTER (width);
|
||||||
|
if (width >= 0)
|
||||||
goto rflag;
|
goto rflag;
|
||||||
width = -width;
|
width = -width;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
@ -457,7 +503,7 @@ reswitch: switch (ch) {
|
|||||||
goto rflag;
|
goto rflag;
|
||||||
case '.':
|
case '.':
|
||||||
if ((ch = *fmt++) == '*') {
|
if ((ch = *fmt++) == '*') {
|
||||||
n = va_arg(ap, int);
|
GETASTER (n);
|
||||||
prec = n < 0 ? -1 : n;
|
prec = n < 0 ? -1 : n;
|
||||||
goto rflag;
|
goto rflag;
|
||||||
}
|
}
|
||||||
@ -483,6 +529,15 @@ reswitch: switch (ch) {
|
|||||||
n = 10 * n + to_digit(ch);
|
n = 10 * n + to_digit(ch);
|
||||||
ch = *fmt++;
|
ch = *fmt++;
|
||||||
} while (is_digit(ch));
|
} while (is_digit(ch));
|
||||||
|
if (ch == '$') {
|
||||||
|
nextarg = n;
|
||||||
|
if (argtable == NULL) {
|
||||||
|
argtable = statargtable;
|
||||||
|
__find_arguments (fmt0, orgap,
|
||||||
|
&argtable);
|
||||||
|
}
|
||||||
|
goto rflag;
|
||||||
|
}
|
||||||
width = n;
|
width = n;
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
#ifdef FLOATING_POINT
|
#ifdef FLOATING_POINT
|
||||||
@ -500,7 +555,7 @@ reswitch: switch (ch) {
|
|||||||
flags |= QUADINT;
|
flags |= QUADINT;
|
||||||
goto rflag;
|
goto rflag;
|
||||||
case 'c':
|
case 'c':
|
||||||
*(cp = buf) = va_arg(ap, int);
|
*(cp = buf) = GETARG(int);
|
||||||
size = 1;
|
size = 1;
|
||||||
sign = '\0';
|
sign = '\0';
|
||||||
break;
|
break;
|
||||||
@ -510,7 +565,7 @@ reswitch: switch (ch) {
|
|||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
if (flags & QUADINT) {
|
if (flags & QUADINT) {
|
||||||
uqval = va_arg(ap, quad_t);
|
uqval = GETARG(quad_t);
|
||||||
if ((quad_t)uqval < 0) {
|
if ((quad_t)uqval < 0) {
|
||||||
uqval = -uqval;
|
uqval = -uqval;
|
||||||
sign = '-';
|
sign = '-';
|
||||||
@ -536,9 +591,9 @@ reswitch: switch (ch) {
|
|||||||
fp_begin: if (prec == -1)
|
fp_begin: if (prec == -1)
|
||||||
prec = DEFPREC;
|
prec = DEFPREC;
|
||||||
if (flags & LONGDBL)
|
if (flags & LONGDBL)
|
||||||
_double = (double)va_arg(ap, long double);
|
_double = (double)GETARG(long double);
|
||||||
else
|
else
|
||||||
_double = va_arg(ap, double);
|
_double = GETARG(double);
|
||||||
/* do this before tricky precision changes */
|
/* do this before tricky precision changes */
|
||||||
if (isinf(_double)) {
|
if (isinf(_double)) {
|
||||||
if (_double < 0)
|
if (_double < 0)
|
||||||
@ -588,20 +643,20 @@ fp_begin: if (prec == -1)
|
|||||||
#endif /* FLOATING_POINT */
|
#endif /* FLOATING_POINT */
|
||||||
case 'n':
|
case 'n':
|
||||||
if (flags & QUADINT)
|
if (flags & QUADINT)
|
||||||
*va_arg(ap, quad_t *) = ret;
|
*GETARG(quad_t *) = ret;
|
||||||
else if (flags & LONGINT)
|
else if (flags & LONGINT)
|
||||||
*va_arg(ap, long *) = ret;
|
*GETARG(long *) = ret;
|
||||||
else if (flags & SHORTINT)
|
else if (flags & SHORTINT)
|
||||||
*va_arg(ap, short *) = ret;
|
*GETARG(short *) = ret;
|
||||||
else
|
else
|
||||||
*va_arg(ap, int *) = ret;
|
*GETARG(int *) = ret;
|
||||||
continue; /* no output */
|
continue; /* no output */
|
||||||
case 'O':
|
case 'O':
|
||||||
flags |= LONGINT;
|
flags |= LONGINT;
|
||||||
/*FALLTHROUGH*/
|
/*FALLTHROUGH*/
|
||||||
case 'o':
|
case 'o':
|
||||||
if (flags & QUADINT)
|
if (flags & QUADINT)
|
||||||
uqval = va_arg(ap, u_quad_t);
|
uqval = GETARG(u_quad_t);
|
||||||
else
|
else
|
||||||
ulval = UARG();
|
ulval = UARG();
|
||||||
base = 8;
|
base = 8;
|
||||||
@ -614,14 +669,14 @@ fp_begin: if (prec == -1)
|
|||||||
* defined manner.''
|
* defined manner.''
|
||||||
* -- ANSI X3J11
|
* -- ANSI X3J11
|
||||||
*/
|
*/
|
||||||
ulval = (u_long)va_arg(ap, void *);
|
ulval = (u_long)GETARG(void *);
|
||||||
base = 16;
|
base = 16;
|
||||||
xdigs = "0123456789abcdef";
|
xdigs = "0123456789abcdef";
|
||||||
flags = (flags & ~QUADINT) | HEXPREFIX;
|
flags = (flags & ~QUADINT) | HEXPREFIX;
|
||||||
ch = 'x';
|
ch = 'x';
|
||||||
goto nosign;
|
goto nosign;
|
||||||
case 's':
|
case 's':
|
||||||
if ((cp = va_arg(ap, char *)) == NULL)
|
if ((cp = GETARG(char *)) == NULL)
|
||||||
cp = "(null)";
|
cp = "(null)";
|
||||||
if (prec >= 0) {
|
if (prec >= 0) {
|
||||||
/*
|
/*
|
||||||
@ -646,7 +701,7 @@ fp_begin: if (prec == -1)
|
|||||||
/*FALLTHROUGH*/
|
/*FALLTHROUGH*/
|
||||||
case 'u':
|
case 'u':
|
||||||
if (flags & QUADINT)
|
if (flags & QUADINT)
|
||||||
uqval = va_arg(ap, u_quad_t);
|
uqval = GETARG(u_quad_t);
|
||||||
else
|
else
|
||||||
ulval = UARG();
|
ulval = UARG();
|
||||||
base = 10;
|
base = 10;
|
||||||
@ -657,7 +712,7 @@ fp_begin: if (prec == -1)
|
|||||||
case 'x':
|
case 'x':
|
||||||
xdigs = "0123456789abcdef";
|
xdigs = "0123456789abcdef";
|
||||||
hex: if (flags & QUADINT)
|
hex: if (flags & QUADINT)
|
||||||
uqval = va_arg(ap, u_quad_t);
|
uqval = GETARG(u_quad_t);
|
||||||
else
|
else
|
||||||
ulval = UARG();
|
ulval = UARG();
|
||||||
base = 16;
|
base = 16;
|
||||||
@ -809,10 +864,333 @@ number: if ((dprec = prec) >= 0)
|
|||||||
#ifdef _THREAD_SAFE
|
#ifdef _THREAD_SAFE
|
||||||
_thread_funlockfile(fp);
|
_thread_funlockfile(fp);
|
||||||
#endif
|
#endif
|
||||||
|
if ((argtable != NULL) && (argtable != statargtable))
|
||||||
|
free (argtable);
|
||||||
return (ret);
|
return (ret);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type ids for argument type table.
|
||||||
|
*/
|
||||||
|
#define T_UNUSED 0
|
||||||
|
#define T_SHORT 1
|
||||||
|
#define T_U_SHORT 2
|
||||||
|
#define TP_SHORT 3
|
||||||
|
#define T_INT 4
|
||||||
|
#define T_U_INT 5
|
||||||
|
#define TP_INT 6
|
||||||
|
#define T_LONG 7
|
||||||
|
#define T_U_LONG 8
|
||||||
|
#define TP_LONG 9
|
||||||
|
#define T_QUAD 10
|
||||||
|
#define T_U_QUAD 11
|
||||||
|
#define TP_QUAD 12
|
||||||
|
#define T_DOUBLE 13
|
||||||
|
#define T_LONG_DOUBLE 14
|
||||||
|
#define TP_CHAR 15
|
||||||
|
#define TP_VOID 16
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all arguments when a positional parameter is encountered. Returns a
|
||||||
|
* table, indexed by argument number, of pointers to each arguments. The
|
||||||
|
* initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
|
||||||
|
* It will be replaces with a malloc-ed on if it overflows.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
__find_arguments (fmt0, ap, argtable)
|
||||||
|
const char *fmt0;
|
||||||
|
va_list ap;
|
||||||
|
void ***argtable;
|
||||||
|
{
|
||||||
|
register char *fmt; /* format string */
|
||||||
|
register int ch; /* character from fmt */
|
||||||
|
register int n, n2; /* handy integer (short term usage) */
|
||||||
|
register char *cp; /* handy char pointer (short term usage) */
|
||||||
|
register int flags; /* flags as above */
|
||||||
|
int width; /* width from format (%8d), or 0 */
|
||||||
|
unsigned char *typetable; /* table of types */
|
||||||
|
unsigned char stattypetable [STATIC_ARG_TBL_SIZE];
|
||||||
|
int tablesize; /* current size of type table */
|
||||||
|
int tablemax; /* largest used index in table */
|
||||||
|
int nextarg; /* 1-based argument index */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add an argument type to the table, expanding if necessary.
|
||||||
|
*/
|
||||||
|
#define ADDTYPE(type) \
|
||||||
|
((nextarg >= tablesize) ? \
|
||||||
|
__grow_type_table(nextarg, &typetable, &tablesize) : 0, \
|
||||||
|
typetable[nextarg++] = type, \
|
||||||
|
(nextarg > tablemax) ? tablemax = nextarg : 0)
|
||||||
|
|
||||||
|
#define ADDSARG() \
|
||||||
|
((flags&LONGINT) ? ADDTYPE(T_LONG) : \
|
||||||
|
((flags&SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
|
||||||
|
|
||||||
|
#define ADDUARG() \
|
||||||
|
((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
|
||||||
|
((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add * arguments to the type array.
|
||||||
|
*/
|
||||||
|
#define ADDASTER() \
|
||||||
|
n2 = 0; \
|
||||||
|
cp = fmt; \
|
||||||
|
while (is_digit(*cp)) { \
|
||||||
|
n2 = 10 * n2 + to_digit(*cp); \
|
||||||
|
cp++; \
|
||||||
|
} \
|
||||||
|
if (*cp == '$') { \
|
||||||
|
int hold = nextarg; \
|
||||||
|
nextarg = n2; \
|
||||||
|
ADDTYPE (T_INT); \
|
||||||
|
nextarg = hold; \
|
||||||
|
fmt = ++cp; \
|
||||||
|
} else { \
|
||||||
|
ADDTYPE (T_INT); \
|
||||||
|
}
|
||||||
|
fmt = (char *)fmt0;
|
||||||
|
typetable = stattypetable;
|
||||||
|
tablesize = STATIC_ARG_TBL_SIZE;
|
||||||
|
tablemax = 0;
|
||||||
|
nextarg = 1;
|
||||||
|
memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan the format for conversions (`%' character).
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
|
||||||
|
/* void */;
|
||||||
|
if (ch == '\0')
|
||||||
|
goto done;
|
||||||
|
fmt++; /* skip over '%' */
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
width = 0;
|
||||||
|
|
||||||
|
rflag: ch = *fmt++;
|
||||||
|
reswitch: switch (ch) {
|
||||||
|
case ' ':
|
||||||
|
case '#':
|
||||||
|
goto rflag;
|
||||||
|
case '*':
|
||||||
|
ADDASTER ();
|
||||||
|
goto rflag;
|
||||||
|
case '-':
|
||||||
|
case '+':
|
||||||
|
goto rflag;
|
||||||
|
case '.':
|
||||||
|
if ((ch = *fmt++) == '*') {
|
||||||
|
ADDASTER ();
|
||||||
|
goto rflag;
|
||||||
|
}
|
||||||
|
while (is_digit(ch)) {
|
||||||
|
ch = *fmt++;
|
||||||
|
}
|
||||||
|
goto reswitch;
|
||||||
|
case '0':
|
||||||
|
goto rflag;
|
||||||
|
case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
n = 0;
|
||||||
|
do {
|
||||||
|
n = 10 * n + to_digit(ch);
|
||||||
|
ch = *fmt++;
|
||||||
|
} while (is_digit(ch));
|
||||||
|
if (ch == '$') {
|
||||||
|
nextarg = n;
|
||||||
|
goto rflag;
|
||||||
|
}
|
||||||
|
width = n;
|
||||||
|
goto reswitch;
|
||||||
|
#ifdef FLOATING_POINT
|
||||||
|
case 'L':
|
||||||
|
flags |= LONGDBL;
|
||||||
|
goto rflag;
|
||||||
|
#endif
|
||||||
|
case 'h':
|
||||||
|
flags |= SHORTINT;
|
||||||
|
goto rflag;
|
||||||
|
case 'l':
|
||||||
|
flags |= LONGINT;
|
||||||
|
goto rflag;
|
||||||
|
case 'q':
|
||||||
|
flags |= QUADINT;
|
||||||
|
goto rflag;
|
||||||
|
case 'c':
|
||||||
|
ADDTYPE(T_INT);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
flags |= LONGINT;
|
||||||
|
/*FALLTHROUGH*/
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
if (flags & QUADINT) {
|
||||||
|
ADDTYPE(T_QUAD);
|
||||||
|
} else {
|
||||||
|
ADDSARG();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef FLOATING_POINT
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'f':
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
if (flags & LONGDBL)
|
||||||
|
ADDTYPE(T_LONG_DOUBLE);
|
||||||
|
else
|
||||||
|
ADDTYPE(T_DOUBLE);
|
||||||
|
break;
|
||||||
|
#endif /* FLOATING_POINT */
|
||||||
|
case 'n':
|
||||||
|
if (flags & QUADINT)
|
||||||
|
ADDTYPE(TP_QUAD);
|
||||||
|
else if (flags & LONGINT)
|
||||||
|
ADDTYPE(TP_LONG);
|
||||||
|
else if (flags & SHORTINT)
|
||||||
|
ADDTYPE(TP_SHORT);
|
||||||
|
else
|
||||||
|
ADDTYPE(TP_INT);
|
||||||
|
continue; /* no output */
|
||||||
|
case 'O':
|
||||||
|
flags |= LONGINT;
|
||||||
|
/*FALLTHROUGH*/
|
||||||
|
case 'o':
|
||||||
|
if (flags & QUADINT)
|
||||||
|
ADDTYPE(T_U_QUAD);
|
||||||
|
else
|
||||||
|
ADDUARG();
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
ADDTYPE(TP_VOID);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
ADDTYPE(TP_CHAR);
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
flags |= LONGINT;
|
||||||
|
/*FALLTHROUGH*/
|
||||||
|
case 'u':
|
||||||
|
if (flags & QUADINT)
|
||||||
|
ADDTYPE(T_U_QUAD);
|
||||||
|
else
|
||||||
|
ADDUARG();
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
if (flags & QUADINT)
|
||||||
|
ADDTYPE(T_U_QUAD);
|
||||||
|
else
|
||||||
|
ADDUARG();
|
||||||
|
break;
|
||||||
|
default: /* "%?" prints ?, unless ? is NUL */
|
||||||
|
if (ch == '\0')
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
/*
|
||||||
|
* Build the argument table.
|
||||||
|
*/
|
||||||
|
if (tablemax >= STATIC_ARG_TBL_SIZE) {
|
||||||
|
*argtable = (void **)
|
||||||
|
malloc (sizeof (void *) * (tablemax + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
(*argtable) [0] = NULL;
|
||||||
|
for (n = 1; n <= tablemax; n++) {
|
||||||
|
(*argtable) [n] = ap;
|
||||||
|
switch (typetable [n]) {
|
||||||
|
case T_UNUSED:
|
||||||
|
(void) va_arg (ap, int);
|
||||||
|
break;
|
||||||
|
case T_SHORT:
|
||||||
|
(void) va_arg (ap, int);
|
||||||
|
break;
|
||||||
|
case T_U_SHORT:
|
||||||
|
(void) va_arg (ap, int);
|
||||||
|
break;
|
||||||
|
case TP_SHORT:
|
||||||
|
(void) va_arg (ap, short *);
|
||||||
|
break;
|
||||||
|
case T_INT:
|
||||||
|
(void) va_arg (ap, int);
|
||||||
|
break;
|
||||||
|
case T_U_INT:
|
||||||
|
(void) va_arg (ap, unsigned int);
|
||||||
|
break;
|
||||||
|
case TP_INT:
|
||||||
|
(void) va_arg (ap, int *);
|
||||||
|
break;
|
||||||
|
case T_LONG:
|
||||||
|
(void) va_arg (ap, long);
|
||||||
|
break;
|
||||||
|
case T_U_LONG:
|
||||||
|
(void) va_arg (ap, unsigned long);
|
||||||
|
break;
|
||||||
|
case TP_LONG:
|
||||||
|
(void) va_arg (ap, long *);
|
||||||
|
break;
|
||||||
|
case T_QUAD:
|
||||||
|
(void) va_arg (ap, quad_t);
|
||||||
|
break;
|
||||||
|
case T_U_QUAD:
|
||||||
|
(void) va_arg (ap, u_quad_t);
|
||||||
|
break;
|
||||||
|
case TP_QUAD:
|
||||||
|
(void) va_arg (ap, quad_t *);
|
||||||
|
break;
|
||||||
|
case T_DOUBLE:
|
||||||
|
(void) va_arg (ap, double);
|
||||||
|
break;
|
||||||
|
case T_LONG_DOUBLE:
|
||||||
|
(void) va_arg (ap, long double);
|
||||||
|
break;
|
||||||
|
case TP_CHAR:
|
||||||
|
(void) va_arg (ap, char *);
|
||||||
|
break;
|
||||||
|
case TP_VOID:
|
||||||
|
(void) va_arg (ap, void *);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((typetable != NULL) && (typetable != stattypetable))
|
||||||
|
free (typetable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increase the size of the type table.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
__grow_type_table (nextarg, typetable, tablesize)
|
||||||
|
int nextarg;
|
||||||
|
unsigned char **typetable;
|
||||||
|
int *tablesize;
|
||||||
|
{
|
||||||
|
unsigned char *oldtable = *typetable;
|
||||||
|
int newsize = *tablesize * 2;
|
||||||
|
|
||||||
|
if (*tablesize == STATIC_ARG_TBL_SIZE) {
|
||||||
|
*typetable = (unsigned char *)
|
||||||
|
malloc (sizeof (unsigned char) * newsize);
|
||||||
|
bcopy (oldtable, *typetable, *tablesize);
|
||||||
|
} else {
|
||||||
|
*typetable = (unsigned char *)
|
||||||
|
realloc (typetable, sizeof (unsigned char) * newsize);
|
||||||
|
|
||||||
|
}
|
||||||
|
memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize));
|
||||||
|
|
||||||
|
*tablesize = newsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef FLOATING_POINT
|
#ifdef FLOATING_POINT
|
||||||
|
|
||||||
extern char *__dtoa __P((double, int, int, int *, int *, char **));
|
extern char *__dtoa __P((double, int, int, int *, int *, char **));
|
||||||
|
Loading…
Reference in New Issue
Block a user