/* * 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 <string.h> #include <parserutils/utils/stack.h> #include "stylesheet.h"#include "lex/lex.h"#include "parse/important.h"#include "parse/language.h"#include "parse/parse.h"#include "parse/propstrings.h"#include "parse/properties/properties.h"#include "parse/properties/utils.h" #include "utils/parserutilserror.h"#include "utils/utils.h" typedef struct context_entry { css_parser_event type; /**< Type of entry */ void *data; /**< Data for context */} context_entry; /* Event handlers */static css_error language_handle_event(css_parser_event type, const parserutils_vector *tokens, void *pw);static css_error handleStartStylesheet(css_language *c, const parserutils_vector *vector);static css_error handleEndStylesheet(css_language *c, const parserutils_vector *vector);static css_error handleStartRuleset(css_language *c, const parserutils_vector *vector);static css_error handleEndRuleset(css_language *c, const parserutils_vector *vector);static css_error handleStartAtRule(css_language *c, const parserutils_vector *vector);static css_error handleEndAtRule(css_language *c, const parserutils_vector *vector);static css_error handleStartBlock(css_language *c, const parserutils_vector *vector);static css_error handleEndBlock(css_language *c, const parserutils_vector *vector);static css_error handleBlockContent(css_language *c, const parserutils_vector *vector);static css_error handleDeclaration(css_language *c, const parserutils_vector *vector); /* At-rule parsing */static css_error parseMediaList(css_language *c, const parserutils_vector *vector, int *ctx, uint64_t *media);static css_error addNamespace(css_language *c, lwc_string *prefix, lwc_string *uri);static css_error lookupNamespace(css_language *c, lwc_string *prefix, lwc_string **uri); /* Selector list parsing */static css_error parseClass(css_language *c, const parserutils_vector *vector, int *ctx, css_selector_detail *specific);static css_error parseAttrib(css_language *c, const parserutils_vector *vector, int *ctx, css_selector_detail *specific);static css_error parseNth(css_language *c, const parserutils_vector *vector, int *ctx, css_selector_detail_value *value);static css_error parsePseudo(css_language *c, const parserutils_vector *vector, int *ctx, bool in_not, css_selector_detail *specific);static css_error parseSpecific(css_language *c, const parserutils_vector *vector, int *ctx, bool in_not, css_selector_detail *specific);static css_error parseAppendSpecific(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **parent);static css_error parseSelectorSpecifics(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **parent);static css_error parseTypeSelector(css_language *c, const parserutils_vector *vector, int *ctx, css_qname *qname);static css_error parseSimpleSelector(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **result);static css_error parseCombinator(css_language *c, const parserutils_vector *vector, int *ctx, css_combinator *result);static css_error parseSelector(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **result);static css_error parseSelectorList(css_language *c, const parserutils_vector *vector, css_rule *rule); /* Declaration parsing */static css_error parseProperty(css_language *c, const css_token *property, const parserutils_vector *vector, int *ctx, css_rule *rule); /** * Create a CSS language parser * * \param sheet The stylesheet object to parse for * \param parser The core parser object to use * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param language Pointer to location to receive parser object * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */css_error css__language_create(css_stylesheet *sheet, css_parser *parser, css_allocator_fn alloc, void *pw, void **language){ css_language *c; css_parser_optparams params; parserutils_error perror; lwc_error lerror; css_error error; int i; if (sheet == NULL || parser == NULL || alloc == NULL || language == NULL) return CSS_BADPARM; c = alloc(NULL, sizeof(css_language), pw); if (c == NULL) return CSS_NOMEM; perror = parserutils_stack_create(sizeof(context_entry), STACK_CHUNK, (parserutils_alloc) alloc, pw, &c->context); if (perror != PARSERUTILS_OK) { alloc(c, 0, pw); return css_error_from_parserutils_error(perror); } /* Intern all known strings */ for (i = 0; i < LAST_KNOWN; i++) { lerror = lwc_intern_string(stringmap[i].data, stringmap[i].len, &(c->strings[i])); if (lerror != lwc_error_ok) { parserutils_stack_destroy(c->context); alloc(c, 0, pw); return CSS_NOMEM; } } params.event_handler.handler = language_handle_event; params.event_handler.pw = c; error = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER, ¶ms); if (error != CSS_OK) { parserutils_stack_destroy(c->context); alloc(c, 0, pw); return error; } c->sheet = sheet; c->state = CHARSET_PERMITTED; c->default_namespace = NULL; c->namespaces = NULL; c->num_namespaces = 0; c->alloc = alloc; c->pw = pw; *language = c; return CSS_OK;} /** * Destroy a CSS language parser * * \param language The parser to destroy * \return CSS_OK on success, appropriate error otherwise */css_error css__language_destroy(css_language *language){ uint32_t i; if (language == NULL) return CSS_BADPARM; if (language->default_namespace != NULL) lwc_string_unref(language->default_namespace); if (language->namespaces != NULL) { for (i = 0; i < language->num_namespaces; i++) { lwc_string_unref(language->namespaces[i].prefix); lwc_string_unref(language->namespaces[i].uri); } language->alloc(language->namespaces, 0, language->pw); } parserutils_stack_destroy(language->context); for (i = 0; i < LAST_KNOWN; ++i) { lwc_string_unref(language->strings[i]); } language->alloc(language, 0, language->pw); return CSS_OK;} /** * Handler for core parser events * * \param type The event type * \param tokens Vector of tokens read since last event, or NULL * \param pw Pointer to handler context * \return CSS_OK on success, CSS_INVALID to indicate parse error, * appropriate error otherwise. */css_error language_handle_event(css_parser_event type, const parserutils_vector *tokens, void *pw){ css_language *language = (css_language *) pw; switch (type) { case CSS_PARSER_START_STYLESHEET: return handleStartStylesheet(language, tokens); case CSS_PARSER_END_STYLESHEET: return handleEndStylesheet(language, tokens); case CSS_PARSER_START_RULESET: return handleStartRuleset(language, tokens); case CSS_PARSER_END_RULESET: return handleEndRuleset(language, tokens); case CSS_PARSER_START_ATRULE: return handleStartAtRule(language, tokens); case CSS_PARSER_END_ATRULE: return handleEndAtRule(language, tokens); case CSS_PARSER_START_BLOCK: return handleStartBlock(language, tokens); case CSS_PARSER_END_BLOCK: return handleEndBlock(language, tokens); case CSS_PARSER_BLOCK_CONTENT: return handleBlockContent(language, tokens); case CSS_PARSER_DECLARATION: return handleDeclaration(language, tokens); } return CSS_OK;} /****************************************************************************** * Parser stages * ******************************************************************************/ css_error handleStartStylesheet(css_language *c, const parserutils_vector *vector){ parserutils_error perror; context_entry entry = { CSS_PARSER_START_STYLESHEET, NULL }; UNUSED(vector); assert(c != NULL); perror = parserutils_stack_push(c->context, (void *) &entry); if (perror != PARSERUTILS_OK) { return css_error_from_parserutils_error(perror); } return CSS_OK;} css_error handleEndStylesheet(css_language *c, const parserutils_vector *vector){ parserutils_error perror; context_entry *entry; UNUSED(vector); assert(c != NULL); entry = parserutils_stack_get_current(c->context); if (entry == NULL || entry->type != CSS_PARSER_START_STYLESHEET) return CSS_INVALID; perror = parserutils_stack_pop(c->context, NULL); if (perror != PARSERUTILS_OK) { return css_error_from_parserutils_error(perror); } return CSS_OK;} css_error handleStartRuleset(css_language *c, const parserutils_vector *vector){ parserutils_error perror; css_error error; context_entry entry = { CSS_PARSER_START_RULESET, NULL }; context_entry *cur; css_rule *parent_rule = NULL; css_rule *rule = NULL; assert(c != NULL); /* Retrieve parent rule from stack, if any */ cur = parserutils_stack_get_current(c->context); if (cur != NULL && cur->type != CSS_PARSER_START_STYLESHEET) parent_rule = cur->data; error = css__stylesheet_rule_create(c->sheet, CSS_RULE_SELECTOR, &rule); if (error != CSS_OK) return error; if (vector != NULL) { /* Parse selectors, if there are any */ error = parseSelectorList(c, vector, rule); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } } entry.data = rule; perror = parserutils_stack_push(c->context, (void *) &entry); if (perror != PARSERUTILS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return css_error_from_parserutils_error(perror); } error = css__stylesheet_add_rule(c->sheet, rule, parent_rule); if (error != CSS_OK) { parserutils_stack_pop(c->context, NULL); css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Flag that we've had a valid rule, so @import/@namespace/@charset * have no effect. */ c->state = HAD_RULE; /* Rule is now owned by the sheet, so no need to destroy it */ return CSS_OK;} css_error handleEndRuleset(css_language *c, const parserutils_vector *vector){ parserutils_error perror; context_entry *entry; UNUSED(vector); assert(c != NULL); entry = parserutils_stack_get_current(c->context); if (entry == NULL || entry->type != CSS_PARSER_START_RULESET) return CSS_INVALID; perror = parserutils_stack_pop(c->context, NULL); if (perror != PARSERUTILS_OK) { return css_error_from_parserutils_error(perror); } return CSS_OK;} css_error handleStartAtRule(css_language *c, const parserutils_vector *vector){ parserutils_error perror; context_entry entry = { CSS_PARSER_START_ATRULE, NULL }; const css_token *token = NULL; const css_token *atkeyword = NULL; int32_t ctx = 0; bool match = false; css_rule *rule; css_error error; /* vector contains: ATKEYWORD ws any0 */ assert(c != NULL); atkeyword = parserutils_vector_iterate(vector, &ctx); consumeWhitespace(vector, &ctx); /* We now have an ATKEYWORD and the context for the start of any0, if * there is one */ assert(atkeyword != NULL && atkeyword->type == CSS_TOKEN_ATKEYWORD); if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[CHARSET], &match) == lwc_error_ok && match) { if (c->state == CHARSET_PERMITTED) { const css_token *charset; /* any0 = STRING */ if (ctx == 0) return CSS_INVALID; charset = parserutils_vector_iterate(vector, &ctx); if (charset == NULL || charset->type != CSS_TOKEN_STRING) return CSS_INVALID; token = parserutils_vector_iterate(vector, &ctx); if (token != NULL) return CSS_INVALID; error = css__stylesheet_rule_create(c->sheet, CSS_RULE_CHARSET, &rule); if (error != CSS_OK) return error; error = css__stylesheet_rule_set_charset(c->sheet, rule, charset->idata); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } error = css__stylesheet_add_rule(c->sheet, rule, NULL); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Rule is now owned by the sheet, * so no need to destroy it */ c->state = IMPORT_PERMITTED; } else { return CSS_INVALID; } } else if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[LIBCSS_IMPORT], &match) == lwc_error_ok && match) { if (c->state <= IMPORT_PERMITTED) { lwc_string *url; uint64_t media = 0; /* any0 = (STRING | URI) ws * (IDENT ws (',' ws IDENT ws)* )? */ const css_token *uri = parserutils_vector_iterate(vector, &ctx); if (uri == NULL || (uri->type != CSS_TOKEN_STRING && uri->type != CSS_TOKEN_URI)) return CSS_INVALID; consumeWhitespace(vector, &ctx); /* Parse media list */ error = parseMediaList(c, vector, &ctx, &media); if (error != CSS_OK) return error; /* Create rule */ error = css__stylesheet_rule_create(c->sheet, CSS_RULE_IMPORT, &rule); if (error != CSS_OK) return error; /* Resolve import URI */ error = c->sheet->resolve(c->sheet->resolve_pw, c->sheet->url, uri->idata, &url); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Inform rule of it */ error = css__stylesheet_rule_set_nascent_import(c->sheet, rule, url, media); if (error != CSS_OK) { lwc_string_unref(url); css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Inform client of need for import */ if (c->sheet->import != NULL) { error = c->sheet->import(c->sheet->import_pw, c->sheet, url, media); if (error != CSS_OK) { lwc_string_unref(url); css__stylesheet_rule_destroy(c->sheet, rule); return error; } } /* No longer care about url */ lwc_string_unref(url); /* Add rule to sheet */ error = css__stylesheet_add_rule(c->sheet, rule, NULL); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule);Lines 1–500 of 1913. 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 <string.h> #include <parserutils/utils/stack.h> #include "stylesheet.h" #include "lex/lex.h" #include "parse/important.h" #include "parse/language.h" #include "parse/parse.h" #include "parse/propstrings.h" #include "parse/properties/properties.h" #include "parse/properties/utils.h" #include "utils/parserutilserror.h" #include "utils/utils.h" typedef struct context_entry { css_parser_event type; /**< Type of entry */ void *data; /**< Data for context */ } context_entry; /* Event handlers */ static css_error language_handle_event(css_parser_event type, const parserutils_vector *tokens, void *pw); static css_error handleStartStylesheet(css_language *c, const parserutils_vector *vector); static css_error handleEndStylesheet(css_language *c, const parserutils_vector *vector); static css_error handleStartRuleset(css_language *c, const parserutils_vector *vector); static css_error handleEndRuleset(css_language *c, const parserutils_vector *vector); static css_error handleStartAtRule(css_language *c, const parserutils_vector *vector); static css_error handleEndAtRule(css_language *c, const parserutils_vector *vector); static css_error handleStartBlock(css_language *c, const parserutils_vector *vector); static css_error handleEndBlock(css_language *c, const parserutils_vector *vector); static css_error handleBlockContent(css_language *c, const parserutils_vector *vector); static css_error handleDeclaration(css_language *c, const parserutils_vector *vector); /* At-rule parsing */ static css_error parseMediaList(css_language *c, const parserutils_vector *vector, int *ctx, uint64_t *media); static css_error addNamespace(css_language *c, lwc_string *prefix, lwc_string *uri); static css_error lookupNamespace(css_language *c, lwc_string *prefix, lwc_string **uri); /* Selector list parsing */ static css_error parseClass(css_language *c, const parserutils_vector *vector, int *ctx, css_selector_detail *specific); static css_error parseAttrib(css_language *c, const parserutils_vector *vector, int *ctx, css_selector_detail *specific); static css_error parseNth(css_language *c, const parserutils_vector *vector, int *ctx, css_selector_detail_value *value); static css_error parsePseudo(css_language *c, const parserutils_vector *vector, int *ctx, bool in_not, css_selector_detail *specific); static css_error parseSpecific(css_language *c, const parserutils_vector *vector, int *ctx, bool in_not, css_selector_detail *specific); static css_error parseAppendSpecific(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **parent); static css_error parseSelectorSpecifics(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **parent); static css_error parseTypeSelector(css_language *c, const parserutils_vector *vector, int *ctx, css_qname *qname); static css_error parseSimpleSelector(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **result); static css_error parseCombinator(css_language *c, const parserutils_vector *vector, int *ctx, css_combinator *result); static css_error parseSelector(css_language *c, const parserutils_vector *vector, int *ctx, css_selector **result); static css_error parseSelectorList(css_language *c, const parserutils_vector *vector, css_rule *rule); /* Declaration parsing */ static css_error parseProperty(css_language *c, const css_token *property, const parserutils_vector *vector, int *ctx, css_rule *rule); /** * Create a CSS language parser * * \param sheet The stylesheet object to parse for * \param parser The core parser object to use * \param alloc Memory (de)allocation function * \param pw Pointer to client-specific private data * \param language Pointer to location to receive parser object * \return CSS_OK on success, * CSS_BADPARM on bad parameters, * CSS_NOMEM on memory exhaustion */ css_error css__language_create(css_stylesheet *sheet, css_parser *parser, css_allocator_fn alloc, void *pw, void **language) { css_language *c; css_parser_optparams params; parserutils_error perror; lwc_error lerror; css_error error; int i; if (sheet == NULL || parser == NULL || alloc == NULL || language == NULL) return CSS_BADPARM; c = alloc(NULL, sizeof(css_language), pw); if (c == NULL) return CSS_NOMEM; perror = parserutils_stack_create(sizeof(context_entry), STACK_CHUNK, (parserutils_alloc) alloc, pw, &c->context); if (perror != PARSERUTILS_OK) { alloc(c, 0, pw); return css_error_from_parserutils_error(perror); } /* Intern all known strings */ for (i = 0; i < LAST_KNOWN; i++) { lerror = lwc_intern_string(stringmap[i].data, stringmap[i].len, &(c->strings[i])); if (lerror != lwc_error_ok) { parserutils_stack_destroy(c->context); alloc(c, 0, pw); return CSS_NOMEM; } } params.event_handler.handler = language_handle_event; params.event_handler.pw = c; error = css__parser_setopt(parser, CSS_PARSER_EVENT_HANDLER, ¶ms); if (error != CSS_OK) { parserutils_stack_destroy(c->context); alloc(c, 0, pw); return error; } c->sheet = sheet; c->state = CHARSET_PERMITTED; c->default_namespace = NULL; c->namespaces = NULL; c->num_namespaces = 0; c->alloc = alloc; c->pw = pw; *language = c; return CSS_OK; } /** * Destroy a CSS language parser * * \param language The parser to destroy * \return CSS_OK on success, appropriate error otherwise */ css_error css__language_destroy(css_language *language) { uint32_t i; if (language == NULL) return CSS_BADPARM; if (language->default_namespace != NULL) lwc_string_unref(language->default_namespace); if (language->namespaces != NULL) { for (i = 0; i < language->num_namespaces; i++) { lwc_string_unref(language->namespaces[i].prefix); lwc_string_unref(language->namespaces[i].uri); } language->alloc(language->namespaces, 0, language->pw); } parserutils_stack_destroy(language->context); for (i = 0; i < LAST_KNOWN; ++i) { lwc_string_unref(language->strings[i]); } language->alloc(language, 0, language->pw); return CSS_OK; } /** * Handler for core parser events * * \param type The event type * \param tokens Vector of tokens read since last event, or NULL * \param pw Pointer to handler context * \return CSS_OK on success, CSS_INVALID to indicate parse error, * appropriate error otherwise. */ css_error language_handle_event(css_parser_event type, const parserutils_vector *tokens, void *pw) { css_language *language = (css_language *) pw; switch (type) { case CSS_PARSER_START_STYLESHEET: return handleStartStylesheet(language, tokens); case CSS_PARSER_END_STYLESHEET: return handleEndStylesheet(language, tokens); case CSS_PARSER_START_RULESET: return handleStartRuleset(language, tokens); case CSS_PARSER_END_RULESET: return handleEndRuleset(language, tokens); case CSS_PARSER_START_ATRULE: return handleStartAtRule(language, tokens); case CSS_PARSER_END_ATRULE: return handleEndAtRule(language, tokens); case CSS_PARSER_START_BLOCK: return handleStartBlock(language, tokens); case CSS_PARSER_END_BLOCK: return handleEndBlock(language, tokens); case CSS_PARSER_BLOCK_CONTENT: return handleBlockContent(language, tokens); case CSS_PARSER_DECLARATION: return handleDeclaration(language, tokens); } return CSS_OK; } /****************************************************************************** * Parser stages * ******************************************************************************/ css_error handleStartStylesheet(css_language *c, const parserutils_vector *vector) { parserutils_error perror; context_entry entry = { CSS_PARSER_START_STYLESHEET, NULL }; UNUSED(vector); assert(c != NULL); perror = parserutils_stack_push(c->context, (void *) &entry); if (perror != PARSERUTILS_OK) { return css_error_from_parserutils_error(perror); } return CSS_OK; } css_error handleEndStylesheet(css_language *c, const parserutils_vector *vector) { parserutils_error perror; context_entry *entry; UNUSED(vector); assert(c != NULL); entry = parserutils_stack_get_current(c->context); if (entry == NULL || entry->type != CSS_PARSER_START_STYLESHEET) return CSS_INVALID; perror = parserutils_stack_pop(c->context, NULL); if (perror != PARSERUTILS_OK) { return css_error_from_parserutils_error(perror); } return CSS_OK; } css_error handleStartRuleset(css_language *c, const parserutils_vector *vector) { parserutils_error perror; css_error error; context_entry entry = { CSS_PARSER_START_RULESET, NULL }; context_entry *cur; css_rule *parent_rule = NULL; css_rule *rule = NULL; assert(c != NULL); /* Retrieve parent rule from stack, if any */ cur = parserutils_stack_get_current(c->context); if (cur != NULL && cur->type != CSS_PARSER_START_STYLESHEET) parent_rule = cur->data; error = css__stylesheet_rule_create(c->sheet, CSS_RULE_SELECTOR, &rule); if (error != CSS_OK) return error; if (vector != NULL) { /* Parse selectors, if there are any */ error = parseSelectorList(c, vector, rule); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } } entry.data = rule; perror = parserutils_stack_push(c->context, (void *) &entry); if (perror != PARSERUTILS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return css_error_from_parserutils_error(perror); } error = css__stylesheet_add_rule(c->sheet, rule, parent_rule); if (error != CSS_OK) { parserutils_stack_pop(c->context, NULL); css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Flag that we've had a valid rule, so @import/@namespace/@charset * have no effect. */ c->state = HAD_RULE; /* Rule is now owned by the sheet, so no need to destroy it */ return CSS_OK; } css_error handleEndRuleset(css_language *c, const parserutils_vector *vector) { parserutils_error perror; context_entry *entry; UNUSED(vector); assert(c != NULL); entry = parserutils_stack_get_current(c->context); if (entry == NULL || entry->type != CSS_PARSER_START_RULESET) return CSS_INVALID; perror = parserutils_stack_pop(c->context, NULL); if (perror != PARSERUTILS_OK) { return css_error_from_parserutils_error(perror); } return CSS_OK; } css_error handleStartAtRule(css_language *c, const parserutils_vector *vector) { parserutils_error perror; context_entry entry = { CSS_PARSER_START_ATRULE, NULL }; const css_token *token = NULL; const css_token *atkeyword = NULL; int32_t ctx = 0; bool match = false; css_rule *rule; css_error error; /* vector contains: ATKEYWORD ws any0 */ assert(c != NULL); atkeyword = parserutils_vector_iterate(vector, &ctx); consumeWhitespace(vector, &ctx); /* We now have an ATKEYWORD and the context for the start of any0, if * there is one */ assert(atkeyword != NULL && atkeyword->type == CSS_TOKEN_ATKEYWORD); if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[CHARSET], &match) == lwc_error_ok && match) { if (c->state == CHARSET_PERMITTED) { const css_token *charset; /* any0 = STRING */ if (ctx == 0) return CSS_INVALID; charset = parserutils_vector_iterate(vector, &ctx); if (charset == NULL || charset->type != CSS_TOKEN_STRING) return CSS_INVALID; token = parserutils_vector_iterate(vector, &ctx); if (token != NULL) return CSS_INVALID; error = css__stylesheet_rule_create(c->sheet, CSS_RULE_CHARSET, &rule); if (error != CSS_OK) return error; error = css__stylesheet_rule_set_charset(c->sheet, rule, charset->idata); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } error = css__stylesheet_add_rule(c->sheet, rule, NULL); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Rule is now owned by the sheet, * so no need to destroy it */ c->state = IMPORT_PERMITTED; } else { return CSS_INVALID; } } else if (lwc_string_caseless_isequal(atkeyword->idata, c->strings[LIBCSS_IMPORT], &match) == lwc_error_ok && match) { if (c->state <= IMPORT_PERMITTED) { lwc_string *url; uint64_t media = 0; /* any0 = (STRING | URI) ws * (IDENT ws (',' ws IDENT ws)* )? */ const css_token *uri = parserutils_vector_iterate(vector, &ctx); if (uri == NULL || (uri->type != CSS_TOKEN_STRING && uri->type != CSS_TOKEN_URI)) return CSS_INVALID; consumeWhitespace(vector, &ctx); /* Parse media list */ error = parseMediaList(c, vector, &ctx, &media); if (error != CSS_OK) return error; /* Create rule */ error = css__stylesheet_rule_create(c->sheet, CSS_RULE_IMPORT, &rule); if (error != CSS_OK) return error; /* Resolve import URI */ error = c->sheet->resolve(c->sheet->resolve_pw, c->sheet->url, uri->idata, &url); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Inform rule of it */ error = css__stylesheet_rule_set_nascent_import(c->sheet, rule, url, media); if (error != CSS_OK) { lwc_string_unref(url); css__stylesheet_rule_destroy(c->sheet, rule); return error; } /* Inform client of need for import */ if (c->sheet->import != NULL) { error = c->sheet->import(c->sheet->import_pw, c->sheet, url, media); if (error != CSS_OK) { lwc_string_unref(url); css__stylesheet_rule_destroy(c->sheet, rule); return error; } } /* No longer care about url */ lwc_string_unref(url); /* Add rule to sheet */ error = css__stylesheet_add_rule(c->sheet, rule, NULL); if (error != CSS_OK) { css__stylesheet_rule_destroy(c->sheet, rule);