/* * This file is part of LibCSS. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org> */ #include <assert.h>#include <ctype.h>#include <stdbool.h> #include <libwapcaplet/libwapcaplet.h> #include <parserutils/input/inputstream.h>#include <parserutils/utils/stack.h>#include <parserutils/utils/vector.h> #include "charset/detect.h"#include "lex/lex.h"#include "parse/parse.h"#include "utils/parserutilserror.h"#include "utils/utils.h" #undef DEBUG_STACK#undef DEBUG_EVENTS #ifndef NDEBUG#include <stdio.h>extern void parserutils_stack_dump(parserutils_stack *stack, const char *prefix, void (*printer)(void *item));extern void parserutils_vector_dump(parserutils_vector *vector, const char *prefix, void (*printer)(void *item));#ifdef DEBUG_STACKstatic void printer(void *item);#endif#ifdef DEBUG_EVENTSstatic void tprinter(void *token);#endif#endif /** * Major state numbers */enum { sStart = 0, sStylesheet = 1, sStatement = 2, sRuleset = 3, sRulesetEnd = 4, sAtRule = 5, sAtRuleEnd = 6, sBlock = 7, sBlockContent = 8, sSelector = 9, sDeclaration = 10, sDeclList = 11, sDeclListEnd = 12, sProperty = 13, sValue0 = 14, sValue1 = 15, sValue = 16, sAny0 = 17, sAny1 = 18, sAny = 19, sMalformedDecl = 20, sMalformedSelector = 21, sMalformedAtRule = 22, sInlineStyle = 23, sISBody0 = 24, sISBody = 25}; /** * Representation of a parser state */typedef struct parser_state{ unsigned int state : 16, substate : 16;} parser_state; /** * CSS parser object */struct css_parser{ parserutils_inputstream *stream; /**< The inputstream */ css_lexer *lexer; /**< The lexer to use */ bool quirks; /**< Whether to enable parsing quirks */ #define STACK_CHUNK 32 parserutils_stack *states; /**< Stack of states */ parserutils_vector *tokens; /**< Vector of pending tokens */ const css_token *pushback; /**< Push back buffer */ bool parseError; /**< A parse error has occurred */ parserutils_stack *open_items; /**< Stack of open brackets */ uint8_t match_char; /**< Close bracket type for parseAny */ bool last_was_ws; /**< Last token was whitespace */ css_parser_event_handler event; /**< Client's event handler */ void *event_pw; /**< Client data for event handler */ css_allocator_fn alloc; /**< Memory (de)allocation function */ void *pw; /**< Client-specific private data */}; static css_error css__parser_create_internal(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, parser_state initial, css_parser **parser); static css_error transition(css_parser *parser, parser_state to, parser_state subsequent);static css_error transitionNoRet(css_parser *parser, parser_state to);static css_error done(css_parser *parser);static css_error expect(css_parser *parser, css_token_type type);static css_error getToken(css_parser *parser, const css_token **token);static css_error pushBack(css_parser *parser, const css_token *token);static css_error eatWS(css_parser *parser); static css_error parseStart(css_parser *parser);static css_error parseStylesheet(css_parser *parser);static css_error parseStatement(css_parser *parser);static css_error parseRuleset(css_parser *parser);static css_error parseRulesetEnd(css_parser *parser);static css_error parseAtRule(css_parser *parser);static css_error parseAtRuleEnd(css_parser *parser);static css_error parseBlock(css_parser *parser);static css_error parseBlockContent(css_parser *parser);static css_error parseSelector(css_parser *parser);static css_error parseDeclaration(css_parser *parser);static css_error parseDeclList(css_parser *parser);static css_error parseDeclListEnd(css_parser *parser);static css_error parseProperty(css_parser *parser);static css_error parseValue0(css_parser *parser);static css_error parseValue1(css_parser *parser);static css_error parseValue(css_parser *parser);static css_error parseAny0(css_parser *parser);static css_error parseAny1(css_parser *parser);static css_error parseAny(css_parser *parser);static css_error parseMalformedDeclaration(css_parser *parser);static css_error parseMalformedSelector(css_parser *parser);static css_error parseMalformedAtRule(css_parser *parser);static css_error parseInlineStyle(css_parser *parser);static css_error parseISBody0(css_parser *parser);static css_error parseISBody(css_parser *parser); static void unref_interned_strings_in_tokens(css_parser *parser); /** * Dispatch table for parsing, indexed by major state number */static css_error (*parseFuncs[])(css_parser *parser) = { parseStart, parseStylesheet, parseStatement, parseRuleset, parseRulesetEnd, parseAtRule, parseAtRuleEnd, parseBlock, parseBlockContent, parseSelector, parseDeclaration, parseDeclList, parseDeclListEnd, parseProperty, parseValue0, parseValue1, parseValue, parseAny0, parseAny1, parseAny, parseMalformedDeclaration, parseMalformedSelector, parseMalformedAtRule, parseInlineStyle, parseISBody0, parseISBody}; /** * Create a CSS parser * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */css_error css__parser_create(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, css_parser **parser){ parser_state initial = { sStart, 0 }; return css__parser_create_internal(charset, cs_source, alloc, pw, initial, parser);} /** * Create a CSS parser for an inline style * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */css_error css__parser_create_for_inline_style(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, css_parser **parser){ parser_state initial = { sInlineStyle, 0 }; return css__parser_create_internal(charset, cs_source, alloc, pw, initial, parser);} /** * Destroy a CSS parser * * \param parser The parser instance to destroy * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_destroy(css_parser *parser){ if (parser == NULL) return CSS_BADPARM; parserutils_stack_destroy(parser->open_items); parserutils_vector_destroy(parser->tokens); parserutils_stack_destroy(parser->states); css__lexer_destroy(parser->lexer); parserutils_inputstream_destroy(parser->stream); parser->alloc(parser, 0, parser->pw); return CSS_OK;} /** * Configure a CSS parser * * \param parser The parser instance to configure * \param type The option to configure * \param params Option-specific data * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_setopt(css_parser *parser, css_parser_opttype type, css_parser_optparams *params){ if (parser == NULL || params == NULL) return CSS_BADPARM; switch (type) { case CSS_PARSER_QUIRKS: parser->quirks = params->quirks; break; case CSS_PARSER_EVENT_HANDLER: parser->event = params->event_handler.handler; parser->event_pw = params->event_handler.pw; break; } return CSS_OK;} /** * Parse a chunk of data using a CSS parser * * \param parser The parser to use * \param data Pointer to the chunk to parse * \param len Length of chunk * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_parse_chunk(css_parser *parser, const uint8_t *data, size_t len){ parserutils_error perror; parser_state *state; css_error error = CSS_OK; if (parser == NULL || data == NULL) return CSS_BADPARM; perror = parserutils_inputstream_append(parser->stream, data, len); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); do { state = parserutils_stack_get_current(parser->states); if (state == NULL) break; error = parseFuncs[state->state](parser); } while (error == CSS_OK); return error;} /** * Inform a CSS parser that all data has been received. * * \param parser The parser to inform * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_completed(css_parser *parser){ parserutils_error perror; parser_state *state; css_error error = CSS_OK; if (parser == NULL) return CSS_BADPARM; /* Send EOF to input stream */ perror = parserutils_inputstream_append(parser->stream, NULL, 0); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); /* Flush through any remaining data */ do { state = parserutils_stack_get_current(parser->states); if (state == NULL) break; error = parseFuncs[state->state](parser); } while (error == CSS_OK); return error;} /** * Retrieve document charset information from a CSS parser * * \param parser The parser instance * \param source Pointer to location to receive charset source * \return Pointer to charset name (constant; do not free) */const char *css__parser_read_charset(css_parser *parser, css_charset_source *source){ const char *charset; uint32_t src; if (parser == NULL || source == NULL) return NULL; charset = parserutils_inputstream_read_charset(parser->stream, &src); *source = (css_charset_source) src; return charset;} /** * Quirks permitted when parsing * * \param parser Parser to query * \return True if quirks permitted, false otherwise */bool css__parser_quirks_permitted(css_parser *parser){ return parser->quirks;} /****************************************************************************** * Parser creation helper * ******************************************************************************/ /** * Create a CSS parser (internal) * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param initial The required initial state of the parser * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */css_error css__parser_create_internal(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, parser_state initial, css_parser **parser){ css_parser *p; parserutils_error perror; css_error error; if (alloc == NULL || parser == NULL) return CSS_BADPARM; p = alloc(NULL, sizeof(css_parser), pw); if (p == NULL) return CSS_NOMEM; perror = parserutils_inputstream_create(charset, cs_source, css__charset_extract, (parserutils_alloc) alloc, pw, &p->stream); if (perror != PARSERUTILS_OK) { alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } error = css__lexer_create(p->stream, alloc, pw, &p->lexer); if (error != CSS_OK) { parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return error; } perror = parserutils_stack_create(sizeof(parser_state), STACK_CHUNK, (parserutils_alloc) alloc, pw, &p->states); if (perror != PARSERUTILS_OK) { css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } perror = parserutils_vector_create(sizeof(css_token), STACK_CHUNK, (parserutils_alloc) alloc, pw, &p->tokens); if (perror != PARSERUTILS_OK) { parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } perror = parserutils_stack_create(sizeof(char), STACK_CHUNK, (parserutils_alloc) alloc, pw, &p->open_items); if (perror != PARSERUTILS_OK) { parserutils_vector_destroy(p->tokens); parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } perror = parserutils_stack_push(p->states, (void *) &initial); if (perror != PARSERUTILS_OK) { parserutils_stack_destroy(p->open_items); parserutils_vector_destroy(p->tokens); parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } p->quirks = false; p->pushback = NULL; p->parseError = false; p->match_char = 0; p->event = NULL; p->last_was_ws = false; p->event_pw = NULL; p->alloc = alloc; p->pw = pw; *parser = p; return CSS_OK;} /****************************************************************************** * Helper functions * ******************************************************************************/ /** * Transition to a new state, ensuring return to the one specified * * \param parser The parser instance * \param to Destination state * \param subsequent The state to return toLines 1–500 of 2633. Load more
/* * This file is part of LibCSS. * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org> */ #include <assert.h> #include <ctype.h> #include <stdbool.h> #include <libwapcaplet/libwapcaplet.h> #include <parserutils/input/inputstream.h> #include <parserutils/utils/stack.h> #include <parserutils/utils/vector.h> #include "charset/detect.h" #include "lex/lex.h" #include "parse/parse.h" #include "utils/parserutilserror.h" #include "utils/utils.h" #undef DEBUG_STACK #undef DEBUG_EVENTS #ifndef NDEBUG #include <stdio.h> extern void parserutils_stack_dump(parserutils_stack *stack, const char *prefix, void (*printer)(void *item)); extern void parserutils_vector_dump(parserutils_vector *vector, const char *prefix, void (*printer)(void *item)); #ifdef DEBUG_STACK static void printer(void *item); #endif #ifdef DEBUG_EVENTS static void tprinter(void *token); #endif #endif /** * Major state numbers */ enum { sStart = 0, sStylesheet = 1, sStatement = 2, sRuleset = 3, sRulesetEnd = 4, sAtRule = 5, sAtRuleEnd = 6, sBlock = 7, sBlockContent = 8, sSelector = 9, sDeclaration = 10, sDeclList = 11, sDeclListEnd = 12, sProperty = 13, sValue0 = 14, sValue1 = 15, sValue = 16, sAny0 = 17, sAny1 = 18, sAny = 19, sMalformedDecl = 20, sMalformedSelector = 21, sMalformedAtRule = 22, sInlineStyle = 23, sISBody0 = 24, sISBody = 25 }; /** * Representation of a parser state */ typedef struct parser_state { unsigned int state : 16, substate : 16; } parser_state; /** * CSS parser object */ struct css_parser { parserutils_inputstream *stream; /**< The inputstream */ css_lexer *lexer; /**< The lexer to use */ bool quirks; /**< Whether to enable parsing quirks */ #define STACK_CHUNK 32 parserutils_stack *states; /**< Stack of states */ parserutils_vector *tokens; /**< Vector of pending tokens */ const css_token *pushback; /**< Push back buffer */ bool parseError; /**< A parse error has occurred */ parserutils_stack *open_items; /**< Stack of open brackets */ uint8_t match_char; /**< Close bracket type for parseAny */ bool last_was_ws; /**< Last token was whitespace */ css_parser_event_handler event; /**< Client's event handler */ void *event_pw; /**< Client data for event handler */ css_allocator_fn alloc; /**< Memory (de)allocation function */ void *pw; /**< Client-specific private data */ }; static css_error css__parser_create_internal(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, parser_state initial, css_parser **parser); static css_error transition(css_parser *parser, parser_state to, parser_state subsequent); static css_error transitionNoRet(css_parser *parser, parser_state to); static css_error done(css_parser *parser); static css_error expect(css_parser *parser, css_token_type type); static css_error getToken(css_parser *parser, const css_token **token); static css_error pushBack(css_parser *parser, const css_token *token); static css_error eatWS(css_parser *parser); static css_error parseStart(css_parser *parser); static css_error parseStylesheet(css_parser *parser); static css_error parseStatement(css_parser *parser); static css_error parseRuleset(css_parser *parser); static css_error parseRulesetEnd(css_parser *parser); static css_error parseAtRule(css_parser *parser); static css_error parseAtRuleEnd(css_parser *parser); static css_error parseBlock(css_parser *parser); static css_error parseBlockContent(css_parser *parser); static css_error parseSelector(css_parser *parser); static css_error parseDeclaration(css_parser *parser); static css_error parseDeclList(css_parser *parser); static css_error parseDeclListEnd(css_parser *parser); static css_error parseProperty(css_parser *parser); static css_error parseValue0(css_parser *parser); static css_error parseValue1(css_parser *parser); static css_error parseValue(css_parser *parser); static css_error parseAny0(css_parser *parser); static css_error parseAny1(css_parser *parser); static css_error parseAny(css_parser *parser); static css_error parseMalformedDeclaration(css_parser *parser); static css_error parseMalformedSelector(css_parser *parser); static css_error parseMalformedAtRule(css_parser *parser); static css_error parseInlineStyle(css_parser *parser); static css_error parseISBody0(css_parser *parser); static css_error parseISBody(css_parser *parser); static void unref_interned_strings_in_tokens(css_parser *parser); /** * Dispatch table for parsing, indexed by major state number */ static css_error (*parseFuncs[])(css_parser *parser) = { parseStart, parseStylesheet, parseStatement, parseRuleset, parseRulesetEnd, parseAtRule, parseAtRuleEnd, parseBlock, parseBlockContent, parseSelector, parseDeclaration, parseDeclList, parseDeclListEnd, parseProperty, parseValue0, parseValue1, parseValue, parseAny0, parseAny1, parseAny, parseMalformedDeclaration, parseMalformedSelector, parseMalformedAtRule, parseInlineStyle, parseISBody0, parseISBody }; /** * Create a CSS parser * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__parser_create(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, css_parser **parser) { parser_state initial = { sStart, 0 }; return css__parser_create_internal(charset, cs_source, alloc, pw, initial, parser); } /** * Create a CSS parser for an inline style * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__parser_create_for_inline_style(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, css_parser **parser) { parser_state initial = { sInlineStyle, 0 }; return css__parser_create_internal(charset, cs_source, alloc, pw, initial, parser); } /** * Destroy a CSS parser * * \param parser The parser instance to destroy * \return CSS_OK on success, appropriate error otherwise */ css_error css__parser_destroy(css_parser *parser) { if (parser == NULL) return CSS_BADPARM; parserutils_stack_destroy(parser->open_items); parserutils_vector_destroy(parser->tokens); parserutils_stack_destroy(parser->states); css__lexer_destroy(parser->lexer); parserutils_inputstream_destroy(parser->stream); parser->alloc(parser, 0, parser->pw); return CSS_OK; } /** * Configure a CSS parser * * \param parser The parser instance to configure * \param type The option to configure * \param params Option-specific data * \return CSS_OK on success, appropriate error otherwise */ css_error css__parser_setopt(css_parser *parser, css_parser_opttype type, css_parser_optparams *params) { if (parser == NULL || params == NULL) return CSS_BADPARM; switch (type) { case CSS_PARSER_QUIRKS: parser->quirks = params->quirks; break; case CSS_PARSER_EVENT_HANDLER: parser->event = params->event_handler.handler; parser->event_pw = params->event_handler.pw; break; } return CSS_OK; } /** * Parse a chunk of data using a CSS parser * * \param parser The parser to use * \param data Pointer to the chunk to parse * \param len Length of chunk * \return CSS_OK on success, appropriate error otherwise */ css_error css__parser_parse_chunk(css_parser *parser, const uint8_t *data, size_t len) { parserutils_error perror; parser_state *state; css_error error = CSS_OK; if (parser == NULL || data == NULL) return CSS_BADPARM; perror = parserutils_inputstream_append(parser->stream, data, len); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); do { state = parserutils_stack_get_current(parser->states); if (state == NULL) break; error = parseFuncs[state->state](parser); } while (error == CSS_OK); return error; } /** * Inform a CSS parser that all data has been received. * * \param parser The parser to inform * \return CSS_OK on success, appropriate error otherwise */ css_error css__parser_completed(css_parser *parser) { parserutils_error perror; parser_state *state; css_error error = CSS_OK; if (parser == NULL) return CSS_BADPARM; /* Send EOF to input stream */ perror = parserutils_inputstream_append(parser->stream, NULL, 0); if (perror != PARSERUTILS_OK) return css_error_from_parserutils_error(perror); /* Flush through any remaining data */ do { state = parserutils_stack_get_current(parser->states); if (state == NULL) break; error = parseFuncs[state->state](parser); } while (error == CSS_OK); return error; } /** * Retrieve document charset information from a CSS parser * * \param parser The parser instance * \param source Pointer to location to receive charset source * \return Pointer to charset name (constant; do not free) */ const char *css__parser_read_charset(css_parser *parser, css_charset_source *source) { const char *charset; uint32_t src; if (parser == NULL || source == NULL) return NULL; charset = parserutils_inputstream_read_charset(parser->stream, &src); *source = (css_charset_source) src; return charset; } /** * Quirks permitted when parsing * * \param parser Parser to query * \return True if quirks permitted, false otherwise */ bool css__parser_quirks_permitted(css_parser *parser) { return parser->quirks; } /****************************************************************************** * Parser creation helper * ******************************************************************************/ /** * Create a CSS parser (internal) * * \param charset Charset of data, if known, or NULL * \param cs_source Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param initial The required initial state of the parser * \param parser Pointer to location to receive parser instance * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__parser_create_internal(const char *charset, css_charset_source cs_source, css_allocator_fn alloc, void *pw, parser_state initial, css_parser **parser) { css_parser *p; parserutils_error perror; css_error error; if (alloc == NULL || parser == NULL) return CSS_BADPARM; p = alloc(NULL, sizeof(css_parser), pw); if (p == NULL) return CSS_NOMEM; perror = parserutils_inputstream_create(charset, cs_source, css__charset_extract, (parserutils_alloc) alloc, pw, &p->stream); if (perror != PARSERUTILS_OK) { alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } error = css__lexer_create(p->stream, alloc, pw, &p->lexer); if (error != CSS_OK) { parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return error; } perror = parserutils_stack_create(sizeof(parser_state), STACK_CHUNK, (parserutils_alloc) alloc, pw, &p->states); if (perror != PARSERUTILS_OK) { css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } perror = parserutils_vector_create(sizeof(css_token), STACK_CHUNK, (parserutils_alloc) alloc, pw, &p->tokens); if (perror != PARSERUTILS_OK) { parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } perror = parserutils_stack_create(sizeof(char), STACK_CHUNK, (parserutils_alloc) alloc, pw, &p->open_items); if (perror != PARSERUTILS_OK) { parserutils_vector_destroy(p->tokens); parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } perror = parserutils_stack_push(p->states, (void *) &initial); if (perror != PARSERUTILS_OK) { parserutils_stack_destroy(p->open_items); parserutils_vector_destroy(p->tokens); parserutils_stack_destroy(p->states); css__lexer_destroy(p->lexer); parserutils_inputstream_destroy(p->stream); alloc(p, 0, pw); return css_error_from_parserutils_error(perror); } p->quirks = false; p->pushback = NULL; p->parseError = false; p->match_char = 0; p->event = NULL; p->last_was_ws = false; p->event_pw = NULL; p->alloc = alloc; p->pw = pw; *parser = p; return CSS_OK; } /****************************************************************************** * Helper functions * ******************************************************************************/ /** * Transition to a new state, ensuring return to the one specified * * \param parser The parser instance * \param to Destination state * \param subsequent The state to return to