예제 #1
0
static bool
parse_argument(const char *string,             /* original user string */
               const char **ret_p,             /* start of argument IN:OUT */
               const cg_blend_string_statement_t *statement,
               int current_arg,
               cg_blend_string_argument_t *arg,             /* OUT */
               cg_error_t **error)
{
    const char *p = *ret_p;
    const char *mark = NULL;
    const char *error_string = NULL;
    parser_arg_state_t state = PARSER_ARG_STATE_START;
    bool parsing_factor = false;
    bool implicit_factor_brace;

    arg->source.is_zero = false;
    arg->source.info = NULL;
    arg->source.texture = 0;
    arg->source.one_minus = false;
    arg->source.mask = statement->mask;

    arg->factor.is_one = false;
    arg->factor.is_color = false;
    arg->factor.is_src_alpha_saturate = false;

    arg->factor.source.is_zero = false;
    arg->factor.source.info = NULL;
    arg->factor.source.texture = 0;
    arg->factor.source.one_minus = false;
    arg->factor.source.mask = statement->mask;

    do {
        if (c_ascii_isspace(*p))
            continue;

        if (*p == '\0') {
            error_string = "Unexpected end of string while parsing argument";
            goto error;
        }

        switch (state) {
        case PARSER_ARG_STATE_START:
            if (*p == '1')
                state = PARSER_ARG_STATE_EXPECT_MINUS;
            else if (*p == '0') {
                arg->source.is_zero = true;
                state = PARSER_ARG_STATE_EXPECT_END;
            } else {
                p--; /* backtrack */
                state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            }
            continue;

        case PARSER_ARG_STATE_EXPECT_MINUS:
            if (*p != '-') {
                error_string = "expected a '-' following the 1";
                goto error;
            }
            arg->source.one_minus = true;
            state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            continue;

        case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME:
            if (!is_symbol_char(*p)) {
                error_string = "expected a color source name";
                goto error;
            }
            state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME;
            mark = p;
            if (parsing_factor)
                arg->factor.is_color = true;

        /* fall through */
        case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME:
            if (!is_symbol_char(*p)) {
                cg_blend_string_color_source_t *source =
                    parsing_factor ? &arg->factor.source : &arg->source;
                source->info = get_color_src_info(mark, p);
                if (!source->info) {
                    error_string = "Unknown color source name";
                    goto error;
                }
                state = PARSER_ARG_STATE_MAYBE_COLOR_MASK;
            } else
                continue;

        /* fall through */
        case PARSER_ARG_STATE_MAYBE_COLOR_MASK:
            if (*p != '[') {
                p--; /* backtrack */
                if (!parsing_factor)
                    state = PARSER_ARG_STATE_MAYBE_MULT;
                else
                    state = PARSER_ARG_STATE_EXPECT_END;
                continue;
            }
            state = PARSER_ARG_STATE_SCRAPING_MASK;
            mark = p;

        /* fall through */
        case PARSER_ARG_STATE_SCRAPING_MASK:
            if (*p == ']') {
                size_t len = p - mark;
                cg_blend_string_color_source_t *source =
                    parsing_factor ? &arg->factor.source : &arg->source;

                if (len == 5 && strncmp(mark, "[RGBA", len) == 0) {
                    if (statement->mask != CG_BLEND_STRING_CHANNEL_MASK_RGBA) {
                        error_string =
                            "You can't use an RGBA color mask if the "
                            "statement hasn't also got an RGBA= mask";
                        goto error;
                    }
                    source->mask = CG_BLEND_STRING_CHANNEL_MASK_RGBA;
                } else if (len == 4 && strncmp(mark, "[RGB", len) == 0)
                    source->mask = CG_BLEND_STRING_CHANNEL_MASK_RGB;
                else if (len == 2 && strncmp(mark, "[A", len) == 0)
                    source->mask = CG_BLEND_STRING_CHANNEL_MASK_ALPHA;
                else {
                    error_string = "Expected a channel mask of [RGBA]"
                                   "[RGB] or [A]";
                    goto error;
                }
                if (parsing_factor)
                    state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
                else
                    state = PARSER_ARG_STATE_MAYBE_MULT;
            }
            continue;

        case PARSER_ARG_STATE_EXPECT_OPEN_PAREN:
            if (*p != '(') {
                if (is_alphanum_char(*p)) {
                    p--; /* compensate for implicit brace and ensure this
                          * char gets considered part of the blend factor */
                    implicit_factor_brace = true;
                } else {
                    error_string = "Expected '(' around blend factor or alpha "
                                   "numeric character for blend factor name";
                    goto error;
                }
            } else
                implicit_factor_brace = false;
            parsing_factor = true;
            state = PARSER_ARG_STATE_EXPECT_FACTOR;
            continue;

        case PARSER_ARG_STATE_EXPECT_FACTOR:
            if (*p == '1')
                state = PARSER_ARG_STATE_MAYBE_MINUS;
            else if (*p == '0') {
                arg->source.is_zero = true;
                state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
            } else {
                state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE;
                mark = p;
            }
            continue;

        case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE:
            if (!is_symbol_char(*p)) {
                size_t len = p - mark;
                if (len >= strlen("SRC_ALPHA_SATURATE") &&
                    strncmp(mark, "SRC_ALPHA_SATURATE", len) == 0) {
                    arg->factor.is_src_alpha_saturate = true;
                    state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
                } else {
                    state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
                    p = mark - 1; /* backtrack */
                }
            }
            continue;

        case PARSER_ARG_STATE_MAYBE_MINUS:
            if (*p == '-') {
                if (implicit_factor_brace) {
                    error_string =
                        "Expected ( ) braces around blend factor with "
                        "a subtraction";
                    goto error;
                }
                arg->factor.source.one_minus = true;
                state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            } else {
                arg->factor.is_one = true;
                state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
            }
            continue;

        case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN:
            if (implicit_factor_brace) {
                p--;
                state = PARSER_ARG_STATE_EXPECT_END;
                continue;
            }
            if (*p != ')') {
                error_string =
                    "Expected closing parenthesis after blend factor";
                goto error;
            }
            state = PARSER_ARG_STATE_EXPECT_END;
            continue;

        case PARSER_ARG_STATE_MAYBE_MULT:
            if (*p == '*') {
                state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN;
                continue;
            }
            arg->factor.is_one = true;
            state = PARSER_ARG_STATE_EXPECT_END;

        /* fall through */
        case PARSER_ARG_STATE_EXPECT_END:
            if (*p != ',' && *p != ')') {
                error_string = "expected , or )";
                goto error;
            }

            *ret_p = p - 1;
            return true;
        }
    } while (p++);

error: {
        int offset = p - string;
        _cg_set_error(error,
                      CG_BLEND_STRING_ERROR,
                      CG_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR,
                      "Syntax error for argument %d at offset %d: %s",
                      current_arg,
                      offset,
                      error_string);

        if (CG_DEBUG_ENABLED(CG_DEBUG_BLEND_STRINGS)) {
            c_debug("Syntax error for argument %d at offset %d: %s",
                    current_arg,
                    offset,
                    error_string);
        }
        return false;
    }
}
예제 #2
0
static gboolean
parse_argument (const char *string, /* original user string */
                const char **ret_p, /* start of argument IN:OUT */
                const CoglBlendStringStatement *statement,
                int current_arg,
                CoglBlendStringArgument *arg, /* OUT */
                CoglBlendStringContext context,
                GError **error)
{
  const char *p = *ret_p;
  const char *mark = NULL;
  const char *error_string = NULL;
  ParserArgState state = PARSER_ARG_STATE_START;
  gboolean parsing_factor = FALSE;

  arg->source.is_zero = FALSE;
  arg->source.info = NULL;
  arg->source.texture = 0;
  arg->source.one_minus = FALSE;
  arg->source.mask = statement->mask;

  arg->factor.is_one = FALSE;
  arg->factor.is_color = FALSE;
  arg->factor.is_src_alpha_saturate = FALSE;

  arg->factor.source.is_zero = FALSE;
  arg->factor.source.info = NULL;
  arg->factor.source.texture = 0;
  arg->factor.source.one_minus = FALSE;
  arg->factor.source.mask = statement->mask;

  do
    {
      if (g_ascii_isspace (*p))
        continue;

      if (*p == '\0')
        {
          error_string = "Unexpected end of string while parsing argument";
          goto error;
        }

      switch (state)
        {
        case PARSER_ARG_STATE_START:
          if (*p == '1')
            state = PARSER_ARG_STATE_EXPECT_MINUS;
          else if (*p == '0')
            {
              arg->source.is_zero = TRUE;
              state = PARSER_ARG_STATE_EXPECT_END;
            }
          else
            {
              p--; /* backtrack */
              state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            }
          continue;

        case PARSER_ARG_STATE_EXPECT_MINUS:
          if (*p != '-')
            {
              error_string = "expected a '-' following the 1";
              goto error;
            }
          arg->source.one_minus = TRUE;
          state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
          continue;

        case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME:
          if (!is_symbol_char (*p))
            {
              error_string = "expected a color source name";
              goto error;
            }
          state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME;
          mark = p;
          if (parsing_factor)
            arg->factor.is_color = TRUE;

          /* fall through */
        case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME:
          if (!is_symbol_char (*p))
            {
              CoglBlendStringColorSource *source =
                parsing_factor ? &arg->factor.source : &arg->source;
              source->info = get_color_src_info (mark, p, context);
              if (!source->info)
                {
                  error_string = "Unknown color source name";
                  goto error;
                }
              if (source->info->type ==
                  COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N)
                {
                  char *endp;
                  source->texture =
                    strtoul (&mark[strlen ("TEXTURE_")], &endp, 10);
                  if (mark == endp)
                    {
                      error_string = "invalid texture number given with "
                                     "TEXTURE_N color source";
                      goto error;
                    }
                  p = endp;
                }
              state = PARSER_ARG_STATE_MAYBE_COLOR_MASK;
            }
          else
            continue;

          /* fall through */
        case PARSER_ARG_STATE_MAYBE_COLOR_MASK:
          if (*p != '[')
            {
              p--; /* backtrack */
              if (!parsing_factor)
                state = PARSER_ARG_STATE_MAYBE_MULT;
              else
                state = PARSER_ARG_STATE_EXPECT_END;
              continue;
            }
          state = PARSER_ARG_STATE_SCRAPING_MASK;
          mark = p;

          /* fall through */
        case PARSER_ARG_STATE_SCRAPING_MASK:
          if (*p == ']')
            {
              gsize len = p - mark;
              CoglBlendStringColorSource *source =
                parsing_factor ? &arg->factor.source : &arg->source;

              if (len == 5 && strncmp (mark, "[RGBA", len) == 0)
                {
                  if (statement->mask != COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
                    {
                      error_string = "You can't use an RGBA color mask if the "
                                     "statement hasn't also got an RGBA= mask";
                      goto error;
                    }
                  source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA;
                }
              else if (len == 4 && strncmp (mark, "[RGB", len) == 0)
                source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
              else if (len == 2 && strncmp (mark, "[A", len) == 0)
                source->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
              else
                {
                  error_string = "Expected a channel mask of [RGBA]"
                                 "[RGB] or [A]";
                  goto error;
                }
              if (parsing_factor)
                state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
              else
                state = PARSER_ARG_STATE_MAYBE_MULT;
            }
          continue;

        case PARSER_ARG_STATE_EXPECT_OPEN_PAREN:
          if (*p != '(')
            {
              error_string = "Expected '(' before blend factor - the parser "
                             "currently requires that all blend factors "
                             "following a '*' be surrounded in brackets";
              goto error;
            }
          parsing_factor = TRUE;
          state = PARSER_ARG_STATE_EXPECT_FACTOR;
          continue;

        case PARSER_ARG_STATE_EXPECT_FACTOR:
          if (*p == '1')
            state = PARSER_ARG_STATE_MAYBE_MINUS;
          else if (*p == '0')
            {
              arg->source.is_zero = TRUE;
              state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
            }
          else
            {
              state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE;
              mark = p;
            }
          continue;

        case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE:
          if (!is_symbol_char (*p))
            {
              gsize len = p - mark;
              if (len >= strlen ("SRC_ALPHA_SATURATE") &&
                  strncmp (mark, "SRC_ALPHA_SATURATE", len) == 0)
                {
                  arg->factor.is_src_alpha_saturate = TRUE;
                  state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
                }
              else
                {
                  state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
                  p = mark - 1; /* backtrack */
                }
            }
          continue;

        case PARSER_ARG_STATE_MAYBE_MINUS:
          if (*p == '-')
            {
              arg->factor.source.one_minus = TRUE;
              state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            }
          else
            {
              arg->factor.is_one = TRUE;
              state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
            }
          continue;

        case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN:
          if (*p != ')')
            {
              error_string = "Expected closing parenthesis after blend factor";
              goto error;
            }
          state = PARSER_ARG_STATE_EXPECT_END;
          continue;

        case PARSER_ARG_STATE_MAYBE_MULT:
          if (*p == '*')
            {
              state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN;
              continue;
            }
          arg->factor.is_one = TRUE;
          state = PARSER_ARG_STATE_EXPECT_END;

          /* fall through */
        case PARSER_ARG_STATE_EXPECT_END:
          if (*p != ',' && *p != ')')
            {
              error_string = "expected , or )";
              goto error;
            }

          *ret_p = p - 1;
          return TRUE;
        }
    }
  while (p++);

error:
  {
    int offset = p - string;
    g_set_error (error,
                 COGL_BLEND_STRING_ERROR,
                 COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR,
                 "Syntax error for argument %d at offset %d: %s",
                 current_arg,
                 offset,
                 error_string);

    if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
      {
        g_debug ("Syntax error for argument %d at offset %d: %s",
                 current_arg, offset, error_string);
      }
    return FALSE;
  }
}