glsl/pp: Validate numbers.
authorMichal Krol <michal@vmware.com>
Wed, 16 Sep 2009 19:51:12 +0000 (21:51 +0200)
committerMichal Krol <michal@vmware.com>
Wed, 16 Sep 2009 19:51:12 +0000 (21:51 +0200)
src/glsl/pp/sl_pp_token.c

index 95fe4f7d85e884c4ba7b5d2e0283a685fc0eb102..a6a2bb2748546ad608fec55bf986cf91640ebf3e 100644 (file)
 #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;
 
-   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;
+   eaten = _parse_float(input);
+   if (!eaten) {
+      eaten = _parse_hex(input);
+      if (!eaten) {
+         eaten = _parse_oct(input);
+         if (!eaten) {
+            eaten = _parse_dec(input);
+         }
       }
-      number[i++] = *input++;
    }
-   number[i++] = '\0';
 
+   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 = sl_pp_context_add_unique_str(context, number);
    if (info->data.number == -1) {
       return -1;
    }
 
-   *pinput = input;
+   *pinput = input + eaten;
    return 0;
 }