glsl/pp: Validate numbers.

This commit is contained in:
Michal Krol
2009-09-16 21:51:12 +02:00
parent de0753e4cb
commit a7382628f2
+229 -25
View File
@@ -29,6 +29,13 @@
#include "sl_pp_token.h"
static int
_is_identifier_char(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static int
_tokenise_identifier(struct sl_pp_context *context,
const char **pinput,
@@ -42,10 +49,7 @@ _tokenise_identifier(struct sl_pp_context *context,
info->data.identifier = -1;
identifier[i++] = *input++;
while ((*input >= 'a' && *input <= 'z') ||
(*input >= 'A' && *input <= 'Z') ||
(*input >= '0' && *input <= '9') ||
(*input == '_')) {
while (_is_identifier_char(*input)) {
if (i >= sizeof(identifier) - 1) {
strcpy(context->error_msg, "out of memory");
return -1;
@@ -64,41 +68,241 @@ _tokenise_identifier(struct sl_pp_context *context,
}
/*
* Return the number of consecutive decimal digits in the input stream.
*/
static unsigned int
_parse_float_digits(const char *input)
{
unsigned int eaten = 0;
while (input[eaten] >= '0' && input[eaten] <= '9') {
eaten++;
}
return eaten;
}
/*
* Try to match one of the following patterns for the fractional part
* of a floating point number.
*
* digits . [digits]
* . digits
*
* Return 0 if the pattern could not be matched, otherwise the number
* of eaten characters from the input stream.
*/
static unsigned int
_parse_float_frac(const char *input)
{
unsigned int eaten;
if (input[0] == '.') {
eaten = _parse_float_digits(&input[1]);
if (eaten) {
return eaten + 1;
}
return 0;
}
eaten = _parse_float_digits(input);
if (eaten && input[eaten] == '.') {
unsigned int trailing;
trailing = _parse_float_digits(&input[eaten + 1]);
if (trailing) {
return eaten + trailing + 1;
}
return eaten + 1;
}
return 0;
}
/*
* Try to match the following pattern for the exponential part
* of a floating point number.
*
* (e|E) [(+|-)] digits
*
* Return 0 if the pattern could not be matched, otherwise the number
* of eaten characters from the input stream.
*/
static unsigned int
_parse_float_exp(const char *input)
{
unsigned int eaten, digits;
if (input[0] != 'e' && input[0] != 'E') {
return 0;
}
if (input[1] == '-' || input[1] == '+') {
eaten = 2;
} else {
eaten = 1;
}
digits = _parse_float_digits(&input[eaten]);
if (!digits) {
return 0;
}
return eaten + digits;
}
/*
* Try to match one of the following patterns for a floating point number.
*
* fract [exp] [(f|F)]
* digits exp [(f|F)]
*
* Return 0 if the pattern could not be matched, otherwise the number
* of eaten characters from the input stream.
*/
static unsigned int
_parse_float(const char *input)
{
unsigned int eaten;
eaten = _parse_float_frac(input);
if (eaten) {
unsigned int exponent;
exponent = _parse_float_exp(&input[eaten]);
if (exponent) {
eaten += exponent;
}
if (input[eaten] == 'f' || input[eaten] == 'F') {
eaten++;
}
return eaten;
}
eaten = _parse_float_digits(input);
if (eaten) {
unsigned int exponent;
exponent = _parse_float_exp(&input[eaten]);
if (exponent) {
eaten += exponent;
if (input[eaten] == 'f' || input[eaten] == 'F') {
eaten++;
}
return eaten;
}
}
return 0;
}
static unsigned int
_parse_hex(const char *input)
{
unsigned int n;
if (input[0] != '0') {
return 0;
}
if (input[1] != 'x' && input[1] != 'X') {
return 0;
}
n = 2;
while ((input[n] >= '0' && input[n] <= '9') ||
(input[n] >= 'a' && input[n] <= 'f') ||
(input[n] >= 'A' && input[n] <= 'F')) {
n++;
}
if (n > 2) {
return n;
}
return 0;
}
static unsigned int
_parse_oct(const char *input)
{
unsigned int n;
if (input[0] != '0') {
return 0;
}
n = 1;
while ((input[n] >= '0' && input[n] <= '7')) {
n++;
}
return n;
}
static unsigned int
_parse_dec(const char *input)
{
unsigned int n = 0;
while ((input[n] >= '0' && input[n] <= '9')) {
n++;
}
return n;
}
static int
_tokenise_number(struct sl_pp_context *context,
const char **pinput,
struct sl_pp_token_info *info)
{
const char *input = *pinput;
unsigned int eaten;
char number[256]; /* XXX: Remove this artifical limit. */
unsigned int i = 0;
eaten = _parse_float(input);
if (!eaten) {
eaten = _parse_hex(input);
if (!eaten) {
eaten = _parse_oct(input);
if (!eaten) {
eaten = _parse_dec(input);
}
}
}
if (!eaten || _is_identifier_char(input[eaten])) {
strcpy(context->error_msg, "expected a number");
return -1;
}
if (eaten > sizeof(number) - 1) {
strcpy(context->error_msg, "out of memory");
return -1;
}
memcpy(number, input, eaten);
number[eaten] = '\0';
info->token = SL_PP_NUMBER;
info->data.number = -1;
number[i++] = *input++;
while ((*input >= '0' && *input <= '9') ||
(*input >= 'a' && *input <= 'f') ||
(*input >= 'A' && *input <= 'F') ||
(*input == 'x') ||
(*input == 'X') ||
(*input == '+') ||
(*input == '-') ||
(*input == '.')) {
if (i >= sizeof(number) - 1) {
strcpy(context->error_msg, "out of memory");
return -1;
}
number[i++] = *input++;
}
number[i++] = '\0';
info->data.number = sl_pp_context_add_unique_str(context, number);
if (info->data.number == -1) {
return -1;
}
*pinput = input;
*pinput = input + eaten;
return 0;
}