1913 lines · 49.4 KB · C
RawDownload
/* * 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, &params);	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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t