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; } }
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; } }