PageRenderTime 111ms CodeModel.GetById 17ms app.highlight 69ms RepoModel.GetById 1ms app.codeStats 2ms

/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 files are truncated, but you can click here to view the full file

   1/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
   2
   3/*
   4 * This file is part of The Croco Library
   5 *
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of version 2.1 of the 
   9 * GNU Lesser General Public
  10 * License as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  20 * USA
  21 *
  22 * Author: Dodji Seketeli
  23 * See COPYRIGHTS file for copyrights information.
  24 */
  25
  26/**
  27 *@file
  28 *The definition of the #CRParser class.
  29 */
  30
  31#include "string.h"
  32#include "cr-parser.h"
  33#include "cr-num.h"
  34#include "cr-term.h"
  35#include "cr-simple-sel.h"
  36#include "cr-attr-sel.h"
  37
  38/*
  39 *Random notes: 
  40 *CSS core syntax vs CSS level 2 syntax
  41 *=====================================
  42 *
  43 *One must keep in mind
  44 *that css UA must comply with two syntax.
  45 *
  46 *1/the specific syntax that defines the css language
  47 *for a given level of specificatin (e.g css2 syntax
  48 *defined in appendix D.1 of the css2 spec)
  49 *
  50 *2/the core (general) syntax that is there to allow
  51 *UAs to parse style sheets written in levels of CSS that
  52 *didn't exist at the time the UAs were created.
  53 *
  54 *the name  of parsing functions (or methods) contained in this  file
  55 *follows the following scheme: cr_parser_parse_<production_name> (...) ;
  56 *where <production_name> is the name 
  57 *of a production of the css2 language.
  58 *When a given production is 
  59 *defined by the css2 level grammar *and* by the
  60 *css core syntax, there will be two functions to parse that production:
  61 *one will parse the production defined by the css2 level grammar and the
  62 *other will parse the production defined by the css core grammar.
  63 *The css2 level grammar related parsing function will be called:
  64 *cr_parser_parse_<production_name> (...) ;
  65 *Then css core grammar related parsing function will be called:
  66 *cr_parser_parse_<production_name>_core (...) ;
  67 *
  68 *If a production is defined only by the css core grammar, then
  69 *it will be named:
  70 *cr_parser_parse_<production_name>_core (...) ;
  71 */
  72
  73/* moved _CRParserError struct to make it public and not opaque
  74   modified by Iago Rubio to cssed */
  75
  76/**
  77 *An abstraction of an error reported by by the
  78 *parsing routines.
  79 */
  80
  81enum CRParserState {
  82        READY_STATE = 0,
  83        TRY_PARSE_CHARSET_STATE,
  84        CHARSET_PARSED_STATE,
  85        TRY_PARSE_IMPORT_STATE,
  86        IMPORT_PARSED_STATE,
  87        TRY_PARSE_RULESET_STATE,
  88        RULESET_PARSED_STATE,
  89        TRY_PARSE_MEDIA_STATE,
  90        MEDIA_PARSED_STATE,
  91        TRY_PARSE_PAGE_STATE,
  92        PAGE_PARSED_STATE,
  93        TRY_PARSE_FONT_FACE_STATE,
  94        FONT_FACE_PARSED_STATE
  95} ;
  96
  97/**
  98 *The private attributes of
  99 *#CRParser.
 100 */
 101struct _CRParserPriv {
 102        /**
 103         *The tokenizer
 104         */
 105        CRTknzr *tknzr;
 106
 107        /**
 108         *The sac handlers to call
 109         *to notify the parsing of
 110         *the css2 constructions.
 111         */
 112        CRDocHandler *sac_handler;
 113
 114        /**
 115         *A stack of errors reported
 116         *by the parsing routines.
 117         *Contains instance of #CRParserError.
 118         *This pointer is the top of the stack.
 119         */
 120        GList *err_stack;
 121
 122        enum CRParserState state;
 123        gboolean resolve_import;
 124        gboolean is_case_sensitive;
 125        gboolean use_core_grammar;
 126};
 127
 128#define PRIVATE(obj) ((obj)->priv)
 129
 130#define CHARS_TAB_SIZE 12
 131
 132/**
 133 *return TRUE if the character is a number ([0-9]), FALSE otherwise
 134 *@param a_char the char to test.
 135 */
 136#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
 137
 138/**
 139 *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
 140 *
 141 *@param status the status (of type enum CRStatus) to test.
 142 *@param is_exception if set to FALSE, the final status returned 
 143 *by the current function will be CR_PARSING_ERROR. If set to TRUE, the
 144 *current status will be the current value of the 'status' variable.
 145 *
 146 */
 147#define CHECK_PARSING_STATUS(status, is_exception) \
 148if ((status) != CR_OK) \
 149{ \
 150        if (is_exception == FALSE) \
 151        { \
 152                status = CR_PARSING_ERROR ; \
 153        } \
 154        goto error ; \
 155}
 156
 157/**
 158 *same as CHECK_PARSING_STATUS() but this one pushes an error
 159 *on the parser error stack when an error arises.
 160 *@param a_this the current instance of #CRParser .
 161 *@param a_status the status to check. Is of type enum #CRStatus.
 162 *@param a_is_exception in case of error, if is TRUE, the status
 163 *is set to CR_PARSING_ERROR before goto error. If is false, the
 164 *real low level status is kept and will be returned by the
 165 *upper level function that called this macro. Usally,this must
 166 *be set to FALSE.
 167 *
 168 */
 169#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\
 170                                 a_err_msg, a_err_status) \
 171if ((a_status) != CR_OK) \
 172{ \
 173        if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \
 174        cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
 175        goto error ; \
 176}
 177
 178/**
 179 *Peeks the next char from the input stream of the current parser
 180 *by invoking cr_tknzr_input_peek_char().
 181 *invokes CHECK_PARSING_STATUS on the status returned by
 182 *cr_tknzr_peek_char().
 183 *
 184 *@param a_this the current instance of #CRParser.
 185 *@param a_to_char a pointer to the char where to store the
 186 *char peeked.
 187 */
 188#define PEEK_NEXT_CHAR(a_this, a_to_char) \
 189{\
 190enum CRStatus status ; \
 191status = cr_tknzr_peek_char  (PRIVATE (a_this)->tknzr, a_to_char) ; \
 192CHECK_PARSING_STATUS (status, TRUE) \
 193}
 194
 195/**
 196 *Reads the next char from the input stream of the current parser.
 197 *In case of error, jumps to the "error:" label located in the
 198 *function where this macro is called.
 199 *@param a_this the curent instance of #CRParser
 200 *@param to_char a pointer to the guint32 char where to store
 201 *the character read.
 202 */
 203#define READ_NEXT_CHAR(a_this, a_to_char) \
 204status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
 205CHECK_PARSING_STATUS (status, TRUE)
 206
 207/**
 208 *Gets information about the current position in
 209 *the input of the parser.
 210 *In case of failure, this macro returns from the 
 211 *calling function and
 212 *returns a status code of type enum #CRStatus.
 213 *@param a_this the current instance of #CRParser.
 214 *@param a_pos out parameter. A pointer to the position 
 215 *inside the current parser input. Must
 216 */
 217#define RECORD_INITIAL_POS(a_this, a_pos) \
 218status = cr_tknzr_get_cur_pos (PRIVATE \
 219(a_this)->tknzr, a_pos) ; \
 220g_return_val_if_fail (status == CR_OK, status)
 221
 222/**
 223 *Gets the address of the current byte inside the
 224 *parser input.
 225 *@param parser the current instance of #CRParser.
 226 *@param addr out parameter a pointer (guchar*)
 227 *to where the address  must be put.
 228 */
 229#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \
 230status = cr_tknzr_get_cur_byte_addr \
 231            (PRIVATE (a_this)->tknzr, a_addr) ; \
 232CHECK_PARSING_STATUS (status, TRUE)
 233
 234/**
 235 *Peeks a byte from the topmost parser input at
 236 *a given offset from the current position.
 237 *If it fails, goto the "error:" label.
 238 *
 239 *@param a_parser the current instance of #CRParser.
 240 *@param a_offset the offset of the byte to peek, the
 241 *current byte having the offset '0'.
 242 *@param a_byte_ptr out parameter a pointer (guchar*) to
 243 *where the peeked char is to be stored.
 244 */
 245#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \
 246status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \
 247                              a_offset, \
 248                              a_byte_ptr) ; \
 249CHECK_PARSING_STATUS (status, TRUE) ;
 250
 251#define BYTE(a_parser, a_offset, a_eof) \
 252cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof)
 253
 254/**
 255 *Reads a byte from the topmost parser input
 256 *steam.
 257 *If it fails, goto the "error" label.
 258 *@param a_this the current instance of #CRParser.
 259 *@param a_byte_ptr the guchar * where to put the read char.
 260 */
 261#define READ_NEXT_BYTE(a_this, a_byte_ptr) \
 262status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \
 263CHECK_PARSING_STATUS (status, TRUE) ;
 264
 265/**
 266 *Skips a given number of byte in the topmost
 267 *parser input. Don't update line and column number.
 268 *In case of error, jumps to the "error:" label
 269 *of the surrounding function.
 270 *@param a_parser the current instance of #CRParser.
 271 *@param a_nb_bytes the number of bytes to skip.
 272 */
 273#define SKIP_BYTES(a_this, a_nb_bytes) \
 274status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \
 275                                        CR_SEEK_CUR, a_nb_bytes) ; \
 276CHECK_PARSING_STATUS (status, TRUE) ;
 277
 278/**
 279 *Skip utf8 encoded characters.
 280 *Updates line and column numbers.
 281 *@param a_parser the current instance of #CRParser.
 282 *@param a_nb_chars the number of chars to skip. Must be of
 283 *type glong.
 284 */
 285#define SKIP_CHARS(a_parser, a_nb_chars) \
 286{ \
 287glong nb_chars = a_nb_chars ; \
 288status = cr_tknzr_consume_chars \
 289     (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \
 290CHECK_PARSING_STATUS (status, TRUE) ; \
 291}
 292
 293/**
 294 *Tests the condition and if it is false, sets
 295 *status to "CR_PARSING_ERROR" and goto the 'error'
 296 *label.
 297 *@param condition the condition to test.
 298 */
 299#define ENSURE_PARSING_COND(condition) \
 300if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
 301
 302#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \
 303                                a_err_msg, a_err_status) \
 304if (! (a_condition)) \
 305{ \
 306        status = CR_PARSING_ERROR; \
 307        cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
 308        goto error ; \
 309}
 310
 311#define GET_NEXT_TOKEN(a_this, a_token_ptr) \
 312status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \
 313                                  a_token_ptr) ; \
 314ENSURE_PARSING_COND (status == CR_OK) ;
 315
 316#ifdef WITH_UNICODE_ESCAPE_AND_RANGE
 317static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this,
 318                                                     guint32 * a_unicode);
 319static enum CRStatus cr_parser_parse_escape (CRParser * a_this,
 320                                             guint32 * a_esc_code);
 321
 322static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this,
 323                                                    CRString ** a_inf,
 324                                                    CRString ** a_sup);
 325#endif
 326
 327static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this);
 328
 329static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this);
 330
 331static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this);
 332
 333static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this);
 334
 335static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this);
 336
 337static enum CRStatus cr_parser_parse_any_core (CRParser * a_this);
 338
 339static enum CRStatus cr_parser_parse_block_core (CRParser * a_this);
 340
 341static enum CRStatus cr_parser_parse_value_core (CRParser * a_this);
 342
 343static enum CRStatus cr_parser_parse_string (CRParser * a_this,
 344                                             CRString ** a_str);
 345
 346static enum CRStatus cr_parser_parse_ident (CRParser * a_this,
 347                                            CRString ** a_str);
 348
 349static enum CRStatus cr_parser_parse_uri (CRParser * a_this,
 350                                          CRString ** a_str);
 351
 352static enum CRStatus cr_parser_parse_function (CRParser * a_this,
 353                                               CRString ** a_func_name,
 354                                               CRTerm ** a_expr);
 355static enum CRStatus cr_parser_parse_property (CRParser * a_this,
 356                                               CRString ** a_property);
 357
 358static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this,
 359                                                         CRAttrSel ** a_sel);
 360
 361static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this,
 362                                                      CRSimpleSel ** a_sel);
 363
 364static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this,
 365                                                  CRSimpleSel ** a_sel);
 366
 367static CRParserError *cr_parser_error_new (const guchar * a_msg,
 368                                           enum CRStatus);
 369
 370static void cr_parser_error_set_msg (CRParserError * a_this,
 371                                     const guchar * a_msg);
 372
 373static void cr_parser_error_dump (CRParserError * a_this);
 374
 375static void cr_parser_error_set_status (CRParserError * a_this,
 376                                        enum CRStatus a_status);
 377
 378static void cr_parser_error_set_pos (CRParserError * a_this,
 379                                     glong a_line,
 380                                     glong a_column, glong a_byte_num);
 381static void
 382  cr_parser_error_destroy (CRParserError * a_this);
 383
 384static enum CRStatus cr_parser_push_error (CRParser * a_this,
 385                                           const guchar * a_msg,
 386                                           enum CRStatus a_status);
 387
 388static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this,
 389                                               gboolean a_clear_errs);
 390static enum CRStatus
 391  cr_parser_clear_errors (CRParser * a_this);
 392
 393/* **********************************************************
 394   Added by Iago Rubio to use it in cssed as syntax validator
 395   ********************************************************** */
 396
 397GList*
 398cr_parser_get_error_stack(CRParser *a_this)
 399{
 400	GList *stack ;
 401	stack = g_list_copy(PRIVATE(a_this)->err_stack);
 402	return stack;
 403}
 404gulong
 405cr_parser_get_pos(CRParser *a_this)
 406{
 407	return cr_tknzr_get_cur_line(PRIVATE(a_this)->tknzr);		
 408}
 409/*****************************
 410 * end iago's changes
 411 *****************************/
 412
 413/*****************************
 414 *error managemet methods
 415 *****************************/
 416
 417/**
 418 *Constructor of #CRParserError class.
 419 *@param a_msg the brute error message.
 420 *@param a_status the error status.
 421 *@return the newly built instance of #CRParserError.
 422 */
 423static CRParserError *
 424cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status)
 425{
 426        CRParserError *result = NULL;
 427
 428        result = g_try_malloc (sizeof (CRParserError));
 429
 430        if (result == NULL) {
 431                cr_utils_trace_info ("Out of memory");
 432                return NULL;
 433        }
 434
 435        memset (result, 0, sizeof (CRParserError));
 436
 437        cr_parser_error_set_msg (result, a_msg);
 438        cr_parser_error_set_status (result, a_status);
 439
 440        return result;
 441}
 442
 443
 444/**
 445 *Sets the message associated to this instance of #CRError.
 446 *@param a_this the current instance of #CRParserError.
 447 *@param a_msg the new message.
 448 */
 449static void
 450cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg)
 451{
 452        g_return_if_fail (a_this);
 453
 454        if (a_this->msg) {
 455                g_free (a_this->msg);
 456        }
 457
 458        a_this->msg = g_strdup (a_msg);
 459}
 460
 461/**
 462 *Sets the error status.
 463 *@param a_this the current instance of #CRParserError.
 464 *@param a_status the new error status.
 465 *
 466 */
 467static void
 468cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status)
 469{
 470        g_return_if_fail (a_this);
 471
 472        a_this->status = a_status;
 473}
 474
 475/**
 476 *Sets the position of the parser error.
 477 *@param a_this the current instance of #CRParserError.
 478 *@param a_line the line number.
 479 *@param a_column the column number.
 480 *@param a_byte_num the byte number.
 481 */
 482static void
 483cr_parser_error_set_pos (CRParserError * a_this,
 484                         glong a_line, glong a_column, glong a_byte_num)
 485{
 486        g_return_if_fail (a_this);
 487
 488        a_this->line = a_line;
 489        a_this->column = a_column;
 490        a_this->byte_num = a_byte_num;
 491}
 492
 493static void
 494cr_parser_error_dump (CRParserError * a_this)
 495{
 496        g_return_if_fail (a_this);
 497
 498        g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column);
 499
 500        g_printerr ("%s\n", a_this->msg);
 501}
 502
 503/**
 504 *The destructor of #CRParserError.
 505 *@param a_this the current instance of #CRParserError.
 506 */
 507static void
 508cr_parser_error_destroy (CRParserError * a_this)
 509{
 510        g_return_if_fail (a_this);
 511
 512        if (a_this->msg) {
 513                g_free (a_this->msg);
 514                a_this->msg = NULL;
 515        }
 516
 517        g_free (a_this);
 518}
 519
 520/**
 521 *Pushes an error on the parser error stack.
 522 *@param a_this the current instance of #CRParser.
 523 *@param a_msg the error message.
 524 *@param a_status the error status.
 525 *@return CR_OK upon successfull completion, an error code otherwise.
 526 */
 527static enum CRStatus
 528cr_parser_push_error (CRParser * a_this,
 529                      const guchar * a_msg, enum CRStatus a_status)
 530{
 531        enum CRStatus status = CR_OK;
 532
 533        CRParserError *error = NULL;
 534        CRInputPos pos;
 535
 536        g_return_val_if_fail (a_this && PRIVATE (a_this)
 537                              && a_msg, CR_BAD_PARAM_ERROR);
 538
 539        error = cr_parser_error_new (a_msg, a_status);
 540
 541        g_return_val_if_fail (error, CR_ERROR);
 542
 543        RECORD_INITIAL_POS (a_this, &pos);
 544
 545        cr_parser_error_set_pos
 546                (error, pos.line, pos.col, pos.next_byte_index - 1);
 547
 548        PRIVATE (a_this)->err_stack =
 549                g_list_prepend (PRIVATE (a_this)->err_stack, error);
 550
 551        if (PRIVATE (a_this)->err_stack == NULL)
 552                goto error;
 553
 554        return CR_OK;
 555
 556      error:
 557
 558        if (error) {
 559                cr_parser_error_destroy (error);
 560                error = NULL;
 561        }
 562
 563        return status;
 564}
 565
 566/**
 567 *Dumps the error stack on stdout.
 568 *@param a_this the current instance of #CRParser.
 569 *@param a_clear_errs whether to clear the error stack
 570 *after the dump or not.
 571 *@return CR_OK upon successfull completion, an error code
 572 *otherwise.
 573 */
 574static enum CRStatus
 575cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs)
 576{
 577        GList *cur = NULL;
 578
 579        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 580
 581        if (PRIVATE (a_this)->err_stack == NULL)
 582                return CR_OK;
 583
 584        for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
 585                cr_parser_error_dump ((CRParserError *) cur->data);
 586        }
 587
 588        if (a_clear_errs == TRUE) {
 589                cr_parser_clear_errors (a_this);
 590        }
 591
 592        return CR_OK;
 593}
 594
 595/**
 596 *Clears all the errors contained in the parser error stack.
 597 *Frees all the errors, and the stack that contains'em.
 598 *@param a_this the current instance of #CRParser.
 599 */
 600static enum CRStatus
 601cr_parser_clear_errors (CRParser * a_this)
 602{
 603        GList *cur = NULL;
 604
 605        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 606
 607        for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
 608                if (cur->data) {
 609                        cr_parser_error_destroy ((CRParserError *)
 610                                                 cur->data);
 611                }
 612        }
 613
 614        if (PRIVATE (a_this)->err_stack) {
 615                g_list_free (PRIVATE (a_this)->err_stack);
 616                PRIVATE (a_this)->err_stack = NULL;
 617        }
 618
 619        return CR_OK;
 620}
 621
 622/**
 623 *Same as cr_parser_try_to_skip_spaces() but this one skips
 624 *spaces and comments.
 625 *
 626 *@param a_this the current instance of #CRParser.
 627 *@return CR_OK upon successfull completion, an error code otherwise.
 628 */
 629enum CRStatus
 630cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this)
 631{
 632        enum CRStatus status = CR_ERROR;
 633        CRToken *token = NULL;
 634
 635        g_return_val_if_fail (a_this && PRIVATE (a_this)
 636                              && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
 637        do {
 638                if (token) {
 639                        cr_token_destroy (token);
 640                        token = NULL;
 641                }
 642
 643                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
 644                                                  &token);
 645                if (status != CR_OK)
 646                        goto error;
 647        }
 648        while ((token != NULL)
 649               && (token->type == COMMENT_TK || token->type == S_TK));
 650
 651        cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
 652
 653        return status;
 654
 655      error:
 656
 657        if (token) {
 658                cr_token_destroy (token);
 659                token = NULL;
 660        }
 661
 662        return status;
 663}
 664
 665/***************************************
 666 *End of Parser input handling routines
 667 ***************************************/
 668
 669
 670/*************************************
 671 *Non trivial terminal productions
 672 *parsing routines
 673 *************************************/
 674
 675/**
 676 *Parses a css stylesheet following the core css grammar.
 677 *This is mainly done for test purposes.
 678 *During the parsing, no callback is called. This is just
 679 *to validate that the stylesheet is well formed according to the
 680 *css core syntax.
 681 *stylesheet  : [ CDO | CDC | S | statement ]*;
 682 *@param a_this the current instance of #CRParser.
 683 *@return CR_OK upon successfull completion, an error code otherwise.
 684 */
 685static enum CRStatus
 686cr_parser_parse_stylesheet_core (CRParser * a_this)
 687{
 688        CRToken *token = NULL;
 689        CRInputPos init_pos;
 690        enum CRStatus status = CR_ERROR;
 691
 692        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 693
 694        RECORD_INITIAL_POS (a_this, &init_pos);
 695
 696 continue_parsing:
 697
 698        if (token) {
 699                cr_token_destroy (token);
 700                token = NULL;
 701        }
 702
 703        cr_parser_try_to_skip_spaces_and_comments (a_this);
 704        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
 705        if (status == CR_END_OF_INPUT_ERROR) {
 706                status = CR_OK;
 707                goto done;
 708        } else if (status != CR_OK) {
 709                goto error;
 710        }
 711
 712        switch (token->type) {
 713
 714        case CDO_TK:
 715        case CDC_TK:
 716                goto continue_parsing;
 717                break;
 718        default:
 719                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
 720                                               token);
 721                CHECK_PARSING_STATUS (status, TRUE);
 722                token = NULL;
 723                status = cr_parser_parse_statement_core (a_this);
 724                cr_parser_clear_errors (a_this);
 725                if (status == CR_OK) {
 726                        goto continue_parsing;
 727                } else if (status == CR_END_OF_INPUT_ERROR) {
 728                        goto done;
 729                } else {
 730                        goto error;
 731                }
 732        }
 733
 734 done:
 735        if (token) {
 736                cr_token_destroy (token);
 737                token = NULL;
 738        }
 739
 740        cr_parser_clear_errors (a_this);
 741        return CR_OK;
 742
 743 error:
 744        cr_parser_push_error
 745                (a_this, "could not recognize next production", CR_ERROR);
 746
 747        //cr_parser_dump_err_stack (a_this, TRUE);
 748
 749        if (token) {
 750                cr_token_destroy (token);
 751                token = NULL;
 752        }
 753
 754        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
 755
 756        return status;
 757}
 758
 759/**
 760 *Parses an at-rule as defined by the css core grammar
 761 *in chapter 4.1 in the css2 spec.
 762 *at-rule     : ATKEYWORD S* any* [ block | ';' S* ];
 763 *@param a_this the current instance of #CRParser.
 764 *@return CR_OK upon successfull completion, an error code
 765 *otherwise.
 766 */
 767static enum CRStatus
 768cr_parser_parse_atrule_core (CRParser * a_this)
 769{
 770        CRToken *token = NULL;
 771        CRInputPos init_pos;
 772        enum CRStatus status = CR_ERROR;
 773
 774        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 775
 776        RECORD_INITIAL_POS (a_this, &init_pos);
 777
 778        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
 779                                          &token);
 780        ENSURE_PARSING_COND (status == CR_OK
 781                             && token
 782                             &&
 783                             (token->type == ATKEYWORD_TK
 784                              || token->type == IMPORT_SYM_TK
 785                              || token->type == PAGE_SYM_TK
 786                              || token->type == MEDIA_SYM_TK
 787                              || token->type == FONT_FACE_SYM_TK
 788                              || token->type == CHARSET_SYM_TK));
 789
 790        cr_token_destroy (token);
 791        token = NULL;
 792
 793        cr_parser_try_to_skip_spaces_and_comments (a_this);
 794
 795        do {
 796                status = cr_parser_parse_any_core (a_this);
 797        } while (status == CR_OK);
 798
 799        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
 800                                          &token);
 801        ENSURE_PARSING_COND (status == CR_OK && token);
 802
 803        if (token->type == CBO_TK) {
 804                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 
 805                                      token);
 806                token = NULL;
 807                status = cr_parser_parse_block_core (a_this);
 808                CHECK_PARSING_STATUS (status,
 809                                      FALSE);
 810                goto done;
 811        } else if (token->type == SEMICOLON_TK) {
 812                goto done;
 813        } else {
 814                status = CR_PARSING_ERROR ;
 815                goto error;
 816        }
 817
 818 done:
 819        if (token) {
 820                cr_token_destroy (token);
 821                token = NULL;
 822        }
 823        return CR_OK;
 824
 825 error:
 826        if (token) {
 827                cr_token_destroy (token);
 828                token = NULL;
 829        }
 830        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
 831                              &init_pos);
 832        return status;
 833}
 834
 835/**
 836 *Parses a ruleset as defined by the css core grammar in chapter
 837 *4.1 of the css2 spec.
 838 *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
 839 *@param a_this the current instance of #CRParser.
 840 *@return CR_OK upon successfull completion, an error code otherwise.
 841 */
 842static enum CRStatus
 843cr_parser_parse_ruleset_core (CRParser * a_this)
 844{
 845        CRToken *token = NULL;
 846        CRInputPos init_pos;
 847        enum CRStatus status = CR_ERROR;
 848
 849        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 850        RECORD_INITIAL_POS (a_this, &init_pos);
 851
 852        status = cr_parser_parse_selector_core (a_this);
 853
 854        ENSURE_PARSING_COND (status == CR_OK
 855                             || status == CR_PARSING_ERROR
 856                             || status == CR_END_OF_INPUT_ERROR);
 857
 858        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
 859        ENSURE_PARSING_COND (status == CR_OK && token
 860                             && token->type == CBO_TK);
 861        cr_token_destroy (token);
 862        token = NULL;
 863
 864        cr_parser_try_to_skip_spaces_and_comments (a_this);
 865        status = cr_parser_parse_declaration_core (a_this);
 866
 867      parse_declaration_list:
 868        if (token) {
 869                cr_token_destroy (token);
 870                token = NULL;
 871        }
 872
 873        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
 874        ENSURE_PARSING_COND (status == CR_OK && token);
 875        if (token->type == CBC_TK) {
 876                goto done;
 877        }
 878
 879        ENSURE_PARSING_COND (status == CR_OK
 880                             && token && token->type == SEMICOLON_TK);
 881
 882        cr_token_destroy (token);
 883        token = NULL;
 884        cr_parser_try_to_skip_spaces_and_comments (a_this);
 885        status = cr_parser_parse_declaration_core (a_this);
 886        cr_parser_clear_errors (a_this);
 887        ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR);
 888        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
 889        ENSURE_PARSING_COND (status == CR_OK && token);
 890        if (token->type == CBC_TK) {
 891                cr_token_destroy (token);
 892                token = NULL;
 893                cr_parser_try_to_skip_spaces_and_comments (a_this);
 894                goto done;
 895        } else {
 896                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
 897                                               token);
 898                token = NULL;
 899                goto parse_declaration_list;
 900        }
 901
 902      done:
 903        if (token) {
 904                cr_token_destroy (token);
 905                token = NULL;
 906        }
 907
 908        if (status == CR_OK) {
 909                return CR_OK;
 910        }
 911
 912      error:
 913        if (token) {
 914                cr_token_destroy (token);
 915                token = NULL;
 916        }
 917
 918        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
 919
 920        return status;
 921}
 922
 923/**
 924 *Parses a "selector" as specified by the css core 
 925 *grammar.
 926 *selector    : any+;
 927 *@param a_this the current instance of #CRParser.
 928 *@return CR_OK upon successfull completion, an error code
 929 *otherwise.
 930 */
 931static enum CRStatus
 932cr_parser_parse_selector_core (CRParser * a_this)
 933{
 934        CRToken *token = NULL;
 935        CRInputPos init_pos;
 936        enum CRStatus status = CR_ERROR;
 937
 938        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 939
 940        RECORD_INITIAL_POS (a_this, &init_pos);
 941
 942        status = cr_parser_parse_any_core (a_this);
 943        CHECK_PARSING_STATUS (status, FALSE);
 944
 945        do {
 946                status = cr_parser_parse_any_core (a_this);
 947
 948        } while (status == CR_OK);
 949
 950        return CR_OK;
 951
 952 error:
 953        if (token) {
 954                cr_token_destroy (token);
 955                token = NULL;
 956        }
 957
 958        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
 959
 960        return status;
 961}
 962
 963/**
 964 *Parses a "block" as defined in the css core grammar
 965 *in chapter 4.1 of the css2 spec.
 966 *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
 967 *@param a_this the current instance of #CRParser.
 968 *FIXME: code this function.
 969 */
 970static enum CRStatus
 971cr_parser_parse_block_core (CRParser * a_this)
 972{
 973        CRToken *token = NULL;
 974        CRInputPos init_pos;
 975        enum CRStatus status = CR_ERROR;
 976
 977        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
 978
 979        RECORD_INITIAL_POS (a_this, &init_pos);
 980
 981        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
 982        ENSURE_PARSING_COND (status == CR_OK && token
 983                             && token->type == CBO_TK);
 984
 985      parse_block_content:
 986
 987        if (token) {
 988                cr_token_destroy (token);
 989                token = NULL;
 990        }
 991
 992        cr_parser_try_to_skip_spaces_and_comments (a_this);
 993
 994        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
 995        ENSURE_PARSING_COND (status == CR_OK && token);
 996
 997        if (token->type == CBC_TK) {
 998                cr_parser_try_to_skip_spaces_and_comments (a_this);
 999                goto done;
1000        } else if (token->type == SEMICOLON_TK) {
1001                goto parse_block_content;
1002        } else if (token->type == ATKEYWORD_TK) {
1003                cr_parser_try_to_skip_spaces_and_comments (a_this);
1004                goto parse_block_content;
1005        } else if (token->type == CBO_TK) {
1006                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
1007                token = NULL;
1008                status = cr_parser_parse_block_core (a_this);
1009                CHECK_PARSING_STATUS (status, FALSE);
1010                goto parse_block_content;
1011        } else {
1012                cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
1013                token = NULL;
1014                status = cr_parser_parse_any_core (a_this);
1015                CHECK_PARSING_STATUS (status, FALSE);
1016                goto parse_block_content;
1017        }
1018
1019      done:
1020        if (token) {
1021                cr_token_destroy (token);
1022                token = NULL;
1023        }
1024
1025        if (status == CR_OK)
1026                return CR_OK;
1027
1028      error:
1029        if (token) {
1030                cr_token_destroy (token);
1031                token = NULL;
1032        }
1033
1034        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
1035
1036        return status;
1037}
1038
1039static enum CRStatus
1040cr_parser_parse_declaration_core (CRParser * a_this)
1041{
1042        CRToken *token = NULL;
1043        CRInputPos init_pos;
1044        enum CRStatus status = CR_ERROR;
1045        CRString *prop = NULL;
1046
1047        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1048
1049        RECORD_INITIAL_POS (a_this, &init_pos);
1050
1051        status = cr_parser_parse_property (a_this, &prop);
1052        CHECK_PARSING_STATUS (status, FALSE);
1053        cr_parser_clear_errors (a_this);
1054        ENSURE_PARSING_COND (status == CR_OK && prop);
1055        cr_string_destroy (prop);
1056        prop = NULL;
1057
1058        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1059        ENSURE_PARSING_COND (status == CR_OK
1060                             && token
1061                             && token->type == DELIM_TK
1062                             && token->u.unichar == ':');
1063        cr_token_destroy (token);
1064        token = NULL;
1065        cr_parser_try_to_skip_spaces_and_comments (a_this);
1066        status = cr_parser_parse_value_core (a_this);
1067        CHECK_PARSING_STATUS (status, FALSE);
1068
1069        return CR_OK;
1070
1071      error:
1072
1073        if (prop) {
1074                cr_string_destroy (prop);
1075                prop = NULL;
1076        }
1077
1078        if (token) {
1079                cr_token_destroy (token);
1080                token = NULL;
1081        }
1082
1083        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
1084
1085        return status;
1086}
1087
1088/**
1089 *Parses a "value" production as defined by the css core grammar
1090 *in chapter 4.1.
1091 *value ::= [ any | block | ATKEYWORD S* ]+;
1092 *@param a_this the current instance of #CRParser.
1093 *@return CR_OK upon successfull completion, an error code otherwise.
1094 */
1095static enum CRStatus
1096cr_parser_parse_value_core (CRParser * a_this)
1097{
1098        CRToken *token = NULL;
1099        CRInputPos init_pos;
1100        enum CRStatus status = CR_ERROR;
1101        glong ref = 0;
1102
1103        g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
1104        RECORD_INITIAL_POS (a_this, &init_pos);
1105
1106      continue_parsing:
1107
1108        if (token) {
1109                cr_token_destroy (token);
1110                token = NULL;
1111        }
1112
1113        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1114        ENSURE_PARSING_COND (status == CR_OK && token);
1115
1116        switch (token->type) {
1117        case CBO_TK:
1118                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
1119                                               token);
1120                token = NULL;
1121                status = cr_parser_parse_block_core (a_this);
1122                CHECK_PARSING_STATUS (status, FALSE);
1123                ref++;
1124                goto continue_parsing;
1125
1126        case ATKEYWORD_TK:
1127                cr_parser_try_to_skip_spaces_and_comments (a_this);
1128                ref++;
1129                goto continue_parsing;
1130
1131        default:
1132                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
1133                                               token);
1134                token = NULL;
1135                status = cr_parser_parse_any_core (a_this);
1136                if (status == CR_OK) {
1137                        ref++;
1138                        goto continue_parsing;
1139                } else if (status == CR_PARSING_ERROR) {
1140                        status = CR_OK;
1141                        goto done;
1142                } else {
1143                        goto error;
1144                }
1145        }
1146
1147      done:
1148        if (token) {
1149                cr_token_destroy (token);
1150                token = NULL;
1151        }
1152
1153        if (status == CR_OK && ref)
1154                return CR_OK;
1155      error:
1156        if (token) {
1157                cr_token_destroy (token);
1158                token = NULL;
1159        }
1160
1161        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
1162
1163        return status;
1164}
1165
1166/**
1167 *Parses an "any" as defined by the css core grammar in the
1168 *css2 spec in chapter 4.1.
1169 *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
1170 *        | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
1171 *        | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
1172 *
1173 *@param a_this the current instance of #CRParser.
1174 *@return CR_OK upon successfull completion, an error code otherwise.
1175 */
1176static enum CRStatus
1177cr_parser_parse_any_core (CRParser * a_this)
1178{
1179        CRToken *token1 = NULL,
1180                *token2 = NULL;
1181        CRInputPos init_pos;
1182        enum CRStatus status = CR_ERROR;
1183
1184        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
1185
1186        RECORD_INITIAL_POS (a_this, &init_pos);
1187
1188        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1);
1189
1190        ENSURE_PARSING_COND (status == CR_OK && token1);
1191
1192        switch (token1->type) {
1193        case IDENT_TK:
1194        case NUMBER_TK:
1195        case RGB_TK:
1196        case PERCENTAGE_TK:
1197        case DIMEN_TK:
1198        case EMS_TK:
1199        case EXS_TK:
1200        case LENGTH_TK:
1201        case ANGLE_TK:
1202        case FREQ_TK:
1203        case TIME_TK:
1204        case STRING_TK:
1205        case DELIM_TK:
1206        case URI_TK:
1207        case HASH_TK:
1208        case UNICODERANGE_TK:
1209        case INCLUDES_TK:
1210        case DASHMATCH_TK:
1211        case S_TK:
1212        case COMMENT_TK:
1213        case IMPORTANT_SYM_TK:
1214                status = CR_OK;
1215                break;
1216        case FUNCTION_TK:
1217                /*
1218                 *this case isn't specified by the spec but it
1219                 *does happen. So we have to handle it.
1220                 *We must consider function with parameters.
1221                 *We consider parameter as being an "any*" production.
1222                 */
1223                do {
1224                        status = cr_parser_parse_any_core (a_this);
1225                } while (status == CR_OK);
1226
1227                ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
1228                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
1229                                                  &token2);
1230                ENSURE_PARSING_COND (status == CR_OK
1231                                     && token2 && token2->type == PC_TK);
1232                break;
1233        case PO_TK:
1234                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
1235                                                  &token2);
1236                ENSURE_PARSING_COND (status == CR_OK && token2);
1237
1238                if (token2->type == PC_TK) {
1239                        cr_token_destroy (token2);
1240                        token2 = NULL;
1241                        goto done;
1242                } else {
1243                        status = cr_tknzr_unget_token
1244                                (PRIVATE (a_this)->tknzr, token2);
1245                        token2 = NULL;
1246                }
1247
1248                do {
1249                        status = cr_parser_parse_any_core (a_this);
1250                } while (status == CR_OK);
1251
1252                ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
1253
1254                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
1255                                                  &token2);
1256                ENSURE_PARSING_COND (status == CR_OK
1257                                     && token2 && token2->type == PC_TK);
1258                status = CR_OK;
1259                break;
1260
1261        case BO_TK:
1262                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
1263                                                  &token2);
1264                ENSURE_PARSING_COND (status == CR_OK && token2);
1265
1266                if (token2->type == BC_TK) {
1267                        cr_token_destroy (token2);
1268                        token2 = NULL;
1269                        goto done;
1270                } else {
1271                        status = cr_tknzr_unget_token
1272                                (PRIVATE (a_this)->tknzr, token2);
1273                        token2 = NULL;
1274                }
1275
1276                do {
1277                        status = cr_parser_parse_any_core (a_this);
1278                } while (status == CR_OK);
1279
1280                ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
1281
1282                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
1283                                                  &token2);
1284                ENSURE_PARSING_COND (status == CR_OK
1285                                     && token2 && token2->type == BC_TK);
1286                status = CR_OK;
1287                break;
1288        default:
1289                status = CR_PARSING_ERROR;
1290                goto error;
1291        }
1292
1293      done:
1294        if (token1) {
1295                cr_token_destroy (token1);
1296                token1 = NULL;
1297        }
1298
1299        if (token2) {
1300                cr_token_destroy (token2);
1301                token2 = NULL;
1302        }
1303
1304        return CR_OK;
1305
1306      error:
1307
1308        if (token1) {
1309                cr_token_destroy (token1);
1310                token1 = NULL;
1311        }
1312
1313        if (token2) {
1314                cr_token_destroy (token2);
1315                token2 = NULL;
1316        }
1317
1318        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
1319        return status;
1320}
1321
1322/**
1323 *Parses an attribute selector as defined in the css2 spec in
1324 *appendix D.1:
1325 *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
1326 *            [ IDENT | STRING ] S* ]? ']'
1327 *
1328 *@param a_this the "this pointer" of the current instance of
1329 *#CRParser .
1330 *@param a_sel out parameter. The successfully parsed attribute selector.
1331 *@return CR_OK upon successfull completion, an error code otherwise.
1332 */
1333static enum CRStatus
1334cr_parser_parse_attribute_selector (CRParser * a_this, 
1335                                    CRAttrSel ** a_sel)
1336{
1337        enum CRStatus status = CR_OK;
1338        CRInputPos init_pos;
1339        CRToken *token = NULL;
1340        CRAttrSel *result = NULL;
1341        CRParsingLocation location = {0} ;
1342
1343        g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
1344
1345        RECORD_INITIAL_POS (a_this, &init_pos);
1346
1347        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1348        ENSURE_PARSING_COND (status == CR_OK && token
1349                             && token->type == BO_TK);
1350        cr_parsing_location_copy
1351                (&location, &token->location) ;
1352        cr_token_destroy (token);
1353        token = NULL;
1354
1355        cr_parser_try_to_skip_spaces_and_comments (a_this);
1356
1357        result = cr_attr_sel_new ();
1358        if (!result) {
1359                cr_utils_trace_info ("result failed")  ;
1360                status = CR_OUT_OF_MEMORY_ERROR ;
1361                goto error ;
1362        }
1363        cr_parsing_location_copy (&result->location,
1364                                  &location) ;
1365        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1366        ENSURE_PARSING_COND (status == CR_OK
1367                             && token && token->type == IDENT_TK);
1368
1369        result->name = token->u.str;
1370        token->u.str = NULL;
1371        cr_token_destroy (token);
1372        token = NULL;
1373
1374        cr_parser_try_to_skip_spaces_and_comments (a_this);
1375
1376        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1377        ENSURE_PARSING_COND (status == CR_OK && token);
1378
1379        if (token->type == INCLUDES_TK) {
1380                result->match_way = INCLUDES;
1381                goto parse_right_part;
1382        } else if (token->type == DASHMATCH_TK) {
1383                result->match_way = DASHMATCH;
1384                goto parse_right_part;
1385        } else if (token->type == DELIM_TK && token->u.unichar == '=') {
1386                result->match_way = EQUALS;
1387                goto parse_right_part;
1388        } else if (token->type == BC_TK) {
1389                result->match_way = SET;
1390                goto done;
1391        }
1392
1393 parse_right_part:
1394
1395        if (token) {
1396                cr_token_destroy (token);
1397                token = NULL;
1398        }
1399
1400        cr_parser_try_to_skip_spaces_and_comments (a_this);
1401
1402        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1403        ENSURE_PARSING_COND (status == CR_OK && token);
1404        
1405        if (token->type == IDENT_TK) {
1406                result->value = token->u.str;
1407                token->u.str = NULL;
1408        } else if (token->type == STRING_TK) {
1409                result->value = token->u.str;
1410                token->u.str = NULL;
1411        } else {
1412                status = CR_PARSING_ERROR;
1413                goto error;
1414        }
1415
1416        if (token) {
1417                cr_token_destroy (token);
1418                token = NULL;
1419        }
1420
1421        cr_parser_try_to_skip_spaces_and_comments (a_this);
1422
1423        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
1424
1425        ENSURE_PARSING_COND (status == CR_OK && token
1426                             && token->type == BC_TK);
1427 done:
1428        if (token) {
1429                cr_token_destroy (token);
1430                token = NULL;
1431        }
1432
1433        if (*a_sel) {
1434                status = cr_attr_sel_append_attr_sel (*a_sel, result);
1435                CHECK_PARSING_STATUS (status, FALSE);
1436        } else {
1437                *a_sel = result;
1438        }
1439
1440        cr_parser_clear_errors (a_this);
1441        return CR_OK;
1442
1443 error:
1444
1445        if (result) {
1446                cr_attr_sel_destroy (result);
1447                result = NULL;
1448        }
1449
1450        if (token) {
1451                cr_token_destroy (token);
1452                token = NULL;
1453        }
1454
1455        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
1456
1457        return status;
1458}
1459
1460/**
1461 *Parses a "property" as specified by the css2 spec at [4.1.1]:
1462 *property : IDENT S*;
1463 *
1464 *@param a_this the "this pointer" of the current instance of #CRParser.
1465 *@param GString a_property out parameter. The parsed property without the
1466 *trailing spaces. If *a_property is NULL, this function allocates a
1467 *new instance of GString and set it content to the parsed property.
1468 *If not, the property is just appended to a_property's previous content.
1469 *In both cases, it is up to the caller to free a_property.
1470 *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the
1471 *next construction was not a "property", or an error code.
1472 */
1473static enum CRStatus
1474cr_parser_parse_property (CRParser * a_this, 
1475                          CRString ** a_property)
1476{
1477        enum CRStatus status = CR_OK;
1478        CRInputPos init_pos;
1479
1480        g_return_val_if_fail (a_this && PRIVATE (a_this)
1481                              && PRIVATE (a_this)->tknzr
1482                              && a_property, 
1483                              CR_BAD_PARAM_ERROR);
1484
1485        RECORD_INITIAL_POS (a_this, &init_pos);
1486
1487        status = cr_parser_parse_ident (a_this, a_property);
1488        CHECK_PARSING_STATUS (status, TRUE);
1489        
1490        cr_parser_try_to_skip_spaces_and_comments (a_this);
1491
1492        cr_parser_clear_errors (a_this);
1493        return CR_OK;
1494
1495      error:
1496
1497        cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
1498
1499        return status;
1500}
1501
1502/**
1503 *Parses a "term" as defined in the css2 spec, appendix D.1:
1504 *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* | 
1505 *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] |
1506 *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
1507 *
1508 *TODO: handle parsing of 'RGB'
1509 *
1510 *@param a_term out parameter. The successfully parsed term.
1511 *@return CR_OK upon successfull completion, an error code otherwise.
1512 */
1513enum CRStatus
1514cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term)
1515{
1516        enum CRStatus status = CR_PARSING_ERROR;
1517        CRInputPos init_pos;
1518        CRTerm *result = NULL;
1519        CRTerm *param = NULL;
1520        CRToken *token = NULL;
1521        CRString *func_name = NULL;
1522        CRParsingLocation location = {0} ;
1523
1524        g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR);
1525
1526        RECORD_INITIAL_POS (a_this, &init_pos);
1527
1528        result = cr_term_new ();
1529
1530        status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
1531                                          &token);
1532        if (status != CR_OK || !token)
1533                goto error;
1534
1535        cr_parsing_location_copy (&location, &token->location) ;
1536        if (token->type == DELIM_TK && token->u.unichar == '+') {
1537                result->unary_op = PLUS_UOP;
1538                cr_token_destroy (token) ;
1539                token = NULL ;
1540                cr_parser_try_to_skip_spaces_and_comments (a_this);
1541                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
1542                                                  &token);
1543                if (status != CR_OK || !token)
1544                        goto error;
1545        } else if (token->type == DELIM_TK && token->u.unichar == '-') {
1546                result->unary_op = MINUS_UOP;
1547                cr_token_destroy (token) ;
1548                token = NULL ;
1549                cr_parser_try_to_skip_spaces_and_comments (a_this);
1550                status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 
1551                                                  &token);
1552                if (status != CR_OK || !token)
1553                        goto error;
1554        }
1555
1556        if (token->type == EMS_TK
1557            || token->type == EXS_TK
1558            || token->type == LENGTH_TK
1559            || token->type == ANGLE_TK
1560            || token->type == TIME_TK
1561            || token->type == FREQ_TK
1562            || token->type == PERCENTAGE_TK
1563            || token->type == NUMBER_TK) {
1564                status = cr_term_set_number (result, token->u.num);
1565                CHECK_PARSING_STATUS (status, TRUE);
1566                token->u.num = NULL;
1567                status = CR_OK;
1568        } else if (token && token->type == FUNCTION_TK) {
1569                status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
1570                                               token);
1571                token = NULL;
1572                status = cr_parser_parse_function (a_this, &func_name,
1573                                                   &param);
1574
1575                if (status == CR_OK) {
1576                        status = cr_term_set_function (result,
1577                                                       func_name,
1578                                                       param);
1579                        CHECK_PARSING_STATUS (status, TRUE);
1580                }
1581        } else if (token && token->type == STRING_TK) {
1582                status = cr_term_set_string (result, 
1583                                             token->u.str);
1584                CHECK_PARSING_STATU

Large files files are truncated, but you can click here to view the full file