/cssed-0.4.0/libcroco/parser/cr-parser.c
# · C · 4469 lines · 3249 code · 592 blank · 628 comment · 788 complexity · f6f52a8ea2487ef05af5aa9724643aaa MD5 · raw file
Large files are truncated click here to view the full file
- /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
- /*
- * This file is part of The Croco Library
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2.1 of the
- * GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
- * Author: Dodji Seketeli
- * See COPYRIGHTS file for copyrights information.
- */
- /**
- *@file
- *The definition of the #CRParser class.
- */
- #include "string.h"
- #include "cr-parser.h"
- #include "cr-num.h"
- #include "cr-term.h"
- #include "cr-simple-sel.h"
- #include "cr-attr-sel.h"
- /*
- *Random notes:
- *CSS core syntax vs CSS level 2 syntax
- *=====================================
- *
- *One must keep in mind
- *that css UA must comply with two syntax.
- *
- *1/the specific syntax that defines the css language
- *for a given level of specificatin (e.g css2 syntax
- *defined in appendix D.1 of the css2 spec)
- *
- *2/the core (general) syntax that is there to allow
- *UAs to parse style sheets written in levels of CSS that
- *didn't exist at the time the UAs were created.
- *
- *the name of parsing functions (or methods) contained in this file
- *follows the following scheme: cr_parser_parse_<production_name> (...) ;
- *where <production_name> is the name
- *of a production of the css2 language.
- *When a given production is
- *defined by the css2 level grammar *and* by the
- *css core syntax, there will be two functions to parse that production:
- *one will parse the production defined by the css2 level grammar and the
- *other will parse the production defined by the css core grammar.
- *The css2 level grammar related parsing function will be called:
- *cr_parser_parse_<production_name> (...) ;
- *Then css core grammar related parsing function will be called:
- *cr_parser_parse_<production_name>_core (...) ;
- *
- *If a production is defined only by the css core grammar, then
- *it will be named:
- *cr_parser_parse_<production_name>_core (...) ;
- */
- /* moved _CRParserError struct to make it public and not opaque
- modified by Iago Rubio to cssed */
- /**
- *An abstraction of an error reported by by the
- *parsing routines.
- */
- enum CRParserState {
- READY_STATE = 0,
- TRY_PARSE_CHARSET_STATE,
- CHARSET_PARSED_STATE,
- TRY_PARSE_IMPORT_STATE,
- IMPORT_PARSED_STATE,
- TRY_PARSE_RULESET_STATE,
- RULESET_PARSED_STATE,
- TRY_PARSE_MEDIA_STATE,
- MEDIA_PARSED_STATE,
- TRY_PARSE_PAGE_STATE,
- PAGE_PARSED_STATE,
- TRY_PARSE_FONT_FACE_STATE,
- FONT_FACE_PARSED_STATE
- } ;
- /**
- *The private attributes of
- *#CRParser.
- */
- struct _CRParserPriv {
- /**
- *The tokenizer
- */
- CRTknzr *tknzr;
- /**
- *The sac handlers to call
- *to notify the parsing of
- *the css2 constructions.
- */
- CRDocHandler *sac_handler;
- /**
- *A stack of errors reported
- *by the parsing routines.
- *Contains instance of #CRParserError.
- *This pointer is the top of the stack.
- */
- GList *err_stack;
- enum CRParserState state;
- gboolean resolve_import;
- gboolean is_case_sensitive;
- gboolean use_core_grammar;
- };
- #define PRIVATE(obj) ((obj)->priv)
- #define CHARS_TAB_SIZE 12
- /**
- *return TRUE if the character is a number ([0-9]), FALSE otherwise
- *@param a_char the char to test.
- */
- #define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
- /**
- *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
- *
- *@param status the status (of type enum CRStatus) to test.
- *@param is_exception if set to FALSE, the final status returned
- *by the current function will be CR_PARSING_ERROR. If set to TRUE, the
- *current status will be the current value of the 'status' variable.
- *
- */
- #define CHECK_PARSING_STATUS(status, is_exception) \
- if ((status) != CR_OK) \
- { \
- if (is_exception == FALSE) \
- { \
- status = CR_PARSING_ERROR ; \
- } \
- goto error ; \
- }
- /**
- *same as CHECK_PARSING_STATUS() but this one pushes an error
- *on the parser error stack when an error arises.
- *@param a_this the current instance of #CRParser .
- *@param a_status the status to check. Is of type enum #CRStatus.
- *@param a_is_exception in case of error, if is TRUE, the status
- *is set to CR_PARSING_ERROR before goto error. If is false, the
- *real low level status is kept and will be returned by the
- *upper level function that called this macro. Usally,this must
- *be set to FALSE.
- *
- */
- #define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\
- a_err_msg, a_err_status) \
- if ((a_status) != CR_OK) \
- { \
- if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \
- cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
- goto error ; \
- }
- /**
- *Peeks the next char from the input stream of the current parser
- *by invoking cr_tknzr_input_peek_char().
- *invokes CHECK_PARSING_STATUS on the status returned by
- *cr_tknzr_peek_char().
- *
- *@param a_this the current instance of #CRParser.
- *@param a_to_char a pointer to the char where to store the
- *char peeked.
- */
- #define PEEK_NEXT_CHAR(a_this, a_to_char) \
- {\
- enum CRStatus status ; \
- status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
- CHECK_PARSING_STATUS (status, TRUE) \
- }
- /**
- *Reads the next char from the input stream of the current parser.
- *In case of error, jumps to the "error:" label located in the
- *function where this macro is called.
- *@param a_this the curent instance of #CRParser
- *@param to_char a pointer to the guint32 char where to store
- *the character read.
- */
- #define READ_NEXT_CHAR(a_this, a_to_char) \
- status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
- CHECK_PARSING_STATUS (status, TRUE)
- /**
- *Gets information about the current position in
- *the input of the parser.
- *In case of failure, this macro returns from the
- *calling function and
- *returns a status code of type enum #CRStatus.
- *@param a_this the current instance of #CRParser.
- *@param a_pos out parameter. A pointer to the position
- *inside the current parser input. Must
- */
- #define RECORD_INITIAL_POS(a_this, a_pos) \
- status = cr_tknzr_get_cur_pos (PRIVATE \
- (a_this)->tknzr, a_pos) ; \
- g_return_val_if_fail (status == CR_OK, status)
- /**
- *Gets the address of the current byte inside the
- *parser input.
- *@param parser the current instance of #CRParser.
- *@param addr out parameter a pointer (guchar*)
- *to where the address must be put.
- */
- #define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \
- status = cr_tknzr_get_cur_byte_addr \
- (PRIVATE (a_this)->tknzr, a_addr) ; \
- CHECK_PARSING_STATUS (status, TRUE)
- /**
- *Peeks a byte from the topmost parser input at
- *a given offset from the current position.
- *If it fails, goto the "error:" label.
- *
- *@param a_parser the current instance of #CRParser.
- *@param a_offset the offset of the byte to peek, the
- *current byte having the offset '0'.
- *@param a_byte_ptr out parameter a pointer (guchar*) to
- *where the peeked char is to be stored.
- */
- #define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \
- status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \
- a_offset, \
- a_byte_ptr) ; \
- CHECK_PARSING_STATUS (status, TRUE) ;
- #define BYTE(a_parser, a_offset, a_eof) \
- cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof)
- /**
- *Reads a byte from the topmost parser input
- *steam.
- *If it fails, goto the "error" label.
- *@param a_this the current instance of #CRParser.
- *@param a_byte_ptr the guchar * where to put the read char.
- */
- #define READ_NEXT_BYTE(a_this, a_byte_ptr) \
- status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \
- CHECK_PARSING_STATUS (status, TRUE) ;
- /**
- *Skips a given number of byte in the topmost
- *parser input. Don't update line and column number.
- *In case of error, jumps to the "error:" label
- *of the surrounding function.
- *@param a_parser the current instance of #CRParser.
- *@param a_nb_bytes the number of bytes to skip.
- */
- #define SKIP_BYTES(a_this, a_nb_bytes) \
- status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \
- CR_SEEK_CUR, a_nb_bytes) ; \
- CHECK_PARSING_STATUS (status, TRUE) ;
- /**
- *Skip utf8 encoded characters.
- *Updates line and column numbers.
- *@param a_parser the current instance of #CRParser.
- *@param a_nb_chars the number of chars to skip. Must be of
- *type glong.
- */
- #define SKIP_CHARS(a_parser, a_nb_chars) \
- { \
- glong nb_chars = a_nb_chars ; \
- status = cr_tknzr_consume_chars \
- (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \
- CHECK_PARSING_STATUS (status, TRUE) ; \
- }
- /**
- *Tests the condition and if it is false, sets
- *status to "CR_PARSING_ERROR" and goto the 'error'
- *label.
- *@param condition the condition to test.
- */
- #define ENSURE_PARSING_COND(condition) \
- if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
- #define ENSURE_PARSING_COND_ERR(a_this, a_condition, \
- a_err_msg, a_err_status) \
- if (! (a_condition)) \
- { \
- status = CR_PARSING_ERROR; \
- cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
- goto error ; \
- }
- #define GET_NEXT_TOKEN(a_this, a_token_ptr) \
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \
- a_token_ptr) ; \
- ENSURE_PARSING_COND (status == CR_OK) ;
- #ifdef WITH_UNICODE_ESCAPE_AND_RANGE
- static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this,
- guint32 * a_unicode);
- static enum CRStatus cr_parser_parse_escape (CRParser * a_this,
- guint32 * a_esc_code);
- static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this,
- CRString ** a_inf,
- CRString ** a_sup);
- #endif
- static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_any_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_block_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_value_core (CRParser * a_this);
- static enum CRStatus cr_parser_parse_string (CRParser * a_this,
- CRString ** a_str);
- static enum CRStatus cr_parser_parse_ident (CRParser * a_this,
- CRString ** a_str);
- static enum CRStatus cr_parser_parse_uri (CRParser * a_this,
- CRString ** a_str);
- static enum CRStatus cr_parser_parse_function (CRParser * a_this,
- CRString ** a_func_name,
- CRTerm ** a_expr);
- static enum CRStatus cr_parser_parse_property (CRParser * a_this,
- CRString ** a_property);
- static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this,
- CRAttrSel ** a_sel);
- static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this,
- CRSimpleSel ** a_sel);
- static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this,
- CRSimpleSel ** a_sel);
- static CRParserError *cr_parser_error_new (const guchar * a_msg,
- enum CRStatus);
- static void cr_parser_error_set_msg (CRParserError * a_this,
- const guchar * a_msg);
- static void cr_parser_error_dump (CRParserError * a_this);
- static void cr_parser_error_set_status (CRParserError * a_this,
- enum CRStatus a_status);
- static void cr_parser_error_set_pos (CRParserError * a_this,
- glong a_line,
- glong a_column, glong a_byte_num);
- static void
- cr_parser_error_destroy (CRParserError * a_this);
- static enum CRStatus cr_parser_push_error (CRParser * a_this,
- const guchar * a_msg,
- enum CRStatus a_status);
- static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this,
- gboolean a_clear_errs);
- static enum CRStatus
- cr_parser_clear_errors (CRParser * a_this);
- /* **********************************************************
- Added by Iago Rubio to use it in cssed as syntax validator
- ********************************************************** */
- GList*
- cr_parser_get_error_stack(CRParser *a_this)
- {
- GList *stack ;
- stack = g_list_copy(PRIVATE(a_this)->err_stack);
- return stack;
- }
- gulong
- cr_parser_get_pos(CRParser *a_this)
- {
- return cr_tknzr_get_cur_line(PRIVATE(a_this)->tknzr);
- }
- /*****************************
- * end iago's changes
- *****************************/
- /*****************************
- *error managemet methods
- *****************************/
- /**
- *Constructor of #CRParserError class.
- *@param a_msg the brute error message.
- *@param a_status the error status.
- *@return the newly built instance of #CRParserError.
- */
- static CRParserError *
- cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status)
- {
- CRParserError *result = NULL;
- result = g_try_malloc (sizeof (CRParserError));
- if (result == NULL) {
- cr_utils_trace_info ("Out of memory");
- return NULL;
- }
- memset (result, 0, sizeof (CRParserError));
- cr_parser_error_set_msg (result, a_msg);
- cr_parser_error_set_status (result, a_status);
- return result;
- }
- /**
- *Sets the message associated to this instance of #CRError.
- *@param a_this the current instance of #CRParserError.
- *@param a_msg the new message.
- */
- static void
- cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg)
- {
- g_return_if_fail (a_this);
- if (a_this->msg) {
- g_free (a_this->msg);
- }
- a_this->msg = g_strdup (a_msg);
- }
- /**
- *Sets the error status.
- *@param a_this the current instance of #CRParserError.
- *@param a_status the new error status.
- *
- */
- static void
- cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status)
- {
- g_return_if_fail (a_this);
- a_this->status = a_status;
- }
- /**
- *Sets the position of the parser error.
- *@param a_this the current instance of #CRParserError.
- *@param a_line the line number.
- *@param a_column the column number.
- *@param a_byte_num the byte number.
- */
- static void
- cr_parser_error_set_pos (CRParserError * a_this,
- glong a_line, glong a_column, glong a_byte_num)
- {
- g_return_if_fail (a_this);
- a_this->line = a_line;
- a_this->column = a_column;
- a_this->byte_num = a_byte_num;
- }
- static void
- cr_parser_error_dump (CRParserError * a_this)
- {
- g_return_if_fail (a_this);
- g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column);
- g_printerr ("%s\n", a_this->msg);
- }
- /**
- *The destructor of #CRParserError.
- *@param a_this the current instance of #CRParserError.
- */
- static void
- cr_parser_error_destroy (CRParserError * a_this)
- {
- g_return_if_fail (a_this);
- if (a_this->msg) {
- g_free (a_this->msg);
- a_this->msg = NULL;
- }
- g_free (a_this);
- }
- /**
- *Pushes an error on the parser error stack.
- *@param a_this the current instance of #CRParser.
- *@param a_msg the error message.
- *@param a_status the error status.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- static enum CRStatus
- cr_parser_push_error (CRParser * a_this,
- const guchar * a_msg, enum CRStatus a_status)
- {
- enum CRStatus status = CR_OK;
- CRParserError *error = NULL;
- CRInputPos pos;
- g_return_val_if_fail (a_this && PRIVATE (a_this)
- && a_msg, CR_BAD_PARAM_ERROR);
- error = cr_parser_error_new (a_msg, a_status);
- g_return_val_if_fail (error, CR_ERROR);
- RECORD_INITIAL_POS (a_this, &pos);
- cr_parser_error_set_pos
- (error, pos.line, pos.col, pos.next_byte_index - 1);
- PRIVATE (a_this)->err_stack =
- g_list_prepend (PRIVATE (a_this)->err_stack, error);
- if (PRIVATE (a_this)->err_stack == NULL)
- goto error;
- return CR_OK;
- error:
- if (error) {
- cr_parser_error_destroy (error);
- error = NULL;
- }
- return status;
- }
- /**
- *Dumps the error stack on stdout.
- *@param a_this the current instance of #CRParser.
- *@param a_clear_errs whether to clear the error stack
- *after the dump or not.
- *@return CR_OK upon successfull completion, an error code
- *otherwise.
- */
- static enum CRStatus
- cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs)
- {
- GList *cur = NULL;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- if (PRIVATE (a_this)->err_stack == NULL)
- return CR_OK;
- for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
- cr_parser_error_dump ((CRParserError *) cur->data);
- }
- if (a_clear_errs == TRUE) {
- cr_parser_clear_errors (a_this);
- }
- return CR_OK;
- }
- /**
- *Clears all the errors contained in the parser error stack.
- *Frees all the errors, and the stack that contains'em.
- *@param a_this the current instance of #CRParser.
- */
- static enum CRStatus
- cr_parser_clear_errors (CRParser * a_this)
- {
- GList *cur = NULL;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
- if (cur->data) {
- cr_parser_error_destroy ((CRParserError *)
- cur->data);
- }
- }
- if (PRIVATE (a_this)->err_stack) {
- g_list_free (PRIVATE (a_this)->err_stack);
- PRIVATE (a_this)->err_stack = NULL;
- }
- return CR_OK;
- }
- /**
- *Same as cr_parser_try_to_skip_spaces() but this one skips
- *spaces and comments.
- *
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- enum CRStatus
- cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this)
- {
- enum CRStatus status = CR_ERROR;
- CRToken *token = NULL;
- g_return_val_if_fail (a_this && PRIVATE (a_this)
- && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
- do {
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token);
- if (status != CR_OK)
- goto error;
- }
- while ((token != NULL)
- && (token->type == COMMENT_TK || token->type == S_TK));
- cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
- return status;
- error:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- return status;
- }
- /***************************************
- *End of Parser input handling routines
- ***************************************/
- /*************************************
- *Non trivial terminal productions
- *parsing routines
- *************************************/
- /**
- *Parses a css stylesheet following the core css grammar.
- *This is mainly done for test purposes.
- *During the parsing, no callback is called. This is just
- *to validate that the stylesheet is well formed according to the
- *css core syntax.
- *stylesheet : [ CDO | CDC | S | statement ]*;
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- static enum CRStatus
- cr_parser_parse_stylesheet_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- continue_parsing:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- if (status == CR_END_OF_INPUT_ERROR) {
- status = CR_OK;
- goto done;
- } else if (status != CR_OK) {
- goto error;
- }
- switch (token->type) {
- case CDO_TK:
- case CDC_TK:
- goto continue_parsing;
- break;
- default:
- status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
- token);
- CHECK_PARSING_STATUS (status, TRUE);
- token = NULL;
- status = cr_parser_parse_statement_core (a_this);
- cr_parser_clear_errors (a_this);
- if (status == CR_OK) {
- goto continue_parsing;
- } else if (status == CR_END_OF_INPUT_ERROR) {
- goto done;
- } else {
- goto error;
- }
- }
- done:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_parser_clear_errors (a_this);
- return CR_OK;
- error:
- cr_parser_push_error
- (a_this, "could not recognize next production", CR_ERROR);
- //cr_parser_dump_err_stack (a_this, TRUE);
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses an at-rule as defined by the css core grammar
- *in chapter 4.1 in the css2 spec.
- *at-rule : ATKEYWORD S* any* [ block | ';' S* ];
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code
- *otherwise.
- */
- static enum CRStatus
- cr_parser_parse_atrule_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token);
- ENSURE_PARSING_COND (status == CR_OK
- && token
- &&
- (token->type == ATKEYWORD_TK
- || token->type == IMPORT_SYM_TK
- || token->type == PAGE_SYM_TK
- || token->type == MEDIA_SYM_TK
- || token->type == FONT_FACE_SYM_TK
- || token->type == CHARSET_SYM_TK));
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- do {
- status = cr_parser_parse_any_core (a_this);
- } while (status == CR_OK);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
- if (token->type == CBO_TK) {
- cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
- token);
- token = NULL;
- status = cr_parser_parse_block_core (a_this);
- CHECK_PARSING_STATUS (status,
- FALSE);
- goto done;
- } else if (token->type == SEMICOLON_TK) {
- goto done;
- } else {
- status = CR_PARSING_ERROR ;
- goto error;
- }
- done:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- return CR_OK;
- error:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
- &init_pos);
- return status;
- }
- /**
- *Parses a ruleset as defined by the css core grammar in chapter
- *4.1 of the css2 spec.
- *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- static enum CRStatus
- cr_parser_parse_ruleset_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_parser_parse_selector_core (a_this);
- ENSURE_PARSING_COND (status == CR_OK
- || status == CR_PARSING_ERROR
- || status == CR_END_OF_INPUT_ERROR);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token
- && token->type == CBO_TK);
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_parser_parse_declaration_core (a_this);
- parse_declaration_list:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
- if (token->type == CBC_TK) {
- goto done;
- }
- ENSURE_PARSING_COND (status == CR_OK
- && token && token->type == SEMICOLON_TK);
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_parser_parse_declaration_core (a_this);
- cr_parser_clear_errors (a_this);
- ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
- if (token->type == CBC_TK) {
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- goto done;
- } else {
- status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
- token);
- token = NULL;
- goto parse_declaration_list;
- }
- done:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- if (status == CR_OK) {
- return CR_OK;
- }
- error:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses a "selector" as specified by the css core
- *grammar.
- *selector : any+;
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code
- *otherwise.
- */
- static enum CRStatus
- cr_parser_parse_selector_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_parser_parse_any_core (a_this);
- CHECK_PARSING_STATUS (status, FALSE);
- do {
- status = cr_parser_parse_any_core (a_this);
- } while (status == CR_OK);
- return CR_OK;
- error:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses a "block" as defined in the css core grammar
- *in chapter 4.1 of the css2 spec.
- *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
- *@param a_this the current instance of #CRParser.
- *FIXME: code this function.
- */
- static enum CRStatus
- cr_parser_parse_block_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token
- && token->type == CBO_TK);
- parse_block_content:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
- if (token->type == CBC_TK) {
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- goto done;
- } else if (token->type == SEMICOLON_TK) {
- goto parse_block_content;
- } else if (token->type == ATKEYWORD_TK) {
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- goto parse_block_content;
- } else if (token->type == CBO_TK) {
- cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
- token = NULL;
- status = cr_parser_parse_block_core (a_this);
- CHECK_PARSING_STATUS (status, FALSE);
- goto parse_block_content;
- } else {
- cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
- token = NULL;
- status = cr_parser_parse_any_core (a_this);
- CHECK_PARSING_STATUS (status, FALSE);
- goto parse_block_content;
- }
- done:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- if (status == CR_OK)
- return CR_OK;
- error:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- static enum CRStatus
- cr_parser_parse_declaration_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- CRString *prop = NULL;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_parser_parse_property (a_this, &prop);
- CHECK_PARSING_STATUS (status, FALSE);
- cr_parser_clear_errors (a_this);
- ENSURE_PARSING_COND (status == CR_OK && prop);
- cr_string_destroy (prop);
- prop = NULL;
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK
- && token
- && token->type == DELIM_TK
- && token->u.unichar == ':');
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_parser_parse_value_core (a_this);
- CHECK_PARSING_STATUS (status, FALSE);
- return CR_OK;
- error:
- if (prop) {
- cr_string_destroy (prop);
- prop = NULL;
- }
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses a "value" production as defined by the css core grammar
- *in chapter 4.1.
- *value ::= [ any | block | ATKEYWORD S* ]+;
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- static enum CRStatus
- cr_parser_parse_value_core (CRParser * a_this)
- {
- CRToken *token = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- glong ref = 0;
- g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- continue_parsing:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
- switch (token->type) {
- case CBO_TK:
- status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
- token);
- token = NULL;
- status = cr_parser_parse_block_core (a_this);
- CHECK_PARSING_STATUS (status, FALSE);
- ref++;
- goto continue_parsing;
- case ATKEYWORD_TK:
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- ref++;
- goto continue_parsing;
- default:
- status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
- token);
- token = NULL;
- status = cr_parser_parse_any_core (a_this);
- if (status == CR_OK) {
- ref++;
- goto continue_parsing;
- } else if (status == CR_PARSING_ERROR) {
- status = CR_OK;
- goto done;
- } else {
- goto error;
- }
- }
- done:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- if (status == CR_OK && ref)
- return CR_OK;
- error:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses an "any" as defined by the css core grammar in the
- *css2 spec in chapter 4.1.
- *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
- * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
- * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
- *
- *@param a_this the current instance of #CRParser.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- static enum CRStatus
- cr_parser_parse_any_core (CRParser * a_this)
- {
- CRToken *token1 = NULL,
- *token2 = NULL;
- CRInputPos init_pos;
- enum CRStatus status = CR_ERROR;
- g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1);
- ENSURE_PARSING_COND (status == CR_OK && token1);
- switch (token1->type) {
- case IDENT_TK:
- case NUMBER_TK:
- case RGB_TK:
- case PERCENTAGE_TK:
- case DIMEN_TK:
- case EMS_TK:
- case EXS_TK:
- case LENGTH_TK:
- case ANGLE_TK:
- case FREQ_TK:
- case TIME_TK:
- case STRING_TK:
- case DELIM_TK:
- case URI_TK:
- case HASH_TK:
- case UNICODERANGE_TK:
- case INCLUDES_TK:
- case DASHMATCH_TK:
- case S_TK:
- case COMMENT_TK:
- case IMPORTANT_SYM_TK:
- status = CR_OK;
- break;
- case FUNCTION_TK:
- /*
- *this case isn't specified by the spec but it
- *does happen. So we have to handle it.
- *We must consider function with parameters.
- *We consider parameter as being an "any*" production.
- */
- do {
- status = cr_parser_parse_any_core (a_this);
- } while (status == CR_OK);
- ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token2);
- ENSURE_PARSING_COND (status == CR_OK
- && token2 && token2->type == PC_TK);
- break;
- case PO_TK:
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token2);
- ENSURE_PARSING_COND (status == CR_OK && token2);
- if (token2->type == PC_TK) {
- cr_token_destroy (token2);
- token2 = NULL;
- goto done;
- } else {
- status = cr_tknzr_unget_token
- (PRIVATE (a_this)->tknzr, token2);
- token2 = NULL;
- }
- do {
- status = cr_parser_parse_any_core (a_this);
- } while (status == CR_OK);
- ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token2);
- ENSURE_PARSING_COND (status == CR_OK
- && token2 && token2->type == PC_TK);
- status = CR_OK;
- break;
- case BO_TK:
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token2);
- ENSURE_PARSING_COND (status == CR_OK && token2);
- if (token2->type == BC_TK) {
- cr_token_destroy (token2);
- token2 = NULL;
- goto done;
- } else {
- status = cr_tknzr_unget_token
- (PRIVATE (a_this)->tknzr, token2);
- token2 = NULL;
- }
- do {
- status = cr_parser_parse_any_core (a_this);
- } while (status == CR_OK);
- ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token2);
- ENSURE_PARSING_COND (status == CR_OK
- && token2 && token2->type == BC_TK);
- status = CR_OK;
- break;
- default:
- status = CR_PARSING_ERROR;
- goto error;
- }
- done:
- if (token1) {
- cr_token_destroy (token1);
- token1 = NULL;
- }
- if (token2) {
- cr_token_destroy (token2);
- token2 = NULL;
- }
- return CR_OK;
- error:
- if (token1) {
- cr_token_destroy (token1);
- token1 = NULL;
- }
- if (token2) {
- cr_token_destroy (token2);
- token2 = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses an attribute selector as defined in the css2 spec in
- *appendix D.1:
- *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
- * [ IDENT | STRING ] S* ]? ']'
- *
- *@param a_this the "this pointer" of the current instance of
- *#CRParser .
- *@param a_sel out parameter. The successfully parsed attribute selector.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- static enum CRStatus
- cr_parser_parse_attribute_selector (CRParser * a_this,
- CRAttrSel ** a_sel)
- {
- enum CRStatus status = CR_OK;
- CRInputPos init_pos;
- CRToken *token = NULL;
- CRAttrSel *result = NULL;
- CRParsingLocation location = {0} ;
- g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token
- && token->type == BO_TK);
- cr_parsing_location_copy
- (&location, &token->location) ;
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- result = cr_attr_sel_new ();
- if (!result) {
- cr_utils_trace_info ("result failed") ;
- status = CR_OUT_OF_MEMORY_ERROR ;
- goto error ;
- }
- cr_parsing_location_copy (&result->location,
- &location) ;
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK
- && token && token->type == IDENT_TK);
- result->name = token->u.str;
- token->u.str = NULL;
- cr_token_destroy (token);
- token = NULL;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
- if (token->type == INCLUDES_TK) {
- result->match_way = INCLUDES;
- goto parse_right_part;
- } else if (token->type == DASHMATCH_TK) {
- result->match_way = DASHMATCH;
- goto parse_right_part;
- } else if (token->type == DELIM_TK && token->u.unichar == '=') {
- result->match_way = EQUALS;
- goto parse_right_part;
- } else if (token->type == BC_TK) {
- result->match_way = SET;
- goto done;
- }
- parse_right_part:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token);
-
- if (token->type == IDENT_TK) {
- result->value = token->u.str;
- token->u.str = NULL;
- } else if (token->type == STRING_TK) {
- result->value = token->u.str;
- token->u.str = NULL;
- } else {
- status = CR_PARSING_ERROR;
- goto error;
- }
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
- ENSURE_PARSING_COND (status == CR_OK && token
- && token->type == BC_TK);
- done:
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- if (*a_sel) {
- status = cr_attr_sel_append_attr_sel (*a_sel, result);
- CHECK_PARSING_STATUS (status, FALSE);
- } else {
- *a_sel = result;
- }
- cr_parser_clear_errors (a_this);
- return CR_OK;
- error:
- if (result) {
- cr_attr_sel_destroy (result);
- result = NULL;
- }
- if (token) {
- cr_token_destroy (token);
- token = NULL;
- }
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses a "property" as specified by the css2 spec at [4.1.1]:
- *property : IDENT S*;
- *
- *@param a_this the "this pointer" of the current instance of #CRParser.
- *@param GString a_property out parameter. The parsed property without the
- *trailing spaces. If *a_property is NULL, this function allocates a
- *new instance of GString and set it content to the parsed property.
- *If not, the property is just appended to a_property's previous content.
- *In both cases, it is up to the caller to free a_property.
- *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the
- *next construction was not a "property", or an error code.
- */
- static enum CRStatus
- cr_parser_parse_property (CRParser * a_this,
- CRString ** a_property)
- {
- enum CRStatus status = CR_OK;
- CRInputPos init_pos;
- g_return_val_if_fail (a_this && PRIVATE (a_this)
- && PRIVATE (a_this)->tknzr
- && a_property,
- CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- status = cr_parser_parse_ident (a_this, a_property);
- CHECK_PARSING_STATUS (status, TRUE);
-
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- cr_parser_clear_errors (a_this);
- return CR_OK;
- error:
- cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
- return status;
- }
- /**
- *Parses a "term" as defined in the css2 spec, appendix D.1:
- *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* |
- *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] |
- *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
- *
- *TODO: handle parsing of 'RGB'
- *
- *@param a_term out parameter. The successfully parsed term.
- *@return CR_OK upon successfull completion, an error code otherwise.
- */
- enum CRStatus
- cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term)
- {
- enum CRStatus status = CR_PARSING_ERROR;
- CRInputPos init_pos;
- CRTerm *result = NULL;
- CRTerm *param = NULL;
- CRToken *token = NULL;
- CRString *func_name = NULL;
- CRParsingLocation location = {0} ;
- g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR);
- RECORD_INITIAL_POS (a_this, &init_pos);
- result = cr_term_new ();
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token);
- if (status != CR_OK || !token)
- goto error;
- cr_parsing_location_copy (&location, &token->location) ;
- if (token->type == DELIM_TK && token->u.unichar == '+') {
- result->unary_op = PLUS_UOP;
- cr_token_destroy (token) ;
- token = NULL ;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token);
- if (status != CR_OK || !token)
- goto error;
- } else if (token->type == DELIM_TK && token->u.unichar == '-') {
- result->unary_op = MINUS_UOP;
- cr_token_destroy (token) ;
- token = NULL ;
- cr_parser_try_to_skip_spaces_and_comments (a_this);
- status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
- &token);
- if (status != CR_OK || !token)
- goto error;
- }
- if (token->type == EMS_TK
- || token->type == EXS_TK
- || token->type == LENGTH_TK
- || token->type == ANGLE_TK
- || token->type == TIME_TK
- || token->type == FREQ_TK
- || token->type == PERCENTAGE_TK
- || token->type == NUMBER_TK) {
- status = cr_term_set_number (result, token->u.num);
- CHECK_PARSING_STATUS (status, TRUE);
- token->u.num = NULL;
- status = CR_OK;
- } else if (token && token->type == FUNCTION_TK) {
- status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
- token);
- token = NULL;
- status = cr_parser_parse_function (a_this, &func_name,
- ¶m);
- if (status == CR_OK) {
- status = cr_term_set_function (result,
- func_name,
- param);
- CHECK_PARSING_STATUS (status, TRUE);
- }
- } else if (token && token->type == STRING_TK) {
- status = cr_term_set_string (result,
- token->u.str);
- CHECK_PARSING_STATU…