newlib: vf[w]scanf: Implement POSIX %m modifier
* The new code is guarded with _WANT_IO_POSIX_EXTENSIONS, but this is automatically enabled with _WANT_IO_C99_FORMATS for now. * vfscanf neglects to implement %l[, so %ml[ is not implemented yet either. * Sidenote: vfwscanf doesn't allow ranges in %[ yet. Strictly this is allowed per POSIX, but it differes from vfscanf as well as from glibc. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
27c1a7972c
commit
d43863f569
|
@ -212,6 +212,7 @@ static void * get_arg (int, va_list *, int *, void **);
|
||||||
#define SUPPRESS 0x10 /* suppress assignment */
|
#define SUPPRESS 0x10 /* suppress assignment */
|
||||||
#define POINTER 0x20 /* weird %p pointer (`fake hex') */
|
#define POINTER 0x20 /* weird %p pointer (`fake hex') */
|
||||||
#define NOSKIP 0x40 /* do not skip blanks */
|
#define NOSKIP 0x40 /* do not skip blanks */
|
||||||
|
#define MALLOC 0x80 /* handle 'm' modifier */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following are used in numeric conversions only:
|
* The following are used in numeric conversions only:
|
||||||
|
@ -453,6 +454,122 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
#ifdef _MB_CAPABLE
|
#ifdef _MB_CAPABLE
|
||||||
mbstate_t state; /* value to keep track of multibyte state */
|
mbstate_t state; /* value to keep track of multibyte state */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _WANT_IO_C99_FORMATS
|
||||||
|
#define _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
#endif
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
/* POSIX requires that fscanf frees all allocated strings from 'm'
|
||||||
|
conversions in case it returns EOF. m_ptr is used to keep track.
|
||||||
|
It will be allocated on the stack the first time an 'm' conversion
|
||||||
|
takes place, and it will be free'd on return from the function.
|
||||||
|
This implementation tries to save space by only allocating 8
|
||||||
|
pointer slots at a time. Most scenarios should never have to call
|
||||||
|
realloc again. This implementation allows only up to 65528 'm'
|
||||||
|
conversions per fscanf invocation for now. That should be enough
|
||||||
|
for almost all scenarios, right? */
|
||||||
|
struct m_ptrs {
|
||||||
|
void ***m_arr; /* Array of pointer args to 'm' conversion */
|
||||||
|
uint16_t m_siz; /* Number of slots in m_arr */
|
||||||
|
uint16_t m_cnt; /* Number of valid entries in m_arr */
|
||||||
|
} *m_ptr = NULL;
|
||||||
|
#define init_m_ptr() \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!m_ptr) \
|
||||||
|
{ \
|
||||||
|
m_ptr = (struct m_ptrs *) alloca (sizeof *m_ptr); \
|
||||||
|
m_ptr->m_arr = NULL; \
|
||||||
|
m_ptr->m_siz = 0; \
|
||||||
|
m_ptr->m_cnt = 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#define push_m_ptr(arg) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (m_ptr->m_cnt >= m_ptr->m_siz) \
|
||||||
|
{ \
|
||||||
|
void ***n = NULL; \
|
||||||
|
\
|
||||||
|
if (m_ptr->m_siz + 8 > 0 && m_ptr->m_siz + 8 < UINT16_MAX) \
|
||||||
|
n = (void ***) realloc (m_ptr->m_arr, \
|
||||||
|
(m_ptr->m_siz + 8) * \
|
||||||
|
sizeof (void **)); \
|
||||||
|
if (!n) \
|
||||||
|
{ \
|
||||||
|
nassigned = EOF; \
|
||||||
|
goto match_failure; \
|
||||||
|
} \
|
||||||
|
m_ptr->m_arr = n; \
|
||||||
|
m_ptr->m_siz += 8; \
|
||||||
|
} \
|
||||||
|
m_ptr->m_arr[m_ptr->m_cnt++] = (void **) (arg); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#define alloc_m_ptr(_type, _p, _p0, _p_p, _w) \
|
||||||
|
({ \
|
||||||
|
_p_p = GET_ARG (N, ap, _type **); \
|
||||||
|
if (!_p_p) \
|
||||||
|
goto match_failure; \
|
||||||
|
_p0 = (_type *) malloc ((_w) * sizeof (_type)); \
|
||||||
|
if (!_p0) \
|
||||||
|
{ \
|
||||||
|
nassigned = EOF; \
|
||||||
|
goto match_failure; \
|
||||||
|
} \
|
||||||
|
*_p_p = _p0; \
|
||||||
|
push_m_ptr (_p_p); \
|
||||||
|
_p = _p0; \
|
||||||
|
_w; \
|
||||||
|
})
|
||||||
|
#define realloc_m_ptr(_type, _p, _p0, _p_p, _w) \
|
||||||
|
({ \
|
||||||
|
size_t _nw = (_w); \
|
||||||
|
if (_p_p && _p - _p0 == _nw) \
|
||||||
|
{ \
|
||||||
|
_p0 = (_type *) realloc (_p0, (_nw << 1) * sizeof (_type)); \
|
||||||
|
if (!_p0) \
|
||||||
|
{ \
|
||||||
|
nassigned = EOF; \
|
||||||
|
goto match_failure; \
|
||||||
|
} \
|
||||||
|
_p = _p0 + _nw; \
|
||||||
|
*_p_p = _p0; \
|
||||||
|
_nw <<= 1; \
|
||||||
|
} \
|
||||||
|
_nw; \
|
||||||
|
})
|
||||||
|
#define shrink_m_ptr(_type, _p_p, _w, _cw) \
|
||||||
|
({ \
|
||||||
|
size_t _nw = (_w); \
|
||||||
|
if (_p_p && _nw < _cw) \
|
||||||
|
{ \
|
||||||
|
_type *_np_p = (_type *) \
|
||||||
|
realloc (*_p_p, _nw * sizeof (_type)); \
|
||||||
|
if (_np_p) \
|
||||||
|
*_p_p = _np_p; \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
#define free_m_ptr() \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (m_ptr) \
|
||||||
|
{ \
|
||||||
|
if (nassigned == EOF) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for (i = 0; i < m_ptr->m_cnt; ++i) \
|
||||||
|
{ \
|
||||||
|
free (*m_ptr->m_arr[i]); \
|
||||||
|
*m_ptr->m_arr[i] = NULL; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (m_ptr->m_arr) \
|
||||||
|
free (m_ptr->m_arr); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CCFN_PARAMS _PARAMS((struct _reent *, const char *, char **, int))
|
#define CCFN_PARAMS _PARAMS((struct _reent *, const char *, char **, int))
|
||||||
u_long (*ccfn)CCFN_PARAMS=0; /* conversion function (strtol/strtoul) */
|
u_long (*ccfn)CCFN_PARAMS=0; /* conversion function (strtol/strtoul) */
|
||||||
|
@ -564,7 +681,7 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
|
if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
|
||||||
|| width)
|
|| width)
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
flags |= SUPPRESS;
|
flags |= SUPPRESS;
|
||||||
|
@ -645,6 +762,14 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
flags |= LONGDBL;
|
flags |= LONGDBL;
|
||||||
goto again;
|
goto again;
|
||||||
#endif /* _WANT_IO_C99_FORMATS */
|
#endif /* _WANT_IO_C99_FORMATS */
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
case 'm':
|
||||||
|
if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
|
||||||
|
goto match_failure;
|
||||||
|
init_m_ptr ();
|
||||||
|
flags |= MALLOC;
|
||||||
|
goto again;
|
||||||
|
#endif
|
||||||
|
|
||||||
case '0':
|
case '0':
|
||||||
case '1':
|
case '1':
|
||||||
|
@ -656,14 +781,14 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
case '7':
|
case '7':
|
||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
if (flags & (CHAR | SHORT | LONG | LONGDBL))
|
if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
width = width * 10 + c - '0';
|
width = width * 10 + c - '0';
|
||||||
goto again;
|
goto again;
|
||||||
|
|
||||||
#ifndef _NO_POS_ARGS
|
#ifndef _NO_POS_ARGS
|
||||||
case '$':
|
case '$':
|
||||||
if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
|
if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
if (width <= MAX_POS_ARGS)
|
if (width <= MAX_POS_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -851,12 +976,21 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
#if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 2
|
#if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 2
|
||||||
if (flags & LONG)
|
if (flags & LONG)
|
||||||
{
|
{
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
wchar_t **wcp_p = NULL;
|
||||||
|
wchar_t *wcp0 = NULL;
|
||||||
|
size_t width0 = 0;
|
||||||
|
#endif
|
||||||
mbstate_t state;
|
mbstate_t state;
|
||||||
memset (&state, 0, sizeof (mbstate_t));
|
memset (&state, 0, sizeof (mbstate_t));
|
||||||
if ((flags & SUPPRESS) == 0)
|
if (flags & SUPPRESS)
|
||||||
wcp = GET_ARG (N, ap, wchar_t *);
|
|
||||||
else
|
|
||||||
wcp = NULL;
|
wcp = NULL;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
else if (flags & MALLOC)
|
||||||
|
width0 = alloc_m_ptr (wchar_t, wcp, wcp0, wcp_p, width);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
wcp = GET_ARG (N, ap, wchar_t *);
|
||||||
n = 0;
|
n = 0;
|
||||||
while (width != 0)
|
while (width != 0)
|
||||||
{
|
{
|
||||||
|
@ -885,6 +1019,9 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (wchar_t, wcp_p, width0 - width, width0);
|
||||||
|
#endif
|
||||||
if (!(flags & SUPPRESS))
|
if (!(flags & SUPPRESS))
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
|
@ -919,10 +1056,20 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t r = _fread_r (rptr, (_PTR) GET_ARG (N, ap, char *), 1, width, fp);
|
size_t r;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
char **p_p = NULL;
|
||||||
|
if (flags & MALLOC)
|
||||||
|
alloc_m_ptr (char, p, p0, p_p, width);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
p = GET_ARG (N, ap, char *);
|
||||||
|
r = _fread_r (rptr, p, 1, width, fp);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
goto input_failure;
|
goto input_failure;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (char, p_p, r, width);
|
||||||
|
#endif
|
||||||
nread += r;
|
nread += r;
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
|
@ -953,11 +1100,22 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p0 = p = GET_ARG (N, ap, char *);
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
char **p_p = NULL;
|
||||||
|
size_t p_siz = 0;
|
||||||
|
|
||||||
|
if (flags & MALLOC)
|
||||||
|
p_siz = alloc_m_ptr (char, p, p0, p_p, 32);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
p0 = p = GET_ARG (N, ap, char *);
|
||||||
while (ccltab[*fp->_p])
|
while (ccltab[*fp->_p])
|
||||||
{
|
{
|
||||||
fp->_r--;
|
fp->_r--;
|
||||||
*p++ = *fp->_p++;
|
*p++ = *fp->_p++;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
p_siz = realloc_m_ptr (char, p, p0, p_p, p_siz);
|
||||||
|
#endif
|
||||||
if (--width == 0)
|
if (--width == 0)
|
||||||
break;
|
break;
|
||||||
if (BufferEmpty)
|
if (BufferEmpty)
|
||||||
|
@ -971,6 +1129,9 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
*p = 0;
|
*p = 0;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (char, p_p, n + 1, p_siz);
|
||||||
|
#endif
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
nread += n;
|
nread += n;
|
||||||
|
@ -983,13 +1144,22 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
#if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 2
|
#if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 2
|
||||||
if (flags & LONG)
|
if (flags & LONG)
|
||||||
{
|
{
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
wchar_t **wcp_p = NULL;
|
||||||
|
wchar_t *wcp0 = NULL;
|
||||||
|
size_t wcp_siz = 0;
|
||||||
|
#endif
|
||||||
/* Process %S and %ls placeholders */
|
/* Process %S and %ls placeholders */
|
||||||
mbstate_t state;
|
mbstate_t state;
|
||||||
memset (&state, 0, sizeof (mbstate_t));
|
memset (&state, 0, sizeof (mbstate_t));
|
||||||
if ((flags & SUPPRESS) == 0)
|
if (flags & SUPPRESS)
|
||||||
wcp = GET_ARG (N, ap, wchar_t *);
|
|
||||||
else
|
|
||||||
wcp = &wc;
|
wcp = &wc;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
else if (flags & MALLOC)
|
||||||
|
wcp_siz = alloc_m_ptr (wchar_t, wcp, wcp0, wcp_p, 32);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
wcp = GET_ARG (N, ap, wchar_t *);
|
||||||
n = 0;
|
n = 0;
|
||||||
while (!isspace (*fp->_p) && width != 0)
|
while (!isspace (*fp->_p) && width != 0)
|
||||||
{
|
{
|
||||||
|
@ -1014,7 +1184,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
nread += n;
|
nread += n;
|
||||||
width -= 1;
|
width -= 1;
|
||||||
if ((flags & SUPPRESS) == 0)
|
if ((flags & SUPPRESS) == 0)
|
||||||
wcp += 1;
|
{
|
||||||
|
wcp += 1;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
wcp_siz = realloc_m_ptr (wchar_t, wcp, wcp0, wcp_p,
|
||||||
|
wcp_siz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
n = 0;
|
n = 0;
|
||||||
}
|
}
|
||||||
if (BufferEmpty)
|
if (BufferEmpty)
|
||||||
|
@ -1027,6 +1203,9 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
if (!(flags & SUPPRESS))
|
if (!(flags & SUPPRESS))
|
||||||
{
|
{
|
||||||
*wcp = L'\0';
|
*wcp = L'\0';
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (wchar_t, wcp_p, wcp - wcp0 + 1, wcp_siz);
|
||||||
|
#endif
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1047,17 +1226,32 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p0 = p = GET_ARG (N, ap, char *);
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
char **p_p = NULL;
|
||||||
|
size_t p_siz = 0;
|
||||||
|
|
||||||
|
if (flags & MALLOC)
|
||||||
|
p_siz = alloc_m_ptr (char, p, p0, p_p, 32);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
p0 = GET_ARG (N, ap, char *);
|
||||||
|
p = p0;
|
||||||
while (!isspace (*fp->_p))
|
while (!isspace (*fp->_p))
|
||||||
{
|
{
|
||||||
fp->_r--;
|
fp->_r--;
|
||||||
*p++ = *fp->_p++;
|
*p++ = *fp->_p++;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
p_siz = realloc_m_ptr (char, p, p0, p_p, p_siz);
|
||||||
|
#endif
|
||||||
if (--width == 0)
|
if (--width == 0)
|
||||||
break;
|
break;
|
||||||
if (BufferEmpty)
|
if (BufferEmpty)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*p = 0;
|
*p = 0;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (char, p_p, p - p0 + 1, p_siz);
|
||||||
|
#endif
|
||||||
nread += p - p0;
|
nread += p - p0;
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
|
@ -1647,6 +1841,9 @@ match_failure:
|
||||||
all_done:
|
all_done:
|
||||||
/* Return number of matches, which can be 0 on match failure. */
|
/* Return number of matches, which can be 0 on match failure. */
|
||||||
_newlib_flockfile_end (fp);
|
_newlib_flockfile_end (fp);
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
free_m_ptr ();
|
||||||
|
#endif
|
||||||
return nassigned;
|
return nassigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,7 @@ static void * get_arg (int, va_list *, int *, void **);
|
||||||
#define SUPPRESS 0x10 /* suppress assignment */
|
#define SUPPRESS 0x10 /* suppress assignment */
|
||||||
#define POINTER 0x20 /* weird %p pointer (`fake hex') */
|
#define POINTER 0x20 /* weird %p pointer (`fake hex') */
|
||||||
#define NOSKIP 0x40 /* do not skip blanks */
|
#define NOSKIP 0x40 /* do not skip blanks */
|
||||||
|
#define MALLOC 0x80 /* handle 'm' modifier */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following are used in numeric conversions only:
|
* The following are used in numeric conversions only:
|
||||||
|
@ -424,6 +425,125 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
#ifndef _NO_LONGLONG
|
#ifndef _NO_LONGLONG
|
||||||
long long *llp;
|
long long *llp;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _WANT_IO_C99_FORMATS
|
||||||
|
#define _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
#endif
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
/* POSIX requires that fwscanf frees all allocated strings from 'm'
|
||||||
|
conversions in case it returns EOF. m_ptr is used to keep track.
|
||||||
|
It will be allocated on the stack the first time an 'm' conversion
|
||||||
|
takes place, and it will be free'd on return from the function.
|
||||||
|
This implementation tries to save space by only allocating 8
|
||||||
|
pointer slots at a time. Most scenarios should never have to call
|
||||||
|
realloc again. This implementation allows only up to 65528 'm'
|
||||||
|
conversions per fwscanf invocation for now. That should be enough
|
||||||
|
for almost all scenarios, right? */
|
||||||
|
struct m_ptrs {
|
||||||
|
void ***m_arr; /* Array of pointer args to 'm' conversion */
|
||||||
|
uint16_t m_siz; /* Number of slots in m_arr */
|
||||||
|
uint16_t m_cnt; /* Number of valid entries in m_arr */
|
||||||
|
} *m_ptr = NULL;
|
||||||
|
#define init_m_ptr() \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!m_ptr) \
|
||||||
|
{ \
|
||||||
|
m_ptr = (struct m_ptrs *) alloca (sizeof *m_ptr); \
|
||||||
|
m_ptr->m_arr = NULL; \
|
||||||
|
m_ptr->m_siz = 0; \
|
||||||
|
m_ptr->m_cnt = 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#define push_m_ptr(arg) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (m_ptr->m_cnt >= m_ptr->m_siz) \
|
||||||
|
{ \
|
||||||
|
void ***n = NULL; \
|
||||||
|
\
|
||||||
|
if (m_ptr->m_siz + 8 > 0 && m_ptr->m_siz + 8 < UINT16_MAX) \
|
||||||
|
n = (void ***) realloc (m_ptr->m_arr, \
|
||||||
|
(m_ptr->m_siz + 8) * \
|
||||||
|
sizeof (void **)); \
|
||||||
|
if (!n) \
|
||||||
|
{ \
|
||||||
|
nassigned = EOF; \
|
||||||
|
goto match_failure; \
|
||||||
|
} \
|
||||||
|
m_ptr->m_arr = n; \
|
||||||
|
m_ptr->m_siz += 8; \
|
||||||
|
} \
|
||||||
|
m_ptr->m_arr[m_ptr->m_cnt++] = (void **) (arg); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#define alloc_m_ptr(_type, _p, _p0, _p_p, _w) \
|
||||||
|
({ \
|
||||||
|
_p_p = GET_ARG (N, ap, _type **); \
|
||||||
|
if (!_p_p) \
|
||||||
|
goto match_failure; \
|
||||||
|
_p0 = (_type *) malloc ((_w) * sizeof (_type)); \
|
||||||
|
if (!_p0) \
|
||||||
|
{ \
|
||||||
|
nassigned = EOF; \
|
||||||
|
goto match_failure; \
|
||||||
|
} \
|
||||||
|
*_p_p = _p0; \
|
||||||
|
push_m_ptr (_p_p); \
|
||||||
|
_p = _p0; \
|
||||||
|
_w; \
|
||||||
|
})
|
||||||
|
#define realloc_m_ptr(_type, _p, _p0, _p_p, _w) \
|
||||||
|
({ \
|
||||||
|
size_t _nw = (_w); \
|
||||||
|
ptrdiff_t _dif = _p - _p0; \
|
||||||
|
if (_p_p && \
|
||||||
|
((sizeof (_type) == 1 && _dif >= _nw - MB_CUR_MAX) \
|
||||||
|
|| (sizeof (_type) != 1 && _dif == _nw))) \
|
||||||
|
{ \
|
||||||
|
_p0 = (_type *) realloc (_p0, (_nw << 1) * sizeof (_type)); \
|
||||||
|
if (!_p0) \
|
||||||
|
{ \
|
||||||
|
nassigned = EOF; \
|
||||||
|
goto match_failure; \
|
||||||
|
} \
|
||||||
|
_p = _p0 + _dif; \
|
||||||
|
*_p_p = _p0; \
|
||||||
|
_nw <<= 1; \
|
||||||
|
} \
|
||||||
|
_nw; \
|
||||||
|
})
|
||||||
|
#define shrink_m_ptr(_type, _p_p, _w, _cw) \
|
||||||
|
({ \
|
||||||
|
size_t _nw = (_w); \
|
||||||
|
if (_p_p && _nw < _cw) \
|
||||||
|
{ \
|
||||||
|
_type *_np_p = (_type *) \
|
||||||
|
realloc (*_p_p, _nw * sizeof (_type)); \
|
||||||
|
if (_np_p) \
|
||||||
|
*_p_p = _np_p; \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
#define free_m_ptr() \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (m_ptr) \
|
||||||
|
{ \
|
||||||
|
if (nassigned == EOF) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for (i = 0; i < m_ptr->m_cnt; ++i) \
|
||||||
|
{ \
|
||||||
|
free (*m_ptr->m_arr[i]); \
|
||||||
|
*m_ptr->m_arr[i] = NULL; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (m_ptr->m_arr) \
|
||||||
|
free (m_ptr->m_arr); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* `basefix' is used to avoid `if' tests in the integer scanner */
|
/* `basefix' is used to avoid `if' tests in the integer scanner */
|
||||||
static _CONST short basefix[17] =
|
static _CONST short basefix[17] =
|
||||||
|
@ -518,7 +638,7 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case L'*':
|
case L'*':
|
||||||
if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
|
if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
|
||||||
|| width)
|
|| width)
|
||||||
flags |= SUPPRESS;
|
flags |= SUPPRESS;
|
||||||
goto again;
|
goto again;
|
||||||
|
@ -598,6 +718,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
flags |= LONGDBL;
|
flags |= LONGDBL;
|
||||||
goto again;
|
goto again;
|
||||||
#endif /* _WANT_IO_C99_FORMATS */
|
#endif /* _WANT_IO_C99_FORMATS */
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
case 'm':
|
||||||
|
if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
|
||||||
|
goto match_failure;
|
||||||
|
init_m_ptr ();
|
||||||
|
flags |= MALLOC;
|
||||||
|
goto again;
|
||||||
|
#endif
|
||||||
|
|
||||||
case L'0':
|
case L'0':
|
||||||
case L'1':
|
case L'1':
|
||||||
|
@ -609,14 +737,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
case L'7':
|
case L'7':
|
||||||
case L'8':
|
case L'8':
|
||||||
case L'9':
|
case L'9':
|
||||||
if (flags & (CHAR | SHORT | LONG | LONGDBL))
|
if (flags & (CHAR | SHORT | LONG | LONGDBL | MALLOC))
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
width = width * 10 + c - L'0';
|
width = width * 10 + c - L'0';
|
||||||
goto again;
|
goto again;
|
||||||
|
|
||||||
#ifndef _NO_POS_ARGS
|
#ifndef _NO_POS_ARGS
|
||||||
case L'$':
|
case L'$':
|
||||||
if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
|
if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS | MALLOC))
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
if (width <= MAX_POS_ARGS)
|
if (width <= MAX_POS_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -787,7 +915,19 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
width = 1;
|
width = 1;
|
||||||
if (flags & LONG)
|
if (flags & LONG)
|
||||||
{
|
{
|
||||||
if (!(flags & SUPPRESS))
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
wchar_t **p_p = NULL;
|
||||||
|
wchar_t *p0 = NULL;
|
||||||
|
size_t width0 = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & SUPPRESS)
|
||||||
|
;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
else if (flags & MALLOC)
|
||||||
|
width0 = alloc_m_ptr (wchar_t, p, p0, p_p, width);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
p = GET_ARG(N, ap, wchar_t *);
|
p = GET_ARG(N, ap, wchar_t *);
|
||||||
n = 0;
|
n = 0;
|
||||||
while (width-- != 0 && (wi = _fgetwc_r (rptr, fp)) != WEOF)
|
while (width-- != 0 && (wi = _fgetwc_r (rptr, fp)) != WEOF)
|
||||||
|
@ -799,12 +939,27 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
goto input_failure;
|
goto input_failure;
|
||||||
nread += n;
|
nread += n;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (wchar_t, p_p, width0 - width, width0);
|
||||||
|
#endif
|
||||||
if (!(flags & SUPPRESS))
|
if (!(flags & SUPPRESS))
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(flags & SUPPRESS))
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
char **mbp_p = NULL;
|
||||||
|
char *mbp0 = NULL;
|
||||||
|
size_t width0 = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & SUPPRESS)
|
||||||
|
;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
else if (flags & MALLOC)
|
||||||
|
width0 = alloc_m_ptr (char, mbp, mbp0, mbp_p, width);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
mbp = GET_ARG(N, ap, char *);
|
mbp = GET_ARG(N, ap, char *);
|
||||||
n = 0;
|
n = 0;
|
||||||
memset ((_PTR)&mbs, '\0', sizeof (mbstate_t));
|
memset ((_PTR)&mbs, '\0', sizeof (mbstate_t));
|
||||||
|
@ -837,6 +992,9 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
goto input_failure;
|
goto input_failure;
|
||||||
nread += n;
|
nread += n;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (char, mbp_p, width0 - width, width0);
|
||||||
|
#endif
|
||||||
if (!(flags & SUPPRESS))
|
if (!(flags & SUPPRESS))
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
|
@ -860,27 +1018,58 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
}
|
}
|
||||||
else if (flags & LONG)
|
else if (flags & LONG)
|
||||||
{
|
{
|
||||||
p0 = p = GET_ARG(N, ap, wchar_t *);
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
wchar_t **p_p = NULL;
|
||||||
|
size_t p_siz = 0;
|
||||||
|
|
||||||
|
if (flags & MALLOC)
|
||||||
|
p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
p0 = p = GET_ARG(N, ap, wchar_t *);
|
||||||
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
||||||
&& width-- != 0 && INCCL (wi))
|
&& width-- != 0 && INCCL (wi))
|
||||||
*p++ = (wchar_t) wi;
|
{
|
||||||
|
*p++ = (wchar_t) wi;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (wi != WEOF)
|
if (wi != WEOF)
|
||||||
_ungetwc_r (rptr, wi, fp);
|
_ungetwc_r (rptr, wi, fp);
|
||||||
n = p - p0;
|
n = p - p0;
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
goto match_failure;
|
goto match_failure;
|
||||||
*p = L'\0';
|
*p = L'\0';
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (wchar_t, p_p, n + 1, p_siz);
|
||||||
|
#endif
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(flags & SUPPRESS))
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
char **mbp_p = NULL;
|
||||||
|
char *mbp0 = NULL;
|
||||||
|
size_t mbp_siz = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & SUPPRESS)
|
||||||
|
;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
else if (flags & MALLOC)
|
||||||
|
mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
mbp = GET_ARG(N, ap, char *);
|
mbp = GET_ARG(N, ap, char *);
|
||||||
n = 0;
|
n = 0;
|
||||||
memset ((_PTR) &mbs, '\0', sizeof (mbstate_t));
|
memset ((_PTR) &mbs, '\0', sizeof (mbstate_t));
|
||||||
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
||||||
&& width != 0 && INCCL (wi))
|
&& width != 0 && INCCL (wi))
|
||||||
{
|
{
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
|
||||||
|
#endif
|
||||||
if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
|
if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
|
||||||
{
|
{
|
||||||
nconv = _wcrtomb_r (rptr, mbp, wi, &mbs);
|
nconv = _wcrtomb_r (rptr, mbp, wi, &mbs);
|
||||||
|
@ -907,6 +1096,9 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
if (!(flags & SUPPRESS))
|
if (!(flags & SUPPRESS))
|
||||||
{
|
{
|
||||||
*mbp = 0;
|
*mbp = 0;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (char, mbp_p, mbp - mbp0 + 1, mbp_siz);
|
||||||
|
#endif
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -927,26 +1119,55 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
}
|
}
|
||||||
else if (flags & LONG)
|
else if (flags & LONG)
|
||||||
{
|
{
|
||||||
p0 = p = GET_ARG(N, ap, wchar_t *);
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
wchar_t **p_p = NULL;
|
||||||
|
size_t p_siz = 0;
|
||||||
|
|
||||||
|
if (flags & MALLOC)
|
||||||
|
p_siz = alloc_m_ptr (wchar_t, p, p0, p_p, 32);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
p0 = p = GET_ARG(N, ap, wchar_t *);
|
||||||
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
||||||
&& width-- != 0 && !iswspace (wi))
|
&& width-- != 0 && !iswspace (wi))
|
||||||
{
|
{
|
||||||
*p++ = (wchar_t) wi;
|
*p++ = (wchar_t) wi;
|
||||||
nread++;
|
nread++;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
p_siz = realloc_m_ptr (wchar_t, p, p0, p_p, p_siz);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (wi != WEOF)
|
if (wi != WEOF)
|
||||||
_ungetwc_r (rptr, wi, fp);
|
_ungetwc_r (rptr, wi, fp);
|
||||||
*p = L'\0';
|
*p = L'\0';
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (wchar_t, p_p, p - p0 + 1, p_siz);
|
||||||
|
#endif
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(flags & SUPPRESS))
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
char **mbp_p = NULL;
|
||||||
|
char *mbp0 = NULL;
|
||||||
|
size_t mbp_siz = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & SUPPRESS)
|
||||||
|
;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
else if (flags & MALLOC)
|
||||||
|
mbp_siz = alloc_m_ptr (char, mbp, mbp0, mbp_p, 32);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
mbp = GET_ARG(N, ap, char *);
|
mbp = GET_ARG(N, ap, char *);
|
||||||
memset ((_PTR) &mbs, '\0', sizeof (mbstate_t));
|
memset ((_PTR) &mbs, '\0', sizeof (mbstate_t));
|
||||||
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
while ((wi = _fgetwc_r (rptr, fp)) != WEOF
|
||||||
&& width != 0 && !iswspace (wi))
|
&& width != 0 && !iswspace (wi))
|
||||||
{
|
{
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
mbp_siz = realloc_m_ptr (char, mbp, mbp0, mbp_p, mbp_siz);
|
||||||
|
#endif
|
||||||
if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
|
if (width >= MB_CUR_MAX && !(flags & SUPPRESS))
|
||||||
{
|
{
|
||||||
nconv = wcrtomb(mbp, wi, &mbs);
|
nconv = wcrtomb(mbp, wi, &mbs);
|
||||||
|
@ -973,6 +1194,9 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
|
||||||
if (!(flags & SUPPRESS))
|
if (!(flags & SUPPRESS))
|
||||||
{
|
{
|
||||||
*mbp = 0;
|
*mbp = 0;
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
shrink_m_ptr (char, mbp_p, mbp - mbp0 + 1, mbp_siz);
|
||||||
|
#endif
|
||||||
nassigned++;
|
nassigned++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1492,6 +1716,9 @@ match_failure:
|
||||||
all_done:
|
all_done:
|
||||||
/* Return number of matches, which can be 0 on match failure. */
|
/* Return number of matches, which can be 0 on match failure. */
|
||||||
_newlib_flockfile_end (fp);
|
_newlib_flockfile_end (fp);
|
||||||
|
#ifdef _WANT_IO_POSIX_EXTENSIONS
|
||||||
|
free_m_ptr ();
|
||||||
|
#endif
|
||||||
return nassigned;
|
return nassigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue