mirror of
https://sourceware.org/git/glibc.git
synced 2025-10-24 13:33:08 +03:00
stdio-common: Convert macros across scanf input specifier tests
Convert 'compare_real', 'read_real', and 'verify_input' macros to functions so as to improve readability and avoid pitfalls. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This commit is contained in:
@@ -66,301 +66,306 @@
|
||||
#define initialize_value(val) \
|
||||
memset (&val, 0xa5, sizeof (val))
|
||||
|
||||
#define compare_real(x, y) \
|
||||
(memcmp (&(x), &(y), sizeof (y)) == 0)
|
||||
#ifndef compare_real
|
||||
static bool
|
||||
compare_real (type_t x, type_t y)
|
||||
{
|
||||
return memcmp (&x, &y, sizeof (y)) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define verify_input(f, val, count, errp) \
|
||||
({ \
|
||||
__label__ out; \
|
||||
bool match = true; \
|
||||
int errx = 0; \
|
||||
type_t v; \
|
||||
\
|
||||
initialize_value (v); \
|
||||
/* Make sure it's been committed. */ \
|
||||
__asm__ ("" : : : "memory"); \
|
||||
\
|
||||
v = read_real (&errx); \
|
||||
if (errx < 0) \
|
||||
goto out; \
|
||||
\
|
||||
match = compare_real (val, v); \
|
||||
if (!match) \
|
||||
{ \
|
||||
union \
|
||||
{ \
|
||||
type_t v; \
|
||||
unsigned char x[sizeof (type_t)]; \
|
||||
} \
|
||||
uv = { .v = v }, ui = { .v = val }; \
|
||||
\
|
||||
printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__); \
|
||||
for (size_t j = 0; j < sizeof (ui.x); j++) \
|
||||
printf ("%02hhx", ui.x[j]); \
|
||||
printf ("'\n"); \
|
||||
printf ("error: %s:%d: value buffer: `", __FILE__, __LINE__); \
|
||||
for (size_t j = 0; j < sizeof (uv.x); j++) \
|
||||
printf ("%02hhx", uv.x[j]); \
|
||||
printf ("'\n"); \
|
||||
} \
|
||||
\
|
||||
out: \
|
||||
*errp = errx; \
|
||||
match; \
|
||||
})
|
||||
static type_t
|
||||
read_real (int *errp)
|
||||
{
|
||||
bool m = false;
|
||||
int err = 0;
|
||||
type_t v;
|
||||
int ch;
|
||||
|
||||
#define read_real(errp) \
|
||||
({ \
|
||||
__label__ out; \
|
||||
bool m = false; \
|
||||
int err = 0; \
|
||||
type_t v; \
|
||||
int ch; \
|
||||
\
|
||||
ch = read_input (); \
|
||||
if (ch == '-' || ch == '+') \
|
||||
{ \
|
||||
m = ch == '-'; \
|
||||
ch = read_input (); \
|
||||
} \
|
||||
\
|
||||
switch (ch) \
|
||||
{ \
|
||||
case '0': \
|
||||
break; \
|
||||
case 'I': \
|
||||
case 'i': \
|
||||
{ \
|
||||
static const char unf[] = { 'N', 'F' }; \
|
||||
static const char lnf[] = { 'n', 'f' }; \
|
||||
size_t i; \
|
||||
\
|
||||
for (i = 0; i < sizeof (unf); i++) \
|
||||
{ \
|
||||
ch = read_input (); \
|
||||
if (ch != unf[i] && ch != lnf[i]) \
|
||||
{ \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ch = read_input (); \
|
||||
if (ch == ':') \
|
||||
{ \
|
||||
v = m ? -INFINITY : +INFINITY; \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
static const char uinity[] = { 'I', 'N', 'I', 'T', 'Y' }; \
|
||||
static const char linity[] = { 'i', 'n', 'i', 't', 'y' }; \
|
||||
\
|
||||
for (i = 0; i < sizeof (uinity); i++) \
|
||||
{ \
|
||||
if (ch != uinity[i] && ch != linity[i]) \
|
||||
{ \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
ch = read_input (); \
|
||||
} \
|
||||
if (ch == ':') \
|
||||
{ \
|
||||
v = m ? -INFINITY : +INFINITY; \
|
||||
goto out; \
|
||||
} \
|
||||
} \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
\
|
||||
case 'N': \
|
||||
case 'n': \
|
||||
{ \
|
||||
static const char uan[] = { 'A', 'N' }; \
|
||||
static const char lan[] = { 'a', 'n' }; \
|
||||
size_t i; \
|
||||
\
|
||||
for (i = 0; i < sizeof (uan); i++) \
|
||||
{ \
|
||||
ch = read_input (); \
|
||||
if (ch != uan[i] && ch != lan[i]) \
|
||||
{ \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ch = read_input (); \
|
||||
if (ch == ':') \
|
||||
{ \
|
||||
v = m ? -nan (v, ".") : nan (v, "."); \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
if (ch == '(') \
|
||||
{ \
|
||||
size_t seq_size = 0; \
|
||||
char *seq = NULL; \
|
||||
i = 0; \
|
||||
while (1) \
|
||||
{ \
|
||||
if (i == seq_size) \
|
||||
{ \
|
||||
seq_size += SIZE_CHUNK; \
|
||||
seq = xrealloc (seq, seq_size); \
|
||||
} \
|
||||
ch = read_input (); \
|
||||
if (ch == ')') \
|
||||
break; \
|
||||
if (ch != '_' && !isdigit (ch) \
|
||||
&& !(ch >= 'A' && ch <= 'Z') \
|
||||
&& !(ch >= 'a' && ch <= 'z')) \
|
||||
{ \
|
||||
free (seq); \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
seq[i++] = ch; \
|
||||
} \
|
||||
seq[i] = '\0'; \
|
||||
\
|
||||
ch = read_input (); \
|
||||
if (ch == ':') \
|
||||
{ \
|
||||
v = m ? -nan (v, seq) : nan (v, seq); \
|
||||
free (seq); \
|
||||
goto out; \
|
||||
} \
|
||||
free (seq); \
|
||||
} \
|
||||
} \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
\
|
||||
default: \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
ch = read_input (); \
|
||||
if (ch != 'X' && ch != 'x') \
|
||||
{ \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
type_t f = m ? -1.0 : 1.0; \
|
||||
v = m ? -0.0 : 0.0; \
|
||||
int i = 0; \
|
||||
do \
|
||||
{ \
|
||||
int d = 0; \
|
||||
\
|
||||
ch = read_input (); \
|
||||
\
|
||||
if (i == 1) \
|
||||
switch (ch) \
|
||||
{ \
|
||||
case '.': \
|
||||
i++; \
|
||||
continue; \
|
||||
\
|
||||
case ':': \
|
||||
case 'P': \
|
||||
case 'p': \
|
||||
break; \
|
||||
\
|
||||
default: \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
switch (ch) \
|
||||
{ \
|
||||
case '0': \
|
||||
case '1': \
|
||||
case '2': \
|
||||
case '3': \
|
||||
case '4': \
|
||||
case '5': \
|
||||
case '6': \
|
||||
case '7': \
|
||||
case '8': \
|
||||
case '9': \
|
||||
d = ch - '0'; \
|
||||
break; \
|
||||
\
|
||||
case 'A': \
|
||||
case 'B': \
|
||||
case 'C': \
|
||||
case 'D': \
|
||||
case 'E': \
|
||||
case 'F': \
|
||||
d = ch - 'A' + 10; \
|
||||
break; \
|
||||
\
|
||||
case 'a': \
|
||||
case 'b': \
|
||||
case 'c': \
|
||||
case 'd': \
|
||||
case 'e': \
|
||||
case 'f': \
|
||||
d = ch - 'a' + 10; \
|
||||
break; \
|
||||
\
|
||||
case ':': \
|
||||
case 'P': \
|
||||
case 'p': \
|
||||
if (i == 0) \
|
||||
{ \
|
||||
err = INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
break; \
|
||||
\
|
||||
default: \
|
||||
err = ch < 0 ? ch : INPUT_FORMAT; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
v += f * d; \
|
||||
f /= 16.0l; \
|
||||
i++; \
|
||||
} \
|
||||
while (ch != ':' && ch != 'P' && ch != 'p'); \
|
||||
\
|
||||
long long exp = 0; \
|
||||
if (ch == 'P' || ch == 'p') \
|
||||
{ \
|
||||
exp = read_integer (&err); \
|
||||
if (err) \
|
||||
{ \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
errno = 0; \
|
||||
v = ldexp (v, exp); \
|
||||
if ((v == HUGE_VALL || v == -HUGE_VALL) && errno != 0) \
|
||||
{ \
|
||||
err = INPUT_OVERFLOW; \
|
||||
v = NAN; \
|
||||
goto out; \
|
||||
} \
|
||||
\
|
||||
out: \
|
||||
*errp = err; \
|
||||
v; \
|
||||
})
|
||||
ch = read_input ();
|
||||
if (ch == '-' || ch == '+')
|
||||
{
|
||||
m = ch == '-';
|
||||
ch = read_input ();
|
||||
}
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '0':
|
||||
break;
|
||||
case 'I':
|
||||
case 'i':
|
||||
{
|
||||
static const char unf[] = { 'N', 'F' };
|
||||
static const char lnf[] = { 'n', 'f' };
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof (unf); i++)
|
||||
{
|
||||
ch = read_input ();
|
||||
if (ch != unf[i] && ch != lnf[i])
|
||||
{
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ch = read_input ();
|
||||
if (ch == ':')
|
||||
{
|
||||
v = m ? -INFINITY : +INFINITY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static const char uinity[] = { 'I', 'N', 'I', 'T', 'Y' };
|
||||
static const char linity[] = { 'i', 'n', 'i', 't', 'y' };
|
||||
|
||||
for (i = 0; i < sizeof (uinity); i++)
|
||||
{
|
||||
if (ch != uinity[i] && ch != linity[i])
|
||||
{
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
ch = read_input ();
|
||||
}
|
||||
if (ch == ':')
|
||||
{
|
||||
v = m ? -INFINITY : +INFINITY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
|
||||
case 'N':
|
||||
case 'n':
|
||||
{
|
||||
static const char uan[] = { 'A', 'N' };
|
||||
static const char lan[] = { 'a', 'n' };
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof (uan); i++)
|
||||
{
|
||||
ch = read_input ();
|
||||
if (ch != uan[i] && ch != lan[i])
|
||||
{
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ch = read_input ();
|
||||
if (ch == ':')
|
||||
{
|
||||
v = m ? -nan (v, ".") : nan (v, ".");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ch == '(')
|
||||
{
|
||||
size_t seq_size = 0;
|
||||
char *seq = NULL;
|
||||
i = 0;
|
||||
while (1)
|
||||
{
|
||||
if (i == seq_size)
|
||||
{
|
||||
seq_size += SIZE_CHUNK;
|
||||
seq = xrealloc (seq, seq_size);
|
||||
}
|
||||
ch = read_input ();
|
||||
if (ch == ')')
|
||||
break;
|
||||
if (ch != '_' && !isdigit (ch)
|
||||
&& !(ch >= 'A' && ch <= 'Z')
|
||||
&& !(ch >= 'a' && ch <= 'z'))
|
||||
{
|
||||
free (seq);
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
seq[i++] = ch;
|
||||
}
|
||||
seq[i] = '\0';
|
||||
|
||||
ch = read_input ();
|
||||
if (ch == ':')
|
||||
{
|
||||
v = m ? -nan (v, seq) : nan (v, seq);
|
||||
free (seq);
|
||||
goto out;
|
||||
}
|
||||
free (seq);
|
||||
}
|
||||
}
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch = read_input ();
|
||||
if (ch != 'X' && ch != 'x')
|
||||
{
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type_t f = m ? -1.0 : 1.0;
|
||||
v = m ? -0.0 : 0.0;
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
int d = 0;
|
||||
|
||||
ch = read_input ();
|
||||
|
||||
if (i == 1)
|
||||
switch (ch)
|
||||
{
|
||||
case '.':
|
||||
i++;
|
||||
continue;
|
||||
|
||||
case ':':
|
||||
case 'P':
|
||||
case 'p':
|
||||
break;
|
||||
|
||||
default:
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
d = ch - '0';
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
d = ch - 'A' + 10;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
d = ch - 'a' + 10;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
case 'P':
|
||||
case 'p':
|
||||
if (i == 0)
|
||||
{
|
||||
err = INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err = ch < 0 ? ch : INPUT_FORMAT;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
v += f * d;
|
||||
f /= 16.0l;
|
||||
i++;
|
||||
}
|
||||
while (ch != ':' && ch != 'P' && ch != 'p');
|
||||
|
||||
long long exp = 0;
|
||||
if (ch == 'P' || ch == 'p')
|
||||
{
|
||||
exp = read_integer (&err);
|
||||
if (err)
|
||||
{
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
v = ldexp (v, exp);
|
||||
if ((v == HUGE_VALL || v == -HUGE_VALL) && errno != 0)
|
||||
{
|
||||
err = INPUT_OVERFLOW;
|
||||
v = NAN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
*errp = err;
|
||||
return v;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_input (char f, type_t val, long long count, int *errp)
|
||||
{
|
||||
bool match = true;
|
||||
int err = 0;
|
||||
type_t v;
|
||||
|
||||
initialize_value (v);
|
||||
/* Make sure it's been committed. */
|
||||
__asm__ ("" : : : "memory");
|
||||
|
||||
v = read_real (&err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
match = compare_real (val, v);
|
||||
if (!match)
|
||||
{
|
||||
union
|
||||
{
|
||||
type_t v;
|
||||
unsigned char x[sizeof (type_t)];
|
||||
}
|
||||
uv = { .v = v }, ui = { .v = val };
|
||||
|
||||
printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);
|
||||
for (size_t j = 0; j < sizeof (ui.x); j++)
|
||||
printf ("%02hhx", ui.x[j]);
|
||||
printf ("'\n");
|
||||
printf ("error: %s:%d: value buffer: `", __FILE__, __LINE__);
|
||||
for (size_t j = 0; j < sizeof (uv.x); j++)
|
||||
printf ("%02hhx", uv.x[j]);
|
||||
printf ("'\n");
|
||||
}
|
||||
|
||||
out:
|
||||
*errp = err;
|
||||
return match;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user