cr-parser.c revision 85a4720f8552abe4a17008a6d76f2c38ae19fbbf
/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
/*
* This file is part of The Croco Library
*
*
* 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.
*/
/**
*@CRParser:
*
*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 syntaxes.
*
*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 (...) ;
*/
typedef struct _CRParserError CRParserError;
/**
*An abstraction of an error reported by by the
*parsing routines.
*/
struct _CRParserError {
};
enum CRParserState {
READY_STATE = 0,
} ;
/**
*The private attributes of
*#CRParser.
*/
struct _CRParserPriv {
/**
*The tokenizer
*/
/**
*The sac handlers to call
*to notify the parsing of
*the css2 constructions.
*/
/**
*A stack of errors reported
*by the parsing routines.
*Contains instance of #CRParserError.
*This pointer is the top of the stack.
*/
enum CRParserState state;
};
#define CHARS_TAB_SIZE 12
/**
* IS_NUM:
*@a_char: the char to test.
*return TRUE if the character is a number ([0-9]), FALSE otherwise
*/
/**
*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.
*
*/
{ \
if (is_exception == FALSE) \
{ \
status = CR_PARSING_ERROR ; \
} \
goto error ; \
}
/**
* CHECK_PARSING_STATUS_ERR:
*@a_this: the current instance of #CRParser .
*@a_status: the status to check. Is of type enum #CRStatus.
*@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.
*
*same as CHECK_PARSING_STATUS() but this one pushes an error
*on the parser error stack when an error arises.
*
*/
{ \
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.
*/
{\
}
/**
*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.
*/
/**
*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
*/
/**
*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.
*/
/**
*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.
*/
a_offset, \
a_byte_ptr) ; \
/**
*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.
*/
/**
*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.
*/
CR_SEEK_CUR, a_nb_bytes) ; \
/**
*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.
*/
{ \
}
/**
*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 (! (a_condition)) \
{ \
status = CR_PARSING_ERROR; \
goto error ; \
}
a_token_ptr) ; \
guint32 * a_esc_code);
#endif
CRString ** a_func_name,
CRString ** a_property);
CRSimpleSel ** a_sel);
CRSimpleSel ** a_sel);
enum CRStatus);
static void
static enum CRStatus
/*****************************
*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_utils_trace_info ("Out of memory");
return NULL;
}
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
{
}
}
/**
*Sets the error status.
*@param a_this the current instance of #CRParserError.
*@param a_status the new error status.
*
*/
static void
{
}
/**
*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
{
}
static void
{
}
/**
*The destructor of #CRParserError.
*@param a_this the current instance of #CRParserError.
*/
static void
{
}
}
/**
*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 successful completion, an error code otherwise.
*/
static enum CRStatus
{
&& a_msg, CR_BAD_PARAM_ERROR);
goto error;
return CR_OK;
if (error) {
}
return status;
}
/**
*Dumps the error stack using g_printerr.
*@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
{
return CR_OK;
}
if (a_clear_errs == TRUE) {
}
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
{
}
}
}
return CR_OK;
}
/**
* cr_parser_try_to_skip_spaces_and_comments:
*@a_this: the current instance of #CRParser.
*
*Same as cr_parser_try_to_skip_spaces() but this one skips
*spaces and comments.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
do {
if (token) {
}
&token);
goto error;
}
return status;
if (token) {
}
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 successful completion, an error code otherwise.
*/
static enum CRStatus
{
if (token) {
}
if (status == CR_END_OF_INPUT_ERROR) {
goto done;
goto error;
}
case CDO_TK:
case CDC_TK:
goto continue_parsing;
break;
default:
token);
goto continue_parsing;
} else if (status == CR_END_OF_INPUT_ERROR) {
goto done;
} else {
goto error;
}
}
done:
if (token) {
}
return CR_OK;
if (token) {
}
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
{
&token);
&& token
&&
do {
&token);
token);
FALSE);
goto done;
goto done;
} else {
goto error;
}
done:
if (token) {
}
return CR_OK;
if (token) {
}
&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
{
|| status == CR_PARSING_ERROR
|| status == CR_END_OF_INPUT_ERROR);
if (token) {
}
goto done;
}
goto done;
} else {
token);
goto parse_declaration_list;
}
done:
if (token) {
}
return CR_OK;
}
if (token) {
}
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
{
do {
return CR_OK;
if (token) {
}
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
{
if (token) {
}
goto done;
goto parse_block_content;
goto parse_block_content;
goto parse_block_content;
} else {
goto parse_block_content;
}
done:
if (token) {
}
return CR_OK;
if (token) {
}
return status;
}
static enum CRStatus
{
&& token
return CR_OK;
if (prop) {
}
if (token) {
}
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
{
if (token) {
}
case CBO_TK:
token);
ref++;
goto continue_parsing;
case ATKEYWORD_TK:
ref++;
goto continue_parsing;
default:
token);
ref++;
goto continue_parsing;
} else if (status == CR_PARSING_ERROR) {
goto done;
} else {
goto error;
}
}
done:
if (token) {
}
return CR_OK;
if (token) {
}
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
{
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:
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 {
&token2);
break;
case PO_TK:
&token2);
goto done;
} else {
}
do {
&token2);
break;
case BO_TK:
&token2);
goto done;
} else {
}
do {
&token2);
break;
default:
goto error;
}
done:
if (token1) {
}
if (token2) {
}
return CR_OK;
if (token1) {
}
if (token2) {
}
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
{
CRParsingLocation location = {0,0,0} ;
result = cr_attr_sel_new ();
if (!result) {
cr_utils_trace_info ("result failed") ;
goto error ;
}
&location) ;
goto parse_right_part;
goto parse_right_part;
goto parse_right_part;
goto done;
}
if (token) {
}
} else {
goto error;
}
if (token) {
}
done:
if (token) {
}
if (*a_sel) {
} else {
}
return CR_OK;
if (result) {
}
if (token) {
}
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
CRString ** a_property)
{
&& a_property,
return CR_OK;
return status;
}
/**
* cr_parser_parse_term:
*@a_term: out parameter. The successfully parsed term.
*
*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'
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
CRParsingLocation location = {0,0,0} ;
result = cr_term_new ();
&token);
goto error;
&token);
goto error;
&token);
goto error;
}
token);
¶m);
param);
}
} else {
}
goto error;
}
&location) ;
if (token) {
}
return CR_OK;
if (result) {
}
if (token) {
}
if (param) {
}
if (func_name) {
}
return status;
}
/**
* cr_parser_parse_simple_selector:
*@a_this: the "this pointer" of the current instance of #CRParser.
*@a_sel: out parameter. Is set to the successfully parsed simple
*selector.
*
*Parses a "simple_selector" as defined by the css2 spec in appendix D.1 :
*element_name? [ HASH | class | attrib | pseudo ]* S*
*and where pseudo is:
*pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ]
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
static enum CRStatus
{
goto error;
sel = cr_simple_sel_new ();
//sel->type_mask |= UNIVERSAL_SELECTOR;
//sel->type_mask |= TYPE_SELECTOR;
} else {
token);
}
if (token) {
}
for (;;) {
if (token) {
}
&token);
goto error;
/*we parsed an attribute id */
(add_sel_list, add_sel);
goto error;
(add_sel_list, add_sel);
} else {
goto error;
}
goto error;
(add_sel_list, add_sel);
/*try to parse a pseudo */
if (token) {
}
pseudo = cr_pseudo_new ();
(a_this);
} else {
goto error;
}
(add_sel_list, add_sel);
}
} else {
break;
}
}
add_sel_list = NULL;
} else {
}
if (token) {
}
return CR_OK;
} else {
}
if (token) {
}
if (add_sel_list) {
add_sel_list = NULL;
}
if (sel) {
}
return status;
}
/**
* cr_parser_parse_simple_sels:
*@a_this: the this pointer of the current instance of #CRParser.
*@a_start: a pointer to the
*first chararcter of the successfully parsed
*string.
*@a_end: a pointer to the last character of the successfully parsed
*string.
*
*Parses a "selector" as defined by the css2 spec in appendix D.1:
*selector ::= simple_selector [ combinator simple_selector ]*
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
static enum CRStatus
CRSimpleSel ** a_sel)
{
&& a_sel,
for (;;) {
int comb = 0;
if (next_char == '+') {
} else if (next_char == '>') {
} else {
}
break;
comb = 0;
}
if (sel) {
sel) ;
}
}
return CR_OK;
return status;
}
/**
* cr_parser_parse_selector:
*@a_this: the current instance of #CRParser.
*@a_selector: the parsed list of comma separated
*selectors.
*
*Parses a comma separated list of selectors.
*
*Returns CR_OK upon successful completion, an error
*code otherwise.
*/
static enum CRStatus
CRSelector ** a_selector)
{
next_char = 0;
if (simple_sels) {
(selector, simple_sels);
if (selector) {
&simple_sels->location) ;
}
simple_sels = NULL;
} else {
goto error ;
}
&next_char);
if (status == CR_END_OF_INPUT_ERROR) {
goto okay;
} else {
goto error;
}
}
if (next_char == ',') {
for (;;) {
simple_sels = NULL;
&next_char);
if (status == CR_END_OF_INPUT_ERROR) {
break;
} else {
goto error;
}
}
if (next_char != ',')
break;
/*consume the ',' char */
(a_this, &simple_sels);
if (simple_sels) {
selector =
(selector, simple_sels);
simple_sels = NULL;
}
}
}
okay:
if (!*a_selector) {
*a_selector = selector;
} else {
}
return CR_OK;
if (simple_sels) {
simple_sels = NULL;
}
if (selector) {
}
return status;
}
/**
* cr_parser_parse_function:
*@a_this: the "this pointer" of the current instance of #CRParser.
*
*@a_func_name: out parameter. The parsed function name
*@a_expr: out parameter. The successfully parsed term.
*
*Parses a "function" as defined in css spec at appendix D.1:
*function ::= FUNCTION S* expr ')' S*
*FUNCTION ::= ident'('
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
static enum CRStatus
CRString ** a_func_name,
{
&& a_func_name,
goto error;
} else {
goto error;
}
goto error;
if (expr) {
}
return CR_OK;
if (*a_func_name) {
*a_func_name = NULL;
}
if (expr) {
}
if (token) {
}
return status;
}
/**
* cr_parser_parse_uri:
*@a_this: the current instance of #CRParser.
*@a_str: the successfully parsed url.
*
*Parses an uri as defined by the css spec [4.1.1]:
* URI ::= url\({w}{string}{w}\)
* |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
static enum CRStatus
{
return status;
}
/**
* cr_parser_parse_string:
*@a_this: the current instance of #CRParser.
*@a_start: out parameter. Upon successfull completion,
*points to the beginning of the string, points to an undefined value
*otherwise.
*@a_end: out parameter. Upon successfull completion, points to
*the beginning of the string, points to an undefined value otherwise.
*
*Parses a string type as defined in css spec [4.1.1]:
*
*string ::= {string1}|{string2}
*string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
*string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
static enum CRStatus
{
&& a_str, CR_BAD_PARAM_ERROR);
return status;
}
/**
*Parses an "ident" as defined in css spec [4.1.1]:
*ident ::= {nmstart}{nmchar}*
*
*@param a_this the currens instance of #CRParser.
*
*@param a_str a pointer to parsed ident. If *a_str is NULL,
*this function allocates a new instance of #CRString. If not,
*the function just appends the parsed string to the one passed.
*In both cases it is up to the caller to free *a_str.
*
*@return CR_OK upon successfull completion, an error code
*otherwise.
*/
static enum CRStatus
{
&& a_str, CR_BAD_PARAM_ERROR);
return status;
}
/**
*the next rule is ignored as well. This seems to be a bug
*Parses a stylesheet as defined in the css2 spec in appendix D.1:
*stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]?
* [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
* [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]*
*
*TODO: Finish the code of this function. Think about splitting it into
*smaller functions.
*
*@param a_this the "this pointer" of the current instance of #CRParser.
*@param a_start out parameter. A pointer to the first character of
*the successfully parsed string.
*@param a_end out parameter. A pointer to the first character of
*the successfully parsed string.
*
*@return CR_OK upon successfull completion, an error code otherwise.
*/
static enum CRStatus
{
}
if (status == CR_END_OF_INPUT_ERROR)
goto done;
CRParsingLocation location = {0,0,0} ;
token);
&charset,
&location);
}
} else if (status != CR_END_OF_INPUT_ERROR) {
}
if (charset) {
}
} else if (token
token);
goto parse_charset ;
} else if (token) {
token);
}
/* parse_imports:*/
do {
if (token) {
}
if (status == CR_END_OF_INPUT_ERROR)
goto done;
} while (token
if (token) {
token);
}
for (;;) {
if (status == CR_END_OF_INPUT_ERROR)
goto done;
CRParsingLocation location = {0,0,0} ;
&location);
if (import_string
/*
*TODO: resolve the
*import rule.
*/
}
}
}
} else if (status != CR_END_OF_INPUT_ERROR) {
}
} else {
goto error ;
}
/*
*then, after calling the appropriate
*SAC handler, free
*the media_list and import_string.
*/
if (media_list) {
/*free the medium list */
}
}
media_list = NULL;
}
if (import_string) {
}
} else if (token
do {
if (token) {
}
if (status == CR_END_OF_INPUT_ERROR)
goto done;
} while (token
} else {
if (token) {
}
goto parse_ruleset_and_others;
}
}
for (;;) {
if (status == CR_END_OF_INPUT_ERROR)
goto done;
if (token
do {
if (token) {
}
(a_this);
} while (token
if (token) {
}
} else if (token
/*
*Try to parse a CSS2 ruleset.
*if the parsing fails, try to parse
*a css core ruleset.
*/
continue;
} else {
}
(a_this);
continue;
} else {
break;
}
}
continue;
} else {
}
continue;
} else {
break;
}
}
continue;
} else {
}
continue;
} else {
break;
}
}
continue;
} else {
}
continue;
} else {
break;
}
}
} else {
continue;
} else {
break;
}
}
}
done:
if (token) {
}
}
return CR_OK;
}
}
return status;
if (token) {
}
}
return status;
}
/****************************************
*Public CRParser Methods
****************************************/
/**
* cr_parser_new:
* @a_tknzr: the tokenizer to use for the parsing.
*
*Creates a new parser to parse data
*coming the input stream given in parameter.
*
*Returns the newly created instance of #CRParser,
*or NULL if an error occured.
*/
CRParser *
{
if (a_tknzr) {
}
return result;
}
/**
* cr_parser_new_from_buf:
*@a_buf: the buffer to parse.
*@a_len: the length of the data in the buffer.
*@a_enc: the encoding of the input buffer a_buf.
*@a_free_buf: if set to TRUE, a_buf will be freed
*during the destruction of the newly built instance
*of #CRParser. If set to FALSE, it is up to the caller to
*eventually free it.
*
*Instanciates a new parser from a memory buffer.
*
*Returns the newly built parser, or NULL if an error arises.
*/
CRParser *
enum CREncoding a_enc,
{
if (!result) {
return NULL;
}
return result;
}
/**
* cr_parser_new_from_input:
* @a_input: the parser input stream to use.
*
* Returns a newly built parser input.
*/
CRParser *
{
if (a_input) {
}
return result;
}
/**
* cr_parser_new_from_file:
* @a_file_uri: the uri of the file to parse.
* @a_enc: the file encoding to use.
*
* Returns the newly built parser.
*/
CRParser *
{
if (!tokenizer) {
cr_utils_trace_info ("Could not open input file");
return NULL;
}
return result;
}
/**
* cr_parser_set_sac_handler:
*@a_this: the "this pointer" of the current instance of #CRParser.
*@a_handler: the handler to set.
*
*Sets a SAC document handler to the parser.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
}
return CR_OK;
}
/**
* cr_parser_get_sac_handler:
*@a_this: the "this pointer" of the current instance of
*#CRParser.
*@a_handler: out parameter. The returned handler.
*
*Gets the SAC document handler.
*
*Returns CR_OK upon successfull completion, an error code
*otherwise.
*/
enum CRStatus
{
return CR_OK;
}
/**
* cr_parser_set_default_sac_handler:
*@a_this: a pointer to the current instance of #CRParser.
*
*Sets the SAC handler associated to the current instance
*of #CRParser to the default SAC handler.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
}
return status;
}
/**
* cr_parser_set_use_core_grammar:
* @a_this: the current instance of #CRParser.
* @a_use_core_grammar: where to parse against the css core grammar.
*
* Returns CR_OK upon succesful completion, an error code otherwise.
*/
enum CRStatus
{
return CR_OK;
}
/**
* cr_parser_get_use_core_grammar:
* @a_this: the current instance of #CRParser.
* @a_use_core_grammar: wether to use the core grammar or not.
*
* Returns CR_OK upon succesful completion, an error code otherwise.
*/
enum CRStatus
{
return CR_OK;
}
/**
* cr_parser_parse_file:
*@a_this: a pointer to the current instance of #CRParser.
*@a_file_uri: the uri to the file to load. For the time being,
*@a_enc: the encoding of the file to parse.
*only local files are supported.
*
*Parses a the given in parameter.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
&& a_file_uri, CR_BAD_PARAM_ERROR);
return status;
}
/**
* cr_parser_parse_expr:
* @a_this: the current instance of #CRParser.
* @a_expr: out parameter. the parsed expression.
*
*Parses an expression as defined by the css2 spec in appendix
*D.1:
*expr: term [ operator term ]*
*
*
* Returns CR_OK upon successful completion, an error code otherwise.
*/
enum CRStatus
{
&& a_expr, CR_BAD_PARAM_ERROR);
for (;;) {
1, &next_byte);
if (status == CR_END_OF_INPUT_ERROR) {
/*
if (!nb_terms)
{
goto error ;
}
*/
break;
} else {
goto error;
}
}
}
break;
}
switch (operatr) {
case '/':
break;
case ',':
default:
break;
}
operatr = 0;
nb_terms++;
}
return CR_OK;
}
if (expr) {
}
if (expr2) {
}
return status;
}
/**
* cr_parser_parse_prio:
*@a_this: the current instance of #CRParser.
*@a_prio: a string representing the priority.
*Today, only "!important" is returned as only this
*priority is defined by css2.
*
*Parses a declaration priority as defined by
*the css2 grammar in appendix C:
*prio: IMPORTANT_SYM S*
*
* Returns CR_OK upon successful completion, an error code otherwise.
*/
enum CRStatus
{
&& a_prio
if (status == CR_END_OF_INPUT_ERROR) {
goto error;
}
return CR_OK;
if (token) {
}
return status;
}
/**
* cr_parser_parse_declaration:
*@a_this: the "this pointer" of the current instance of #CRParser.
*@a_property: the successfully parsed property. The caller
* *must* free the returned pointer.
*@a_expr: the expression that represents the attribute value.
*The caller *must* free the returned pointer.
*
*TODO: return the parsed priority, so that
*upper layers can take benefit from it.
*Parses a "declaration" as defined by the css2 spec in appendix D.1:
*declaration ::= [property ':' S* expr prio?]?
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
CRString ** a_property,
{
&& a_property && a_expr
if (status == CR_END_OF_INPUT_ERROR)
goto error;
"while parsing declaration: next property is malformed",
if (cur_char != ':') {
(a_this,
"while parsing declaration: this char must be ':'",
goto error;
}
"while parsing declaration: next expression is malformed",
if (prio) {
*a_important = TRUE;
} else {
*a_important = FALSE;
}
if (*a_expr) {
} else {
}
return CR_OK;
if (expr) {
}
if (*a_property) {
*a_property = NULL;
}
return status;
}
/**
* cr_parser_parse_statement_core:
*@a_this: the current instance of #CRParser.
*
*Parses a statement as defined by the css core grammar in
*chapter 4.1 of the css2 spec.
*statement : ruleset | at-rule;
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
case ATKEYWORD_TK:
case IMPORT_SYM_TK:
case PAGE_SYM_TK:
case MEDIA_SYM_TK:
case FONT_FACE_SYM_TK:
case CHARSET_SYM_TK:
break;
default:
}
return CR_OK;
if (token) {
}
return status;
}
/**
* cr_parser_parse_ruleset:
*@a_this: the "this pointer" of the current instance of #CRParser.
*
*Parses a "ruleset" as defined in the css2 spec at appendix D.1.
*ruleset ::= selector [ ',' S* selector ]*
*'{' S* declaration? [ ';' S* declaration? ]* '}' S*;
*
*This methods calls the SAC handler on the relevant SAC handler
*callbacks whenever it encounters some specific constructions.
*See the documentation of #CRDocHandler (the SAC handler) to know
*when which SAC handler is called.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
next_char = 0;
"while parsing rulset: current char should be '{'",
/*
*the selector is ref counted so that the parser's user
*can choose to keep it.
*/
if (selector) {
}
}
&expr,
&is_important);
if (expr) {
cr_term_ref (expr);
}
}
/*
*free the allocated
*'property' and 'term' before parsing
*next declarations.
*/
if (property) {
}
if (expr) {
}
} else {/*status != CR_OK*/
guint32 c = 0 ;
/*
*test if we have reached '}', which
*would mean that we are parsing an empty ruleset (eg. x{ })
*In that case, goto end_of_ruleset.
*/
goto end_of_ruleset ;
}
}
"while parsing ruleset: next construction should be a declaration",
for (;;) {
if (next_char != ';')
break;
/*consume the ';' char */
&expr, &is_important);
if (expr) {
cr_term_ref (expr);
}
}
if (property) {
}
if (expr) {
}
}
"while parsing rulset: current char must be a '}'",
}
if (expr) {
}
if (simple_sels) {
simple_sels = NULL;
}
if (selector) {
}
return CR_OK;
if (start_selector == TRUE
}
if (expr) {
}
if (simple_sels) {
simple_sels = NULL;
}
if (property) {
}
if (selector) {
}
return status;
}
/**
* cr_parser_parse_import:
*@a_this: the "this pointer" of the current instance
*of #CRParser.
*@a_media_list: out parameter. A linked list of
*#CRString
*Each CRString is a string that contains
*a 'medium' declaration part of the successfully
*parsed 'import' declaration.
*@a_import_string: out parameter.
*A string that contains the 'import
*string". The import string can be either an uri (if it starts with
*the substring "uri(") or a any other css2 string. Note that
* *a_import_string must be initially set to NULL or else, this function
*will return CR_BAD_PARAM_ERROR.
*@a_location: the location (line, column) where the import has been parsed
*
*Parses an 'import' declaration as defined in the css2 spec
*in appendix D.1:
*
*import ::=
*\@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S*
*
*Returns CR_OK upon sucessfull completion, an error code otherwise.
*/
enum CRStatus
GList ** a_media_list,
{
next_char = 0;
&& (*a_import_string == NULL),
if (a_location) {
(a_this, a_location) ;
}
} else {
goto error;
}
} else {
}
}
if (status == CR_END_OF_INPUT_ERROR) {
goto okay;
}
goto error;
}
if (next_char == ',') {
} else {
break;
}
}
}
okay:
return CR_OK;
if (*a_media_list) {
/*
*free each element of *a_media_list.
*Note that each element of *a_medium list *must*
*be a GString* or else, the code that is coming next
*will corrupt the memory and lead to hard to debug
*random crashes.
*This is where C++ and its compile time
*type checking mecanism (through STL containers) would
*have prevented us to go through this hassle.
*/
}
}
*a_media_list = NULL;
}
if (*a_import_string) {
*a_import_string = NULL;
}
if (medium) {
}
return status;
}
/**
* cr_parser_parse_media:
*@a_this: the "this pointer" of the current instance of #CRParser.
*
*Parses a 'media' declaration as specified in the css2 spec at
*appendix D.1:
*
*media ::= \@media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S*
*
*Note that this function calls the required sac handlers during the parsing
*to notify media productions. See #CRDocHandler to know the callback called
*during \@media parsing.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
cur_char = 0;
CRParsingLocation location = {0,0,0} ;
&token);
&& token
if (medium) {
}
if (next_char == ',') {
} else {
break;
}
if (medium) {
}
}
/*
*call the SAC handler api here.
*/
&location);
}
}
/*
*call the right SAC handler api here.
*/
}
/*
*Then, free the data structures passed to
*the last call to the SAC handler.
*/
if (medium) {
}
if (media_list) {
}
media_list = NULL;
}
return CR_OK;
if (token) {
}
if (medium) {
}
if (media_list) {
}
media_list = NULL;
}
return status;
}
/**
* cr_parser_parse_page:
*@a_this: the "this pointer" of the current instance of #CRParser.
*
*Parses '\@page' rule as specified in the css2 spec in appendix D.1:
*page ::= PAGE_SYM S* IDENT? pseudo_page? S*
*'{' S* declaration [ ';' S* declaration ]* '}' S*
*
*This function also calls the relevant SAC handlers whenever it
*encounters a construction that must
*be reported to the calling application.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
CRParsingLocation location = {0,0,0} ;
&token) ;
&& token
} else {
}
/*
*try to parse pseudo_page
*/
} else {
}
/*
*parse_block
*
*/
/*
*Call the appropriate SAC handler here.
*/
&location);
}
&important);
/*
*call the relevant SAC handler here...
*/
if (css_expression)
}
/*
*... and free the data structure passed to that last
*SAC handler.
*/
if (property) {
}
if (css_expression) {
}
for (;;) {
/*parse the other ';' separated declarations */
if (token) {
}
token);
break;
}
&important);
break ;
/*
*call the relevant SAC handler here...
*/
}
/*
*... and free the data structure passed to that last
*SAC handler.
*/
if (property) {
}
if (css_expression) {
}
}
(a_this) ;
if (token) {
}
&& token
/*
*call the relevant SAC handler here.
*/
}
if (page_selector) {
}
if (page_pseudo_class) {
}
/*here goes the former implem of this function ... */
return CR_OK;
if (token) {
}
if (page_selector) {
}
if (page_pseudo_class) {
}
if (property) {
}
if (css_expression) {
}
return status;
}
/**
* cr_parser_parse_charset:
*@a_this: the "this pointer" of the current instance of #CRParser.
*@a_value: out parameter. The actual parsed value of the charset
*declararation. Note that for safety check reasons, *a_value must be
*set to NULL.
*@a_charset_sym_location: the parsing location of the charset rule
*
*Parses a charset declaration as defined implictly by the css2 spec in
*appendix D.1:
*charset ::= CHARSET_SYM S* STRING S* ';'
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
if (a_charset_sym_location) {
}
if (charset_str) {
*a_value = charset_str;
charset_str = NULL;
}
return CR_OK;
if (token) {
}
if (*a_value) {
}
if (charset_str) {
charset_str = NULL;
}
return status;
}
/**
* cr_parser_parse_font_face:
*@a_this: the current instance of #CRParser.
*
*Parses the "\@font-face" rule specified in the css1 spec in
*appendix D.1:
*
*font_face ::= FONT_FACE_SYM S*
*'{' S* declaration [ ';' S* declaration ]* '}' S*
*
*This function will call SAC handlers whenever it is necessary.
*
*Returns CR_OK upon successfull completion, an error code otherwise.
*/
enum CRStatus
{
cur_char = 0;
CRParsingLocation location = {0,0,0} ;
&& token
if (token) {
}
&token);
if (token) {
}
/*
*here, call the relevant SAC handler.
*/
}
/*
*and resume the parsing.
*/
&css_expression, &important);
/*
*here, call the relevant SAC handler.
*/
}
}
/*free the data structures allocated during last parsing. */
if (property) {
}
if (css_expression) {
}
for (;;) {
if (next_char == ';') {
} else {
break;
}
&property,
&important);
break;
/*
*here, call the relevant SAC handler.
*/
}
/*
*Then, free the data structures allocated during
*last parsing.
*/
if (property) {
}
if (css_expression) {
}
}
/*
*here, call the relevant SAC handler.
*/
}
if (token) {
}
return CR_OK;
if (token) {
}
if (property) {
}
if (css_expression) {
}
return status;
}
/**
* cr_parser_parse:
*@a_this: the current instance of #CRParser.
*
*Parses the data that comes from the
*input previously associated to the current instance of
*#CRParser.
*
*Returns CR_OK upon succesful completion, an error code otherwise.
*/
enum CRStatus
{
} else {
}
return status;
}
/**
* cr_parser_set_tknzr:
* @a_this: the current instance of #CRParser;
* @a_tknzr: the new tokenizer.
*
* Returns CR_OK upon successful completion, an error code otherwise.
*/
enum CRStatus
{
}
if (a_tknzr)
return CR_OK;
}
/**
* cr_parser_get_tknzr:
*@a_this: the current instance of #CRParser
*@a_tknzr: out parameter. The returned tokenizer
*
*Getter of the parser's underlying tokenizer
*
*Returns CR_OK upon succesful completion, an error code
*otherwise
*/
enum CRStatus
{
&& a_tknzr, CR_BAD_PARAM_ERROR);
return CR_OK;
}
/**
* cr_parser_get_parsing_location:
*@a_this: the current instance of #CRParser
*@a_loc: the parsing location to get.
*
*Gets the current parsing location.
*
*Returns CR_OK upon succesful completion, an error code
*otherwise.
*/
enum CRStatus
{
&& a_loc, CR_BAD_PARAM_ERROR) ;
}
/**
* cr_parser_parse_buf:
*@a_this: the current instance of #CRparser
*@a_buf: the input buffer
*@a_len: the length of the input buffer
*@a_enc: the encoding of the buffer
*
*Parses a stylesheet from a buffer
*
*Returns CR_OK upon successful completion, an error code otherwise.
*/
enum CRStatus
{
&& a_buf, CR_BAD_PARAM_ERROR);
return status;
}
/**
* cr_parser_destroy:
*@a_this: the current instance of #CRParser to
*destroy.
*
*Destroys the current instance
*of #CRParser.
*/
void
{
}
}
}
}
}