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 *@CRParser: 28 * 29 *The definition of the #CRParser class. 30 */ 31 32#include <config.h> 33#include "string.h" 34#include "cr-parser.h" 35#include "cr-num.h" 36#include "cr-term.h" 37#include "cr-simple-sel.h" 38#include "cr-attr-sel.h" 39 40/* 41 *Random notes: 42 *CSS core syntax vs CSS level 2 syntax 43 *===================================== 44 * 45 *One must keep in mind 46 *that css UA must comply with two syntaxes. 47 * 48 *1/the specific syntax that defines the css language 49 *for a given level of specificatin (e.g css2 syntax 50 *defined in appendix D.1 of the css2 spec) 51 * 52 *2/the core (general) syntax that is there to allow 53 *UAs to parse style sheets written in levels of CSS that 54 *didn't exist at the time the UAs were created. 55 * 56 *the name of parsing functions (or methods) contained in this file 57 *follows the following scheme: cr_parser_parse_<production_name> (...) ; 58 *where <production_name> is the name 59 *of a production of the css2 language. 60 *When a given production is 61 *defined by the css2 level grammar *and* by the 62 *css core syntax, there will be two functions to parse that production: 63 *one will parse the production defined by the css2 level grammar and the 64 *other will parse the production defined by the css core grammar. 65 *The css2 level grammar related parsing function will be called: 66 *cr_parser_parse_<production_name> (...) ; 67 *Then css core grammar related parsing function will be called: 68 *cr_parser_parse_<production_name>_core (...) ; 69 * 70 *If a production is defined only by the css core grammar, then 71 *it will be named: 72 *cr_parser_parse_<production_name>_core (...) ; 73 */ 74 75typedef struct _CRParserError CRParserError; 76 77/** 78 *An abstraction of an error reported by by the 79 *parsing routines. 80 */ 81struct _CRParserError { 82 guchar *msg; 83 enum CRStatus status; 84 glong line; 85 glong column; 86 glong byte_num; 87}; 88 89enum CRParserState { 90 READY_STATE = 0, 91 TRY_PARSE_CHARSET_STATE, 92 CHARSET_PARSED_STATE, 93 TRY_PARSE_IMPORT_STATE, 94 IMPORT_PARSED_STATE, 95 TRY_PARSE_RULESET_STATE, 96 RULESET_PARSED_STATE, 97 TRY_PARSE_MEDIA_STATE, 98 MEDIA_PARSED_STATE, 99 TRY_PARSE_PAGE_STATE, 100 PAGE_PARSED_STATE, 101 TRY_PARSE_FONT_FACE_STATE, 102 FONT_FACE_PARSED_STATE 103} ; 104 105/** 106 *The private attributes of 107 *#CRParser. 108 */ 109struct _CRParserPriv { 110 /** 111 *The tokenizer 112 */ 113 CRTknzr *tknzr; 114 115 /** 116 *The sac handlers to call 117 *to notify the parsing of 118 *the css2 constructions. 119 */ 120 CRDocHandler *sac_handler; 121 122 /** 123 *A stack of errors reported 124 *by the parsing routines. 125 *Contains instance of #CRParserError. 126 *This pointer is the top of the stack. 127 */ 128 GList *err_stack; 129 130 enum CRParserState state; 131 gboolean resolve_import; 132 gboolean is_case_sensitive; 133 gboolean use_core_grammar; 134}; 135 136#define PRIVATE(obj) ((obj)->priv) 137 138#define CHARS_TAB_SIZE 12 139 140/** 141 * IS_NUM: 142 *@a_char: the char to test. 143 *return TRUE if the character is a number ([0-9]), FALSE otherwise 144 */ 145#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) 146 147/** 148 *Checks if 'status' equals CR_OK. If not, goto the 'error' label. 149 * 150 *@param status the status (of type enum CRStatus) to test. 151 *@param is_exception if set to FALSE, the final status returned 152 *by the current function will be CR_PARSING_ERROR. If set to TRUE, the 153 *current status will be the current value of the 'status' variable. 154 * 155 */ 156#define CHECK_PARSING_STATUS(status, is_exception) \ 157if ((status) != CR_OK) \ 158{ \ 159 if (is_exception == FALSE) \ 160 { \ 161 status = CR_PARSING_ERROR ; \ 162 } \ 163 goto error ; \ 164} 165 166/** 167 * CHECK_PARSING_STATUS_ERR: 168 *@a_this: the current instance of #CRParser . 169 *@a_status: the status to check. Is of type enum #CRStatus. 170 *@a_is_exception: in case of error, if is TRUE, the status 171 *is set to CR_PARSING_ERROR before goto error. If is false, the 172 *real low level status is kept and will be returned by the 173 *upper level function that called this macro. Usally,this must 174 *be set to FALSE. 175 * 176 *same as CHECK_PARSING_STATUS() but this one pushes an error 177 *on the parser error stack when an error arises. 178 * 179 */ 180#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\ 181 a_err_msg, a_err_status) \ 182if ((a_status) != CR_OK) \ 183{ \ 184 if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \ 185 cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ 186 goto error ; \ 187} 188 189/** 190 *Peeks the next char from the input stream of the current parser 191 *by invoking cr_tknzr_input_peek_char(). 192 *invokes CHECK_PARSING_STATUS on the status returned by 193 *cr_tknzr_peek_char(). 194 * 195 *@param a_this the current instance of #CRParser. 196 *@param a_to_char a pointer to the char where to store the 197 *char peeked. 198 */ 199#define PEEK_NEXT_CHAR(a_this, a_to_char) \ 200{\ 201enum CRStatus status ; \ 202status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ 203CHECK_PARSING_STATUS (status, TRUE) \ 204} 205 206/** 207 *Reads the next char from the input stream of the current parser. 208 *In case of error, jumps to the "error:" label located in the 209 *function where this macro is called. 210 *@param a_this the curent instance of #CRParser 211 *@param to_char a pointer to the guint32 char where to store 212 *the character read. 213 */ 214#define READ_NEXT_CHAR(a_this, a_to_char) \ 215status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ 216CHECK_PARSING_STATUS (status, TRUE) 217 218/** 219 *Gets information about the current position in 220 *the input of the parser. 221 *In case of failure, this macro returns from the 222 *calling function and 223 *returns a status code of type enum #CRStatus. 224 *@param a_this the current instance of #CRParser. 225 *@param a_pos out parameter. A pointer to the position 226 *inside the current parser input. Must 227 */ 228#define RECORD_INITIAL_POS(a_this, a_pos) \ 229status = cr_tknzr_get_cur_pos (PRIVATE \ 230(a_this)->tknzr, a_pos) ; \ 231g_return_val_if_fail (status == CR_OK, status) 232 233/** 234 *Gets the address of the current byte inside the 235 *parser input. 236 *@param parser the current instance of #CRParser. 237 *@param addr out parameter a pointer (guchar*) 238 *to where the address must be put. 239 */ 240#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \ 241status = cr_tknzr_get_cur_byte_addr \ 242 (PRIVATE (a_this)->tknzr, a_addr) ; \ 243CHECK_PARSING_STATUS (status, TRUE) 244 245/** 246 *Peeks a byte from the topmost parser input at 247 *a given offset from the current position. 248 *If it fails, goto the "error:" label. 249 * 250 *@param a_parser the current instance of #CRParser. 251 *@param a_offset the offset of the byte to peek, the 252 *current byte having the offset '0'. 253 *@param a_byte_ptr out parameter a pointer (guchar*) to 254 *where the peeked char is to be stored. 255 */ 256#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \ 257status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \ 258 a_offset, \ 259 a_byte_ptr) ; \ 260CHECK_PARSING_STATUS (status, TRUE) ; 261 262#define BYTE(a_parser, a_offset, a_eof) \ 263cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof) 264 265/** 266 *Reads a byte from the topmost parser input 267 *steam. 268 *If it fails, goto the "error" label. 269 *@param a_this the current instance of #CRParser. 270 *@param a_byte_ptr the guchar * where to put the read char. 271 */ 272#define READ_NEXT_BYTE(a_this, a_byte_ptr) \ 273status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \ 274CHECK_PARSING_STATUS (status, TRUE) ; 275 276/** 277 *Skips a given number of byte in the topmost 278 *parser input. Don't update line and column number. 279 *In case of error, jumps to the "error:" label 280 *of the surrounding function. 281 *@param a_parser the current instance of #CRParser. 282 *@param a_nb_bytes the number of bytes to skip. 283 */ 284#define SKIP_BYTES(a_this, a_nb_bytes) \ 285status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \ 286 CR_SEEK_CUR, a_nb_bytes) ; \ 287CHECK_PARSING_STATUS (status, TRUE) ; 288 289/** 290 *Skip utf8 encoded characters. 291 *Updates line and column numbers. 292 *@param a_parser the current instance of #CRParser. 293 *@param a_nb_chars the number of chars to skip. Must be of 294 *type glong. 295 */ 296#define SKIP_CHARS(a_parser, a_nb_chars) \ 297{ \ 298glong nb_chars = a_nb_chars ; \ 299status = cr_tknzr_consume_chars \ 300 (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \ 301CHECK_PARSING_STATUS (status, TRUE) ; \ 302} 303 304/** 305 *Tests the condition and if it is false, sets 306 *status to "CR_PARSING_ERROR" and goto the 'error' 307 *label. 308 *@param condition the condition to test. 309 */ 310#define ENSURE_PARSING_COND(condition) \ 311if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} 312 313#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \ 314 a_err_msg, a_err_status) \ 315if (! (a_condition)) \ 316{ \ 317 status = CR_PARSING_ERROR; \ 318 cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ 319 goto error ; \ 320} 321 322#define GET_NEXT_TOKEN(a_this, a_token_ptr) \ 323status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \ 324 a_token_ptr) ; \ 325ENSURE_PARSING_COND (status == CR_OK) ; 326 327#ifdef WITH_UNICODE_ESCAPE_AND_RANGE 328static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this, 329 guint32 * a_unicode); 330static enum CRStatus cr_parser_parse_escape (CRParser * a_this, 331 guint32 * a_esc_code); 332 333static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this, 334 CRString ** a_inf, 335 CRString ** a_sup); 336#endif 337 338static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this); 339 340static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this); 341 342static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this); 343 344static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); 345 346static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); 347 348static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); 349 350static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); 351 352static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); 353 354static enum CRStatus cr_parser_parse_string (CRParser * a_this, 355 CRString ** a_str); 356 357static enum CRStatus cr_parser_parse_ident (CRParser * a_this, 358 CRString ** a_str); 359 360static enum CRStatus cr_parser_parse_uri (CRParser * a_this, 361 CRString ** a_str); 362 363static enum CRStatus cr_parser_parse_function (CRParser * a_this, 364 CRString ** a_func_name, 365 CRTerm ** a_expr); 366static enum CRStatus cr_parser_parse_property (CRParser * a_this, 367 CRString ** a_property); 368 369static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this, 370 CRAttrSel ** a_sel); 371 372static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this, 373 CRSimpleSel ** a_sel); 374 375static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this, 376 CRSimpleSel ** a_sel); 377 378static CRParserError *cr_parser_error_new (const guchar * a_msg, 379 enum CRStatus); 380 381static void cr_parser_error_set_msg (CRParserError * a_this, 382 const guchar * a_msg); 383 384static void cr_parser_error_dump (CRParserError * a_this); 385 386static void cr_parser_error_set_status (CRParserError * a_this, 387 enum CRStatus a_status); 388 389static void cr_parser_error_set_pos (CRParserError * a_this, 390 glong a_line, 391 glong a_column, glong a_byte_num); 392static void 393 cr_parser_error_destroy (CRParserError * a_this); 394 395static enum CRStatus cr_parser_push_error (CRParser * a_this, 396 const guchar * a_msg, 397 enum CRStatus a_status); 398 399static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this, 400 gboolean a_clear_errs); 401static enum CRStatus 402 cr_parser_clear_errors (CRParser * a_this); 403 404/***************************** 405 *error managemet methods 406 *****************************/ 407 408/** 409 *Constructor of #CRParserError class. 410 *@param a_msg the brute error message. 411 *@param a_status the error status. 412 *@return the newly built instance of #CRParserError. 413 */ 414static CRParserError * 415cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status) 416{ 417 CRParserError *result = NULL; 418 419 result = g_try_malloc (sizeof (CRParserError)); 420 421 if (result == NULL) { 422 cr_utils_trace_info ("Out of memory"); 423 return NULL; 424 } 425 426 memset (result, 0, sizeof (CRParserError)); 427 428 cr_parser_error_set_msg (result, a_msg); 429 cr_parser_error_set_status (result, a_status); 430 431 return result; 432} 433 434/** 435 *Sets the message associated to this instance of #CRError. 436 *@param a_this the current instance of #CRParserError. 437 *@param a_msg the new message. 438 */ 439static void 440cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg) 441{ 442 g_return_if_fail (a_this); 443 444 if (a_this->msg) { 445 g_free (a_this->msg); 446 } 447 448 a_this->msg = g_strdup (a_msg); 449} 450 451/** 452 *Sets the error status. 453 *@param a_this the current instance of #CRParserError. 454 *@param a_status the new error status. 455 * 456 */ 457static void 458cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status) 459{ 460 g_return_if_fail (a_this); 461 462 a_this->status = a_status; 463} 464 465/** 466 *Sets the position of the parser error. 467 *@param a_this the current instance of #CRParserError. 468 *@param a_line the line number. 469 *@param a_column the column number. 470 *@param a_byte_num the byte number. 471 */ 472static void 473cr_parser_error_set_pos (CRParserError * a_this, 474 glong a_line, glong a_column, glong a_byte_num) 475{ 476 g_return_if_fail (a_this); 477 478 a_this->line = a_line; 479 a_this->column = a_column; 480 a_this->byte_num = a_byte_num; 481} 482 483static void 484cr_parser_error_dump (CRParserError * a_this) 485{ 486 g_return_if_fail (a_this); 487 488 g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column); 489 490 g_printerr ("%s\n", a_this->msg); 491} 492 493/** 494 *The destructor of #CRParserError. 495 *@param a_this the current instance of #CRParserError. 496 */ 497static void 498cr_parser_error_destroy (CRParserError * a_this) 499{ 500 g_return_if_fail (a_this); 501 502 if (a_this->msg) { 503 g_free (a_this->msg); 504 a_this->msg = NULL; 505 } 506 507 g_free (a_this); 508} 509 510/** 511 *Pushes an error on the parser error stack. 512 *@param a_this the current instance of #CRParser. 513 *@param a_msg the error message. 514 *@param a_status the error status. 515 *@return CR_OK upon successfull completion, an error code otherwise. 516 */ 517static enum CRStatus 518cr_parser_push_error (CRParser * a_this, 519 const guchar * a_msg, enum CRStatus a_status) 520{ 521 enum CRStatus status = CR_OK; 522 523 CRParserError *error = NULL; 524 CRInputPos pos; 525 526 g_return_val_if_fail (a_this && PRIVATE (a_this) 527 && a_msg, CR_BAD_PARAM_ERROR); 528 529 error = cr_parser_error_new (a_msg, a_status); 530 531 g_return_val_if_fail (error, CR_ERROR); 532 533 RECORD_INITIAL_POS (a_this, &pos); 534 535 cr_parser_error_set_pos 536 (error, pos.line, pos.col, pos.next_byte_index - 1); 537 538 PRIVATE (a_this)->err_stack = 539 g_list_prepend (PRIVATE (a_this)->err_stack, error); 540 541 if (PRIVATE (a_this)->err_stack == NULL) 542 goto error; 543 544 return CR_OK; 545 546 error: 547 548 if (error) { 549 cr_parser_error_destroy (error); 550 error = NULL; 551 } 552 553 return status; 554} 555 556/** 557 *Dumps the error stack on stdout. 558 *@param a_this the current instance of #CRParser. 559 *@param a_clear_errs whether to clear the error stack 560 *after the dump or not. 561 *@return CR_OK upon successfull completion, an error code 562 *otherwise. 563 */ 564static enum CRStatus 565cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs) 566{ 567 GList *cur = NULL; 568 569 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 570 571 if (PRIVATE (a_this)->err_stack == NULL) 572 return CR_OK; 573 574 for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { 575 cr_parser_error_dump ((CRParserError *) cur->data); 576 } 577 578 if (a_clear_errs == TRUE) { 579 cr_parser_clear_errors (a_this); 580 } 581 582 return CR_OK; 583} 584 585/** 586 *Clears all the errors contained in the parser error stack. 587 *Frees all the errors, and the stack that contains'em. 588 *@param a_this the current instance of #CRParser. 589 */ 590static enum CRStatus 591cr_parser_clear_errors (CRParser * a_this) 592{ 593 GList *cur = NULL; 594 595 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 596 597 for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { 598 if (cur->data) { 599 cr_parser_error_destroy ((CRParserError *) 600 cur->data); 601 } 602 } 603 604 if (PRIVATE (a_this)->err_stack) { 605 g_list_free (PRIVATE (a_this)->err_stack); 606 PRIVATE (a_this)->err_stack = NULL; 607 } 608 609 return CR_OK; 610} 611 612/** 613 * cr_parser_try_to_skip_spaces_and_comments: 614 *@a_this: the current instance of #CRParser. 615 * 616 *Same as cr_parser_try_to_skip_spaces() but this one skips 617 *spaces and comments. 618 * 619 *Returns CR_OK upon successfull completion, an error code otherwise. 620 */ 621enum CRStatus 622cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this) 623{ 624 enum CRStatus status = CR_ERROR; 625 CRToken *token = NULL; 626 627 g_return_val_if_fail (a_this && PRIVATE (a_this) 628 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 629 do { 630 if (token) { 631 cr_token_destroy (token); 632 token = NULL; 633 } 634 635 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 636 &token); 637 if (status != CR_OK) 638 goto error; 639 } 640 while ((token != NULL) 641 && (token->type == COMMENT_TK || token->type == S_TK)); 642 643 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 644 645 return status; 646 647 error: 648 649 if (token) { 650 cr_token_destroy (token); 651 token = NULL; 652 } 653 654 return status; 655} 656 657/*************************************** 658 *End of Parser input handling routines 659 ***************************************/ 660 661 662/************************************* 663 *Non trivial terminal productions 664 *parsing routines 665 *************************************/ 666 667/** 668 *Parses a css stylesheet following the core css grammar. 669 *This is mainly done for test purposes. 670 *During the parsing, no callback is called. This is just 671 *to validate that the stylesheet is well formed according to the 672 *css core syntax. 673 *stylesheet : [ CDO | CDC | S | statement ]*; 674 *@param a_this the current instance of #CRParser. 675 *@return CR_OK upon successful completion, an error code otherwise. 676 */ 677static enum CRStatus 678cr_parser_parse_stylesheet_core (CRParser * a_this) 679{ 680 CRToken *token = NULL; 681 CRInputPos init_pos; 682 enum CRStatus status = CR_ERROR; 683 684 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 685 686 RECORD_INITIAL_POS (a_this, &init_pos); 687 688 continue_parsing: 689 690 if (token) { 691 cr_token_destroy (token); 692 token = NULL; 693 } 694 695 cr_parser_try_to_skip_spaces_and_comments (a_this); 696 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 697 if (status == CR_END_OF_INPUT_ERROR) { 698 status = CR_OK; 699 goto done; 700 } else if (status != CR_OK) { 701 goto error; 702 } 703 704 switch (token->type) { 705 706 case CDO_TK: 707 case CDC_TK: 708 goto continue_parsing; 709 break; 710 default: 711 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 712 token); 713 CHECK_PARSING_STATUS (status, TRUE); 714 token = NULL; 715 status = cr_parser_parse_statement_core (a_this); 716 cr_parser_clear_errors (a_this); 717 if (status == CR_OK) { 718 goto continue_parsing; 719 } else if (status == CR_END_OF_INPUT_ERROR) { 720 goto done; 721 } else { 722 goto error; 723 } 724 } 725 726 done: 727 if (token) { 728 cr_token_destroy (token); 729 token = NULL; 730 } 731 732 cr_parser_clear_errors (a_this); 733 return CR_OK; 734 735 error: 736 cr_parser_push_error 737 (a_this, "could not recognize next production", CR_ERROR); 738 739 cr_parser_dump_err_stack (a_this, TRUE); 740 741 if (token) { 742 cr_token_destroy (token); 743 token = NULL; 744 } 745 746 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 747 748 return status; 749} 750 751/** 752 *Parses an at-rule as defined by the css core grammar 753 *in chapter 4.1 in the css2 spec. 754 *at-rule : ATKEYWORD S* any* [ block | ';' S* ]; 755 *@param a_this the current instance of #CRParser. 756 *@return CR_OK upon successfull completion, an error code 757 *otherwise. 758 */ 759static enum CRStatus 760cr_parser_parse_atrule_core (CRParser * a_this) 761{ 762 CRToken *token = NULL; 763 CRInputPos init_pos; 764 enum CRStatus status = CR_ERROR; 765 766 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 767 768 RECORD_INITIAL_POS (a_this, &init_pos); 769 770 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 771 &token); 772 ENSURE_PARSING_COND (status == CR_OK 773 && token 774 && 775 (token->type == ATKEYWORD_TK 776 || token->type == IMPORT_SYM_TK 777 || token->type == PAGE_SYM_TK 778 || token->type == MEDIA_SYM_TK 779 || token->type == FONT_FACE_SYM_TK 780 || token->type == CHARSET_SYM_TK)); 781 782 cr_token_destroy (token); 783 token = NULL; 784 785 cr_parser_try_to_skip_spaces_and_comments (a_this); 786 787 do { 788 status = cr_parser_parse_any_core (a_this); 789 } while (status == CR_OK); 790 791 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 792 &token); 793 ENSURE_PARSING_COND (status == CR_OK && token); 794 795 if (token->type == CBO_TK) { 796 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 797 token); 798 token = NULL; 799 status = cr_parser_parse_block_core (a_this); 800 CHECK_PARSING_STATUS (status, 801 FALSE); 802 goto done; 803 } else if (token->type == SEMICOLON_TK) { 804 goto done; 805 } else { 806 status = CR_PARSING_ERROR ; 807 goto error; 808 } 809 810 done: 811 if (token) { 812 cr_token_destroy (token); 813 token = NULL; 814 } 815 return CR_OK; 816 817 error: 818 if (token) { 819 cr_token_destroy (token); 820 token = NULL; 821 } 822 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, 823 &init_pos); 824 return status; 825} 826 827/** 828 *Parses a ruleset as defined by the css core grammar in chapter 829 *4.1 of the css2 spec. 830 *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*; 831 *@param a_this the current instance of #CRParser. 832 *@return CR_OK upon successfull completion, an error code otherwise. 833 */ 834static enum CRStatus 835cr_parser_parse_ruleset_core (CRParser * a_this) 836{ 837 CRToken *token = NULL; 838 CRInputPos init_pos; 839 enum CRStatus status = CR_ERROR; 840 841 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 842 RECORD_INITIAL_POS (a_this, &init_pos); 843 844 status = cr_parser_parse_selector_core (a_this); 845 846 ENSURE_PARSING_COND (status == CR_OK 847 || status == CR_PARSING_ERROR 848 || status == CR_END_OF_INPUT_ERROR); 849 850 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 851 ENSURE_PARSING_COND (status == CR_OK && token 852 && token->type == CBO_TK); 853 cr_token_destroy (token); 854 token = NULL; 855 856 cr_parser_try_to_skip_spaces_and_comments (a_this); 857 status = cr_parser_parse_declaration_core (a_this); 858 859 parse_declaration_list: 860 if (token) { 861 cr_token_destroy (token); 862 token = NULL; 863 } 864 865 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 866 ENSURE_PARSING_COND (status == CR_OK && token); 867 if (token->type == CBC_TK) { 868 goto done; 869 } 870 871 ENSURE_PARSING_COND (status == CR_OK 872 && token && token->type == SEMICOLON_TK); 873 874 cr_token_destroy (token); 875 token = NULL; 876 cr_parser_try_to_skip_spaces_and_comments (a_this); 877 status = cr_parser_parse_declaration_core (a_this); 878 cr_parser_clear_errors (a_this); 879 ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR); 880 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 881 ENSURE_PARSING_COND (status == CR_OK && token); 882 if (token->type == CBC_TK) { 883 cr_token_destroy (token); 884 token = NULL; 885 cr_parser_try_to_skip_spaces_and_comments (a_this); 886 goto done; 887 } else { 888 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 889 token); 890 token = NULL; 891 goto parse_declaration_list; 892 } 893 894 done: 895 if (token) { 896 cr_token_destroy (token); 897 token = NULL; 898 } 899 900 if (status == CR_OK) { 901 return CR_OK; 902 } 903 904 error: 905 if (token) { 906 cr_token_destroy (token); 907 token = NULL; 908 } 909 910 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 911 912 return status; 913} 914 915/** 916 *Parses a "selector" as specified by the css core 917 *grammar. 918 *selector : any+; 919 *@param a_this the current instance of #CRParser. 920 *@return CR_OK upon successfull completion, an error code 921 *otherwise. 922 */ 923static enum CRStatus 924cr_parser_parse_selector_core (CRParser * a_this) 925{ 926 CRToken *token = NULL; 927 CRInputPos init_pos; 928 enum CRStatus status = CR_ERROR; 929 930 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 931 932 RECORD_INITIAL_POS (a_this, &init_pos); 933 934 status = cr_parser_parse_any_core (a_this); 935 CHECK_PARSING_STATUS (status, FALSE); 936 937 do { 938 status = cr_parser_parse_any_core (a_this); 939 940 } while (status == CR_OK); 941 942 return CR_OK; 943 944 error: 945 if (token) { 946 cr_token_destroy (token); 947 token = NULL; 948 } 949 950 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 951 952 return status; 953} 954 955/** 956 *Parses a "block" as defined in the css core grammar 957 *in chapter 4.1 of the css2 spec. 958 *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; 959 *@param a_this the current instance of #CRParser. 960 *FIXME: code this function. 961 */ 962static enum CRStatus 963cr_parser_parse_block_core (CRParser * a_this) 964{ 965 CRToken *token = NULL; 966 CRInputPos init_pos; 967 enum CRStatus status = CR_ERROR; 968 969 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 970 971 RECORD_INITIAL_POS (a_this, &init_pos); 972 973 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 974 ENSURE_PARSING_COND (status == CR_OK && token 975 && token->type == CBO_TK); 976 977 parse_block_content: 978 979 if (token) { 980 cr_token_destroy (token); 981 token = NULL; 982 } 983 984 cr_parser_try_to_skip_spaces_and_comments (a_this); 985 986 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 987 ENSURE_PARSING_COND (status == CR_OK && token); 988 989 if (token->type == CBC_TK) { 990 cr_parser_try_to_skip_spaces_and_comments (a_this); 991 goto done; 992 } else if (token->type == SEMICOLON_TK) { 993 goto parse_block_content; 994 } else if (token->type == ATKEYWORD_TK) { 995 cr_parser_try_to_skip_spaces_and_comments (a_this); 996 goto parse_block_content; 997 } else if (token->type == CBO_TK) { 998 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 999 token = NULL; 1000 status = cr_parser_parse_block_core (a_this); 1001 CHECK_PARSING_STATUS (status, FALSE); 1002 goto parse_block_content; 1003 } else { 1004 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 1005 token = NULL; 1006 status = cr_parser_parse_any_core (a_this); 1007 CHECK_PARSING_STATUS (status, FALSE); 1008 goto parse_block_content; 1009 } 1010 1011 done: 1012 if (token) { 1013 cr_token_destroy (token); 1014 token = NULL; 1015 } 1016 1017 if (status == CR_OK) 1018 return CR_OK; 1019 1020 error: 1021 if (token) { 1022 cr_token_destroy (token); 1023 token = NULL; 1024 } 1025 1026 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1027 1028 return status; 1029} 1030 1031static enum CRStatus 1032cr_parser_parse_declaration_core (CRParser * a_this) 1033{ 1034 CRToken *token = NULL; 1035 CRInputPos init_pos; 1036 enum CRStatus status = CR_ERROR; 1037 CRString *prop = NULL; 1038 1039 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 1040 1041 RECORD_INITIAL_POS (a_this, &init_pos); 1042 1043 status = cr_parser_parse_property (a_this, &prop); 1044 CHECK_PARSING_STATUS (status, FALSE); 1045 cr_parser_clear_errors (a_this); 1046 ENSURE_PARSING_COND (status == CR_OK && prop); 1047 cr_string_destroy (prop); 1048 prop = NULL; 1049 1050 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1051 ENSURE_PARSING_COND (status == CR_OK 1052 && token 1053 && token->type == DELIM_TK 1054 && token->u.unichar == ':'); 1055 cr_token_destroy (token); 1056 token = NULL; 1057 cr_parser_try_to_skip_spaces_and_comments (a_this); 1058 status = cr_parser_parse_value_core (a_this); 1059 CHECK_PARSING_STATUS (status, FALSE); 1060 1061 return CR_OK; 1062 1063 error: 1064 1065 if (prop) { 1066 cr_string_destroy (prop); 1067 prop = NULL; 1068 } 1069 1070 if (token) { 1071 cr_token_destroy (token); 1072 token = NULL; 1073 } 1074 1075 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1076 1077 return status; 1078} 1079 1080/** 1081 *Parses a "value" production as defined by the css core grammar 1082 *in chapter 4.1. 1083 *value ::= [ any | block | ATKEYWORD S* ]+; 1084 *@param a_this the current instance of #CRParser. 1085 *@return CR_OK upon successfull completion, an error code otherwise. 1086 */ 1087static enum CRStatus 1088cr_parser_parse_value_core (CRParser * a_this) 1089{ 1090 CRToken *token = NULL; 1091 CRInputPos init_pos; 1092 enum CRStatus status = CR_ERROR; 1093 glong ref = 0; 1094 1095 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 1096 RECORD_INITIAL_POS (a_this, &init_pos); 1097 1098 continue_parsing: 1099 1100 if (token) { 1101 cr_token_destroy (token); 1102 token = NULL; 1103 } 1104 1105 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1106 ENSURE_PARSING_COND (status == CR_OK && token); 1107 1108 switch (token->type) { 1109 case CBO_TK: 1110 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 1111 token); 1112 token = NULL; 1113 status = cr_parser_parse_block_core (a_this); 1114 CHECK_PARSING_STATUS (status, FALSE); 1115 ref++; 1116 goto continue_parsing; 1117 1118 case ATKEYWORD_TK: 1119 cr_parser_try_to_skip_spaces_and_comments (a_this); 1120 ref++; 1121 goto continue_parsing; 1122 1123 default: 1124 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 1125 token); 1126 token = NULL; 1127 status = cr_parser_parse_any_core (a_this); 1128 if (status == CR_OK) { 1129 ref++; 1130 goto continue_parsing; 1131 } else if (status == CR_PARSING_ERROR) { 1132 status = CR_OK; 1133 goto done; 1134 } else { 1135 goto error; 1136 } 1137 } 1138 1139 done: 1140 if (token) { 1141 cr_token_destroy (token); 1142 token = NULL; 1143 } 1144 1145 if (status == CR_OK && ref) 1146 return CR_OK; 1147 error: 1148 if (token) { 1149 cr_token_destroy (token); 1150 token = NULL; 1151 } 1152 1153 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1154 1155 return status; 1156} 1157 1158/** 1159 *Parses an "any" as defined by the css core grammar in the 1160 *css2 spec in chapter 4.1. 1161 *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING 1162 * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES 1163 * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; 1164 * 1165 *@param a_this the current instance of #CRParser. 1166 *@return CR_OK upon successfull completion, an error code otherwise. 1167 */ 1168static enum CRStatus 1169cr_parser_parse_any_core (CRParser * a_this) 1170{ 1171 CRToken *token1 = NULL, 1172 *token2 = NULL; 1173 CRInputPos init_pos; 1174 enum CRStatus status = CR_ERROR; 1175 1176 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 1177 1178 RECORD_INITIAL_POS (a_this, &init_pos); 1179 1180 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); 1181 1182 ENSURE_PARSING_COND (status == CR_OK && token1); 1183 1184 switch (token1->type) { 1185 case IDENT_TK: 1186 case NUMBER_TK: 1187 case RGB_TK: 1188 case PERCENTAGE_TK: 1189 case DIMEN_TK: 1190 case EMS_TK: 1191 case EXS_TK: 1192 case LENGTH_TK: 1193 case ANGLE_TK: 1194 case FREQ_TK: 1195 case TIME_TK: 1196 case STRING_TK: 1197 case DELIM_TK: 1198 case URI_TK: 1199 case HASH_TK: 1200 case UNICODERANGE_TK: 1201 case INCLUDES_TK: 1202 case DASHMATCH_TK: 1203 case S_TK: 1204 case COMMENT_TK: 1205 case IMPORTANT_SYM_TK: 1206 status = CR_OK; 1207 break; 1208 case FUNCTION_TK: 1209 /* 1210 *this case isn't specified by the spec but it 1211 *does happen. So we have to handle it. 1212 *We must consider function with parameters. 1213 *We consider parameter as being an "any*" production. 1214 */ 1215 do { 1216 status = cr_parser_parse_any_core (a_this); 1217 } while (status == CR_OK); 1218 1219 ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 1220 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1221 &token2); 1222 ENSURE_PARSING_COND (status == CR_OK 1223 && token2 && token2->type == PC_TK); 1224 break; 1225 case PO_TK: 1226 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1227 &token2); 1228 ENSURE_PARSING_COND (status == CR_OK && token2); 1229 1230 if (token2->type == PC_TK) { 1231 cr_token_destroy (token2); 1232 token2 = NULL; 1233 goto done; 1234 } else { 1235 status = cr_tknzr_unget_token 1236 (PRIVATE (a_this)->tknzr, token2); 1237 token2 = NULL; 1238 } 1239 1240 do { 1241 status = cr_parser_parse_any_core (a_this); 1242 } while (status == CR_OK); 1243 1244 ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 1245 1246 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1247 &token2); 1248 ENSURE_PARSING_COND (status == CR_OK 1249 && token2 && token2->type == PC_TK); 1250 status = CR_OK; 1251 break; 1252 1253 case BO_TK: 1254 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1255 &token2); 1256 ENSURE_PARSING_COND (status == CR_OK && token2); 1257 1258 if (token2->type == BC_TK) { 1259 cr_token_destroy (token2); 1260 token2 = NULL; 1261 goto done; 1262 } else { 1263 status = cr_tknzr_unget_token 1264 (PRIVATE (a_this)->tknzr, token2); 1265 token2 = NULL; 1266 } 1267 1268 do { 1269 status = cr_parser_parse_any_core (a_this); 1270 } while (status == CR_OK); 1271 1272 ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 1273 1274 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1275 &token2); 1276 ENSURE_PARSING_COND (status == CR_OK 1277 && token2 && token2->type == BC_TK); 1278 status = CR_OK; 1279 break; 1280 default: 1281 status = CR_PARSING_ERROR; 1282 goto error; 1283 } 1284 1285 done: 1286 if (token1) { 1287 cr_token_destroy (token1); 1288 token1 = NULL; 1289 } 1290 1291 if (token2) { 1292 cr_token_destroy (token2); 1293 token2 = NULL; 1294 } 1295 1296 return CR_OK; 1297 1298 error: 1299 1300 if (token1) { 1301 cr_token_destroy (token1); 1302 token1 = NULL; 1303 } 1304 1305 if (token2) { 1306 cr_token_destroy (token2); 1307 token2 = NULL; 1308 } 1309 1310 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1311 return status; 1312} 1313 1314/** 1315 *Parses an attribute selector as defined in the css2 spec in 1316 *appendix D.1: 1317 *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* 1318 * [ IDENT | STRING ] S* ]? ']' 1319 * 1320 *@param a_this the "this pointer" of the current instance of 1321 *#CRParser . 1322 *@param a_sel out parameter. The successfully parsed attribute selector. 1323 *@return CR_OK upon successfull completion, an error code otherwise. 1324 */ 1325static enum CRStatus 1326cr_parser_parse_attribute_selector (CRParser * a_this, 1327 CRAttrSel ** a_sel) 1328{ 1329 enum CRStatus status = CR_OK; 1330 CRInputPos init_pos; 1331 CRToken *token = NULL; 1332 CRAttrSel *result = NULL; 1333 CRParsingLocation location = {0} ; 1334 1335 g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); 1336 1337 RECORD_INITIAL_POS (a_this, &init_pos); 1338 1339 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1340 ENSURE_PARSING_COND (status == CR_OK && token 1341 && token->type == BO_TK); 1342 cr_parsing_location_copy 1343 (&location, &token->location) ; 1344 cr_token_destroy (token); 1345 token = NULL; 1346 1347 cr_parser_try_to_skip_spaces_and_comments (a_this); 1348 1349 result = cr_attr_sel_new (); 1350 if (!result) { 1351 cr_utils_trace_info ("result failed") ; 1352 status = CR_OUT_OF_MEMORY_ERROR ; 1353 goto error ; 1354 } 1355 cr_parsing_location_copy (&result->location, 1356 &location) ; 1357 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1358 ENSURE_PARSING_COND (status == CR_OK 1359 && token && token->type == IDENT_TK); 1360 1361 result->name = token->u.str; 1362 token->u.str = NULL; 1363 cr_token_destroy (token); 1364 token = NULL; 1365 1366 cr_parser_try_to_skip_spaces_and_comments (a_this); 1367 1368 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1369 ENSURE_PARSING_COND (status == CR_OK && token); 1370 1371 if (token->type == INCLUDES_TK) { 1372 result->match_way = INCLUDES; 1373 goto parse_right_part; 1374 } else if (token->type == DASHMATCH_TK) { 1375 result->match_way = DASHMATCH; 1376 goto parse_right_part; 1377 } else if (token->type == DELIM_TK && token->u.unichar == '=') { 1378 result->match_way = EQUALS; 1379 goto parse_right_part; 1380 } else if (token->type == BC_TK) { 1381 result->match_way = SET; 1382 goto done; 1383 } 1384 1385 parse_right_part: 1386 1387 if (token) { 1388 cr_token_destroy (token); 1389 token = NULL; 1390 } 1391 1392 cr_parser_try_to_skip_spaces_and_comments (a_this); 1393 1394 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1395 ENSURE_PARSING_COND (status == CR_OK && token); 1396 1397 if (token->type == IDENT_TK) { 1398 result->value = token->u.str; 1399 token->u.str = NULL; 1400 } else if (token->type == STRING_TK) { 1401 result->value = token->u.str; 1402 token->u.str = NULL; 1403 } else { 1404 status = CR_PARSING_ERROR; 1405 goto error; 1406 } 1407 1408 if (token) { 1409 cr_token_destroy (token); 1410 token = NULL; 1411 } 1412 1413 cr_parser_try_to_skip_spaces_and_comments (a_this); 1414 1415 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1416 1417 ENSURE_PARSING_COND (status == CR_OK && token 1418 && token->type == BC_TK); 1419 done: 1420 if (token) { 1421 cr_token_destroy (token); 1422 token = NULL; 1423 } 1424 1425 if (*a_sel) { 1426 status = cr_attr_sel_append_attr_sel (*a_sel, result); 1427 CHECK_PARSING_STATUS (status, FALSE); 1428 } else { 1429 *a_sel = result; 1430 } 1431 1432 cr_parser_clear_errors (a_this); 1433 return CR_OK; 1434 1435 error: 1436 1437 if (result) { 1438 cr_attr_sel_destroy (result); 1439 result = NULL; 1440 } 1441 1442 if (token) { 1443 cr_token_destroy (token); 1444 token = NULL; 1445 } 1446 1447 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1448 1449 return status; 1450} 1451 1452/** 1453 *Parses a "property" as specified by the css2 spec at [4.1.1]: 1454 *property : IDENT S*; 1455 * 1456 *@param a_this the "this pointer" of the current instance of #CRParser. 1457 *@param GString a_property out parameter. The parsed property without the 1458 *trailing spaces. If *a_property is NULL, this function allocates a 1459 *new instance of GString and set it content to the parsed property. 1460 *If not, the property is just appended to a_property's previous content. 1461 *In both cases, it is up to the caller to free a_property. 1462 *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the 1463 *next construction was not a "property", or an error code. 1464 */ 1465static enum CRStatus 1466cr_parser_parse_property (CRParser * a_this, 1467 CRString ** a_property) 1468{ 1469 enum CRStatus status = CR_OK; 1470 CRInputPos init_pos; 1471 1472 g_return_val_if_fail (a_this && PRIVATE (a_this) 1473 && PRIVATE (a_this)->tknzr 1474 && a_property, 1475 CR_BAD_PARAM_ERROR); 1476 1477 RECORD_INITIAL_POS (a_this, &init_pos); 1478 1479 status = cr_parser_parse_ident (a_this, a_property); 1480 CHECK_PARSING_STATUS (status, TRUE); 1481 1482 cr_parser_try_to_skip_spaces_and_comments (a_this); 1483 1484 cr_parser_clear_errors (a_this); 1485 return CR_OK; 1486 1487 error: 1488 1489 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1490 1491 return status; 1492} 1493 1494/** 1495 * cr_parser_parse_term: 1496 *@a_term: out parameter. The successfully parsed term. 1497 * 1498 *Parses a "term" as defined in the css2 spec, appendix D.1: 1499 *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* | 1500 *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] | 1501 *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor 1502 * 1503 *TODO: handle parsing of 'RGB' 1504 * 1505 *Returns CR_OK upon successfull completion, an error code otherwise. 1506 */ 1507enum CRStatus 1508cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term) 1509{ 1510 enum CRStatus status = CR_PARSING_ERROR; 1511 CRInputPos init_pos; 1512 CRTerm *result = NULL; 1513 CRTerm *param = NULL; 1514 CRToken *token = NULL; 1515 CRString *func_name = NULL; 1516 CRParsingLocation location = {0} ; 1517 1518 g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR); 1519 1520 RECORD_INITIAL_POS (a_this, &init_pos); 1521 1522 result = cr_term_new (); 1523 1524 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1525 &token); 1526 if (status != CR_OK || !token) 1527 goto error; 1528 1529 cr_parsing_location_copy (&location, &token->location) ; 1530 if (token->type == DELIM_TK && token->u.unichar == '+') { 1531 result->unary_op = PLUS_UOP; 1532 cr_token_destroy (token) ; 1533 token = NULL ; 1534 cr_parser_try_to_skip_spaces_and_comments (a_this); 1535 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1536 &token); 1537 if (status != CR_OK || !token) 1538 goto error; 1539 } else if (token->type == DELIM_TK && token->u.unichar == '-') { 1540 result->unary_op = MINUS_UOP; 1541 cr_token_destroy (token) ; 1542 token = NULL ; 1543 cr_parser_try_to_skip_spaces_and_comments (a_this); 1544 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 1545 &token); 1546 if (status != CR_OK || !token) 1547 goto error; 1548 } 1549 1550 if (token->type == EMS_TK 1551 || token->type == EXS_TK 1552 || token->type == LENGTH_TK 1553 || token->type == ANGLE_TK 1554 || token->type == TIME_TK 1555 || token->type == FREQ_TK 1556 || token->type == PERCENTAGE_TK 1557 || token->type == NUMBER_TK) { 1558 status = cr_term_set_number (result, token->u.num); 1559 CHECK_PARSING_STATUS (status, TRUE); 1560 token->u.num = NULL; 1561 status = CR_OK; 1562 } else if (token && token->type == FUNCTION_TK) { 1563 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 1564 token); 1565 token = NULL; 1566 status = cr_parser_parse_function (a_this, &func_name, 1567 ¶m); 1568 1569 if (status == CR_OK) { 1570 status = cr_term_set_function (result, 1571 func_name, 1572 param); 1573 CHECK_PARSING_STATUS (status, TRUE); 1574 } 1575 } else if (token && token->type == STRING_TK) { 1576 status = cr_term_set_string (result, 1577 token->u.str); 1578 CHECK_PARSING_STATUS (status, TRUE); 1579 token->u.str = NULL; 1580 } else if (token && token->type == IDENT_TK) { 1581 status = cr_term_set_ident (result, token->u.str); 1582 CHECK_PARSING_STATUS (status, TRUE); 1583 token->u.str = NULL; 1584 } else if (token && token->type == URI_TK) { 1585 status = cr_term_set_uri (result, token->u.str); 1586 CHECK_PARSING_STATUS (status, TRUE); 1587 token->u.str = NULL; 1588 } else if (token && token->type == RGB_TK) { 1589 status = cr_term_set_rgb (result, token->u.rgb); 1590 CHECK_PARSING_STATUS (status, TRUE); 1591 token->u.rgb = NULL; 1592 } else if (token && token->type == UNICODERANGE_TK) { 1593 result->type = TERM_UNICODERANGE; 1594 status = CR_PARSING_ERROR; 1595 } else if (token && token->type == HASH_TK) { 1596 status = cr_term_set_hash (result, token->u.str); 1597 CHECK_PARSING_STATUS (status, TRUE); 1598 token->u.str = NULL; 1599 } else { 1600 status = CR_PARSING_ERROR; 1601 } 1602 1603 if (status != CR_OK) { 1604 goto error; 1605 } 1606 cr_parsing_location_copy (&result->location, 1607 &location) ; 1608 *a_term = cr_term_append_term (*a_term, result); 1609 1610 result = NULL; 1611 1612 cr_parser_try_to_skip_spaces_and_comments (a_this); 1613 1614 if (token) { 1615 cr_token_destroy (token); 1616 token = NULL; 1617 } 1618 1619 cr_parser_clear_errors (a_this); 1620 return CR_OK; 1621 1622 error: 1623 1624 if (result) { 1625 cr_term_destroy (result); 1626 result = NULL; 1627 } 1628 1629 if (token) { 1630 cr_token_destroy (token); 1631 token = NULL; 1632 } 1633 1634 if (param) { 1635 cr_term_destroy (param); 1636 param = NULL; 1637 } 1638 1639 if (func_name) { 1640 cr_string_destroy (func_name); 1641 func_name = NULL; 1642 } 1643 1644 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1645 1646 return status; 1647} 1648 1649/** 1650 * cr_parser_parse_simple_selector: 1651 *@a_this: the "this pointer" of the current instance of #CRParser. 1652 *@a_sel: out parameter. Is set to the successfully parsed simple 1653 *selector. 1654 * 1655 *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 : 1656 *element_name? [ HASH | class | attrib | pseudo ]* S* 1657 *and where pseudo is: 1658 *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ] 1659 * 1660 *Returns CR_OK upon successfull completion, an error code otherwise. 1661 */ 1662static enum CRStatus 1663cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel) 1664{ 1665 enum CRStatus status = CR_ERROR; 1666 CRInputPos init_pos; 1667 CRToken *token = NULL; 1668 CRSimpleSel *sel = NULL; 1669 CRAdditionalSel *add_sel_list = NULL; 1670 gboolean found_sel = FALSE; 1671 guint32 cur_char = 0; 1672 1673 g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); 1674 1675 RECORD_INITIAL_POS (a_this, &init_pos); 1676 1677 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 1678 if (status != CR_OK) 1679 goto error; 1680 1681 sel = cr_simple_sel_new (); 1682 ENSURE_PARSING_COND (sel); 1683 1684 cr_parsing_location_copy 1685 (&sel->location, 1686 &token->location) ; 1687 1688 if (token && token->type == DELIM_TK 1689 && token->u.unichar == '*') { 1690 sel->type_mask |= UNIVERSAL_SELECTOR; 1691 sel->name = cr_string_new_from_string ("*"); 1692 found_sel = TRUE; 1693 } else if (token && token->type == IDENT_TK) { 1694 sel->name = token->u.str; 1695 sel->type_mask |= TYPE_SELECTOR; 1696 token->u.str = NULL; 1697 found_sel = TRUE; 1698 } else { 1699 status = cr_tknzr_unget_token 1700 (PRIVATE (a_this)->tknzr, 1701 token); 1702 token = NULL; 1703 } 1704 1705 if (token) { 1706 cr_token_destroy (token); 1707 token = NULL; 1708 } 1709 1710 cr_parser_try_to_skip_spaces_and_comments (a_this); 1711 1712 for (;;) { 1713 if (token) { 1714 cr_token_destroy (token); 1715 token = NULL; 1716 } 1717 1718 status = cr_tknzr_get_next_token 1719 (PRIVATE (a_this)->tknzr, 1720 &token); 1721 if (status != CR_OK) 1722 goto error; 1723 1724 if (token && token->type == HASH_TK) { 1725 /*we parsed an attribute id */ 1726 CRAdditionalSel *add_sel = NULL; 1727 1728 add_sel = cr_additional_sel_new_with_type 1729 (ID_ADD_SELECTOR); 1730 1731 add_sel->content.id_name = token->u.str; 1732 token->u.str = NULL; 1733 1734 cr_parsing_location_copy 1735 (&add_sel->location, 1736 &token->location) ; 1737 add_sel_list = 1738 cr_additional_sel_append 1739 (add_sel_list, add_sel); 1740 found_sel = TRUE; 1741 } else if (token && (token->type == DELIM_TK) 1742 && (token->u.unichar == '.')) { 1743 cr_token_destroy (token); 1744 token = NULL; 1745 1746 status = cr_tknzr_get_next_token 1747 (PRIVATE (a_this)->tknzr, &token); 1748 if (status != CR_OK) 1749 goto error; 1750 1751 if (token && token->type == IDENT_TK) { 1752 CRAdditionalSel *add_sel = NULL; 1753 1754 add_sel = cr_additional_sel_new_with_type 1755 (CLASS_ADD_SELECTOR); 1756 1757 add_sel->content.class_name = token->u.str; 1758 token->u.str = NULL; 1759 1760 add_sel_list = 1761 cr_additional_sel_append 1762 (add_sel_list, add_sel); 1763 found_sel = TRUE; 1764 1765 cr_parsing_location_copy 1766 (&add_sel->location, 1767 & token->location) ; 1768 } else { 1769 status = CR_PARSING_ERROR; 1770 goto error; 1771 } 1772 } else if (token && token->type == BO_TK) { 1773 CRAttrSel *attr_sel = NULL; 1774 CRAdditionalSel *add_sel = NULL; 1775 1776 status = cr_tknzr_unget_token 1777 (PRIVATE (a_this)->tknzr, token); 1778 if (status != CR_OK) 1779 goto error; 1780 token = NULL; 1781 1782 status = cr_parser_parse_attribute_selector 1783 (a_this, &attr_sel); 1784 CHECK_PARSING_STATUS (status, FALSE); 1785 1786 add_sel = cr_additional_sel_new_with_type 1787 (ATTRIBUTE_ADD_SELECTOR); 1788 1789 ENSURE_PARSING_COND (add_sel != NULL); 1790 1791 add_sel->content.attr_sel = attr_sel; 1792 1793 add_sel_list = 1794 cr_additional_sel_append 1795 (add_sel_list, add_sel); 1796 found_sel = TRUE; 1797 cr_parsing_location_copy 1798 (&add_sel->location, 1799 &attr_sel->location) ; 1800 } else if (token && (token->type == DELIM_TK) 1801 && (token->u.unichar == ':')) { 1802 CRPseudo *pseudo = NULL; 1803 1804 /*try to parse a pseudo */ 1805 1806 if (token) { 1807 cr_token_destroy (token); 1808 token = NULL; 1809 } 1810 1811 pseudo = cr_pseudo_new (); 1812 1813 status = cr_tknzr_get_next_token 1814 (PRIVATE (a_this)->tknzr, &token); 1815 ENSURE_PARSING_COND (status == CR_OK && token); 1816 1817 cr_parsing_location_copy 1818 (&pseudo->location, 1819 &token->location) ; 1820 1821 if (token->type == IDENT_TK) { 1822 pseudo->type = IDENT_PSEUDO; 1823 pseudo->name = token->u.str; 1824 token->u.str = NULL; 1825 found_sel = TRUE; 1826 } else if (token->type == FUNCTION_TK) { 1827 pseudo->name = token->u.str; 1828 token->u.str = NULL; 1829 cr_parser_try_to_skip_spaces_and_comments 1830 (a_this); 1831 status = cr_parser_parse_ident 1832 (a_this, &pseudo->extra); 1833 1834 ENSURE_PARSING_COND (status == CR_OK); 1835 READ_NEXT_CHAR (a_this, &cur_char); 1836 ENSURE_PARSING_COND (cur_char == ')'); 1837 pseudo->type = FUNCTION_PSEUDO; 1838 found_sel = TRUE; 1839 } else { 1840 status = CR_PARSING_ERROR; 1841 goto error; 1842 } 1843 1844 if (status == CR_OK) { 1845 CRAdditionalSel *add_sel = NULL; 1846 1847 add_sel = cr_additional_sel_new_with_type 1848 (PSEUDO_CLASS_ADD_SELECTOR); 1849 1850 add_sel->content.pseudo = pseudo; 1851 cr_parsing_location_copy 1852 (&add_sel->location, 1853 &pseudo->location) ; 1854 add_sel_list = 1855 cr_additional_sel_append 1856 (add_sel_list, add_sel); 1857 status = CR_OK; 1858 } 1859 } else { 1860 status = cr_tknzr_unget_token 1861 (PRIVATE (a_this)->tknzr, token); 1862 token = NULL; 1863 break; 1864 } 1865 } 1866 1867 if (status == CR_OK && found_sel == TRUE) { 1868 cr_parser_try_to_skip_spaces_and_comments (a_this); 1869 1870 sel->add_sel = add_sel_list; 1871 add_sel_list = NULL; 1872 1873 if (*a_sel == NULL) { 1874 *a_sel = sel; 1875 } else { 1876 cr_simple_sel_append_simple_sel (*a_sel, sel); 1877 } 1878 1879 sel = NULL; 1880 1881 if (token) { 1882 cr_token_destroy (token); 1883 token = NULL; 1884 } 1885 1886 cr_parser_clear_errors (a_this); 1887 return CR_OK; 1888 } else { 1889 status = CR_PARSING_ERROR; 1890 } 1891 1892 error: 1893 1894 if (token) { 1895 cr_token_destroy (token); 1896 token = NULL; 1897 } 1898 1899 if (add_sel_list) { 1900 cr_additional_sel_destroy (add_sel_list); 1901 add_sel_list = NULL; 1902 } 1903 1904 if (sel) { 1905 cr_simple_sel_destroy (sel); 1906 sel = NULL; 1907 } 1908 1909 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1910 1911 return status; 1912 1913} 1914 1915/** 1916 * cr_parser_parse_simple_sels: 1917 *@a_this: the this pointer of the current instance of #CRParser. 1918 *@a_start: a pointer to the 1919 *first chararcter of the successfully parsed 1920 *string. 1921 *@a_end: a pointer to the last character of the successfully parsed 1922 *string. 1923 * 1924 *Parses a "selector" as defined by the css2 spec in appendix D.1: 1925 *selector ::= simple_selector [ combinator simple_selector ]* 1926 * 1927 *Returns CR_OK upon successfull completion, an error code otherwise. 1928 */ 1929static enum CRStatus 1930cr_parser_parse_simple_sels (CRParser * a_this, 1931 CRSimpleSel ** a_sel) 1932{ 1933 enum CRStatus status = CR_ERROR; 1934 CRInputPos init_pos; 1935 CRSimpleSel *sel = NULL; 1936 guint32 cur_char = 0; 1937 1938 g_return_val_if_fail (a_this 1939 && PRIVATE (a_this) 1940 && a_sel, 1941 CR_BAD_PARAM_ERROR); 1942 1943 RECORD_INITIAL_POS (a_this, &init_pos); 1944 1945 status = cr_parser_parse_simple_selector (a_this, &sel); 1946 CHECK_PARSING_STATUS (status, FALSE); 1947 1948 *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel); 1949 1950 for (;;) { 1951 guint32 next_char = 0; 1952 enum Combinator comb = 0; 1953 1954 sel = NULL; 1955 1956 PEEK_NEXT_CHAR (a_this, &next_char); 1957 1958 if (next_char == '+') { 1959 READ_NEXT_CHAR (a_this, &cur_char); 1960 comb = COMB_PLUS; 1961 cr_parser_try_to_skip_spaces_and_comments (a_this); 1962 } else if (next_char == '>') { 1963 READ_NEXT_CHAR (a_this, &cur_char); 1964 comb = COMB_GT; 1965 cr_parser_try_to_skip_spaces_and_comments (a_this); 1966 } else { 1967 comb = COMB_WS; 1968 } 1969 1970 status = cr_parser_parse_simple_selector (a_this, &sel); 1971 if (status != CR_OK) 1972 break; 1973 1974 if (comb && sel) { 1975 sel->combinator = comb; 1976 comb = 0; 1977 } 1978 if (sel) { 1979 *a_sel = cr_simple_sel_append_simple_sel (*a_sel, 1980 sel) ; 1981 } 1982 } 1983 cr_parser_clear_errors (a_this); 1984 return CR_OK; 1985 1986 error: 1987 1988 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 1989 1990 return status; 1991} 1992 1993/** 1994 * cr_parser_parse_selector: 1995 *@a_this: the current instance of #CRParser. 1996 *@a_selector: the parsed list of comma separated 1997 *selectors. 1998 * 1999 *Parses a comma separated list of selectors. 2000 * 2001 *Returns CR_OK upon successful completion, an error 2002 *code otherwise. 2003 */ 2004static enum CRStatus 2005cr_parser_parse_selector (CRParser * a_this, 2006 CRSelector ** a_selector) 2007{ 2008 enum CRStatus status = CR_OK; 2009 CRInputPos init_pos; 2010 guint32 cur_char = 0, 2011 next_char = 0; 2012 CRSimpleSel *simple_sels = NULL; 2013 CRSelector *selector = NULL; 2014 2015 g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR); 2016 2017 RECORD_INITIAL_POS (a_this, &init_pos); 2018 2019 status = cr_parser_parse_simple_sels (a_this, &simple_sels); 2020 CHECK_PARSING_STATUS (status, FALSE); 2021 2022 if (simple_sels) { 2023 selector = cr_selector_append_simple_sel 2024 (selector, simple_sels); 2025 if (selector) { 2026 cr_parsing_location_copy 2027 (&selector->location, 2028 &simple_sels->location) ; 2029 } 2030 simple_sels = NULL; 2031 } else { 2032 status = CR_PARSING_ERROR ; 2033 goto error ; 2034 } 2035 2036 status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, 2037 &next_char); 2038 if (status != CR_OK) { 2039 if (status == CR_END_OF_INPUT_ERROR) { 2040 status = CR_OK; 2041 goto okay; 2042 } else { 2043 goto error; 2044 } 2045 } 2046 2047 if (next_char == ',') { 2048 for (;;) { 2049 simple_sels = NULL; 2050 2051 status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, 2052 &next_char); 2053 if (status != CR_OK) { 2054 if (status == CR_END_OF_INPUT_ERROR) { 2055 status = CR_OK; 2056 break; 2057 } else { 2058 goto error; 2059 } 2060 } 2061 2062 if (next_char != ',') 2063 break; 2064 2065 /*consume the ',' char */ 2066 READ_NEXT_CHAR (a_this, &cur_char); 2067 2068 cr_parser_try_to_skip_spaces_and_comments (a_this); 2069 2070 status = cr_parser_parse_simple_sels 2071 (a_this, &simple_sels); 2072 2073 CHECK_PARSING_STATUS (status, FALSE); 2074 2075 if (simple_sels) { 2076 selector = 2077 cr_selector_append_simple_sel 2078 (selector, simple_sels); 2079 2080 simple_sels = NULL; 2081 } 2082 } 2083 } 2084 2085 okay: 2086 cr_parser_try_to_skip_spaces_and_comments (a_this); 2087 2088 if (!*a_selector) { 2089 *a_selector = selector; 2090 } else { 2091 *a_selector = cr_selector_append (*a_selector, selector); 2092 } 2093 2094 selector = NULL; 2095 return CR_OK; 2096 2097 error: 2098 2099 if (simple_sels) { 2100 cr_simple_sel_destroy (simple_sels); 2101 simple_sels = NULL; 2102 } 2103 2104 if (selector) { 2105 cr_selector_unref (selector); 2106 selector = NULL; 2107 } 2108 2109 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 2110 2111 return status; 2112} 2113 2114/** 2115 * cr_parser_parse_function: 2116 *@a_this: the "this pointer" of the current instance of #CRParser. 2117 * 2118 *@a_func_name: out parameter. The parsed function name 2119 *@a_expr: out parameter. The successfully parsed term. 2120 * 2121 *Parses a "function" as defined in css spec at appendix D.1: 2122 *function ::= FUNCTION S* expr ')' S* 2123 *FUNCTION ::= ident'(' 2124 * 2125 *Returns CR_OK upon successfull completion, an error code otherwise. 2126 */ 2127static enum CRStatus 2128cr_parser_parse_function (CRParser * a_this, 2129 CRString ** a_func_name, 2130 CRTerm ** a_expr) 2131{ 2132 CRInputPos init_pos; 2133 enum CRStatus status = CR_OK; 2134 CRToken *token = NULL; 2135 CRTerm *expr = NULL; 2136 2137 g_return_val_if_fail (a_this && PRIVATE (a_this) 2138 && a_func_name, 2139 CR_BAD_PARAM_ERROR); 2140 2141 RECORD_INITIAL_POS (a_this, &init_pos); 2142 2143 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 2144 if (status != CR_OK) 2145 goto error; 2146 2147 if (token && token->type == FUNCTION_TK) { 2148 *a_func_name = token->u.str; 2149 token->u.str = NULL; 2150 } else { 2151 status = CR_PARSING_ERROR; 2152 goto error; 2153 } 2154 cr_token_destroy (token); 2155 token = NULL; 2156 2157 cr_parser_try_to_skip_spaces_and_comments (a_this) ; 2158 2159 status = cr_parser_parse_expr (a_this, &expr); 2160 2161 CHECK_PARSING_STATUS (status, FALSE); 2162 2163 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 2164 if (status != CR_OK) 2165 goto error; 2166 2167 ENSURE_PARSING_COND (token && token->type == PC_TK); 2168 2169 cr_token_destroy (token); 2170 token = NULL; 2171 2172 if (expr) { 2173 *a_expr = cr_term_append_term (*a_expr, expr); 2174 expr = NULL; 2175 } 2176 2177 cr_parser_clear_errors (a_this); 2178 return CR_OK; 2179 2180 error: 2181 2182 if (*a_func_name) { 2183 cr_string_destroy (*a_func_name); 2184 *a_func_name = NULL; 2185 } 2186 2187 if (expr) { 2188 cr_term_destroy (expr); 2189 expr = NULL; 2190 } 2191 2192 if (token) { 2193 cr_token_destroy (token); 2194 2195 } 2196 2197 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 2198 2199 return status; 2200} 2201 2202/** 2203 * cr_parser_parse_uri: 2204 *@a_this: the current instance of #CRParser. 2205 *@a_str: the successfully parsed url. 2206 * 2207 *Parses an uri as defined by the css spec [4.1.1]: 2208 * URI ::= url\({w}{string}{w}\) 2209 * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) 2210 * 2211 *Returns CR_OK upon successfull completion, an error code otherwise. 2212 */ 2213static enum CRStatus 2214cr_parser_parse_uri (CRParser * a_this, CRString ** a_str) 2215{ 2216 2217 enum CRStatus status = CR_PARSING_ERROR; 2218 2219 g_return_val_if_fail (a_this && PRIVATE (a_this) 2220 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 2221 2222 status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, 2223 URI_TK, NO_ET, a_str, NULL); 2224 return status; 2225} 2226 2227/** 2228 * cr_parser_parse_string: 2229 *@a_this: the current instance of #CRParser. 2230 *@a_start: out parameter. Upon successfull completion, 2231 *points to the beginning of the string, points to an undefined value 2232 *otherwise. 2233 *@a_end: out parameter. Upon successfull completion, points to 2234 *the beginning of the string, points to an undefined value otherwise. 2235 * 2236 *Parses a string type as defined in css spec [4.1.1]: 2237 * 2238 *string ::= {string1}|{string2} 2239 *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" 2240 *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' 2241 * 2242 *Returns CR_OK upon successfull completion, an error code otherwise. 2243 */ 2244static enum CRStatus 2245cr_parser_parse_string (CRParser * a_this, CRString ** a_str) 2246{ 2247 enum CRStatus status = CR_OK; 2248 2249 g_return_val_if_fail (a_this && PRIVATE (a_this) 2250 && PRIVATE (a_this)->tknzr 2251 && a_str, CR_BAD_PARAM_ERROR); 2252 2253 status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, 2254 STRING_TK, NO_ET, a_str, NULL); 2255 return status; 2256} 2257 2258/** 2259 *Parses an "ident" as defined in css spec [4.1.1]: 2260 *ident ::= {nmstart}{nmchar}* 2261 * 2262 *@param a_this the currens instance of #CRParser. 2263 * 2264 *@param a_str a pointer to parsed ident. If *a_str is NULL, 2265 *this function allocates a new instance of #CRString. If not, 2266 *the function just appends the parsed string to the one passed. 2267 *In both cases it is up to the caller to free *a_str. 2268 * 2269 *@return CR_OK upon successfull completion, an error code 2270 *otherwise. 2271 */ 2272static enum CRStatus 2273cr_parser_parse_ident (CRParser * a_this, CRString ** a_str) 2274{ 2275 enum CRStatus status = CR_OK; 2276 2277 g_return_val_if_fail (a_this && PRIVATE (a_this) 2278 && PRIVATE (a_this)->tknzr 2279 && a_str, CR_BAD_PARAM_ERROR); 2280 2281 status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, 2282 IDENT_TK, NO_ET, a_str, NULL); 2283 return status; 2284} 2285 2286/** 2287 *the next rule is ignored as well. This seems to be a bug 2288 *Parses a stylesheet as defined in the css2 spec in appendix D.1: 2289 *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]? 2290 * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* 2291 * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]* 2292 * 2293 *TODO: Finish the code of this function. Think about splitting it into 2294 *smaller functions. 2295 * 2296 *@param a_this the "this pointer" of the current instance of #CRParser. 2297 *@param a_start out parameter. A pointer to the first character of 2298 *the successfully parsed string. 2299 *@param a_end out parameter. A pointer to the first character of 2300 *the successfully parsed string. 2301 * 2302 *@return CR_OK upon successfull completion, an error code otherwise. 2303 */ 2304static enum CRStatus 2305cr_parser_parse_stylesheet (CRParser * a_this) 2306{ 2307 enum CRStatus status = CR_OK; 2308 CRInputPos init_pos; 2309 CRToken *token = NULL; 2310 CRString *charset = NULL; 2311 2312 g_return_val_if_fail (a_this && PRIVATE (a_this) 2313 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 2314 2315 RECORD_INITIAL_POS (a_this, &init_pos); 2316 2317 PRIVATE (a_this)->state = READY_STATE; 2318 2319 if (PRIVATE (a_this)->sac_handler 2320 && PRIVATE (a_this)->sac_handler->start_document) { 2321 PRIVATE (a_this)->sac_handler->start_document 2322 (PRIVATE (a_this)->sac_handler); 2323 } 2324 2325 parse_charset: 2326 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 2327 2328 if (status == CR_END_OF_INPUT_ERROR) 2329 goto done; 2330 CHECK_PARSING_STATUS (status, TRUE); 2331 2332 if (token && token->type == CHARSET_SYM_TK) { 2333 CRParsingLocation location = {0} ; 2334 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 2335 token); 2336 CHECK_PARSING_STATUS (status, TRUE); 2337 token = NULL; 2338 2339 status = cr_parser_parse_charset (a_this, 2340 &charset, 2341 &location); 2342 2343 if (status == CR_OK && charset) { 2344 if (PRIVATE (a_this)->sac_handler 2345 && PRIVATE (a_this)->sac_handler->charset) { 2346 PRIVATE (a_this)->sac_handler->charset 2347 (PRIVATE (a_this)->sac_handler, 2348 charset, &location); 2349 } 2350 } else if (status != CR_END_OF_INPUT_ERROR) { 2351 status = cr_parser_parse_atrule_core (a_this); 2352 CHECK_PARSING_STATUS (status, FALSE); 2353 } 2354 2355 if (charset) { 2356 cr_string_destroy (charset); 2357 charset = NULL; 2358 } 2359 } else if (token 2360 && (token->type == S_TK 2361 || token->type == COMMENT_TK)) { 2362 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 2363 token); 2364 token = NULL; 2365 CHECK_PARSING_STATUS (status, TRUE); 2366 2367 cr_parser_try_to_skip_spaces_and_comments (a_this); 2368 goto parse_charset ; 2369 } else if (token) { 2370 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 2371 token); 2372 token = NULL; 2373 CHECK_PARSING_STATUS (status, TRUE); 2374 } 2375 2376/* parse_imports:*/ 2377 do { 2378 if (token) { 2379 cr_token_destroy (token); 2380 token = NULL; 2381 } 2382 cr_parser_try_to_skip_spaces_and_comments (a_this) ; 2383 status = cr_tknzr_get_next_token 2384 (PRIVATE (a_this)->tknzr, &token); 2385 2386 if (status == CR_END_OF_INPUT_ERROR) 2387 goto done; 2388 CHECK_PARSING_STATUS (status, TRUE); 2389 } while (token 2390 && (token->type == S_TK 2391 || token->type == CDO_TK || token->type == CDC_TK)); 2392 2393 if (token) { 2394 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 2395 token); 2396 token = NULL; 2397 } 2398 2399 for (;;) { 2400 status = cr_tknzr_get_next_token 2401 (PRIVATE (a_this)->tknzr, &token); 2402 if (status == CR_END_OF_INPUT_ERROR) 2403 goto done; 2404 CHECK_PARSING_STATUS (status, TRUE); 2405 2406 if (token && token->type == IMPORT_SYM_TK) { 2407 GList *media_list = NULL; 2408 CRString *import_string = NULL; 2409 CRParsingLocation location = {0} ; 2410 2411 status = cr_tknzr_unget_token 2412 (PRIVATE (a_this)->tknzr, token); 2413 token = NULL; 2414 CHECK_PARSING_STATUS (status, TRUE); 2415 2416 status = cr_parser_parse_import (a_this, 2417 &media_list, 2418 &import_string, 2419 &location); 2420 if (status == CR_OK) { 2421 if (import_string 2422 && PRIVATE (a_this)->sac_handler 2423 && PRIVATE (a_this)->sac_handler->import_style) { 2424 PRIVATE (a_this)->sac_handler->import_style 2425 (PRIVATE(a_this)->sac_handler, 2426 media_list, 2427 import_string, 2428 NULL, &location) ; 2429 2430 if ((PRIVATE (a_this)->sac_handler->resolve_import == TRUE)) { 2431 /* 2432 *TODO: resolve the 2433 *import rule. 2434 */ 2435 } 2436 2437 if ((PRIVATE (a_this)->sac_handler->import_style_result)) { 2438 PRIVATE (a_this)->sac_handler->import_style_result 2439 (PRIVATE (a_this)->sac_handler, 2440 media_list, import_string, 2441 NULL, NULL); 2442 } 2443 } 2444 } else if (status != CR_END_OF_INPUT_ERROR) { 2445 if (PRIVATE (a_this)->sac_handler 2446 && PRIVATE (a_this)->sac_handler->error) { 2447 PRIVATE (a_this)->sac_handler->error 2448 (PRIVATE (a_this)->sac_handler); 2449 } 2450 status = cr_parser_parse_atrule_core (a_this); 2451 CHECK_PARSING_STATUS (status, TRUE) ; 2452 } else { 2453 goto error ; 2454 } 2455 2456 /* 2457 *then, after calling the appropriate 2458 *SAC handler, free 2459 *the media_list and import_string. 2460 */ 2461 if (media_list) { 2462 GList *cur = NULL; 2463 2464 /*free the medium list */ 2465 for (cur = media_list; cur; cur = cur->next) { 2466 if (cur->data) { 2467 cr_string_destroy (cur->data); 2468 } 2469 } 2470 2471 g_list_free (media_list); 2472 media_list = NULL; 2473 } 2474 2475 if (import_string) { 2476 cr_string_destroy (import_string); 2477 import_string = NULL; 2478 } 2479 2480 cr_parser_try_to_skip_spaces_and_comments (a_this); 2481 } else if (token 2482 && (token->type == S_TK 2483 || token->type == CDO_TK 2484 || token->type == CDC_TK)) { 2485 status = cr_tknzr_unget_token 2486 (PRIVATE (a_this)->tknzr, token); 2487 token = NULL; 2488 2489 do { 2490 if (token) { 2491 cr_token_destroy (token); 2492 token = NULL; 2493 } 2494 2495 status = cr_tknzr_get_next_token 2496 (PRIVATE (a_this)->tknzr, &token); 2497 2498 if (status == CR_END_OF_INPUT_ERROR) 2499 goto done; 2500 CHECK_PARSING_STATUS (status, TRUE); 2501 } while (token 2502 && (token->type == S_TK 2503 || token->type == CDO_TK 2504 || token->type == CDC_TK)); 2505 } else { 2506 if (token) { 2507 status = cr_tknzr_unget_token 2508 (PRIVATE (a_this)->tknzr, token); 2509 token = NULL; 2510 } 2511 goto parse_ruleset_and_others; 2512 } 2513 } 2514 2515 parse_ruleset_and_others: 2516 2517 cr_parser_try_to_skip_spaces_and_comments (a_this); 2518 2519 for (;;) { 2520 status = cr_tknzr_get_next_token 2521 (PRIVATE (a_this)->tknzr, &token); 2522 if (status == CR_END_OF_INPUT_ERROR) 2523 goto done; 2524 CHECK_PARSING_STATUS (status, TRUE); 2525 2526 if (token 2527 && (token->type == S_TK 2528 || token->type == CDO_TK || token->type == CDC_TK)) { 2529 status = cr_tknzr_unget_token 2530 (PRIVATE (a_this)->tknzr, token); 2531 token = NULL; 2532 2533 do { 2534 if (token) { 2535 cr_token_destroy (token); 2536 token = NULL; 2537 } 2538 2539 cr_parser_try_to_skip_spaces_and_comments 2540 (a_this); 2541 status = cr_tknzr_get_next_token 2542 (PRIVATE (a_this)->tknzr, &token); 2543 } while (token 2544 && (token->type == S_TK 2545 || token->type == COMMENT_TK 2546 || token->type == CDO_TK 2547 || token->type == CDC_TK)); 2548 if (token) { 2549 cr_tknzr_unget_token 2550 (PRIVATE (a_this)->tknzr, token); 2551 token = NULL; 2552 } 2553 } else if (token 2554 && (token->type == HASH_TK 2555 || (token->type == DELIM_TK 2556 && token->u.unichar == '.') 2557 || (token->type == DELIM_TK 2558 && token->u.unichar == ':') 2559 || (token->type == DELIM_TK 2560 && token->u.unichar == '*') 2561 || (token->type == BO_TK) 2562 || token->type == IDENT_TK)) { 2563 /* 2564 *Try to parse a CSS2 ruleset. 2565 *if the parsing fails, try to parse 2566 *a css core ruleset. 2567 */ 2568 status = cr_tknzr_unget_token 2569 (PRIVATE (a_this)->tknzr, token); 2570 CHECK_PARSING_STATUS (status, TRUE); 2571 token = NULL; 2572 2573 status = cr_parser_parse_ruleset (a_this); 2574 2575 if (status == CR_OK) { 2576 continue; 2577 } else { 2578 if (PRIVATE (a_this)->sac_handler 2579 && PRIVATE (a_this)->sac_handler->error) { 2580 PRIVATE (a_this)->sac_handler-> 2581 error 2582 (PRIVATE (a_this)-> 2583 sac_handler); 2584 } 2585 2586 status = cr_parser_parse_ruleset_core 2587 (a_this); 2588 2589 if (status == CR_OK) { 2590 continue; 2591 } else { 2592 break; 2593 } 2594 } 2595 } else if (token && token->type == MEDIA_SYM_TK) { 2596 status = cr_tknzr_unget_token 2597 (PRIVATE (a_this)->tknzr, token); 2598 CHECK_PARSING_STATUS (status, TRUE); 2599 token = NULL; 2600 2601 status = cr_parser_parse_media (a_this); 2602 if (status == CR_OK) { 2603 continue; 2604 } else { 2605 if (PRIVATE (a_this)->sac_handler 2606 && PRIVATE (a_this)->sac_handler->error) { 2607 PRIVATE (a_this)->sac_handler-> 2608 error 2609 (PRIVATE (a_this)-> 2610 sac_handler); 2611 } 2612 2613 status = cr_parser_parse_atrule_core (a_this); 2614 2615 if (status == CR_OK) { 2616 continue; 2617 } else { 2618 break; 2619 } 2620 } 2621 2622 } else if (token && token->type == PAGE_SYM_TK) { 2623 status = cr_tknzr_unget_token 2624 (PRIVATE (a_this)->tknzr, token); 2625 CHECK_PARSING_STATUS (status, TRUE); 2626 token = NULL; 2627 status = cr_parser_parse_page (a_this); 2628 2629 if (status == CR_OK) { 2630 continue; 2631 } else { 2632 if (PRIVATE (a_this)->sac_handler 2633 && PRIVATE (a_this)->sac_handler->error) { 2634 PRIVATE (a_this)->sac_handler-> 2635 error 2636 (PRIVATE (a_this)-> 2637 sac_handler); 2638 } 2639 2640 status = cr_parser_parse_atrule_core (a_this); 2641 2642 if (status == CR_OK) { 2643 continue; 2644 } else { 2645 break; 2646 } 2647 } 2648 } else if (token && token->type == FONT_FACE_SYM_TK) { 2649 status = cr_tknzr_unget_token 2650 (PRIVATE (a_this)->tknzr, token); 2651 CHECK_PARSING_STATUS (status, TRUE); 2652 token = NULL; 2653 status = cr_parser_parse_font_face (a_this); 2654 2655 if (status == CR_OK) { 2656 continue; 2657 } else { 2658 if (PRIVATE (a_this)->sac_handler 2659 && PRIVATE (a_this)->sac_handler->error) { 2660 PRIVATE (a_this)->sac_handler-> 2661 error 2662 (PRIVATE (a_this)-> 2663 sac_handler); 2664 } 2665 2666 status = cr_parser_parse_atrule_core (a_this); 2667 2668 if (status == CR_OK) { 2669 continue; 2670 } else { 2671 break; 2672 } 2673 } 2674 } else { 2675 status = cr_tknzr_unget_token 2676 (PRIVATE (a_this)->tknzr, token); 2677 CHECK_PARSING_STATUS (status, TRUE); 2678 token = NULL; 2679 status = cr_parser_parse_statement_core (a_this); 2680 2681 if (status == CR_OK) { 2682 continue; 2683 } else { 2684 break; 2685 } 2686 } 2687 } 2688 2689 done: 2690 if (token) { 2691 cr_token_destroy (token); 2692 token = NULL; 2693 } 2694 2695 if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) { 2696 2697 if (PRIVATE (a_this)->sac_handler 2698 && PRIVATE (a_this)->sac_handler->end_document) { 2699 PRIVATE (a_this)->sac_handler->end_document 2700 (PRIVATE (a_this)->sac_handler); 2701 } 2702 2703 return CR_OK; 2704 } 2705 2706 cr_parser_push_error 2707 (a_this, "could not recognize next production", CR_ERROR); 2708 2709 if (PRIVATE (a_this)->sac_handler 2710 && PRIVATE (a_this)->sac_handler->unrecoverable_error) { 2711 PRIVATE (a_this)->sac_handler-> 2712 unrecoverable_error (PRIVATE (a_this)->sac_handler); 2713 } 2714 2715 cr_parser_dump_err_stack (a_this, TRUE); 2716 2717 return status; 2718 2719 error: 2720 2721 if (token) { 2722 cr_token_destroy (token); 2723 token = NULL; 2724 } 2725 2726 if (PRIVATE (a_this)->sac_handler 2727 && PRIVATE (a_this)->sac_handler->unrecoverable_error) { 2728 PRIVATE (a_this)->sac_handler-> 2729 unrecoverable_error (PRIVATE (a_this)->sac_handler); 2730 } 2731 2732 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 2733 2734 return status; 2735} 2736 2737/**************************************** 2738 *Public CRParser Methods 2739 ****************************************/ 2740 2741/** 2742 * cr_parser_new: 2743 * @a_tknzr: the tokenizer to use for the parsing. 2744 * 2745 *Creates a new parser to parse data 2746 *coming the input stream given in parameter. 2747 * 2748 *Returns the newly created instance of #CRParser, 2749 *or NULL if an error occured. 2750 */ 2751CRParser * 2752cr_parser_new (CRTknzr * a_tknzr) 2753{ 2754 CRParser *result = NULL; 2755 enum CRStatus status = CR_OK; 2756 2757 result = g_malloc0 (sizeof (CRParser)); 2758 2759 PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv)); 2760 2761 if (a_tknzr) { 2762 status = cr_parser_set_tknzr (result, a_tknzr); 2763 } 2764 2765 g_return_val_if_fail (status == CR_OK, NULL); 2766 2767 return result; 2768} 2769 2770/** 2771 * cr_parser_new_from_buf: 2772 *@a_buf: the buffer to parse. 2773 *@a_len: the length of the data in the buffer. 2774 *@a_enc: the encoding of the input buffer a_buf. 2775 *@a_free_buf: if set to TRUE, a_buf will be freed 2776 *during the destruction of the newly built instance 2777 *of #CRParser. If set to FALSE, it is up to the caller to 2778 *eventually free it. 2779 * 2780 *Instanciates a new parser from a memory buffer. 2781 * 2782 *Returns the newly built parser, or NULL if an error arises. 2783 */ 2784CRParser * 2785cr_parser_new_from_buf (guchar * a_buf, 2786 gulong a_len, 2787 enum CREncoding a_enc, 2788 gboolean a_free_buf) 2789{ 2790 CRParser *result = NULL; 2791 CRInput *input = NULL; 2792 2793 g_return_val_if_fail (a_buf && a_len, NULL); 2794 2795 input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf); 2796 g_return_val_if_fail (input, NULL); 2797 2798 result = cr_parser_new_from_input (input); 2799 if (!result) { 2800 cr_input_destroy (input); 2801 input = NULL; 2802 return NULL; 2803 } 2804 return result; 2805} 2806 2807/** 2808 * cr_parser_new_from_input: 2809 * @a_input: the parser input stream to use. 2810 * 2811 * Returns a newly built parser input. 2812 */ 2813CRParser * 2814cr_parser_new_from_input (CRInput * a_input) 2815{ 2816 CRParser *result = NULL; 2817 CRTknzr *tokenizer = NULL; 2818 2819 if (a_input) { 2820 tokenizer = cr_tknzr_new (a_input); 2821 g_return_val_if_fail (tokenizer, NULL); 2822 } 2823 2824 result = cr_parser_new (tokenizer); 2825 g_return_val_if_fail (result, NULL); 2826 2827 return result; 2828} 2829 2830/** 2831 * cr_parser_new_from_file: 2832 * @a_file_uri: the uri of the file to parse. 2833 * @a_enc: the file encoding to use. 2834 * 2835 * Returns the newly built parser. 2836 */ 2837CRParser * 2838cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc) 2839{ 2840 CRParser *result = NULL; 2841 CRTknzr *tokenizer = NULL; 2842 2843 tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc); 2844 if (!tokenizer) { 2845 cr_utils_trace_info ("Could not open input file"); 2846 return NULL; 2847 } 2848 2849 result = cr_parser_new (tokenizer); 2850 g_return_val_if_fail (result, NULL); 2851 return result; 2852} 2853 2854/** 2855 * cr_parser_set_sac_handler: 2856 *@a_this: the "this pointer" of the current instance of #CRParser. 2857 *@a_handler: the handler to set. 2858 * 2859 *Sets a SAC document handler to the parser. 2860 * 2861 *Returns CR_OK upon successfull completion, an error code otherwise. 2862 */ 2863enum CRStatus 2864cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler) 2865{ 2866 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 2867 2868 if (PRIVATE (a_this)->sac_handler) { 2869 cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); 2870 } 2871 2872 PRIVATE (a_this)->sac_handler = a_handler; 2873 cr_doc_handler_ref (a_handler); 2874 2875 return CR_OK; 2876} 2877 2878/** 2879 * cr_parser_get_sac_handler: 2880 *@a_this: the "this pointer" of the current instance of 2881 *#CRParser. 2882 *@a_handler: out parameter. The returned handler. 2883 * 2884 *Gets the SAC document handler. 2885 * 2886 *Returns CR_OK upon successfull completion, an error code 2887 *otherwise. 2888 */ 2889enum CRStatus 2890cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler) 2891{ 2892 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 2893 2894 *a_handler = PRIVATE (a_this)->sac_handler; 2895 2896 return CR_OK; 2897} 2898 2899/** 2900 * cr_parser_set_default_sac_handler: 2901 *@a_this: a pointer to the current instance of #CRParser. 2902 * 2903 *Sets the SAC handler associated to the current instance 2904 *of #CRParser to the default SAC handler. 2905 * 2906 *Returns CR_OK upon successfull completion, an error code otherwise. 2907 */ 2908enum CRStatus 2909cr_parser_set_default_sac_handler (CRParser * a_this) 2910{ 2911 CRDocHandler *default_sac_handler = NULL; 2912 enum CRStatus status = CR_ERROR; 2913 2914 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 2915 2916 default_sac_handler = cr_doc_handler_new (); 2917 2918 cr_doc_handler_set_default_sac_handler (default_sac_handler); 2919 2920 status = cr_parser_set_sac_handler (a_this, default_sac_handler); 2921 2922 if (status != CR_OK) { 2923 cr_doc_handler_destroy (default_sac_handler); 2924 default_sac_handler = NULL; 2925 } 2926 2927 return status; 2928} 2929 2930/** 2931 * cr_parser_set_use_core_grammar: 2932 * @a_this: the current instance of #CRParser. 2933 * @a_use_core_grammar: where to parse against the css core grammar. 2934 * 2935 * Returns CR_OK upon succesful completion, an error code otherwise. 2936 */ 2937enum CRStatus 2938cr_parser_set_use_core_grammar (CRParser * a_this, 2939 gboolean a_use_core_grammar) 2940{ 2941 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 2942 2943 PRIVATE (a_this)->use_core_grammar = a_use_core_grammar; 2944 2945 return CR_OK; 2946} 2947 2948/** 2949 * cr_parser_get_use_core_grammar: 2950 * @a_this: the current instance of #CRParser. 2951 * @a_use_core_grammar: wether to use the core grammar or not. 2952 * 2953 * Returns CR_OK upon succesful completion, an error code otherwise. 2954 */ 2955enum CRStatus 2956cr_parser_get_use_core_grammar (CRParser * a_this, 2957 gboolean * a_use_core_grammar) 2958{ 2959 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 2960 2961 *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar; 2962 2963 return CR_OK; 2964} 2965 2966/** 2967 * cr_parser_parse_file: 2968 *@a_this: a pointer to the current instance of #CRParser. 2969 *@a_file_uri: the uri to the file to load. For the time being, 2970 *@a_enc: the encoding of the file to parse. 2971 *only local files are supported. 2972 * 2973 *Parses a the given in parameter. 2974 * 2975 *Returns CR_OK upon successfull completion, an error code otherwise. 2976 */ 2977enum CRStatus 2978cr_parser_parse_file (CRParser * a_this, 2979 const guchar * a_file_uri, enum CREncoding a_enc) 2980{ 2981 enum CRStatus status = CR_ERROR; 2982 CRTknzr *tknzr = NULL; 2983 2984 g_return_val_if_fail (a_this && PRIVATE (a_this) 2985 && a_file_uri, CR_BAD_PARAM_ERROR); 2986 2987 tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc); 2988 2989 g_return_val_if_fail (tknzr != NULL, CR_ERROR); 2990 2991 status = cr_parser_set_tknzr (a_this, tknzr); 2992 g_return_val_if_fail (status == CR_OK, CR_ERROR); 2993 2994 status = cr_parser_parse (a_this); 2995 2996 return status; 2997} 2998 2999/** 3000 * cr_parser_parse_expr: 3001 * @a_this: the current instance of #CRParser. 3002 * @a_expr: out parameter. the parsed expression. 3003 * 3004 *Parses an expression as defined by the css2 spec in appendix 3005 *D.1: 3006 *expr: term [ operator term ]* 3007 * 3008 * 3009 * Returns CR_OK upon successful completion, an error code otherwise. 3010 */ 3011enum CRStatus 3012cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr) 3013{ 3014 enum CRStatus status = CR_ERROR; 3015 CRInputPos init_pos; 3016 CRTerm *expr = NULL, 3017 *expr2 = NULL; 3018 guchar next_byte = 0; 3019 gulong nb_terms = 0; 3020 3021 g_return_val_if_fail (a_this && PRIVATE (a_this) 3022 && a_expr, CR_BAD_PARAM_ERROR); 3023 3024 RECORD_INITIAL_POS (a_this, &init_pos); 3025 3026 status = cr_parser_parse_term (a_this, &expr); 3027 3028 CHECK_PARSING_STATUS (status, FALSE); 3029 3030 for (;;) { 3031 guchar operator = 0; 3032 3033 status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, 3034 1, &next_byte); 3035 if (status != CR_OK) { 3036 if (status == CR_END_OF_INPUT_ERROR) { 3037 /* 3038 if (!nb_terms) 3039 { 3040 goto error ; 3041 } 3042 */ 3043 status = CR_OK; 3044 break; 3045 } else { 3046 goto error; 3047 } 3048 } 3049 3050 if (next_byte == '/' || next_byte == ',') { 3051 READ_NEXT_BYTE (a_this, &operator); 3052 } 3053 3054 cr_parser_try_to_skip_spaces_and_comments (a_this); 3055 3056 status = cr_parser_parse_term (a_this, &expr2); 3057 3058 if (status != CR_OK || expr2 == NULL) { 3059 status = CR_OK; 3060 break; 3061 } 3062 3063 switch (operator) { 3064 case '/': 3065 expr2->the_operator = DIVIDE; 3066 break; 3067 case ',': 3068 expr2->the_operator = COMMA; 3069 3070 default: 3071 break; 3072 } 3073 3074 expr = cr_term_append_term (expr, expr2); 3075 expr2 = NULL; 3076 operator = 0; 3077 nb_terms++; 3078 } 3079 3080 if (status == CR_OK) { 3081 *a_expr = cr_term_append_term (*a_expr, expr); 3082 expr = NULL; 3083 3084 cr_parser_clear_errors (a_this); 3085 return CR_OK; 3086 } 3087 3088 error: 3089 3090 if (expr) { 3091 cr_term_destroy (expr); 3092 expr = NULL; 3093 } 3094 3095 if (expr2) { 3096 cr_term_destroy (expr2); 3097 expr2 = NULL; 3098 } 3099 3100 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3101 3102 return status; 3103} 3104 3105/** 3106 * cr_parser_parse_prio: 3107 *@a_this: the current instance of #CRParser. 3108 *@a_prio: a string representing the priority. 3109 *Today, only "!important" is returned as only this 3110 *priority is defined by css2. 3111 * 3112 *Parses a declaration priority as defined by 3113 *the css2 grammar in appendix C: 3114 *prio: IMPORTANT_SYM S* 3115 * 3116 * Returns CR_OK upon successful completion, an error code otherwise. 3117 */ 3118enum CRStatus 3119cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio) 3120{ 3121 enum CRStatus status = CR_ERROR; 3122 CRInputPos init_pos; 3123 CRToken *token = NULL; 3124 3125 g_return_val_if_fail (a_this && PRIVATE (a_this) 3126 && a_prio 3127 && *a_prio == NULL, CR_BAD_PARAM_ERROR); 3128 3129 RECORD_INITIAL_POS (a_this, &init_pos); 3130 3131 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 3132 if (status == CR_END_OF_INPUT_ERROR) { 3133 goto error; 3134 } 3135 ENSURE_PARSING_COND (status == CR_OK 3136 && token && token->type == IMPORTANT_SYM_TK); 3137 3138 cr_parser_try_to_skip_spaces_and_comments (a_this); 3139 *a_prio = cr_string_new_from_string ("!important"); 3140 cr_token_destroy (token); 3141 token = NULL; 3142 return CR_OK; 3143 3144 error: 3145 if (token) { 3146 cr_token_destroy (token); 3147 token = NULL; 3148 } 3149 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3150 3151 return status; 3152} 3153 3154/** 3155 * cr_parser_parse_declaration: 3156 *@a_this: the "this pointer" of the current instance of #CRParser. 3157 *@a_property: the successfully parsed property. The caller 3158 * *must* free the returned pointer. 3159 *@a_expr: the expression that represents the attribute value. 3160 *The caller *must* free the returned pointer. 3161 * 3162 *TODO: return the parsed priority, so that 3163 *upper layers can take benefit from it. 3164 *Parses a "declaration" as defined by the css2 spec in appendix D.1: 3165 *declaration ::= [property ':' S* expr prio?]? 3166 * 3167 *Returns CR_OK upon successfull completion, an error code otherwise. 3168 */ 3169enum CRStatus 3170cr_parser_parse_declaration (CRParser * a_this, 3171 CRString ** a_property, 3172 CRTerm ** a_expr, gboolean * a_important) 3173{ 3174 enum CRStatus status = CR_ERROR; 3175 CRInputPos init_pos; 3176 guint32 cur_char = 0; 3177 CRTerm *expr = NULL; 3178 CRString *prio = NULL; 3179 3180 g_return_val_if_fail (a_this && PRIVATE (a_this) 3181 && a_property && a_expr 3182 && a_important, CR_BAD_PARAM_ERROR); 3183 3184 RECORD_INITIAL_POS (a_this, &init_pos); 3185 3186 status = cr_parser_parse_property (a_this, a_property); 3187 3188 if (status == CR_END_OF_INPUT_ERROR) 3189 goto error; 3190 3191 CHECK_PARSING_STATUS_ERR 3192 (a_this, status, FALSE, 3193 "while parsing declaration: next property is malformed", 3194 CR_SYNTAX_ERROR); 3195 3196 READ_NEXT_CHAR (a_this, &cur_char); 3197 3198 if (cur_char != ':') { 3199 status = CR_PARSING_ERROR; 3200 cr_parser_push_error 3201 (a_this, 3202 "while parsing declaration: this char must be ':'", 3203 CR_SYNTAX_ERROR); 3204 goto error; 3205 } 3206 3207 cr_parser_try_to_skip_spaces_and_comments (a_this); 3208 3209 status = cr_parser_parse_expr (a_this, &expr); 3210 3211 CHECK_PARSING_STATUS_ERR 3212 (a_this, status, FALSE, 3213 "while parsing declaration: next expression is malformed", 3214 CR_SYNTAX_ERROR); 3215 3216 cr_parser_try_to_skip_spaces_and_comments (a_this); 3217 status = cr_parser_parse_prio (a_this, &prio); 3218 if (prio) { 3219 cr_string_destroy (prio); 3220 prio = NULL; 3221 *a_important = TRUE; 3222 } else { 3223 *a_important = FALSE; 3224 } 3225 if (*a_expr) { 3226 cr_term_append_term (*a_expr, expr); 3227 expr = NULL; 3228 } else { 3229 *a_expr = expr; 3230 expr = NULL; 3231 } 3232 3233 cr_parser_clear_errors (a_this); 3234 return CR_OK; 3235 3236 error: 3237 3238 if (expr) { 3239 cr_term_destroy (expr); 3240 expr = NULL; 3241 } 3242 3243 if (*a_property) { 3244 cr_string_destroy (*a_property); 3245 *a_property = NULL; 3246 } 3247 3248 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3249 3250 return status; 3251} 3252 3253/** 3254 * cr_parser_parse_statement_core: 3255 *@a_this: the current instance of #CRParser. 3256 * 3257 *Parses a statement as defined by the css core grammar in 3258 *chapter 4.1 of the css2 spec. 3259 *statement : ruleset | at-rule; 3260 * 3261 *Returns CR_OK upon successfull completion, an error code otherwise. 3262 */ 3263enum CRStatus 3264cr_parser_parse_statement_core (CRParser * a_this) 3265{ 3266 CRToken *token = NULL; 3267 CRInputPos init_pos; 3268 enum CRStatus status = CR_ERROR; 3269 3270 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 3271 3272 RECORD_INITIAL_POS (a_this, &init_pos); 3273 3274 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 3275 3276 ENSURE_PARSING_COND (status == CR_OK && token); 3277 3278 switch (token->type) { 3279 case ATKEYWORD_TK: 3280 case IMPORT_SYM_TK: 3281 case PAGE_SYM_TK: 3282 case MEDIA_SYM_TK: 3283 case FONT_FACE_SYM_TK: 3284 case CHARSET_SYM_TK: 3285 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 3286 token = NULL; 3287 status = cr_parser_parse_atrule_core (a_this); 3288 CHECK_PARSING_STATUS (status, TRUE); 3289 break; 3290 3291 default: 3292 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 3293 token = NULL; 3294 status = cr_parser_parse_ruleset_core (a_this); 3295 cr_parser_clear_errors (a_this); 3296 CHECK_PARSING_STATUS (status, TRUE); 3297 } 3298 3299 return CR_OK; 3300 3301 error: 3302 if (token) { 3303 cr_token_destroy (token); 3304 token = NULL; 3305 } 3306 3307 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3308 3309 return status; 3310} 3311 3312/** 3313 * cr_parser_parse_ruleset: 3314 *@a_this: the "this pointer" of the current instance of #CRParser. 3315 * 3316 *Parses a "ruleset" as defined in the css2 spec at appendix D.1. 3317 *ruleset ::= selector [ ',' S* selector ]* 3318 *'{' S* declaration? [ ';' S* declaration? ]* '}' S*; 3319 * 3320 *This methods calls the the SAC handler on the relevant SAC handler 3321 *callbacks whenever it encounters some specific constructions. 3322 *See the documentation of #CRDocHandler (the SAC handler) to know 3323 *when which SAC handler is called. 3324 * 3325 *Returns CR_OK upon successfull completion, an error code otherwise. 3326 */ 3327enum CRStatus 3328cr_parser_parse_ruleset (CRParser * a_this) 3329{ 3330 enum CRStatus status = CR_OK; 3331 CRInputPos init_pos; 3332 guint32 cur_char = 0, 3333 next_char = 0; 3334 CRString *property = NULL; 3335 CRTerm *expr = NULL; 3336 CRSimpleSel *simple_sels = NULL; 3337 CRSelector *selector = NULL; 3338 gboolean start_selector = FALSE, 3339 is_important = FALSE; 3340 3341 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 3342 3343 RECORD_INITIAL_POS (a_this, &init_pos); 3344 3345 status = cr_parser_parse_selector (a_this, &selector); 3346 CHECK_PARSING_STATUS (status, FALSE); 3347 3348 READ_NEXT_CHAR (a_this, &cur_char); 3349 3350 ENSURE_PARSING_COND_ERR 3351 (a_this, cur_char == '{', 3352 "while parsing rulset: current char should be '{'", 3353 CR_SYNTAX_ERROR); 3354 3355 if (PRIVATE (a_this)->sac_handler 3356 && PRIVATE (a_this)->sac_handler->start_selector) { 3357 /* 3358 *the selector is ref counted so that the parser's user 3359 *can choose to keep it. 3360 */ 3361 if (selector) { 3362 cr_selector_ref (selector); 3363 } 3364 3365 PRIVATE (a_this)->sac_handler->start_selector 3366 (PRIVATE (a_this)->sac_handler, selector); 3367 start_selector = TRUE; 3368 } 3369 3370 cr_parser_try_to_skip_spaces_and_comments (a_this); 3371 3372 PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE; 3373 3374 status = cr_parser_parse_declaration (a_this, &property, 3375 &expr, 3376 &is_important); 3377 if (expr) { 3378 cr_term_ref (expr); 3379 } 3380 if (status == CR_OK 3381 && PRIVATE (a_this)->sac_handler 3382 && PRIVATE (a_this)->sac_handler->property) { 3383 PRIVATE (a_this)->sac_handler->property 3384 (PRIVATE (a_this)->sac_handler, property, expr, 3385 is_important); 3386 } 3387 if (status == CR_OK) { 3388 /* 3389 *free the allocated 3390 *'property' and 'term' before parsing 3391 *next declarations. 3392 */ 3393 if (property) { 3394 cr_string_destroy (property); 3395 property = NULL; 3396 } 3397 if (expr) { 3398 cr_term_unref (expr); 3399 expr = NULL; 3400 } 3401 } else {/*status != CR_OK*/ 3402 guint32 c = 0 ; 3403 /* 3404 *test if we have reached '}', which 3405 *would mean that we are parsing an empty ruleset (eg. x{ }) 3406 *In that case, goto end_of_ruleset. 3407 */ 3408 status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ; 3409 if (status == CR_OK && c == '}') { 3410 status = CR_OK ; 3411 goto end_of_ruleset ; 3412 } 3413 } 3414 CHECK_PARSING_STATUS_ERR 3415 (a_this, status, FALSE, 3416 "while parsing ruleset: next construction should be a declaration", 3417 CR_SYNTAX_ERROR); 3418 3419 for (;;) { 3420 PEEK_NEXT_CHAR (a_this, &next_char); 3421 if (next_char != ';') 3422 break; 3423 3424 /*consume the ';' char */ 3425 READ_NEXT_CHAR (a_this, &cur_char); 3426 3427 cr_parser_try_to_skip_spaces_and_comments (a_this); 3428 3429 status = cr_parser_parse_declaration (a_this, &property, 3430 &expr, &is_important); 3431 3432 if (expr) { 3433 cr_term_ref (expr); 3434 } 3435 if (status == CR_OK 3436 && PRIVATE (a_this)->sac_handler 3437 && PRIVATE (a_this)->sac_handler->property) { 3438 PRIVATE (a_this)->sac_handler->property 3439 (PRIVATE (a_this)->sac_handler, 3440 property, expr, is_important); 3441 } 3442 if (property) { 3443 cr_string_destroy (property); 3444 property = NULL; 3445 } 3446 if (expr) { 3447 cr_term_unref (expr); 3448 expr = NULL; 3449 } 3450 } 3451 3452 end_of_ruleset: 3453 cr_parser_try_to_skip_spaces_and_comments (a_this); 3454 READ_NEXT_CHAR (a_this, &cur_char); 3455 ENSURE_PARSING_COND_ERR 3456 (a_this, cur_char == '}', 3457 "while parsing rulset: current char must be a '}'", 3458 CR_SYNTAX_ERROR); 3459 3460 if (PRIVATE (a_this)->sac_handler 3461 && PRIVATE (a_this)->sac_handler->end_selector) { 3462 PRIVATE (a_this)->sac_handler->end_selector 3463 (PRIVATE (a_this)->sac_handler, selector); 3464 start_selector = FALSE; 3465 } 3466 3467 if (expr) { 3468 cr_term_unref (expr); 3469 expr = NULL; 3470 } 3471 3472 if (simple_sels) { 3473 cr_simple_sel_destroy (simple_sels); 3474 simple_sels = NULL; 3475 } 3476 3477 if (selector) { 3478 cr_selector_unref (selector); 3479 selector = NULL; 3480 } 3481 3482 cr_parser_clear_errors (a_this); 3483 PRIVATE (a_this)->state = RULESET_PARSED_STATE; 3484 3485 return CR_OK; 3486 3487 error: 3488 if (start_selector == TRUE 3489 && PRIVATE (a_this)->sac_handler 3490 && PRIVATE (a_this)->sac_handler->error) { 3491 PRIVATE (a_this)->sac_handler->error 3492 (PRIVATE (a_this)->sac_handler); 3493 } 3494 if (expr) { 3495 cr_term_unref (expr); 3496 expr = NULL; 3497 } 3498 if (simple_sels) { 3499 cr_simple_sel_destroy (simple_sels); 3500 simple_sels = NULL; 3501 } 3502 if (property) { 3503 cr_string_destroy (property); 3504 } 3505 if (selector) { 3506 cr_selector_unref (selector); 3507 selector = NULL; 3508 } 3509 3510 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3511 3512 return status; 3513} 3514 3515/** 3516 * cr_parser_parse_import: 3517 *@a_this: the "this pointer" of the current instance 3518 *of #CRParser. 3519 *@a_media_list: out parameter. A linked list of 3520 *#CRString 3521 *Each CRString is a string that contains 3522 *a 'medium' declaration part of the successfully 3523 *parsed 'import' declaration. 3524 *@a_import_string: out parameter. 3525 *A string that contains the 'import 3526 *string". The import string can be either an uri (if it starts with 3527 *the substring "uri(") or a any other css2 string. Note that 3528 * *a_import_string must be initially set to NULL or else, this function 3529 *will return CR_BAD_PARAM_ERROR. 3530 *@a_location: the location (line, column) where the import has been parsed 3531 * 3532 *Parses an 'import' declaration as defined in the css2 spec 3533 *in appendix D.1: 3534 * 3535 *import ::= 3536 *@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S* 3537 * 3538 *Returns CR_OK upon sucessfull completion, an error code otherwise. 3539 */ 3540enum CRStatus 3541cr_parser_parse_import (CRParser * a_this, 3542 GList ** a_media_list, 3543 CRString ** a_import_string, 3544 CRParsingLocation *a_location) 3545{ 3546 enum CRStatus status = CR_OK; 3547 CRInputPos init_pos; 3548 guint32 cur_char = 0, 3549 next_char = 0; 3550 CRString *medium = NULL; 3551 3552 g_return_val_if_fail (a_this 3553 && a_import_string 3554 && (*a_import_string == NULL), 3555 CR_BAD_PARAM_ERROR); 3556 3557 RECORD_INITIAL_POS (a_this, &init_pos); 3558 3559 if (BYTE (a_this, 1, NULL) == '@' 3560 && BYTE (a_this, 2, NULL) == 'i' 3561 && BYTE (a_this, 3, NULL) == 'm' 3562 && BYTE (a_this, 4, NULL) == 'p' 3563 && BYTE (a_this, 5, NULL) == 'o' 3564 && BYTE (a_this, 6, NULL) == 'r' 3565 && BYTE (a_this, 7, NULL) == 't') { 3566 SKIP_CHARS (a_this, 1); 3567 if (a_location) { 3568 cr_parser_get_parsing_location 3569 (a_this, a_location) ; 3570 } 3571 SKIP_CHARS (a_this, 6); 3572 status = CR_OK; 3573 } else { 3574 status = CR_PARSING_ERROR; 3575 goto error; 3576 } 3577 3578 cr_parser_try_to_skip_spaces_and_comments (a_this); 3579 3580 PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE; 3581 3582 PEEK_NEXT_CHAR (a_this, &next_char); 3583 3584 if (next_char == '"' || next_char == '\'') { 3585 status = cr_parser_parse_string (a_this, a_import_string); 3586 3587 CHECK_PARSING_STATUS (status, FALSE); 3588 } else { 3589 status = cr_parser_parse_uri (a_this, a_import_string); 3590 3591 CHECK_PARSING_STATUS (status, FALSE); 3592 } 3593 3594 cr_parser_try_to_skip_spaces_and_comments (a_this); 3595 3596 status = cr_parser_parse_ident (a_this, &medium); 3597 3598 if (status == CR_OK && medium) { 3599 *a_media_list = g_list_append (*a_media_list, medium); 3600 medium = NULL; 3601 } 3602 3603 cr_parser_try_to_skip_spaces_and_comments (a_this); 3604 3605 for (; status == CR_OK;) { 3606 if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, 3607 &next_char)) != CR_OK) { 3608 if (status == CR_END_OF_INPUT_ERROR) { 3609 status = CR_OK; 3610 goto okay; 3611 } 3612 goto error; 3613 } 3614 3615 if (next_char == ',') { 3616 READ_NEXT_CHAR (a_this, &cur_char); 3617 } else { 3618 break; 3619 } 3620 3621 cr_parser_try_to_skip_spaces_and_comments (a_this); 3622 3623 status = cr_parser_parse_ident (a_this, &medium); 3624 3625 cr_parser_try_to_skip_spaces_and_comments (a_this); 3626 3627 if ((status == CR_OK) && medium) { 3628 *a_media_list = g_list_append (*a_media_list, medium); 3629 3630 medium = NULL; 3631 } 3632 3633 CHECK_PARSING_STATUS (status, FALSE); 3634 cr_parser_try_to_skip_spaces_and_comments (a_this); 3635 } 3636 cr_parser_try_to_skip_spaces_and_comments (a_this); 3637 READ_NEXT_CHAR (a_this, &cur_char); 3638 ENSURE_PARSING_COND (cur_char == ';'); 3639 cr_parser_try_to_skip_spaces_and_comments (a_this); 3640 okay: 3641 cr_parser_clear_errors (a_this); 3642 PRIVATE (a_this)->state = IMPORT_PARSED_STATE; 3643 3644 return CR_OK; 3645 3646 error: 3647 3648 if (*a_media_list) { 3649 GList *cur = NULL; 3650 3651 /* 3652 *free each element of *a_media_list. 3653 *Note that each element of *a_medium list *must* 3654 *be a GString* or else, the code that is coming next 3655 *will corrupt the memory and lead to hard to debug 3656 *random crashes. 3657 *This is where C++ and its compile time 3658 *type checking mecanism (through STL containers) would 3659 *have prevented us to go through this hassle. 3660 */ 3661 for (cur = *a_media_list; cur; cur = cur->next) { 3662 if (cur->data) { 3663 cr_string_destroy (cur->data); 3664 } 3665 } 3666 3667 g_list_free (*a_media_list); 3668 *a_media_list = NULL; 3669 } 3670 3671 if (*a_import_string) { 3672 cr_string_destroy (*a_import_string); 3673 *a_import_string = NULL; 3674 } 3675 3676 if (medium) { 3677 cr_string_destroy (medium); 3678 medium = NULL; 3679 } 3680 3681 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3682 3683 return status; 3684} 3685 3686/** 3687 * cr_parser_parse_media: 3688 *@a_this: the "this pointer" of the current instance of #CRParser. 3689 * 3690 *Parses a 'media' declaration as specified in the css2 spec at 3691 *appendix D.1: 3692 * 3693 *media ::= @media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S* 3694 * 3695 *Note that this function calls the required sac handlers during the parsing 3696 *to notify media productions. See #CRDocHandler to know the callback called 3697 *during @media parsing. 3698 * 3699 *Returns CR_OK upon successfull completion, an error code otherwise. 3700 */ 3701enum CRStatus 3702cr_parser_parse_media (CRParser * a_this) 3703{ 3704 enum CRStatus status = CR_OK; 3705 CRInputPos init_pos; 3706 CRToken *token = NULL; 3707 guint32 next_char = 0, 3708 cur_char = 0; 3709 CRString *medium = NULL; 3710 GList *media_list = NULL; 3711 CRParsingLocation location = {0} ; 3712 3713 g_return_val_if_fail (a_this 3714 && PRIVATE (a_this), 3715 CR_BAD_PARAM_ERROR); 3716 3717 RECORD_INITIAL_POS (a_this, &init_pos); 3718 3719 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 3720 &token); 3721 ENSURE_PARSING_COND (status == CR_OK 3722 && token 3723 && token->type == MEDIA_SYM_TK); 3724 cr_parsing_location_copy (&location, &token->location) ; 3725 cr_token_destroy (token); 3726 token = NULL; 3727 3728 cr_parser_try_to_skip_spaces_and_comments (a_this); 3729 3730 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 3731 ENSURE_PARSING_COND (status == CR_OK 3732 && token && token->type == IDENT_TK); 3733 3734 medium = token->u.str; 3735 token->u.str = NULL; 3736 cr_token_destroy (token); 3737 token = NULL; 3738 3739 if (medium) { 3740 media_list = g_list_append (media_list, medium); 3741 medium = NULL; 3742 } 3743 3744 for (; status == CR_OK;) { 3745 cr_parser_try_to_skip_spaces_and_comments (a_this); 3746 PEEK_NEXT_CHAR (a_this, &next_char); 3747 3748 if (next_char == ',') { 3749 READ_NEXT_CHAR (a_this, &cur_char); 3750 } else { 3751 break; 3752 } 3753 3754 cr_parser_try_to_skip_spaces_and_comments (a_this); 3755 3756 status = cr_parser_parse_ident (a_this, &medium); 3757 3758 CHECK_PARSING_STATUS (status, FALSE); 3759 3760 if (medium) { 3761 media_list = g_list_append (media_list, medium); 3762 medium = NULL; 3763 } 3764 } 3765 3766 READ_NEXT_CHAR (a_this, &cur_char); 3767 3768 ENSURE_PARSING_COND (cur_char == '{'); 3769 3770 /* 3771 *call the SAC handler api here. 3772 */ 3773 if (PRIVATE (a_this)->sac_handler 3774 && PRIVATE (a_this)->sac_handler->start_media) { 3775 PRIVATE (a_this)->sac_handler->start_media 3776 (PRIVATE (a_this)->sac_handler, media_list, 3777 &location); 3778 } 3779 3780 cr_parser_try_to_skip_spaces_and_comments (a_this); 3781 3782 PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE; 3783 3784 for (; status == CR_OK;) { 3785 status = cr_parser_parse_ruleset (a_this); 3786 cr_parser_try_to_skip_spaces_and_comments (a_this); 3787 } 3788 3789 READ_NEXT_CHAR (a_this, &cur_char); 3790 3791 ENSURE_PARSING_COND (cur_char == '}'); 3792 3793 /* 3794 *call the right SAC handler api here. 3795 */ 3796 if (PRIVATE (a_this)->sac_handler 3797 && PRIVATE (a_this)->sac_handler->end_media) { 3798 PRIVATE (a_this)->sac_handler->end_media 3799 (PRIVATE (a_this)->sac_handler, media_list); 3800 } 3801 3802 cr_parser_try_to_skip_spaces_and_comments (a_this); 3803 3804 /* 3805 *Then, free the data structures passed to 3806 *the last call to the SAC handler. 3807 */ 3808 if (medium) { 3809 cr_string_destroy (medium); 3810 medium = NULL; 3811 } 3812 3813 if (media_list) { 3814 GList *cur = NULL; 3815 3816 for (cur = media_list; cur; cur = cur->next) { 3817 cr_string_destroy (cur->data); 3818 } 3819 3820 g_list_free (media_list); 3821 media_list = NULL; 3822 } 3823 3824 cr_parser_clear_errors (a_this); 3825 PRIVATE (a_this)->state = MEDIA_PARSED_STATE; 3826 3827 return CR_OK; 3828 3829 error: 3830 3831 if (token) { 3832 cr_token_destroy (token); 3833 token = NULL; 3834 } 3835 3836 if (medium) { 3837 cr_string_destroy (medium); 3838 medium = NULL; 3839 } 3840 3841 if (media_list) { 3842 GList *cur = NULL; 3843 3844 for (cur = media_list; cur; cur = cur->next) { 3845 cr_string_destroy (cur->data); 3846 } 3847 3848 g_list_free (media_list); 3849 media_list = NULL; 3850 } 3851 3852 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 3853 3854 return status; 3855} 3856 3857/** 3858 * cr_parser_parse_page: 3859 *@a_this: the "this pointer" of the current instance of #CRParser. 3860 * 3861 *Parses '@page' rule as specified in the css2 spec in appendix D.1: 3862 *page ::= PAGE_SYM S* IDENT? pseudo_page? S* 3863 *'{' S* declaration [ ';' S* declaration ]* '}' S* 3864 * 3865 *This function also calls the relevant SAC handlers whenever it 3866 *encounters a construction that must 3867 *be reported to the calling application. 3868 * 3869 *Returns CR_OK upon successfull completion, an error code otherwise. 3870 */ 3871enum CRStatus 3872cr_parser_parse_page (CRParser * a_this) 3873{ 3874 enum CRStatus status = CR_OK; 3875 CRInputPos init_pos; 3876 CRToken *token = NULL; 3877 CRTerm *css_expression = NULL; 3878 CRString *page_selector = NULL, 3879 *page_pseudo_class = NULL, 3880 *property = NULL; 3881 gboolean important = TRUE; 3882 CRParsingLocation location = {0} ; 3883 3884 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 3885 3886 RECORD_INITIAL_POS (a_this, &init_pos); 3887 3888 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 3889 &token) ; 3890 ENSURE_PARSING_COND (status == CR_OK 3891 && token 3892 && token->type == PAGE_SYM_TK); 3893 3894 cr_parsing_location_copy (&location, &token->location) ; 3895 cr_token_destroy (token); 3896 token = NULL; 3897 3898 cr_parser_try_to_skip_spaces_and_comments (a_this); 3899 3900 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 3901 ENSURE_PARSING_COND (status == CR_OK && token); 3902 3903 if (token->type == IDENT_TK) { 3904 page_selector = token->u.str; 3905 token->u.str = NULL; 3906 cr_token_destroy (token); 3907 token = NULL; 3908 } else { 3909 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 3910 token = NULL; 3911 } 3912 3913 /* 3914 *try to parse pseudo_page 3915 */ 3916 cr_parser_try_to_skip_spaces_and_comments (a_this); 3917 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 3918 ENSURE_PARSING_COND (status == CR_OK && token); 3919 3920 if (token->type == DELIM_TK && token->u.unichar == ':') { 3921 cr_token_destroy (token); 3922 token = NULL; 3923 status = cr_parser_parse_ident (a_this, &page_pseudo_class); 3924 CHECK_PARSING_STATUS (status, FALSE); 3925 } else { 3926 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 3927 token = NULL; 3928 } 3929 3930 /* 3931 *parse_block 3932 * 3933 */ 3934 cr_parser_try_to_skip_spaces_and_comments (a_this); 3935 3936 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 3937 3938 ENSURE_PARSING_COND (status == CR_OK && token 3939 && token->type == CBO_TK); 3940 3941 cr_token_destroy (token); 3942 token = NULL; 3943 3944 /* 3945 *Call the appropriate SAC handler here. 3946 */ 3947 if (PRIVATE (a_this)->sac_handler 3948 && PRIVATE (a_this)->sac_handler->start_page) { 3949 PRIVATE (a_this)->sac_handler->start_page 3950 (PRIVATE (a_this)->sac_handler, 3951 page_selector, page_pseudo_class, 3952 &location); 3953 } 3954 cr_parser_try_to_skip_spaces_and_comments (a_this); 3955 3956 PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE; 3957 3958 status = cr_parser_parse_declaration (a_this, &property, 3959 &css_expression, 3960 &important); 3961 ENSURE_PARSING_COND (status == CR_OK); 3962 3963 /* 3964 *call the relevant SAC handler here... 3965 */ 3966 if (PRIVATE (a_this)->sac_handler 3967 && PRIVATE (a_this)->sac_handler->property) { 3968 if (css_expression) 3969 cr_term_ref (css_expression); 3970 3971 PRIVATE (a_this)->sac_handler->property 3972 (PRIVATE (a_this)->sac_handler, 3973 property, css_expression, important); 3974 } 3975 /* 3976 *... and free the data structure passed to that last 3977 *SAC handler. 3978 */ 3979 if (property) { 3980 cr_string_destroy (property); 3981 property = NULL; 3982 } 3983 if (css_expression) { 3984 cr_term_unref (css_expression); 3985 css_expression = NULL; 3986 } 3987 3988 for (;;) { 3989 /*parse the other ';' separated declarations */ 3990 if (token) { 3991 cr_token_destroy (token); 3992 token = NULL; 3993 } 3994 status = cr_tknzr_get_next_token 3995 (PRIVATE (a_this)->tknzr, &token); 3996 3997 ENSURE_PARSING_COND (status == CR_OK && token); 3998 3999 if (token->type != SEMICOLON_TK) { 4000 cr_tknzr_unget_token 4001 (PRIVATE (a_this)->tknzr, 4002 token); 4003 token = NULL ; 4004 break; 4005 } 4006 4007 cr_token_destroy (token); 4008 token = NULL; 4009 cr_parser_try_to_skip_spaces_and_comments (a_this); 4010 4011 status = cr_parser_parse_declaration (a_this, &property, 4012 &css_expression, 4013 &important); 4014 if (status != CR_OK) 4015 break ; 4016 4017 /* 4018 *call the relevant SAC handler here... 4019 */ 4020 if (PRIVATE (a_this)->sac_handler 4021 && PRIVATE (a_this)->sac_handler->property) { 4022 cr_term_ref (css_expression); 4023 PRIVATE (a_this)->sac_handler->property 4024 (PRIVATE (a_this)->sac_handler, 4025 property, css_expression, important); 4026 } 4027 /* 4028 *... and free the data structure passed to that last 4029 *SAC handler. 4030 */ 4031 if (property) { 4032 cr_string_destroy (property); 4033 property = NULL; 4034 } 4035 if (css_expression) { 4036 cr_term_unref (css_expression); 4037 css_expression = NULL; 4038 } 4039 } 4040 cr_parser_try_to_skip_spaces_and_comments 4041 (a_this) ; 4042 if (token) { 4043 cr_token_destroy (token) ; 4044 token = NULL ; 4045 } 4046 4047 status = cr_tknzr_get_next_token 4048 (PRIVATE (a_this)->tknzr, &token); 4049 ENSURE_PARSING_COND (status == CR_OK 4050 && token 4051 && token->type == CBC_TK) ; 4052 cr_token_destroy (token) ; 4053 token = NULL ; 4054 /* 4055 *call the relevant SAC handler here. 4056 */ 4057 if (PRIVATE (a_this)->sac_handler 4058 && PRIVATE (a_this)->sac_handler->end_page) { 4059 PRIVATE (a_this)->sac_handler->end_page 4060 (PRIVATE (a_this)->sac_handler, 4061 page_selector, page_pseudo_class); 4062 } 4063 4064 if (page_selector) { 4065 cr_string_destroy (page_selector); 4066 page_selector = NULL; 4067 } 4068 4069 if (page_pseudo_class) { 4070 cr_string_destroy (page_pseudo_class); 4071 page_pseudo_class = NULL; 4072 } 4073 4074 cr_parser_try_to_skip_spaces_and_comments (a_this); 4075 4076 /*here goes the former implem of this function ... */ 4077 4078 cr_parser_clear_errors (a_this); 4079 PRIVATE (a_this)->state = PAGE_PARSED_STATE; 4080 4081 return CR_OK; 4082 4083 error: 4084 if (token) { 4085 cr_token_destroy (token); 4086 token = NULL; 4087 } 4088 if (page_selector) { 4089 cr_string_destroy (page_selector); 4090 page_selector = NULL; 4091 } 4092 if (page_pseudo_class) { 4093 cr_string_destroy (page_pseudo_class); 4094 page_pseudo_class = NULL; 4095 } 4096 if (property) { 4097 cr_string_destroy (property); 4098 property = NULL; 4099 } 4100 if (css_expression) { 4101 cr_term_destroy (css_expression); 4102 css_expression = NULL; 4103 } 4104 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 4105 return status; 4106} 4107 4108/** 4109 * cr_parser_parse_charset: 4110 *@a_this: the "this pointer" of the current instance of #CRParser. 4111 *@a_value: out parameter. The actual parsed value of the charset 4112 *declararation. Note that for safety check reasons, *a_value must be 4113 *set to NULL. 4114 *@a_charset_sym_location: the parsing location of the charset rule 4115 * 4116 *Parses a charset declaration as defined implictly by the css2 spec in 4117 *appendix D.1: 4118 *charset ::= CHARSET_SYM S* STRING S* ';' 4119 * 4120 *Returns CR_OK upon successfull completion, an error code otherwise. 4121 */ 4122enum CRStatus 4123cr_parser_parse_charset (CRParser * a_this, CRString ** a_value, 4124 CRParsingLocation *a_charset_sym_location) 4125{ 4126 enum CRStatus status = CR_OK; 4127 CRInputPos init_pos; 4128 CRToken *token = NULL; 4129 CRString *charset_str = NULL; 4130 4131 g_return_val_if_fail (a_this && a_value 4132 && (*a_value == NULL), 4133 CR_BAD_PARAM_ERROR); 4134 4135 RECORD_INITIAL_POS (a_this, &init_pos); 4136 4137 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 4138 4139 ENSURE_PARSING_COND (status == CR_OK 4140 && token && token->type == CHARSET_SYM_TK); 4141 if (a_charset_sym_location) { 4142 cr_parsing_location_copy (a_charset_sym_location, 4143 &token->location) ; 4144 } 4145 cr_token_destroy (token); 4146 token = NULL; 4147 4148 PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE; 4149 4150 cr_parser_try_to_skip_spaces_and_comments (a_this); 4151 4152 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 4153 ENSURE_PARSING_COND (status == CR_OK 4154 && token && token->type == STRING_TK); 4155 charset_str = token->u.str; 4156 token->u.str = NULL; 4157 cr_token_destroy (token); 4158 token = NULL; 4159 4160 cr_parser_try_to_skip_spaces_and_comments (a_this); 4161 4162 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 4163 4164 ENSURE_PARSING_COND (status == CR_OK 4165 && token && token->type == SEMICOLON_TK); 4166 cr_token_destroy (token); 4167 token = NULL; 4168 4169 if (charset_str) { 4170 *a_value = charset_str; 4171 charset_str = NULL; 4172 } 4173 4174 PRIVATE (a_this)->state = CHARSET_PARSED_STATE; 4175 return CR_OK; 4176 4177 error: 4178 4179 if (token) { 4180 cr_token_destroy (token); 4181 token = NULL; 4182 } 4183 4184 if (*a_value) { 4185 cr_string_destroy (*a_value); 4186 *a_value = NULL; 4187 } 4188 4189 if (charset_str) { 4190 cr_string_destroy (charset_str); 4191 charset_str = NULL; 4192 } 4193 4194 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 4195 4196 return status; 4197} 4198 4199/** 4200 * cr_parser_parse_font_face: 4201 *@a_this: the current instance of #CRParser. 4202 * 4203 *Parses the "@font-face" rule specified in the css1 spec in 4204 *appendix D.1: 4205 * 4206 *font_face ::= FONT_FACE_SYM S* 4207 *'{' S* declaration [ ';' S* declaration ]* '}' S* 4208 * 4209 *This function will call SAC handlers whenever it is necessary. 4210 * 4211 *Returns CR_OK upon successfull completion, an error code otherwise. 4212 */ 4213enum CRStatus 4214cr_parser_parse_font_face (CRParser * a_this) 4215{ 4216 enum CRStatus status = CR_ERROR; 4217 CRInputPos init_pos; 4218 CRString *property = NULL; 4219 CRTerm *css_expression = NULL; 4220 CRToken *token = NULL; 4221 gboolean important = FALSE; 4222 guint32 next_char = 0, 4223 cur_char = 0; 4224 CRParsingLocation location = {0} ; 4225 4226 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 4227 4228 RECORD_INITIAL_POS (a_this, &init_pos); 4229 4230 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 4231 ENSURE_PARSING_COND (status == CR_OK 4232 && token 4233 && token->type == FONT_FACE_SYM_TK); 4234 4235 cr_parser_try_to_skip_spaces_and_comments (a_this); 4236 if (token) { 4237 cr_parsing_location_copy (&location, 4238 &token->location) ; 4239 cr_token_destroy (token); 4240 token = NULL; 4241 } 4242 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 4243 &token); 4244 ENSURE_PARSING_COND (status == CR_OK && token 4245 && token->type == CBO_TK); 4246 if (token) { 4247 cr_token_destroy (token); 4248 token = NULL; 4249 } 4250 /* 4251 *here, call the relevant SAC handler. 4252 */ 4253 if (PRIVATE (a_this)->sac_handler 4254 && PRIVATE (a_this)->sac_handler->start_font_face) { 4255 PRIVATE (a_this)->sac_handler->start_font_face 4256 (PRIVATE (a_this)->sac_handler, &location); 4257 } 4258 PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE; 4259 /* 4260 *and resume the parsing. 4261 */ 4262 cr_parser_try_to_skip_spaces_and_comments (a_this); 4263 status = cr_parser_parse_declaration (a_this, &property, 4264 &css_expression, &important); 4265 if (status == CR_OK) { 4266 /* 4267 *here, call the relevant SAC handler. 4268 */ 4269 cr_term_ref (css_expression); 4270 if (PRIVATE (a_this)->sac_handler && 4271 PRIVATE (a_this)->sac_handler->property) { 4272 PRIVATE (a_this)->sac_handler->property 4273 (PRIVATE (a_this)->sac_handler, 4274 property, css_expression, important); 4275 } 4276 ENSURE_PARSING_COND (css_expression && property); 4277 } 4278 /*free the data structures allocated during last parsing. */ 4279 if (property) { 4280 cr_string_destroy (property); 4281 property = NULL; 4282 } 4283 if (css_expression) { 4284 cr_term_unref (css_expression); 4285 css_expression = NULL; 4286 } 4287 for (;;) { 4288 PEEK_NEXT_CHAR (a_this, &next_char); 4289 if (next_char == ';') { 4290 READ_NEXT_CHAR (a_this, &cur_char); 4291 } else { 4292 break; 4293 } 4294 cr_parser_try_to_skip_spaces_and_comments (a_this); 4295 status = cr_parser_parse_declaration (a_this, 4296 &property, 4297 &css_expression, 4298 &important); 4299 if (status != CR_OK) 4300 break; 4301 /* 4302 *here, call the relevant SAC handler. 4303 */ 4304 cr_term_ref (css_expression); 4305 if (PRIVATE (a_this)->sac_handler->property) { 4306 PRIVATE (a_this)->sac_handler->property 4307 (PRIVATE (a_this)->sac_handler, 4308 property, css_expression, important); 4309 } 4310 /* 4311 *Then, free the data structures allocated during 4312 *last parsing. 4313 */ 4314 if (property) { 4315 cr_string_destroy (property); 4316 property = NULL; 4317 } 4318 if (css_expression) { 4319 cr_term_unref (css_expression); 4320 css_expression = NULL; 4321 } 4322 } 4323 cr_parser_try_to_skip_spaces_and_comments (a_this); 4324 READ_NEXT_CHAR (a_this, &cur_char); 4325 ENSURE_PARSING_COND (cur_char == '}'); 4326 /* 4327 *here, call the relevant SAC handler. 4328 */ 4329 if (PRIVATE (a_this)->sac_handler->end_font_face) { 4330 PRIVATE (a_this)->sac_handler->end_font_face 4331 (PRIVATE (a_this)->sac_handler); 4332 } 4333 cr_parser_try_to_skip_spaces_and_comments (a_this); 4334 4335 if (token) { 4336 cr_token_destroy (token); 4337 token = NULL; 4338 } 4339 cr_parser_clear_errors (a_this); 4340 PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE; 4341 return CR_OK; 4342 4343 error: 4344 if (token) { 4345 cr_token_destroy (token); 4346 token = NULL; 4347 } 4348 if (property) { 4349 cr_string_destroy (property); 4350 property = NULL; 4351 } 4352 if (css_expression) { 4353 cr_term_destroy (css_expression); 4354 css_expression = NULL; 4355 } 4356 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 4357 return status; 4358} 4359 4360/** 4361 * cr_parser_parse: 4362 *@a_this: the current instance of #CRParser. 4363 * 4364 *Parses the data that comes from the 4365 *input previously associated to the current instance of 4366 *#CRParser. 4367 * 4368 *Returns CR_OK upon succesful completion, an error code otherwise. 4369 */ 4370enum CRStatus 4371cr_parser_parse (CRParser * a_this) 4372{ 4373 enum CRStatus status = CR_ERROR; 4374 4375 g_return_val_if_fail (a_this && PRIVATE (a_this) 4376 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 4377 4378 if (PRIVATE (a_this)->use_core_grammar == FALSE) { 4379 status = cr_parser_parse_stylesheet (a_this); 4380 } else { 4381 status = cr_parser_parse_stylesheet_core (a_this); 4382 } 4383 4384 return status; 4385} 4386 4387/** 4388 * cr_parser_set_tknzr: 4389 * @a_this: the current instance of #CRParser; 4390 * @a_tknzr: the new tokenizer. 4391 * 4392 * Returns CR_OK upon successful completion, an error code otherwise. 4393 */ 4394enum CRStatus 4395cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr) 4396{ 4397 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 4398 4399 if (PRIVATE (a_this)->tknzr) { 4400 cr_tknzr_unref (PRIVATE (a_this)->tknzr); 4401 } 4402 4403 PRIVATE (a_this)->tknzr = a_tknzr; 4404 4405 if (a_tknzr) 4406 cr_tknzr_ref (a_tknzr); 4407 4408 return CR_OK; 4409} 4410 4411/** 4412 * cr_parser_get_tknzr: 4413 *@a_this: the current instance of #CRParser 4414 *@a_tknzr: out parameter. The returned tokenizer 4415 * 4416 *Getter of the parser's underlying tokenizer 4417 * 4418 *Returns CR_OK upon succesful completion, an error code 4419 *otherwise 4420 */ 4421enum CRStatus 4422cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr) 4423{ 4424 g_return_val_if_fail (a_this && PRIVATE (a_this) 4425 && a_tknzr, CR_BAD_PARAM_ERROR); 4426 4427 *a_tknzr = PRIVATE (a_this)->tknzr; 4428 return CR_OK; 4429} 4430 4431/** 4432 * cr_parser_get_parsing_location: 4433 *@a_this: the current instance of #CRParser 4434 *@a_loc: the parsing location to get. 4435 * 4436 *Gets the current parsing location. 4437 * 4438 *Returns CR_OK upon succesful completion, an error code 4439 *otherwise. 4440 */ 4441enum CRStatus 4442cr_parser_get_parsing_location (CRParser *a_this, 4443 CRParsingLocation *a_loc) 4444{ 4445 g_return_val_if_fail (a_this 4446 && PRIVATE (a_this) 4447 && a_loc, CR_BAD_PARAM_ERROR) ; 4448 4449 return cr_tknzr_get_parsing_location 4450 (PRIVATE (a_this)->tknzr, a_loc) ; 4451} 4452 4453/** 4454 * cr_parser_parse_buf: 4455 *@a_this: the current instance of #CRparser 4456 *@a_buf: the input buffer 4457 *@a_len: the length of the input buffer 4458 *@a_enc: the encoding of the buffer 4459 * 4460 *Parses a stylesheet from a buffer 4461 * 4462 *Returns CR_OK upon successful completion, an error code otherwise. 4463 */ 4464enum CRStatus 4465cr_parser_parse_buf (CRParser * a_this, 4466 const guchar * a_buf, 4467 gulong a_len, enum CREncoding a_enc) 4468{ 4469 enum CRStatus status = CR_ERROR; 4470 CRTknzr *tknzr = NULL; 4471 4472 g_return_val_if_fail (a_this && PRIVATE (a_this) 4473 && a_buf, CR_BAD_PARAM_ERROR); 4474 4475 tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE); 4476 4477 g_return_val_if_fail (tknzr != NULL, CR_ERROR); 4478 4479 status = cr_parser_set_tknzr (a_this, tknzr); 4480 g_return_val_if_fail (status == CR_OK, CR_ERROR); 4481 4482 status = cr_parser_parse (a_this); 4483 4484 return status; 4485} 4486 4487/** 4488 * cr_parser_destroy: 4489 *@a_this: the current instance of #CRParser to 4490 *destroy. 4491 * 4492 *Destroys the current instance 4493 *of #CRParser. 4494 */ 4495void 4496cr_parser_destroy (CRParser * a_this) 4497{ 4498 g_return_if_fail (a_this && PRIVATE (a_this)); 4499 4500 if (PRIVATE (a_this)->tknzr) { 4501 if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE) 4502 PRIVATE (a_this)->tknzr = NULL; 4503 } 4504 4505 if (PRIVATE (a_this)->sac_handler) { 4506 cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); 4507 PRIVATE (a_this)->sac_handler = NULL; 4508 } 4509 4510 if (PRIVATE (a_this)->err_stack) { 4511 cr_parser_clear_errors (a_this); 4512 PRIVATE (a_this)->err_stack = NULL; 4513 } 4514 4515 if (PRIVATE (a_this)) { 4516 g_free (PRIVATE (a_this)); 4517 PRIVATE (a_this) = NULL; 4518 } 4519 4520 if (a_this) { 4521 g_free (a_this); 4522 a_this = NULL; /*useless. Just for the sake of coherence */ 4523 } 4524} 4525