From 9a3ec8622b2fb10c95112188c7f5ff1424c738e6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 23 May 2007 20:36:28 +0000 Subject: [PATCH] * libc/stdio/vfscanf.c (__SVFSCANF_R): Support scanf(%1$s). Avoid warning when !FLOATING_POINT. * libc/stdio/vfprintf.c (_VFPRINTF_R): Simplify _NO_POS_ARGS slightly. --- newlib/ChangeLog | 7 +++ newlib/libc/stdio/vfprintf.c | 40 ++++++------- newlib/libc/stdio/vfscanf.c | 112 ++++++++++++++++++++++++++++------- 3 files changed, 116 insertions(+), 43 deletions(-) diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 0566b8a30..a72b01318 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,10 @@ +2007-05-23 Eric Blake + + * libc/stdio/vfscanf.c (__SVFSCANF_R): Support scanf(%1$s). + Avoid warning when !FLOATING_POINT. + * libc/stdio/vfprintf.c (_VFPRINTF_R): Simplify _NO_POS_ARGS + slightly. + 2007-05-23 Corinna Vinschen * libc/argz/argz_create_sep.c (argz_create_sep): Initialize *argz_len diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c index 72bd7e89e..e734cb19c 100644 --- a/newlib/libc/stdio/vfprintf.c +++ b/newlib/libc/stdio/vfprintf.c @@ -125,8 +125,8 @@ static char *rcsid = "$Id$"; # endif #endif -#define _NO_POS_ARGS -#if defined _WANT_IO_POS_ARGS +#define _NO_POS_ARGS +#ifdef _WANT_IO_POS_ARGS # undef _NO_POS_ARGS #endif @@ -385,9 +385,9 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap), register struct __siov *iovp;/* for PRINT macro */ register int flags; /* flags as above */ char *fmt_anchor; /* current format spec being processed */ +#ifndef _NO_POS_ARGS int N; /* arg number */ int arg_index; /* index into args processed directly */ -#ifndef _NO_POS_ARGS int numargs; /* number of varargs read */ char *saved_fmt; /* saved fmt pointer */ union arg_val args[MAX_POS_ARGS]; @@ -472,21 +472,21 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap), /* Macros to support positional arguments */ #ifndef _NO_POS_ARGS -#define GET_ARG(n, ap, type) \ - ( is_pos_arg \ - ? n < numargs \ - ? args[n].val_##type \ - : get_arg (data, n, fmt_anchor, &ap, &numargs, args, arg_type, &saved_fmt)->val_##type \ - : arg_index++ < numargs \ - ? args[n].val_##type \ - : numargs < MAX_POS_ARGS \ - ? args[numargs++].val_##type = va_arg (ap, type) \ - : va_arg (ap, type) \ - ) +# define GET_ARG(n, ap, type) \ + (is_pos_arg \ + ? (n < numargs \ + ? args[n].val_##type \ + : get_arg (data, n, fmt_anchor, &ap, &numargs, args, \ + arg_type, &saved_fmt)->val_##type) \ + : (arg_index++ < numargs \ + ? args[n].val_##type \ + : (numargs < MAX_POS_ARGS \ + ? args[numargs++].val_##type = va_arg (ap, type) \ + : va_arg (ap, type)))) #else -#define GET_ARG(n, ap, type) (va_arg (ap, type)) +# define GET_ARG(n, ap, type) (va_arg (ap, type)) #endif - + /* * To extend shorts properly, we need both signed and unsigned * argument extraction methods. @@ -538,8 +538,8 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap), uio.uio_resid = 0; uio.uio_iovcnt = 0; ret = 0; - arg_index = 0; #ifndef _NO_POS_ARGS + arg_index = 0; saved_fmt = NULL; arg_type[0] = -1; numargs = 0; @@ -580,8 +580,8 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap), width = 0; prec = -1; sign = '\0'; - N = arg_index; #ifndef _NO_POS_ARGS + N = arg_index; is_pos_arg = 0; #endif @@ -609,9 +609,9 @@ reswitch: switch (ch) { flags |= ALT; goto rflag; case '*': - n = N; #ifndef _NO_POS_ARGS /* we must check for positional arg used for dynamic width */ + n = N; old_is_pos_arg = is_pos_arg; is_pos_arg = 0; if (is_digit (*fmt)) { @@ -661,9 +661,9 @@ reswitch: switch (ch) { goto rflag; case '.': if ((ch = *fmt++) == '*') { - n = N; #ifndef _NO_POS_ARGS /* we must check for positional arg used for dynamic width */ + n = N; old_is_pos_arg = is_pos_arg; is_pos_arg = 0; if (is_digit (*fmt)) { diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c index bd597b395..e73e8764f 100644 --- a/newlib/libc/stdio/vfscanf.c +++ b/newlib/libc/stdio/vfscanf.c @@ -113,11 +113,8 @@ Supporting OS subroutines required: #include #include #include -#ifdef _HAVE_STDC #include -#else -#include -#endif +#include #include "local.h" #ifdef INTEGER_ONLY @@ -169,6 +166,18 @@ extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); # undef _NO_LONGLONG #endif +#define _NO_POS_ARGS +#ifdef _WANT_IO_POS_ARGS +# undef _NO_POS_ARGS +# ifdef NL_ARGMAX +# define MAX_POS_ARGS NL_ARGMAX +# else +# define MAX_POS_ARGS 32 +# endif + +static void * get_arg (int, va_list *, int *, void **); +#endif /* _WANT_IO_POS_ARGS */ + /* * Flags used during conversion. */ @@ -276,6 +285,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), register char *p0; /* saves original value of p when necessary */ int nassigned; /* number of fields assigned */ int nread; /* number of characters consumed from fp */ +#ifndef _NO_POS_ARGS + int N; /* arg number */ + int arg_index = 0; /* index into args processed directly */ + int numargs = 0; /* number of varargs read */ + void *args[MAX_POS_ARGS]; /* positional args read */ + int is_pos_arg; /* is current format positional? */ +#endif int base = 0; /* base argument to strtol/strtoul */ int nbytes = 1; /* number of bytes read from fmt string */ wchar_t wc; /* wchar to use to read format string */ @@ -291,9 +307,11 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), char *cp; short *sp; int *ip; +#ifdef FLOATING_POINT float *flp; _LONG_DOUBLE *ldp; double *dp; +#endif long *lp; #ifndef _NO_LONGLONG long long *llp; @@ -303,6 +321,22 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), static _CONST short basefix[17] = {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + /* Macro to support positional arguments */ +#ifndef _NO_POS_ARGS +# define GET_ARG(n, ap, type) \ + ((type) (is_pos_arg \ + ? (n < numargs \ + ? args[n] \ + : get_arg (n, &ap, &numargs, args)) \ + : (arg_index++ < numargs \ + ? args[n] \ + : (numargs < MAX_POS_ARGS \ + ? args[numargs++] = va_arg (ap, void *) \ + : va_arg (ap, void *))))) +#else +# define GET_ARG(n, ap, type) (va_arg (ap, type)) +#endif + _flockfile (fp); nassigned = 0; @@ -332,6 +366,10 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), goto literal; width = 0; flags = 0; +#ifndef _NO_POS_ARGS + N = arg_index; + is_pos_arg = 0; +#endif /* * switch on the format. continue if done; break once format @@ -439,6 +477,19 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), width = width * 10 + c - '0'; goto again; +#ifndef _NO_POS_ARGS + case '$': + if (width <= MAX_POS_ARGS) + { + N = width - 1; + is_pos_arg = 1; + width = 0; + goto again; + } + rptr->_errno = EINVAL; + goto input_failure; +#endif /* !_NO_POS_ARGS */ + /* * Conversions. Those marked `compat' are for * 4.[123]BSD compatibility. @@ -540,31 +591,31 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), #ifdef _WANT_IO_C99_FORMATS if (flags & CHAR) { - cp = va_arg (ap, char *); + cp = GET_ARG (N, ap, char *); *cp = nread; } else #endif if (flags & SHORT) { - sp = va_arg (ap, short *); + sp = GET_ARG (N, ap, short *); *sp = nread; } else if (flags & LONG) { - lp = va_arg (ap, long *); + lp = GET_ARG (N, ap, long *); *lp = nread; } #ifndef _NO_LONGLONG else if (flags & LONGDBL) { - llp = va_arg (ap, long long*); + llp = GET_ARG (N, ap, long long*); *llp = nread; } #endif else { - ip = va_arg (ap, int *); + ip = GET_ARG (N, ap, int *); *ip = nread; } continue; @@ -626,7 +677,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), if (flags & LONG) { if ((flags & SUPPRESS) == 0) - wcp = va_arg (ap, wchar_t *); + wcp = GET_ARG (N, ap, wchar_t *); else wcp = NULL; n = 0; @@ -690,7 +741,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } else { - size_t r = fread ((_PTR) va_arg (ap, char *), 1, width, fp); + size_t r = fread ((_PTR) GET_ARG (N, ap, char *), 1, width, fp); if (r == 0) goto input_failure; @@ -724,7 +775,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } else { - p0 = p = va_arg (ap, char *); + p0 = p = GET_ARG (N, ap, char *); while (ccltab[*fp->_p]) { fp->_r--; @@ -755,7 +806,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), { /* Process %S and %ls placeholders */ if ((flags & SUPPRESS) == 0) - wcp = va_arg (ap, wchar_t *); + wcp = GET_ARG (N, ap, wchar_t *); else wcp = &wc; n = 0; @@ -814,7 +865,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), } else { - p0 = p = va_arg (ap, char *); + p0 = p = GET_ARG (N, ap, char *); while (!isspace (*fp->_p)) { fp->_r--; @@ -993,22 +1044,22 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), *p = 0; res = (*ccfn) (rptr, buf, (char **) NULL, base); if (flags & POINTER) - *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res; + *(GET_ARG (N, ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res; #ifdef _WANT_IO_C99_FORMATS else if (flags & CHAR) { - cp = va_arg (ap, char *); + cp = GET_ARG (N, ap, char *); *cp = res; } #endif else if (flags & SHORT) { - sp = va_arg (ap, short *); + sp = GET_ARG (N, ap, short *); *sp = res; } else if (flags & LONG) { - lp = va_arg (ap, long *); + lp = GET_ARG (N, ap, long *); *lp = res; } #ifndef _NO_LONGLONG @@ -1019,13 +1070,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), resll = _strtoull_r (rptr, buf, (char **) NULL, base); else resll = _strtoll_r (rptr, buf, (char **) NULL, base); - llp = va_arg (ap, long long*); + llp = GET_ARG (N, ap, long long*); *llp = resll; } #endif else { - ip = va_arg (ap, int *); + ip = GET_ARG (N, ap, int *); *ip = res; } nassigned++; @@ -1257,17 +1308,17 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), if (flags & LONG) { - dp = va_arg (ap, double *); + dp = GET_ARG (N, ap, double *); *dp = res; } else if (flags & LONGDBL) { - ldp = va_arg (ap, _LONG_DOUBLE *); + ldp = GET_ARG (N, ap, _LONG_DOUBLE *); *ldp = QUAD_RES; } else { - flp = va_arg (ap, float *); + flp = GET_ARG (N, ap, float *); if (isnan (res)) *flp = nanf (NULL); else @@ -1288,3 +1339,18 @@ all_done: _funlockfile (fp); return nassigned; } + +#ifndef _NO_POS_ARGS +/* Process all intermediate arguments. Fortunately, with scanf, all + intermediate arguments are sizeof(void*), so we don't need to scan + ahead in the format string. */ +static void * +get_arg (int n, va_list *ap, int *numargs_p, void **args) +{ + int numargs = *numargs_p; + while (n >= numargs) + args[numargs++] = va_arg (*ap, void *); + *numargs_p = numargs; + return args[n]; +} +#endif /* !_NO_POS_ARGS */