Libcroco
|
00001 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */ 00002 00003 /* 00004 * This file is part of The Croco Library 00005 * 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of version 2.1 of the 00009 * GNU Lesser General Public 00010 * License as published by the Free Software Foundation. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00020 * USA 00021 * 00022 * Author: Dodji Seketeli 00023 * See COPYRIGHTS file for copyrights information. 00024 */ 00025 00026 /** 00027 *@CRParser: 00028 * 00029 *The definition of the #CRParser class. 00030 */ 00031 00032 #include "string.h" 00033 #include "cr-parser.h" 00034 #include "cr-num.h" 00035 #include "cr-term.h" 00036 #include "cr-simple-sel.h" 00037 #include "cr-attr-sel.h" 00038 00039 /* 00040 *Random notes: 00041 *CSS core syntax vs CSS level 2 syntax 00042 *===================================== 00043 * 00044 *One must keep in mind 00045 *that css UA must comply with two syntaxes. 00046 * 00047 *1/the specific syntax that defines the css language 00048 *for a given level of specificatin (e.g css2 syntax 00049 *defined in appendix D.1 of the css2 spec) 00050 * 00051 *2/the core (general) syntax that is there to allow 00052 *UAs to parse style sheets written in levels of CSS that 00053 *didn't exist at the time the UAs were created. 00054 * 00055 *the name of parsing functions (or methods) contained in this file 00056 *follows the following scheme: cr_parser_parse_<production_name> (...) ; 00057 *where <production_name> is the name 00058 *of a production of the css2 language. 00059 *When a given production is 00060 *defined by the css2 level grammar *and* by the 00061 *css core syntax, there will be two functions to parse that production: 00062 *one will parse the production defined by the css2 level grammar and the 00063 *other will parse the production defined by the css core grammar. 00064 *The css2 level grammar related parsing function will be called: 00065 *cr_parser_parse_<production_name> (...) ; 00066 *Then css core grammar related parsing function will be called: 00067 *cr_parser_parse_<production_name>_core (...) ; 00068 * 00069 *If a production is defined only by the css core grammar, then 00070 *it will be named: 00071 *cr_parser_parse_<production_name>_core (...) ; 00072 */ 00073 00074 typedef struct _CRParserError CRParserError; 00075 00076 /** 00077 *An abstraction of an error reported by by the 00078 *parsing routines. 00079 */ 00080 struct _CRParserError { 00081 guchar *msg; 00082 enum CRStatus status; 00083 glong line; 00084 glong column; 00085 glong byte_num; 00086 }; 00087 00088 enum CRParserState { 00089 READY_STATE = 0, 00090 TRY_PARSE_CHARSET_STATE, 00091 CHARSET_PARSED_STATE, 00092 TRY_PARSE_IMPORT_STATE, 00093 IMPORT_PARSED_STATE, 00094 TRY_PARSE_RULESET_STATE, 00095 RULESET_PARSED_STATE, 00096 TRY_PARSE_MEDIA_STATE, 00097 MEDIA_PARSED_STATE, 00098 TRY_PARSE_PAGE_STATE, 00099 PAGE_PARSED_STATE, 00100 TRY_PARSE_FONT_FACE_STATE, 00101 FONT_FACE_PARSED_STATE 00102 } ; 00103 00104 /** 00105 *The private attributes of 00106 *#CRParser. 00107 */ 00108 struct _CRParserPriv { 00109 /** 00110 *The tokenizer 00111 */ 00112 CRTknzr *tknzr; 00113 00114 /** 00115 *The sac handlers to call 00116 *to notify the parsing of 00117 *the css2 constructions. 00118 */ 00119 CRDocHandler *sac_handler; 00120 00121 /** 00122 *A stack of errors reported 00123 *by the parsing routines. 00124 *Contains instance of #CRParserError. 00125 *This pointer is the top of the stack. 00126 */ 00127 GList *err_stack; 00128 00129 enum CRParserState state; 00130 gboolean resolve_import; 00131 gboolean is_case_sensitive; 00132 gboolean use_core_grammar; 00133 }; 00134 00135 #define PRIVATE(obj) ((obj)->priv) 00136 00137 #define CHARS_TAB_SIZE 12 00138 00139 /** 00140 * IS_NUM: 00141 *@a_char: the char to test. 00142 *return TRUE if the character is a number ([0-9]), FALSE otherwise 00143 */ 00144 #define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE) 00145 00146 /** 00147 *Checks if 'status' equals CR_OK. If not, goto the 'error' label. 00148 * 00149 *@param status the status (of type enum CRStatus) to test. 00150 *@param is_exception if set to FALSE, the final status returned 00151 *by the current function will be CR_PARSING_ERROR. If set to TRUE, the 00152 *current status will be the current value of the 'status' variable. 00153 * 00154 */ 00155 #define CHECK_PARSING_STATUS(status, is_exception) \ 00156 if ((status) != CR_OK) \ 00157 { \ 00158 if (is_exception == FALSE) \ 00159 { \ 00160 status = CR_PARSING_ERROR ; \ 00161 } \ 00162 goto error ; \ 00163 } 00164 00165 /** 00166 * CHECK_PARSING_STATUS_ERR: 00167 *@a_this: the current instance of #CRParser . 00168 *@a_status: the status to check. Is of type enum #CRStatus. 00169 *@a_is_exception: in case of error, if is TRUE, the status 00170 *is set to CR_PARSING_ERROR before goto error. If is false, the 00171 *real low level status is kept and will be returned by the 00172 *upper level function that called this macro. Usally,this must 00173 *be set to FALSE. 00174 * 00175 *same as CHECK_PARSING_STATUS() but this one pushes an error 00176 *on the parser error stack when an error arises. 00177 * 00178 */ 00179 #define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\ 00180 a_err_msg, a_err_status) \ 00181 if ((a_status) != CR_OK) \ 00182 { \ 00183 if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \ 00184 cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ 00185 goto error ; \ 00186 } 00187 00188 /** 00189 *Peeks the next char from the input stream of the current parser 00190 *by invoking cr_tknzr_input_peek_char(). 00191 *invokes CHECK_PARSING_STATUS on the status returned by 00192 *cr_tknzr_peek_char(). 00193 * 00194 *@param a_this the current instance of #CRParser. 00195 *@param a_to_char a pointer to the char where to store the 00196 *char peeked. 00197 */ 00198 #define PEEK_NEXT_CHAR(a_this, a_to_char) \ 00199 {\ 00200 enum CRStatus pnc_status ; \ 00201 pnc_status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ 00202 CHECK_PARSING_STATUS (pnc_status, TRUE) \ 00203 } 00204 00205 /** 00206 *Reads the next char from the input stream of the current parser. 00207 *In case of error, jumps to the "error:" label located in the 00208 *function where this macro is called. 00209 *@param a_this the curent instance of #CRParser 00210 *@param to_char a pointer to the guint32 char where to store 00211 *the character read. 00212 */ 00213 #define READ_NEXT_CHAR(a_this, a_to_char) \ 00214 status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ 00215 CHECK_PARSING_STATUS (status, TRUE) 00216 00217 /** 00218 *Gets information about the current position in 00219 *the input of the parser. 00220 *In case of failure, this macro returns from the 00221 *calling function and 00222 *returns a status code of type enum #CRStatus. 00223 *@param a_this the current instance of #CRParser. 00224 *@param a_pos out parameter. A pointer to the position 00225 *inside the current parser input. Must 00226 */ 00227 #define RECORD_INITIAL_POS(a_this, a_pos) \ 00228 status = cr_tknzr_get_cur_pos (PRIVATE \ 00229 (a_this)->tknzr, a_pos) ; \ 00230 g_return_val_if_fail (status == CR_OK, status) 00231 00232 /** 00233 *Gets the address of the current byte inside the 00234 *parser input. 00235 *@param parser the current instance of #CRParser. 00236 *@param addr out parameter a pointer (guchar*) 00237 *to where the address must be put. 00238 */ 00239 #define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \ 00240 status = cr_tknzr_get_cur_byte_addr \ 00241 (PRIVATE (a_this)->tknzr, a_addr) ; \ 00242 CHECK_PARSING_STATUS (status, TRUE) 00243 00244 /** 00245 *Peeks a byte from the topmost parser input at 00246 *a given offset from the current position. 00247 *If it fails, goto the "error:" label. 00248 * 00249 *@param a_parser the current instance of #CRParser. 00250 *@param a_offset the offset of the byte to peek, the 00251 *current byte having the offset '0'. 00252 *@param a_byte_ptr out parameter a pointer (guchar*) to 00253 *where the peeked char is to be stored. 00254 */ 00255 #define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \ 00256 status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \ 00257 a_offset, \ 00258 a_byte_ptr) ; \ 00259 CHECK_PARSING_STATUS (status, TRUE) ; 00260 00261 #define BYTE(a_parser, a_offset, a_eof) \ 00262 cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof) 00263 00264 /** 00265 *Reads a byte from the topmost parser input 00266 *steam. 00267 *If it fails, goto the "error" label. 00268 *@param a_this the current instance of #CRParser. 00269 *@param a_byte_ptr the guchar * where to put the read char. 00270 */ 00271 #define READ_NEXT_BYTE(a_this, a_byte_ptr) \ 00272 status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \ 00273 CHECK_PARSING_STATUS (status, TRUE) ; 00274 00275 /** 00276 *Skips a given number of byte in the topmost 00277 *parser input. Don't update line and column number. 00278 *In case of error, jumps to the "error:" label 00279 *of the surrounding function. 00280 *@param a_parser the current instance of #CRParser. 00281 *@param a_nb_bytes the number of bytes to skip. 00282 */ 00283 #define SKIP_BYTES(a_this, a_nb_bytes) \ 00284 status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \ 00285 CR_SEEK_CUR, a_nb_bytes) ; \ 00286 CHECK_PARSING_STATUS (status, TRUE) ; 00287 00288 /** 00289 *Skip utf8 encoded characters. 00290 *Updates line and column numbers. 00291 *@param a_parser the current instance of #CRParser. 00292 *@param a_nb_chars the number of chars to skip. Must be of 00293 *type glong. 00294 */ 00295 #define SKIP_CHARS(a_parser, a_nb_chars) \ 00296 { \ 00297 glong nb_chars = a_nb_chars ; \ 00298 status = cr_tknzr_consume_chars \ 00299 (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \ 00300 CHECK_PARSING_STATUS (status, TRUE) ; \ 00301 } 00302 00303 /** 00304 *Tests the condition and if it is false, sets 00305 *status to "CR_PARSING_ERROR" and goto the 'error' 00306 *label. 00307 *@param condition the condition to test. 00308 */ 00309 #define ENSURE_PARSING_COND(condition) \ 00310 if (! (condition)) {status = CR_PARSING_ERROR; goto error ;} 00311 00312 #define ENSURE_PARSING_COND_ERR(a_this, a_condition, \ 00313 a_err_msg, a_err_status) \ 00314 if (! (a_condition)) \ 00315 { \ 00316 status = CR_PARSING_ERROR; \ 00317 cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \ 00318 goto error ; \ 00319 } 00320 00321 #define GET_NEXT_TOKEN(a_this, a_token_ptr) \ 00322 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \ 00323 a_token_ptr) ; \ 00324 ENSURE_PARSING_COND (status == CR_OK) ; 00325 00326 #ifdef WITH_UNICODE_ESCAPE_AND_RANGE 00327 static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this, 00328 guint32 * a_unicode); 00329 static enum CRStatus cr_parser_parse_escape (CRParser * a_this, 00330 guint32 * a_esc_code); 00331 00332 static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this, 00333 CRString ** a_inf, 00334 CRString ** a_sup); 00335 #endif 00336 00337 static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this); 00338 00339 static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this); 00340 00341 static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this); 00342 00343 static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); 00344 00345 static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); 00346 00347 static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); 00348 00349 static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); 00350 00351 static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); 00352 00353 static enum CRStatus cr_parser_parse_string (CRParser * a_this, 00354 CRString ** a_str); 00355 00356 static enum CRStatus cr_parser_parse_ident (CRParser * a_this, 00357 CRString ** a_str); 00358 00359 static enum CRStatus cr_parser_parse_uri (CRParser * a_this, 00360 CRString ** a_str); 00361 00362 static enum CRStatus cr_parser_parse_function (CRParser * a_this, 00363 CRString ** a_func_name, 00364 CRTerm ** a_expr); 00365 static enum CRStatus cr_parser_parse_property (CRParser * a_this, 00366 CRString ** a_property); 00367 00368 static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this, 00369 CRAttrSel ** a_sel); 00370 00371 static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this, 00372 CRSimpleSel ** a_sel); 00373 00374 static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this, 00375 CRSimpleSel ** a_sel); 00376 00377 static CRParserError *cr_parser_error_new (const guchar * a_msg, 00378 enum CRStatus); 00379 00380 static void cr_parser_error_set_msg (CRParserError * a_this, 00381 const guchar * a_msg); 00382 00383 static void cr_parser_error_dump (CRParserError * a_this); 00384 00385 static void cr_parser_error_set_status (CRParserError * a_this, 00386 enum CRStatus a_status); 00387 00388 static void cr_parser_error_set_pos (CRParserError * a_this, 00389 glong a_line, 00390 glong a_column, glong a_byte_num); 00391 static void 00392 cr_parser_error_destroy (CRParserError * a_this); 00393 00394 static enum CRStatus cr_parser_push_error (CRParser * a_this, 00395 const guchar * a_msg, 00396 enum CRStatus a_status); 00397 00398 static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this, 00399 gboolean a_clear_errs); 00400 static enum CRStatus 00401 cr_parser_clear_errors (CRParser * a_this); 00402 00403 /***************************** 00404 *error managemet methods 00405 *****************************/ 00406 00407 /** 00408 *Constructor of #CRParserError class. 00409 *@param a_msg the brute error message. 00410 *@param a_status the error status. 00411 *@return the newly built instance of #CRParserError. 00412 */ 00413 static CRParserError * 00414 cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status) 00415 { 00416 CRParserError *result = NULL; 00417 00418 result = g_try_malloc (sizeof (CRParserError)); 00419 00420 if (result == NULL) { 00421 cr_utils_trace_info ("Out of memory"); 00422 return NULL; 00423 } 00424 00425 memset (result, 0, sizeof (CRParserError)); 00426 00427 cr_parser_error_set_msg (result, a_msg); 00428 cr_parser_error_set_status (result, a_status); 00429 00430 return result; 00431 } 00432 00433 /** 00434 *Sets the message associated to this instance of #CRError. 00435 *@param a_this the current instance of #CRParserError. 00436 *@param a_msg the new message. 00437 */ 00438 static void 00439 cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg) 00440 { 00441 g_return_if_fail (a_this); 00442 00443 if (a_this->msg) { 00444 g_free (a_this->msg); 00445 } 00446 00447 a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg); 00448 } 00449 00450 /** 00451 *Sets the error status. 00452 *@param a_this the current instance of #CRParserError. 00453 *@param a_status the new error status. 00454 * 00455 */ 00456 static void 00457 cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status) 00458 { 00459 g_return_if_fail (a_this); 00460 00461 a_this->status = a_status; 00462 } 00463 00464 /** 00465 *Sets the position of the parser error. 00466 *@param a_this the current instance of #CRParserError. 00467 *@param a_line the line number. 00468 *@param a_column the column number. 00469 *@param a_byte_num the byte number. 00470 */ 00471 static void 00472 cr_parser_error_set_pos (CRParserError * a_this, 00473 glong a_line, glong a_column, glong a_byte_num) 00474 { 00475 g_return_if_fail (a_this); 00476 00477 a_this->line = a_line; 00478 a_this->column = a_column; 00479 a_this->byte_num = a_byte_num; 00480 } 00481 00482 static void 00483 cr_parser_error_dump (CRParserError * a_this) 00484 { 00485 g_return_if_fail (a_this); 00486 00487 g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column); 00488 00489 g_printerr ("%s\n", a_this->msg); 00490 } 00491 00492 /** 00493 *The destructor of #CRParserError. 00494 *@param a_this the current instance of #CRParserError. 00495 */ 00496 static void 00497 cr_parser_error_destroy (CRParserError * a_this) 00498 { 00499 g_return_if_fail (a_this); 00500 00501 if (a_this->msg) { 00502 g_free (a_this->msg); 00503 a_this->msg = NULL; 00504 } 00505 00506 g_free (a_this); 00507 } 00508 00509 /** 00510 *Pushes an error on the parser error stack. 00511 *@param a_this the current instance of #CRParser. 00512 *@param a_msg the error message. 00513 *@param a_status the error status. 00514 *@return CR_OK upon successfull completion, an error code otherwise. 00515 */ 00516 static enum CRStatus 00517 cr_parser_push_error (CRParser * a_this, 00518 const guchar * a_msg, enum CRStatus a_status) 00519 { 00520 enum CRStatus status = CR_OK; 00521 00522 CRParserError *error = NULL; 00523 CRInputPos pos; 00524 00525 g_return_val_if_fail (a_this && PRIVATE (a_this) 00526 && a_msg, CR_BAD_PARAM_ERROR); 00527 00528 error = cr_parser_error_new (a_msg, a_status); 00529 00530 g_return_val_if_fail (error, CR_ERROR); 00531 00532 RECORD_INITIAL_POS (a_this, &pos); 00533 00534 cr_parser_error_set_pos 00535 (error, pos.line, pos.col, pos.next_byte_index - 1); 00536 00537 PRIVATE (a_this)->err_stack = 00538 g_list_prepend (PRIVATE (a_this)->err_stack, error); 00539 00540 if (PRIVATE (a_this)->err_stack == NULL) 00541 goto error; 00542 00543 return CR_OK; 00544 00545 error: 00546 00547 if (error) { 00548 cr_parser_error_destroy (error); 00549 error = NULL; 00550 } 00551 00552 return status; 00553 } 00554 00555 /** 00556 *Dumps the error stack on stdout. 00557 *@param a_this the current instance of #CRParser. 00558 *@param a_clear_errs whether to clear the error stack 00559 *after the dump or not. 00560 *@return CR_OK upon successfull completion, an error code 00561 *otherwise. 00562 */ 00563 static enum CRStatus 00564 cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs) 00565 { 00566 GList *cur = NULL; 00567 00568 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00569 00570 if (PRIVATE (a_this)->err_stack == NULL) 00571 return CR_OK; 00572 00573 for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { 00574 cr_parser_error_dump ((CRParserError *) cur->data); 00575 } 00576 00577 if (a_clear_errs == TRUE) { 00578 cr_parser_clear_errors (a_this); 00579 } 00580 00581 return CR_OK; 00582 } 00583 00584 /** 00585 *Clears all the errors contained in the parser error stack. 00586 *Frees all the errors, and the stack that contains'em. 00587 *@param a_this the current instance of #CRParser. 00588 */ 00589 static enum CRStatus 00590 cr_parser_clear_errors (CRParser * a_this) 00591 { 00592 GList *cur = NULL; 00593 00594 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00595 00596 for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) { 00597 if (cur->data) { 00598 cr_parser_error_destroy ((CRParserError *) 00599 cur->data); 00600 } 00601 } 00602 00603 if (PRIVATE (a_this)->err_stack) { 00604 g_list_free (PRIVATE (a_this)->err_stack); 00605 PRIVATE (a_this)->err_stack = NULL; 00606 } 00607 00608 return CR_OK; 00609 } 00610 00611 /** 00612 * cr_parser_try_to_skip_spaces_and_comments: 00613 *@a_this: the current instance of #CRParser. 00614 * 00615 *Same as cr_parser_try_to_skip_spaces() but this one skips 00616 *spaces and comments. 00617 * 00618 *Returns CR_OK upon successfull completion, an error code otherwise. 00619 */ 00620 enum CRStatus 00621 cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this) 00622 { 00623 enum CRStatus status = CR_ERROR; 00624 CRToken *token = NULL; 00625 00626 g_return_val_if_fail (a_this && PRIVATE (a_this) 00627 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 00628 do { 00629 if (token) { 00630 cr_token_destroy (token); 00631 token = NULL; 00632 } 00633 00634 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 00635 &token); 00636 if (status != CR_OK) 00637 goto error; 00638 } 00639 while ((token != NULL) 00640 && (token->type == COMMENT_TK || token->type == S_TK)); 00641 00642 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 00643 00644 return status; 00645 00646 error: 00647 00648 if (token) { 00649 cr_token_destroy (token); 00650 token = NULL; 00651 } 00652 00653 return status; 00654 } 00655 00656 /*************************************** 00657 *End of Parser input handling routines 00658 ***************************************/ 00659 00660 00661 /************************************* 00662 *Non trivial terminal productions 00663 *parsing routines 00664 *************************************/ 00665 00666 /** 00667 *Parses a css stylesheet following the core css grammar. 00668 *This is mainly done for test purposes. 00669 *During the parsing, no callback is called. This is just 00670 *to validate that the stylesheet is well formed according to the 00671 *css core syntax. 00672 *stylesheet : [ CDO | CDC | S | statement ]*; 00673 *@param a_this the current instance of #CRParser. 00674 *@return CR_OK upon successful completion, an error code otherwise. 00675 */ 00676 static enum CRStatus 00677 cr_parser_parse_stylesheet_core (CRParser * a_this) 00678 { 00679 CRToken *token = NULL; 00680 CRInputPos init_pos; 00681 enum CRStatus status = CR_ERROR; 00682 00683 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00684 00685 RECORD_INITIAL_POS (a_this, &init_pos); 00686 00687 continue_parsing: 00688 00689 if (token) { 00690 cr_token_destroy (token); 00691 token = NULL; 00692 } 00693 00694 cr_parser_try_to_skip_spaces_and_comments (a_this); 00695 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 00696 if (status == CR_END_OF_INPUT_ERROR) { 00697 status = CR_OK; 00698 goto done; 00699 } else if (status != CR_OK) { 00700 goto error; 00701 } 00702 00703 switch (token->type) { 00704 00705 case CDO_TK: 00706 case CDC_TK: 00707 goto continue_parsing; 00708 break; 00709 default: 00710 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 00711 token); 00712 CHECK_PARSING_STATUS (status, TRUE); 00713 token = NULL; 00714 status = cr_parser_parse_statement_core (a_this); 00715 cr_parser_clear_errors (a_this); 00716 if (status == CR_OK) { 00717 goto continue_parsing; 00718 } else if (status == CR_END_OF_INPUT_ERROR) { 00719 goto done; 00720 } else { 00721 goto error; 00722 } 00723 } 00724 00725 done: 00726 if (token) { 00727 cr_token_destroy (token); 00728 token = NULL; 00729 } 00730 00731 cr_parser_clear_errors (a_this); 00732 return CR_OK; 00733 00734 error: 00735 cr_parser_push_error 00736 (a_this, (const guchar *) "could not recognize next production", CR_ERROR); 00737 00738 cr_parser_dump_err_stack (a_this, TRUE); 00739 00740 if (token) { 00741 cr_token_destroy (token); 00742 token = NULL; 00743 } 00744 00745 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 00746 00747 return status; 00748 } 00749 00750 /** 00751 *Parses an at-rule as defined by the css core grammar 00752 *in chapter 4.1 in the css2 spec. 00753 *at-rule : ATKEYWORD S* any* [ block | ';' S* ]; 00754 *@param a_this the current instance of #CRParser. 00755 *@return CR_OK upon successfull completion, an error code 00756 *otherwise. 00757 */ 00758 static enum CRStatus 00759 cr_parser_parse_atrule_core (CRParser * a_this) 00760 { 00761 CRToken *token = NULL; 00762 CRInputPos init_pos; 00763 enum CRStatus status = CR_ERROR; 00764 00765 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00766 00767 RECORD_INITIAL_POS (a_this, &init_pos); 00768 00769 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 00770 &token); 00771 ENSURE_PARSING_COND (status == CR_OK 00772 && token 00773 && 00774 (token->type == ATKEYWORD_TK 00775 || token->type == IMPORT_SYM_TK 00776 || token->type == PAGE_SYM_TK 00777 || token->type == MEDIA_SYM_TK 00778 || token->type == FONT_FACE_SYM_TK 00779 || token->type == CHARSET_SYM_TK)); 00780 00781 cr_token_destroy (token); 00782 token = NULL; 00783 00784 cr_parser_try_to_skip_spaces_and_comments (a_this); 00785 00786 do { 00787 status = cr_parser_parse_any_core (a_this); 00788 } while (status == CR_OK); 00789 00790 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 00791 &token); 00792 ENSURE_PARSING_COND (status == CR_OK && token); 00793 00794 if (token->type == CBO_TK) { 00795 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 00796 token); 00797 token = NULL; 00798 status = cr_parser_parse_block_core (a_this); 00799 CHECK_PARSING_STATUS (status, 00800 FALSE); 00801 goto done; 00802 } else if (token->type == SEMICOLON_TK) { 00803 goto done; 00804 } else { 00805 status = CR_PARSING_ERROR ; 00806 goto error; 00807 } 00808 00809 done: 00810 if (token) { 00811 cr_token_destroy (token); 00812 token = NULL; 00813 } 00814 return CR_OK; 00815 00816 error: 00817 if (token) { 00818 cr_token_destroy (token); 00819 token = NULL; 00820 } 00821 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, 00822 &init_pos); 00823 return status; 00824 } 00825 00826 /** 00827 *Parses a ruleset as defined by the css core grammar in chapter 00828 *4.1 of the css2 spec. 00829 *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*; 00830 *@param a_this the current instance of #CRParser. 00831 *@return CR_OK upon successfull completion, an error code otherwise. 00832 */ 00833 static enum CRStatus 00834 cr_parser_parse_ruleset_core (CRParser * a_this) 00835 { 00836 CRToken *token = NULL; 00837 CRInputPos init_pos; 00838 enum CRStatus status = CR_ERROR; 00839 00840 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00841 RECORD_INITIAL_POS (a_this, &init_pos); 00842 00843 status = cr_parser_parse_selector_core (a_this); 00844 00845 ENSURE_PARSING_COND (status == CR_OK 00846 || status == CR_PARSING_ERROR 00847 || status == CR_END_OF_INPUT_ERROR); 00848 00849 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 00850 ENSURE_PARSING_COND (status == CR_OK && token 00851 && token->type == CBO_TK); 00852 cr_token_destroy (token); 00853 token = NULL; 00854 00855 cr_parser_try_to_skip_spaces_and_comments (a_this); 00856 status = cr_parser_parse_declaration_core (a_this); 00857 00858 parse_declaration_list: 00859 if (token) { 00860 cr_token_destroy (token); 00861 token = NULL; 00862 } 00863 00864 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 00865 ENSURE_PARSING_COND (status == CR_OK && token); 00866 if (token->type == CBC_TK) { 00867 goto done; 00868 } 00869 00870 ENSURE_PARSING_COND (status == CR_OK 00871 && token && token->type == SEMICOLON_TK); 00872 00873 cr_token_destroy (token); 00874 token = NULL; 00875 cr_parser_try_to_skip_spaces_and_comments (a_this); 00876 status = cr_parser_parse_declaration_core (a_this); 00877 cr_parser_clear_errors (a_this); 00878 ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR); 00879 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 00880 ENSURE_PARSING_COND (status == CR_OK && token); 00881 if (token->type == CBC_TK) { 00882 cr_token_destroy (token); 00883 token = NULL; 00884 cr_parser_try_to_skip_spaces_and_comments (a_this); 00885 goto done; 00886 } else { 00887 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 00888 token); 00889 token = NULL; 00890 goto parse_declaration_list; 00891 } 00892 00893 done: 00894 if (token) { 00895 cr_token_destroy (token); 00896 token = NULL; 00897 } 00898 00899 if (status == CR_OK) { 00900 return CR_OK; 00901 } 00902 00903 error: 00904 if (token) { 00905 cr_token_destroy (token); 00906 token = NULL; 00907 } 00908 00909 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 00910 00911 return status; 00912 } 00913 00914 /** 00915 *Parses a "selector" as specified by the css core 00916 *grammar. 00917 *selector : any+; 00918 *@param a_this the current instance of #CRParser. 00919 *@return CR_OK upon successfull completion, an error code 00920 *otherwise. 00921 */ 00922 static enum CRStatus 00923 cr_parser_parse_selector_core (CRParser * a_this) 00924 { 00925 CRToken *token = NULL; 00926 CRInputPos init_pos; 00927 enum CRStatus status = CR_ERROR; 00928 00929 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00930 00931 RECORD_INITIAL_POS (a_this, &init_pos); 00932 00933 status = cr_parser_parse_any_core (a_this); 00934 CHECK_PARSING_STATUS (status, FALSE); 00935 00936 do { 00937 status = cr_parser_parse_any_core (a_this); 00938 00939 } while (status == CR_OK); 00940 00941 return CR_OK; 00942 00943 error: 00944 if (token) { 00945 cr_token_destroy (token); 00946 token = NULL; 00947 } 00948 00949 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 00950 00951 return status; 00952 } 00953 00954 /** 00955 *Parses a "block" as defined in the css core grammar 00956 *in chapter 4.1 of the css2 spec. 00957 *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; 00958 *@param a_this the current instance of #CRParser. 00959 *FIXME: code this function. 00960 */ 00961 static enum CRStatus 00962 cr_parser_parse_block_core (CRParser * a_this) 00963 { 00964 CRToken *token = NULL; 00965 CRInputPos init_pos; 00966 enum CRStatus status = CR_ERROR; 00967 00968 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 00969 00970 RECORD_INITIAL_POS (a_this, &init_pos); 00971 00972 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 00973 ENSURE_PARSING_COND (status == CR_OK && token 00974 && token->type == CBO_TK); 00975 00976 parse_block_content: 00977 00978 if (token) { 00979 cr_token_destroy (token); 00980 token = NULL; 00981 } 00982 00983 cr_parser_try_to_skip_spaces_and_comments (a_this); 00984 00985 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 00986 ENSURE_PARSING_COND (status == CR_OK && token); 00987 00988 if (token->type == CBC_TK) { 00989 cr_parser_try_to_skip_spaces_and_comments (a_this); 00990 goto done; 00991 } else if (token->type == SEMICOLON_TK) { 00992 goto parse_block_content; 00993 } else if (token->type == ATKEYWORD_TK) { 00994 cr_parser_try_to_skip_spaces_and_comments (a_this); 00995 goto parse_block_content; 00996 } else if (token->type == CBO_TK) { 00997 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 00998 token = NULL; 00999 status = cr_parser_parse_block_core (a_this); 01000 CHECK_PARSING_STATUS (status, FALSE); 01001 goto parse_block_content; 01002 } else { 01003 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 01004 token = NULL; 01005 status = cr_parser_parse_any_core (a_this); 01006 CHECK_PARSING_STATUS (status, FALSE); 01007 goto parse_block_content; 01008 } 01009 01010 done: 01011 if (token) { 01012 cr_token_destroy (token); 01013 token = NULL; 01014 } 01015 01016 if (status == CR_OK) 01017 return CR_OK; 01018 01019 error: 01020 if (token) { 01021 cr_token_destroy (token); 01022 token = NULL; 01023 } 01024 01025 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01026 01027 return status; 01028 } 01029 01030 static enum CRStatus 01031 cr_parser_parse_declaration_core (CRParser * a_this) 01032 { 01033 CRToken *token = NULL; 01034 CRInputPos init_pos; 01035 enum CRStatus status = CR_ERROR; 01036 CRString *prop = NULL; 01037 01038 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 01039 01040 RECORD_INITIAL_POS (a_this, &init_pos); 01041 01042 status = cr_parser_parse_property (a_this, &prop); 01043 CHECK_PARSING_STATUS (status, FALSE); 01044 cr_parser_clear_errors (a_this); 01045 ENSURE_PARSING_COND (status == CR_OK && prop); 01046 cr_string_destroy (prop); 01047 prop = NULL; 01048 01049 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01050 ENSURE_PARSING_COND (status == CR_OK 01051 && token 01052 && token->type == DELIM_TK 01053 && token->u.unichar == ':'); 01054 cr_token_destroy (token); 01055 token = NULL; 01056 cr_parser_try_to_skip_spaces_and_comments (a_this); 01057 status = cr_parser_parse_value_core (a_this); 01058 CHECK_PARSING_STATUS (status, FALSE); 01059 01060 return CR_OK; 01061 01062 error: 01063 01064 if (prop) { 01065 cr_string_destroy (prop); 01066 prop = NULL; 01067 } 01068 01069 if (token) { 01070 cr_token_destroy (token); 01071 token = NULL; 01072 } 01073 01074 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01075 01076 return status; 01077 } 01078 01079 /** 01080 *Parses a "value" production as defined by the css core grammar 01081 *in chapter 4.1. 01082 *value ::= [ any | block | ATKEYWORD S* ]+; 01083 *@param a_this the current instance of #CRParser. 01084 *@return CR_OK upon successfull completion, an error code otherwise. 01085 */ 01086 static enum CRStatus 01087 cr_parser_parse_value_core (CRParser * a_this) 01088 { 01089 CRToken *token = NULL; 01090 CRInputPos init_pos; 01091 enum CRStatus status = CR_ERROR; 01092 glong ref = 0; 01093 01094 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 01095 RECORD_INITIAL_POS (a_this, &init_pos); 01096 01097 continue_parsing: 01098 01099 if (token) { 01100 cr_token_destroy (token); 01101 token = NULL; 01102 } 01103 01104 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01105 ENSURE_PARSING_COND (status == CR_OK && token); 01106 01107 switch (token->type) { 01108 case CBO_TK: 01109 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 01110 token); 01111 token = NULL; 01112 status = cr_parser_parse_block_core (a_this); 01113 CHECK_PARSING_STATUS (status, FALSE); 01114 ref++; 01115 goto continue_parsing; 01116 01117 case ATKEYWORD_TK: 01118 cr_parser_try_to_skip_spaces_and_comments (a_this); 01119 ref++; 01120 goto continue_parsing; 01121 01122 default: 01123 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 01124 token); 01125 token = NULL; 01126 status = cr_parser_parse_any_core (a_this); 01127 if (status == CR_OK) { 01128 ref++; 01129 goto continue_parsing; 01130 } else if (status == CR_PARSING_ERROR) { 01131 status = CR_OK; 01132 goto done; 01133 } else { 01134 goto error; 01135 } 01136 } 01137 01138 done: 01139 if (token) { 01140 cr_token_destroy (token); 01141 token = NULL; 01142 } 01143 01144 if (status == CR_OK && ref) 01145 return CR_OK; 01146 error: 01147 if (token) { 01148 cr_token_destroy (token); 01149 token = NULL; 01150 } 01151 01152 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01153 01154 return status; 01155 } 01156 01157 /** 01158 *Parses an "any" as defined by the css core grammar in the 01159 *css2 spec in chapter 4.1. 01160 *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING 01161 * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES 01162 * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; 01163 * 01164 *@param a_this the current instance of #CRParser. 01165 *@return CR_OK upon successfull completion, an error code otherwise. 01166 */ 01167 static enum CRStatus 01168 cr_parser_parse_any_core (CRParser * a_this) 01169 { 01170 CRToken *token1 = NULL, 01171 *token2 = NULL; 01172 CRInputPos init_pos; 01173 enum CRStatus status = CR_ERROR; 01174 01175 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 01176 01177 RECORD_INITIAL_POS (a_this, &init_pos); 01178 01179 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); 01180 01181 ENSURE_PARSING_COND (status == CR_OK && token1); 01182 01183 switch (token1->type) { 01184 case IDENT_TK: 01185 case NUMBER_TK: 01186 case RGB_TK: 01187 case PERCENTAGE_TK: 01188 case DIMEN_TK: 01189 case EMS_TK: 01190 case EXS_TK: 01191 case LENGTH_TK: 01192 case ANGLE_TK: 01193 case FREQ_TK: 01194 case TIME_TK: 01195 case STRING_TK: 01196 case DELIM_TK: 01197 case URI_TK: 01198 case HASH_TK: 01199 case UNICODERANGE_TK: 01200 case INCLUDES_TK: 01201 case DASHMATCH_TK: 01202 case S_TK: 01203 case COMMENT_TK: 01204 case IMPORTANT_SYM_TK: 01205 status = CR_OK; 01206 break; 01207 case FUNCTION_TK: 01208 /* 01209 *this case isn't specified by the spec but it 01210 *does happen. So we have to handle it. 01211 *We must consider function with parameters. 01212 *We consider parameter as being an "any*" production. 01213 */ 01214 do { 01215 status = cr_parser_parse_any_core (a_this); 01216 } while (status == CR_OK); 01217 01218 ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 01219 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01220 &token2); 01221 ENSURE_PARSING_COND (status == CR_OK 01222 && token2 && token2->type == PC_TK); 01223 break; 01224 case PO_TK: 01225 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01226 &token2); 01227 ENSURE_PARSING_COND (status == CR_OK && token2); 01228 01229 if (token2->type == PC_TK) { 01230 cr_token_destroy (token2); 01231 token2 = NULL; 01232 goto done; 01233 } else { 01234 status = cr_tknzr_unget_token 01235 (PRIVATE (a_this)->tknzr, token2); 01236 token2 = NULL; 01237 } 01238 01239 do { 01240 status = cr_parser_parse_any_core (a_this); 01241 } while (status == CR_OK); 01242 01243 ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 01244 01245 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01246 &token2); 01247 ENSURE_PARSING_COND (status == CR_OK 01248 && token2 && token2->type == PC_TK); 01249 status = CR_OK; 01250 break; 01251 01252 case BO_TK: 01253 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01254 &token2); 01255 ENSURE_PARSING_COND (status == CR_OK && token2); 01256 01257 if (token2->type == BC_TK) { 01258 cr_token_destroy (token2); 01259 token2 = NULL; 01260 goto done; 01261 } else { 01262 status = cr_tknzr_unget_token 01263 (PRIVATE (a_this)->tknzr, token2); 01264 token2 = NULL; 01265 } 01266 01267 do { 01268 status = cr_parser_parse_any_core (a_this); 01269 } while (status == CR_OK); 01270 01271 ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 01272 01273 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01274 &token2); 01275 ENSURE_PARSING_COND (status == CR_OK 01276 && token2 && token2->type == BC_TK); 01277 status = CR_OK; 01278 break; 01279 default: 01280 status = CR_PARSING_ERROR; 01281 goto error; 01282 } 01283 01284 done: 01285 if (token1) { 01286 cr_token_destroy (token1); 01287 token1 = NULL; 01288 } 01289 01290 if (token2) { 01291 cr_token_destroy (token2); 01292 token2 = NULL; 01293 } 01294 01295 return CR_OK; 01296 01297 error: 01298 01299 if (token1) { 01300 cr_token_destroy (token1); 01301 token1 = NULL; 01302 } 01303 01304 if (token2) { 01305 cr_token_destroy (token2); 01306 token2 = NULL; 01307 } 01308 01309 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01310 return status; 01311 } 01312 01313 /** 01314 *Parses an attribute selector as defined in the css2 spec in 01315 *appendix D.1: 01316 *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* 01317 * [ IDENT | STRING ] S* ]? ']' 01318 * 01319 *@param a_this the "this pointer" of the current instance of 01320 *#CRParser . 01321 *@param a_sel out parameter. The successfully parsed attribute selector. 01322 *@return CR_OK upon successfull completion, an error code otherwise. 01323 */ 01324 static enum CRStatus 01325 cr_parser_parse_attribute_selector (CRParser * a_this, 01326 CRAttrSel ** a_sel) 01327 { 01328 enum CRStatus status = CR_OK; 01329 CRInputPos init_pos; 01330 CRToken *token = NULL; 01331 CRAttrSel *result = NULL; 01332 CRParsingLocation location = {0} ; 01333 01334 g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); 01335 01336 RECORD_INITIAL_POS (a_this, &init_pos); 01337 01338 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01339 ENSURE_PARSING_COND (status == CR_OK && token 01340 && token->type == BO_TK); 01341 cr_parsing_location_copy 01342 (&location, &token->location) ; 01343 cr_token_destroy (token); 01344 token = NULL; 01345 01346 cr_parser_try_to_skip_spaces_and_comments (a_this); 01347 01348 result = cr_attr_sel_new (); 01349 if (!result) { 01350 cr_utils_trace_info ("result failed") ; 01351 status = CR_OUT_OF_MEMORY_ERROR ; 01352 goto error ; 01353 } 01354 cr_parsing_location_copy (&result->location, 01355 &location) ; 01356 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01357 ENSURE_PARSING_COND (status == CR_OK 01358 && token && token->type == IDENT_TK); 01359 01360 result->name = token->u.str; 01361 token->u.str = NULL; 01362 cr_token_destroy (token); 01363 token = NULL; 01364 01365 cr_parser_try_to_skip_spaces_and_comments (a_this); 01366 01367 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01368 ENSURE_PARSING_COND (status == CR_OK && token); 01369 01370 if (token->type == INCLUDES_TK) { 01371 result->match_way = INCLUDES; 01372 goto parse_right_part; 01373 } else if (token->type == DASHMATCH_TK) { 01374 result->match_way = DASHMATCH; 01375 goto parse_right_part; 01376 } else if (token->type == DELIM_TK && token->u.unichar == '=') { 01377 result->match_way = EQUALS; 01378 goto parse_right_part; 01379 } else if (token->type == BC_TK) { 01380 result->match_way = SET; 01381 goto done; 01382 } 01383 01384 parse_right_part: 01385 01386 if (token) { 01387 cr_token_destroy (token); 01388 token = NULL; 01389 } 01390 01391 cr_parser_try_to_skip_spaces_and_comments (a_this); 01392 01393 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01394 ENSURE_PARSING_COND (status == CR_OK && token); 01395 01396 if (token->type == IDENT_TK) { 01397 result->value = token->u.str; 01398 token->u.str = NULL; 01399 } else if (token->type == STRING_TK) { 01400 result->value = token->u.str; 01401 token->u.str = NULL; 01402 } else { 01403 status = CR_PARSING_ERROR; 01404 goto error; 01405 } 01406 01407 if (token) { 01408 cr_token_destroy (token); 01409 token = NULL; 01410 } 01411 01412 cr_parser_try_to_skip_spaces_and_comments (a_this); 01413 01414 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01415 01416 ENSURE_PARSING_COND (status == CR_OK && token 01417 && token->type == BC_TK); 01418 done: 01419 if (token) { 01420 cr_token_destroy (token); 01421 token = NULL; 01422 } 01423 01424 if (*a_sel) { 01425 status = cr_attr_sel_append_attr_sel (*a_sel, result); 01426 CHECK_PARSING_STATUS (status, FALSE); 01427 } else { 01428 *a_sel = result; 01429 } 01430 01431 cr_parser_clear_errors (a_this); 01432 return CR_OK; 01433 01434 error: 01435 01436 if (result) { 01437 cr_attr_sel_destroy (result); 01438 result = NULL; 01439 } 01440 01441 if (token) { 01442 cr_token_destroy (token); 01443 token = NULL; 01444 } 01445 01446 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01447 01448 return status; 01449 } 01450 01451 /** 01452 *Parses a "property" as specified by the css2 spec at [4.1.1]: 01453 *property : IDENT S*; 01454 * 01455 *@param a_this the "this pointer" of the current instance of #CRParser. 01456 *@param GString a_property out parameter. The parsed property without the 01457 *trailing spaces. If *a_property is NULL, this function allocates a 01458 *new instance of GString and set it content to the parsed property. 01459 *If not, the property is just appended to a_property's previous content. 01460 *In both cases, it is up to the caller to free a_property. 01461 *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the 01462 *next construction was not a "property", or an error code. 01463 */ 01464 static enum CRStatus 01465 cr_parser_parse_property (CRParser * a_this, 01466 CRString ** a_property) 01467 { 01468 enum CRStatus status = CR_OK; 01469 CRInputPos init_pos; 01470 01471 g_return_val_if_fail (a_this && PRIVATE (a_this) 01472 && PRIVATE (a_this)->tknzr 01473 && a_property, 01474 CR_BAD_PARAM_ERROR); 01475 01476 RECORD_INITIAL_POS (a_this, &init_pos); 01477 01478 status = cr_parser_parse_ident (a_this, a_property); 01479 CHECK_PARSING_STATUS (status, TRUE); 01480 01481 cr_parser_try_to_skip_spaces_and_comments (a_this); 01482 01483 cr_parser_clear_errors (a_this); 01484 return CR_OK; 01485 01486 error: 01487 01488 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01489 01490 return status; 01491 } 01492 01493 /** 01494 * cr_parser_parse_term: 01495 *@a_term: out parameter. The successfully parsed term. 01496 * 01497 *Parses a "term" as defined in the css2 spec, appendix D.1: 01498 *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* | 01499 *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] | 01500 *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor 01501 * 01502 *TODO: handle parsing of 'RGB' 01503 * 01504 *Returns CR_OK upon successfull completion, an error code otherwise. 01505 */ 01506 enum CRStatus 01507 cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term) 01508 { 01509 enum CRStatus status = CR_PARSING_ERROR; 01510 CRInputPos init_pos; 01511 CRTerm *result = NULL; 01512 CRTerm *param = NULL; 01513 CRToken *token = NULL; 01514 CRString *func_name = NULL; 01515 CRParsingLocation location = {0} ; 01516 01517 g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR); 01518 01519 RECORD_INITIAL_POS (a_this, &init_pos); 01520 01521 result = cr_term_new (); 01522 01523 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01524 &token); 01525 if (status != CR_OK || !token) 01526 goto error; 01527 01528 cr_parsing_location_copy (&location, &token->location) ; 01529 if (token->type == DELIM_TK && token->u.unichar == '+') { 01530 result->unary_op = PLUS_UOP; 01531 cr_token_destroy (token) ; 01532 token = NULL ; 01533 cr_parser_try_to_skip_spaces_and_comments (a_this); 01534 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01535 &token); 01536 if (status != CR_OK || !token) 01537 goto error; 01538 } else if (token->type == DELIM_TK && token->u.unichar == '-') { 01539 result->unary_op = MINUS_UOP; 01540 cr_token_destroy (token) ; 01541 token = NULL ; 01542 cr_parser_try_to_skip_spaces_and_comments (a_this); 01543 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 01544 &token); 01545 if (status != CR_OK || !token) 01546 goto error; 01547 } 01548 01549 if (token->type == EMS_TK 01550 || token->type == EXS_TK 01551 || token->type == LENGTH_TK 01552 || token->type == ANGLE_TK 01553 || token->type == TIME_TK 01554 || token->type == FREQ_TK 01555 || token->type == PERCENTAGE_TK 01556 || token->type == NUMBER_TK) { 01557 status = cr_term_set_number (result, token->u.num); 01558 CHECK_PARSING_STATUS (status, TRUE); 01559 token->u.num = NULL; 01560 status = CR_OK; 01561 } else if (token && token->type == FUNCTION_TK) { 01562 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 01563 token); 01564 token = NULL; 01565 status = cr_parser_parse_function (a_this, &func_name, 01566 ¶m); 01567 01568 if (status == CR_OK) { 01569 status = cr_term_set_function (result, 01570 func_name, 01571 param); 01572 CHECK_PARSING_STATUS (status, TRUE); 01573 } 01574 } else if (token && token->type == STRING_TK) { 01575 status = cr_term_set_string (result, 01576 token->u.str); 01577 CHECK_PARSING_STATUS (status, TRUE); 01578 token->u.str = NULL; 01579 } else if (token && token->type == IDENT_TK) { 01580 status = cr_term_set_ident (result, token->u.str); 01581 CHECK_PARSING_STATUS (status, TRUE); 01582 token->u.str = NULL; 01583 } else if (token && token->type == URI_TK) { 01584 status = cr_term_set_uri (result, token->u.str); 01585 CHECK_PARSING_STATUS (status, TRUE); 01586 token->u.str = NULL; 01587 } else if (token && token->type == RGB_TK) { 01588 status = cr_term_set_rgb (result, token->u.rgb); 01589 CHECK_PARSING_STATUS (status, TRUE); 01590 token->u.rgb = NULL; 01591 } else if (token && token->type == UNICODERANGE_TK) { 01592 result->type = TERM_UNICODERANGE; 01593 status = CR_PARSING_ERROR; 01594 } else if (token && token->type == HASH_TK) { 01595 status = cr_term_set_hash (result, token->u.str); 01596 CHECK_PARSING_STATUS (status, TRUE); 01597 token->u.str = NULL; 01598 } else { 01599 status = CR_PARSING_ERROR; 01600 } 01601 01602 if (status != CR_OK) { 01603 goto error; 01604 } 01605 cr_parsing_location_copy (&result->location, 01606 &location) ; 01607 *a_term = cr_term_append_term (*a_term, result); 01608 01609 result = NULL; 01610 01611 cr_parser_try_to_skip_spaces_and_comments (a_this); 01612 01613 if (token) { 01614 cr_token_destroy (token); 01615 token = NULL; 01616 } 01617 01618 cr_parser_clear_errors (a_this); 01619 return CR_OK; 01620 01621 error: 01622 01623 if (result) { 01624 cr_term_destroy (result); 01625 result = NULL; 01626 } 01627 01628 if (token) { 01629 cr_token_destroy (token); 01630 token = NULL; 01631 } 01632 01633 if (param) { 01634 cr_term_destroy (param); 01635 param = NULL; 01636 } 01637 01638 if (func_name) { 01639 cr_string_destroy (func_name); 01640 func_name = NULL; 01641 } 01642 01643 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01644 01645 return status; 01646 } 01647 01648 /** 01649 * cr_parser_parse_simple_selector: 01650 *@a_this: the "this pointer" of the current instance of #CRParser. 01651 *@a_sel: out parameter. Is set to the successfully parsed simple 01652 *selector. 01653 * 01654 *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 : 01655 *element_name? [ HASH | class | attrib | pseudo ]* S* 01656 *and where pseudo is: 01657 *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ] 01658 * 01659 *Returns CR_OK upon successfull completion, an error code otherwise. 01660 */ 01661 static enum CRStatus 01662 cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel) 01663 { 01664 enum CRStatus status = CR_ERROR; 01665 CRInputPos init_pos; 01666 CRToken *token = NULL; 01667 CRSimpleSel *sel = NULL; 01668 CRAdditionalSel *add_sel_list = NULL; 01669 gboolean found_sel = FALSE; 01670 guint32 cur_char = 0; 01671 01672 g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR); 01673 01674 RECORD_INITIAL_POS (a_this, &init_pos); 01675 01676 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 01677 if (status != CR_OK) 01678 goto error; 01679 01680 sel = cr_simple_sel_new (); 01681 ENSURE_PARSING_COND (sel); 01682 01683 cr_parsing_location_copy 01684 (&sel->location, 01685 &token->location) ; 01686 01687 if (token && token->type == DELIM_TK 01688 && token->u.unichar == '*') { 01689 sel->type_mask |= UNIVERSAL_SELECTOR; 01690 sel->name = cr_string_new_from_string ("*"); 01691 found_sel = TRUE; 01692 } else if (token && token->type == IDENT_TK) { 01693 sel->name = token->u.str; 01694 sel->type_mask |= TYPE_SELECTOR; 01695 token->u.str = NULL; 01696 found_sel = TRUE; 01697 } else { 01698 status = cr_tknzr_unget_token 01699 (PRIVATE (a_this)->tknzr, 01700 token); 01701 token = NULL; 01702 } 01703 01704 if (token) { 01705 cr_token_destroy (token); 01706 token = NULL; 01707 } 01708 01709 cr_parser_try_to_skip_spaces_and_comments (a_this); 01710 01711 for (;;) { 01712 if (token) { 01713 cr_token_destroy (token); 01714 token = NULL; 01715 } 01716 01717 status = cr_tknzr_get_next_token 01718 (PRIVATE (a_this)->tknzr, 01719 &token); 01720 if (status != CR_OK) 01721 goto error; 01722 01723 if (token && token->type == HASH_TK) { 01724 /*we parsed an attribute id */ 01725 CRAdditionalSel *add_sel = NULL; 01726 01727 add_sel = cr_additional_sel_new_with_type 01728 (ID_ADD_SELECTOR); 01729 01730 add_sel->content.id_name = token->u.str; 01731 token->u.str = NULL; 01732 01733 cr_parsing_location_copy 01734 (&add_sel->location, 01735 &token->location) ; 01736 add_sel_list = 01737 cr_additional_sel_append 01738 (add_sel_list, add_sel); 01739 found_sel = TRUE; 01740 } else if (token && (token->type == DELIM_TK) 01741 && (token->u.unichar == '.')) { 01742 cr_token_destroy (token); 01743 token = NULL; 01744 01745 status = cr_tknzr_get_next_token 01746 (PRIVATE (a_this)->tknzr, &token); 01747 if (status != CR_OK) 01748 goto error; 01749 01750 if (token && token->type == IDENT_TK) { 01751 CRAdditionalSel *add_sel = NULL; 01752 01753 add_sel = cr_additional_sel_new_with_type 01754 (CLASS_ADD_SELECTOR); 01755 01756 add_sel->content.class_name = token->u.str; 01757 token->u.str = NULL; 01758 01759 add_sel_list = 01760 cr_additional_sel_append 01761 (add_sel_list, add_sel); 01762 found_sel = TRUE; 01763 01764 cr_parsing_location_copy 01765 (&add_sel->location, 01766 & token->location) ; 01767 } else { 01768 status = CR_PARSING_ERROR; 01769 goto error; 01770 } 01771 } else if (token && token->type == BO_TK) { 01772 CRAttrSel *attr_sel = NULL; 01773 CRAdditionalSel *add_sel = NULL; 01774 01775 status = cr_tknzr_unget_token 01776 (PRIVATE (a_this)->tknzr, token); 01777 if (status != CR_OK) 01778 goto error; 01779 token = NULL; 01780 01781 status = cr_parser_parse_attribute_selector 01782 (a_this, &attr_sel); 01783 CHECK_PARSING_STATUS (status, FALSE); 01784 01785 add_sel = cr_additional_sel_new_with_type 01786 (ATTRIBUTE_ADD_SELECTOR); 01787 01788 ENSURE_PARSING_COND (add_sel != NULL); 01789 01790 add_sel->content.attr_sel = attr_sel; 01791 01792 add_sel_list = 01793 cr_additional_sel_append 01794 (add_sel_list, add_sel); 01795 found_sel = TRUE; 01796 cr_parsing_location_copy 01797 (&add_sel->location, 01798 &attr_sel->location) ; 01799 } else if (token && (token->type == DELIM_TK) 01800 && (token->u.unichar == ':')) { 01801 CRPseudo *pseudo = NULL; 01802 01803 /*try to parse a pseudo */ 01804 01805 if (token) { 01806 cr_token_destroy (token); 01807 token = NULL; 01808 } 01809 01810 pseudo = cr_pseudo_new (); 01811 01812 status = cr_tknzr_get_next_token 01813 (PRIVATE (a_this)->tknzr, &token); 01814 ENSURE_PARSING_COND (status == CR_OK && token); 01815 01816 cr_parsing_location_copy 01817 (&pseudo->location, 01818 &token->location) ; 01819 01820 if (token->type == IDENT_TK) { 01821 pseudo->type = IDENT_PSEUDO; 01822 pseudo->name = token->u.str; 01823 token->u.str = NULL; 01824 found_sel = TRUE; 01825 } else if (token->type == FUNCTION_TK) { 01826 pseudo->name = token->u.str; 01827 token->u.str = NULL; 01828 cr_parser_try_to_skip_spaces_and_comments 01829 (a_this); 01830 status = cr_parser_parse_ident 01831 (a_this, &pseudo->extra); 01832 01833 ENSURE_PARSING_COND (status == CR_OK); 01834 READ_NEXT_CHAR (a_this, &cur_char); 01835 ENSURE_PARSING_COND (cur_char == ')'); 01836 pseudo->type = FUNCTION_PSEUDO; 01837 found_sel = TRUE; 01838 } else { 01839 status = CR_PARSING_ERROR; 01840 goto error; 01841 } 01842 01843 if (status == CR_OK) { 01844 CRAdditionalSel *add_sel = NULL; 01845 01846 add_sel = cr_additional_sel_new_with_type 01847 (PSEUDO_CLASS_ADD_SELECTOR); 01848 01849 add_sel->content.pseudo = pseudo; 01850 cr_parsing_location_copy 01851 (&add_sel->location, 01852 &pseudo->location) ; 01853 add_sel_list = 01854 cr_additional_sel_append 01855 (add_sel_list, add_sel); 01856 status = CR_OK; 01857 } 01858 } else { 01859 status = cr_tknzr_unget_token 01860 (PRIVATE (a_this)->tknzr, token); 01861 token = NULL; 01862 break; 01863 } 01864 } 01865 01866 if (status == CR_OK && found_sel == TRUE) { 01867 cr_parser_try_to_skip_spaces_and_comments (a_this); 01868 01869 sel->add_sel = add_sel_list; 01870 add_sel_list = NULL; 01871 01872 if (*a_sel == NULL) { 01873 *a_sel = sel; 01874 } else { 01875 cr_simple_sel_append_simple_sel (*a_sel, sel); 01876 } 01877 01878 sel = NULL; 01879 01880 if (token) { 01881 cr_token_destroy (token); 01882 token = NULL; 01883 } 01884 01885 cr_parser_clear_errors (a_this); 01886 return CR_OK; 01887 } else { 01888 status = CR_PARSING_ERROR; 01889 } 01890 01891 error: 01892 01893 if (token) { 01894 cr_token_destroy (token); 01895 token = NULL; 01896 } 01897 01898 if (add_sel_list) { 01899 cr_additional_sel_destroy (add_sel_list); 01900 add_sel_list = NULL; 01901 } 01902 01903 if (sel) { 01904 cr_simple_sel_destroy (sel); 01905 sel = NULL; 01906 } 01907 01908 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01909 01910 return status; 01911 01912 } 01913 01914 /** 01915 * cr_parser_parse_simple_sels: 01916 *@a_this: the this pointer of the current instance of #CRParser. 01917 *@a_start: a pointer to the 01918 *first chararcter of the successfully parsed 01919 *string. 01920 *@a_end: a pointer to the last character of the successfully parsed 01921 *string. 01922 * 01923 *Parses a "selector" as defined by the css2 spec in appendix D.1: 01924 *selector ::= simple_selector [ combinator simple_selector ]* 01925 * 01926 *Returns CR_OK upon successfull completion, an error code otherwise. 01927 */ 01928 static enum CRStatus 01929 cr_parser_parse_simple_sels (CRParser * a_this, 01930 CRSimpleSel ** a_sel) 01931 { 01932 enum CRStatus status = CR_ERROR; 01933 CRInputPos init_pos; 01934 CRSimpleSel *sel = NULL; 01935 guint32 cur_char = 0; 01936 01937 g_return_val_if_fail (a_this 01938 && PRIVATE (a_this) 01939 && a_sel, 01940 CR_BAD_PARAM_ERROR); 01941 01942 RECORD_INITIAL_POS (a_this, &init_pos); 01943 01944 status = cr_parser_parse_simple_selector (a_this, &sel); 01945 CHECK_PARSING_STATUS (status, FALSE); 01946 01947 *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel); 01948 01949 for (;;) { 01950 guint32 next_char = 0; 01951 enum Combinator comb = 0; 01952 01953 sel = NULL; 01954 01955 PEEK_NEXT_CHAR (a_this, &next_char); 01956 01957 if (next_char == '+') { 01958 READ_NEXT_CHAR (a_this, &cur_char); 01959 comb = COMB_PLUS; 01960 cr_parser_try_to_skip_spaces_and_comments (a_this); 01961 } else if (next_char == '>') { 01962 READ_NEXT_CHAR (a_this, &cur_char); 01963 comb = COMB_GT; 01964 cr_parser_try_to_skip_spaces_and_comments (a_this); 01965 } else { 01966 comb = COMB_WS; 01967 } 01968 01969 status = cr_parser_parse_simple_selector (a_this, &sel); 01970 if (status != CR_OK) 01971 break; 01972 01973 if (comb && sel) { 01974 sel->combinator = comb; 01975 comb = 0; 01976 } 01977 if (sel) { 01978 *a_sel = cr_simple_sel_append_simple_sel (*a_sel, 01979 sel) ; 01980 } 01981 } 01982 cr_parser_clear_errors (a_this); 01983 return CR_OK; 01984 01985 error: 01986 01987 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 01988 01989 return status; 01990 } 01991 01992 /** 01993 * cr_parser_parse_selector: 01994 *@a_this: the current instance of #CRParser. 01995 *@a_selector: the parsed list of comma separated 01996 *selectors. 01997 * 01998 *Parses a comma separated list of selectors. 01999 * 02000 *Returns CR_OK upon successful completion, an error 02001 *code otherwise. 02002 */ 02003 static enum CRStatus 02004 cr_parser_parse_selector (CRParser * a_this, 02005 CRSelector ** a_selector) 02006 { 02007 enum CRStatus status = CR_OK; 02008 CRInputPos init_pos; 02009 guint32 cur_char = 0, 02010 next_char = 0; 02011 CRSimpleSel *simple_sels = NULL; 02012 CRSelector *selector = NULL; 02013 02014 g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR); 02015 02016 RECORD_INITIAL_POS (a_this, &init_pos); 02017 02018 status = cr_parser_parse_simple_sels (a_this, &simple_sels); 02019 CHECK_PARSING_STATUS (status, FALSE); 02020 02021 if (simple_sels) { 02022 selector = cr_selector_append_simple_sel 02023 (selector, simple_sels); 02024 if (selector) { 02025 cr_parsing_location_copy 02026 (&selector->location, 02027 &simple_sels->location) ; 02028 } 02029 simple_sels = NULL; 02030 } else { 02031 status = CR_PARSING_ERROR ; 02032 goto error ; 02033 } 02034 02035 status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, 02036 &next_char); 02037 if (status != CR_OK) { 02038 if (status == CR_END_OF_INPUT_ERROR) { 02039 status = CR_OK; 02040 goto okay; 02041 } else { 02042 goto error; 02043 } 02044 } 02045 02046 if (next_char == ',') { 02047 for (;;) { 02048 simple_sels = NULL; 02049 02050 status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, 02051 &next_char); 02052 if (status != CR_OK) { 02053 if (status == CR_END_OF_INPUT_ERROR) { 02054 status = CR_OK; 02055 break; 02056 } else { 02057 goto error; 02058 } 02059 } 02060 02061 if (next_char != ',') 02062 break; 02063 02064 /*consume the ',' char */ 02065 READ_NEXT_CHAR (a_this, &cur_char); 02066 02067 cr_parser_try_to_skip_spaces_and_comments (a_this); 02068 02069 status = cr_parser_parse_simple_sels 02070 (a_this, &simple_sels); 02071 02072 CHECK_PARSING_STATUS (status, FALSE); 02073 02074 if (simple_sels) { 02075 selector = 02076 cr_selector_append_simple_sel 02077 (selector, simple_sels); 02078 02079 simple_sels = NULL; 02080 } 02081 } 02082 } 02083 02084 okay: 02085 cr_parser_try_to_skip_spaces_and_comments (a_this); 02086 02087 if (!*a_selector) { 02088 *a_selector = selector; 02089 } else { 02090 *a_selector = cr_selector_append (*a_selector, selector); 02091 } 02092 02093 selector = NULL; 02094 return CR_OK; 02095 02096 error: 02097 02098 if (simple_sels) { 02099 cr_simple_sel_destroy (simple_sels); 02100 simple_sels = NULL; 02101 } 02102 02103 if (selector) { 02104 cr_selector_unref (selector); 02105 selector = NULL; 02106 } 02107 02108 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 02109 02110 return status; 02111 } 02112 02113 /** 02114 * cr_parser_parse_function: 02115 *@a_this: the "this pointer" of the current instance of #CRParser. 02116 * 02117 *@a_func_name: out parameter. The parsed function name 02118 *@a_expr: out parameter. The successfully parsed term. 02119 * 02120 *Parses a "function" as defined in css spec at appendix D.1: 02121 *function ::= FUNCTION S* expr ')' S* 02122 *FUNCTION ::= ident'(' 02123 * 02124 *Returns CR_OK upon successfull completion, an error code otherwise. 02125 */ 02126 static enum CRStatus 02127 cr_parser_parse_function (CRParser * a_this, 02128 CRString ** a_func_name, 02129 CRTerm ** a_expr) 02130 { 02131 CRInputPos init_pos; 02132 enum CRStatus status = CR_OK; 02133 CRToken *token = NULL; 02134 CRTerm *expr = NULL; 02135 02136 g_return_val_if_fail (a_this && PRIVATE (a_this) 02137 && a_func_name, 02138 CR_BAD_PARAM_ERROR); 02139 02140 RECORD_INITIAL_POS (a_this, &init_pos); 02141 02142 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 02143 if (status != CR_OK) 02144 goto error; 02145 02146 if (token && token->type == FUNCTION_TK) { 02147 *a_func_name = token->u.str; 02148 token->u.str = NULL; 02149 } else { 02150 status = CR_PARSING_ERROR; 02151 goto error; 02152 } 02153 cr_token_destroy (token); 02154 token = NULL; 02155 02156 cr_parser_try_to_skip_spaces_and_comments (a_this) ; 02157 02158 status = cr_parser_parse_expr (a_this, &expr); 02159 02160 CHECK_PARSING_STATUS (status, FALSE); 02161 02162 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 02163 if (status != CR_OK) 02164 goto error; 02165 02166 ENSURE_PARSING_COND (token && token->type == PC_TK); 02167 02168 cr_token_destroy (token); 02169 token = NULL; 02170 02171 if (expr) { 02172 *a_expr = cr_term_append_term (*a_expr, expr); 02173 expr = NULL; 02174 } 02175 02176 cr_parser_clear_errors (a_this); 02177 return CR_OK; 02178 02179 error: 02180 02181 if (*a_func_name) { 02182 cr_string_destroy (*a_func_name); 02183 *a_func_name = NULL; 02184 } 02185 02186 if (expr) { 02187 cr_term_destroy (expr); 02188 expr = NULL; 02189 } 02190 02191 if (token) { 02192 cr_token_destroy (token); 02193 02194 } 02195 02196 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 02197 02198 return status; 02199 } 02200 02201 /** 02202 * cr_parser_parse_uri: 02203 *@a_this: the current instance of #CRParser. 02204 *@a_str: the successfully parsed url. 02205 * 02206 *Parses an uri as defined by the css spec [4.1.1]: 02207 * URI ::= url\({w}{string}{w}\) 02208 * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\) 02209 * 02210 *Returns CR_OK upon successfull completion, an error code otherwise. 02211 */ 02212 static enum CRStatus 02213 cr_parser_parse_uri (CRParser * a_this, CRString ** a_str) 02214 { 02215 02216 enum CRStatus status = CR_PARSING_ERROR; 02217 02218 g_return_val_if_fail (a_this && PRIVATE (a_this) 02219 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 02220 02221 status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, 02222 URI_TK, NO_ET, a_str, NULL); 02223 return status; 02224 } 02225 02226 /** 02227 * cr_parser_parse_string: 02228 *@a_this: the current instance of #CRParser. 02229 *@a_start: out parameter. Upon successfull completion, 02230 *points to the beginning of the string, points to an undefined value 02231 *otherwise. 02232 *@a_end: out parameter. Upon successfull completion, points to 02233 *the beginning of the string, points to an undefined value otherwise. 02234 * 02235 *Parses a string type as defined in css spec [4.1.1]: 02236 * 02237 *string ::= {string1}|{string2} 02238 *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" 02239 *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' 02240 * 02241 *Returns CR_OK upon successfull completion, an error code otherwise. 02242 */ 02243 static enum CRStatus 02244 cr_parser_parse_string (CRParser * a_this, CRString ** a_str) 02245 { 02246 enum CRStatus status = CR_OK; 02247 02248 g_return_val_if_fail (a_this && PRIVATE (a_this) 02249 && PRIVATE (a_this)->tknzr 02250 && a_str, CR_BAD_PARAM_ERROR); 02251 02252 status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, 02253 STRING_TK, NO_ET, a_str, NULL); 02254 return status; 02255 } 02256 02257 /** 02258 *Parses an "ident" as defined in css spec [4.1.1]: 02259 *ident ::= {nmstart}{nmchar}* 02260 * 02261 *@param a_this the currens instance of #CRParser. 02262 * 02263 *@param a_str a pointer to parsed ident. If *a_str is NULL, 02264 *this function allocates a new instance of #CRString. If not, 02265 *the function just appends the parsed string to the one passed. 02266 *In both cases it is up to the caller to free *a_str. 02267 * 02268 *@return CR_OK upon successfull completion, an error code 02269 *otherwise. 02270 */ 02271 static enum CRStatus 02272 cr_parser_parse_ident (CRParser * a_this, CRString ** a_str) 02273 { 02274 enum CRStatus status = CR_OK; 02275 02276 g_return_val_if_fail (a_this && PRIVATE (a_this) 02277 && PRIVATE (a_this)->tknzr 02278 && a_str, CR_BAD_PARAM_ERROR); 02279 02280 status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr, 02281 IDENT_TK, NO_ET, a_str, NULL); 02282 return status; 02283 } 02284 02285 /** 02286 *the next rule is ignored as well. This seems to be a bug 02287 *Parses a stylesheet as defined in the css2 spec in appendix D.1: 02288 *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]? 02289 * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* 02290 * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]* 02291 * 02292 *TODO: Finish the code of this function. Think about splitting it into 02293 *smaller functions. 02294 * 02295 *@param a_this the "this pointer" of the current instance of #CRParser. 02296 *@param a_start out parameter. A pointer to the first character of 02297 *the successfully parsed string. 02298 *@param a_end out parameter. A pointer to the first character of 02299 *the successfully parsed string. 02300 * 02301 *@return CR_OK upon successfull completion, an error code otherwise. 02302 */ 02303 static enum CRStatus 02304 cr_parser_parse_stylesheet (CRParser * a_this) 02305 { 02306 enum CRStatus status = CR_OK; 02307 CRInputPos init_pos; 02308 CRToken *token = NULL; 02309 CRString *charset = NULL; 02310 02311 g_return_val_if_fail (a_this && PRIVATE (a_this) 02312 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 02313 02314 RECORD_INITIAL_POS (a_this, &init_pos); 02315 02316 PRIVATE (a_this)->state = READY_STATE; 02317 02318 if (PRIVATE (a_this)->sac_handler 02319 && PRIVATE (a_this)->sac_handler->start_document) { 02320 PRIVATE (a_this)->sac_handler->start_document 02321 (PRIVATE (a_this)->sac_handler); 02322 } 02323 02324 parse_charset: 02325 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 02326 02327 if (status == CR_END_OF_INPUT_ERROR) 02328 goto done; 02329 CHECK_PARSING_STATUS (status, TRUE); 02330 02331 if (token && token->type == CHARSET_SYM_TK) { 02332 CRParsingLocation location = {0} ; 02333 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 02334 token); 02335 CHECK_PARSING_STATUS (status, TRUE); 02336 token = NULL; 02337 02338 status = cr_parser_parse_charset (a_this, 02339 &charset, 02340 &location); 02341 02342 if (status == CR_OK && charset) { 02343 if (PRIVATE (a_this)->sac_handler 02344 && PRIVATE (a_this)->sac_handler->charset) { 02345 PRIVATE (a_this)->sac_handler->charset 02346 (PRIVATE (a_this)->sac_handler, 02347 charset, &location); 02348 } 02349 } else if (status != CR_END_OF_INPUT_ERROR) { 02350 status = cr_parser_parse_atrule_core (a_this); 02351 CHECK_PARSING_STATUS (status, FALSE); 02352 } 02353 02354 if (charset) { 02355 cr_string_destroy (charset); 02356 charset = NULL; 02357 } 02358 } else if (token 02359 && (token->type == S_TK 02360 || token->type == COMMENT_TK)) { 02361 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 02362 token); 02363 token = NULL; 02364 CHECK_PARSING_STATUS (status, TRUE); 02365 02366 cr_parser_try_to_skip_spaces_and_comments (a_this); 02367 goto parse_charset ; 02368 } else if (token) { 02369 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 02370 token); 02371 token = NULL; 02372 CHECK_PARSING_STATUS (status, TRUE); 02373 } 02374 02375 /* parse_imports:*/ 02376 do { 02377 if (token) { 02378 cr_token_destroy (token); 02379 token = NULL; 02380 } 02381 cr_parser_try_to_skip_spaces_and_comments (a_this) ; 02382 status = cr_tknzr_get_next_token 02383 (PRIVATE (a_this)->tknzr, &token); 02384 02385 if (status == CR_END_OF_INPUT_ERROR) 02386 goto done; 02387 CHECK_PARSING_STATUS (status, TRUE); 02388 } while (token 02389 && (token->type == S_TK 02390 || token->type == CDO_TK || token->type == CDC_TK)); 02391 02392 if (token) { 02393 status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 02394 token); 02395 token = NULL; 02396 } 02397 02398 for (;;) { 02399 status = cr_tknzr_get_next_token 02400 (PRIVATE (a_this)->tknzr, &token); 02401 if (status == CR_END_OF_INPUT_ERROR) 02402 goto done; 02403 CHECK_PARSING_STATUS (status, TRUE); 02404 02405 if (token && token->type == IMPORT_SYM_TK) { 02406 GList *media_list = NULL; 02407 CRString *import_string = NULL; 02408 CRParsingLocation location = {0} ; 02409 02410 status = cr_tknzr_unget_token 02411 (PRIVATE (a_this)->tknzr, token); 02412 token = NULL; 02413 CHECK_PARSING_STATUS (status, TRUE); 02414 02415 status = cr_parser_parse_import (a_this, 02416 &media_list, 02417 &import_string, 02418 &location); 02419 if (status == CR_OK) { 02420 if (import_string 02421 && PRIVATE (a_this)->sac_handler 02422 && PRIVATE (a_this)->sac_handler->import_style) { 02423 PRIVATE (a_this)->sac_handler->import_style 02424 (PRIVATE(a_this)->sac_handler, 02425 media_list, 02426 import_string, 02427 NULL, &location) ; 02428 02429 if ((PRIVATE (a_this)->sac_handler->resolve_import == TRUE)) { 02430 /* 02431 *TODO: resolve the 02432 *import rule. 02433 */ 02434 } 02435 02436 if ((PRIVATE (a_this)->sac_handler->import_style_result)) { 02437 PRIVATE (a_this)->sac_handler->import_style_result 02438 (PRIVATE (a_this)->sac_handler, 02439 media_list, import_string, 02440 NULL, NULL); 02441 } 02442 } 02443 } else if (status != CR_END_OF_INPUT_ERROR) { 02444 if (PRIVATE (a_this)->sac_handler 02445 && PRIVATE (a_this)->sac_handler->error) { 02446 PRIVATE (a_this)->sac_handler->error 02447 (PRIVATE (a_this)->sac_handler); 02448 } 02449 status = cr_parser_parse_atrule_core (a_this); 02450 CHECK_PARSING_STATUS (status, TRUE) ; 02451 } else { 02452 goto error ; 02453 } 02454 02455 /* 02456 *then, after calling the appropriate 02457 *SAC handler, free 02458 *the media_list and import_string. 02459 */ 02460 if (media_list) { 02461 GList *cur = NULL; 02462 02463 /*free the medium list */ 02464 for (cur = media_list; cur; cur = cur->next) { 02465 if (cur->data) { 02466 cr_string_destroy (cur->data); 02467 } 02468 } 02469 02470 g_list_free (media_list); 02471 media_list = NULL; 02472 } 02473 02474 if (import_string) { 02475 cr_string_destroy (import_string); 02476 import_string = NULL; 02477 } 02478 02479 cr_parser_try_to_skip_spaces_and_comments (a_this); 02480 } else if (token 02481 && (token->type == S_TK 02482 || token->type == CDO_TK 02483 || token->type == CDC_TK)) { 02484 status = cr_tknzr_unget_token 02485 (PRIVATE (a_this)->tknzr, token); 02486 token = NULL; 02487 02488 do { 02489 if (token) { 02490 cr_token_destroy (token); 02491 token = NULL; 02492 } 02493 02494 status = cr_tknzr_get_next_token 02495 (PRIVATE (a_this)->tknzr, &token); 02496 02497 if (status == CR_END_OF_INPUT_ERROR) 02498 goto done; 02499 CHECK_PARSING_STATUS (status, TRUE); 02500 } while (token 02501 && (token->type == S_TK 02502 || token->type == CDO_TK 02503 || token->type == CDC_TK)); 02504 } else { 02505 if (token) { 02506 status = cr_tknzr_unget_token 02507 (PRIVATE (a_this)->tknzr, token); 02508 token = NULL; 02509 } 02510 goto parse_ruleset_and_others; 02511 } 02512 } 02513 02514 parse_ruleset_and_others: 02515 02516 cr_parser_try_to_skip_spaces_and_comments (a_this); 02517 02518 for (;;) { 02519 status = cr_tknzr_get_next_token 02520 (PRIVATE (a_this)->tknzr, &token); 02521 if (status == CR_END_OF_INPUT_ERROR) 02522 goto done; 02523 CHECK_PARSING_STATUS (status, TRUE); 02524 02525 if (token 02526 && (token->type == S_TK 02527 || token->type == CDO_TK || token->type == CDC_TK)) { 02528 status = cr_tknzr_unget_token 02529 (PRIVATE (a_this)->tknzr, token); 02530 token = NULL; 02531 02532 do { 02533 if (token) { 02534 cr_token_destroy (token); 02535 token = NULL; 02536 } 02537 02538 cr_parser_try_to_skip_spaces_and_comments 02539 (a_this); 02540 status = cr_tknzr_get_next_token 02541 (PRIVATE (a_this)->tknzr, &token); 02542 } while (token 02543 && (token->type == S_TK 02544 || token->type == COMMENT_TK 02545 || token->type == CDO_TK 02546 || token->type == CDC_TK)); 02547 if (token) { 02548 cr_tknzr_unget_token 02549 (PRIVATE (a_this)->tknzr, token); 02550 token = NULL; 02551 } 02552 } else if (token 02553 && (token->type == HASH_TK 02554 || (token->type == DELIM_TK 02555 && token->u.unichar == '.') 02556 || (token->type == DELIM_TK 02557 && token->u.unichar == ':') 02558 || (token->type == DELIM_TK 02559 && token->u.unichar == '*') 02560 || (token->type == BO_TK) 02561 || token->type == IDENT_TK)) { 02562 /* 02563 *Try to parse a CSS2 ruleset. 02564 *if the parsing fails, try to parse 02565 *a css core ruleset. 02566 */ 02567 status = cr_tknzr_unget_token 02568 (PRIVATE (a_this)->tknzr, token); 02569 CHECK_PARSING_STATUS (status, TRUE); 02570 token = NULL; 02571 02572 status = cr_parser_parse_ruleset (a_this); 02573 02574 if (status == CR_OK) { 02575 continue; 02576 } else { 02577 if (PRIVATE (a_this)->sac_handler 02578 && PRIVATE (a_this)->sac_handler->error) { 02579 PRIVATE (a_this)->sac_handler-> 02580 error 02581 (PRIVATE (a_this)-> 02582 sac_handler); 02583 } 02584 02585 status = cr_parser_parse_ruleset_core 02586 (a_this); 02587 02588 if (status == CR_OK) { 02589 continue; 02590 } else { 02591 break; 02592 } 02593 } 02594 } else if (token && token->type == MEDIA_SYM_TK) { 02595 status = cr_tknzr_unget_token 02596 (PRIVATE (a_this)->tknzr, token); 02597 CHECK_PARSING_STATUS (status, TRUE); 02598 token = NULL; 02599 02600 status = cr_parser_parse_media (a_this); 02601 if (status == CR_OK) { 02602 continue; 02603 } else { 02604 if (PRIVATE (a_this)->sac_handler 02605 && PRIVATE (a_this)->sac_handler->error) { 02606 PRIVATE (a_this)->sac_handler-> 02607 error 02608 (PRIVATE (a_this)-> 02609 sac_handler); 02610 } 02611 02612 status = cr_parser_parse_atrule_core (a_this); 02613 02614 if (status == CR_OK) { 02615 continue; 02616 } else { 02617 break; 02618 } 02619 } 02620 02621 } else if (token && token->type == PAGE_SYM_TK) { 02622 status = cr_tknzr_unget_token 02623 (PRIVATE (a_this)->tknzr, token); 02624 CHECK_PARSING_STATUS (status, TRUE); 02625 token = NULL; 02626 status = cr_parser_parse_page (a_this); 02627 02628 if (status == CR_OK) { 02629 continue; 02630 } else { 02631 if (PRIVATE (a_this)->sac_handler 02632 && PRIVATE (a_this)->sac_handler->error) { 02633 PRIVATE (a_this)->sac_handler-> 02634 error 02635 (PRIVATE (a_this)-> 02636 sac_handler); 02637 } 02638 02639 status = cr_parser_parse_atrule_core (a_this); 02640 02641 if (status == CR_OK) { 02642 continue; 02643 } else { 02644 break; 02645 } 02646 } 02647 } else if (token && token->type == FONT_FACE_SYM_TK) { 02648 status = cr_tknzr_unget_token 02649 (PRIVATE (a_this)->tknzr, token); 02650 CHECK_PARSING_STATUS (status, TRUE); 02651 token = NULL; 02652 status = cr_parser_parse_font_face (a_this); 02653 02654 if (status == CR_OK) { 02655 continue; 02656 } else { 02657 if (PRIVATE (a_this)->sac_handler 02658 && PRIVATE (a_this)->sac_handler->error) { 02659 PRIVATE (a_this)->sac_handler-> 02660 error 02661 (PRIVATE (a_this)-> 02662 sac_handler); 02663 } 02664 02665 status = cr_parser_parse_atrule_core (a_this); 02666 02667 if (status == CR_OK) { 02668 continue; 02669 } else { 02670 break; 02671 } 02672 } 02673 } else { 02674 status = cr_tknzr_unget_token 02675 (PRIVATE (a_this)->tknzr, token); 02676 CHECK_PARSING_STATUS (status, TRUE); 02677 token = NULL; 02678 status = cr_parser_parse_statement_core (a_this); 02679 02680 if (status == CR_OK) { 02681 continue; 02682 } else { 02683 break; 02684 } 02685 } 02686 } 02687 02688 done: 02689 if (token) { 02690 cr_token_destroy (token); 02691 token = NULL; 02692 } 02693 02694 if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) { 02695 02696 if (PRIVATE (a_this)->sac_handler 02697 && PRIVATE (a_this)->sac_handler->end_document) { 02698 PRIVATE (a_this)->sac_handler->end_document 02699 (PRIVATE (a_this)->sac_handler); 02700 } 02701 02702 return CR_OK; 02703 } 02704 02705 cr_parser_push_error 02706 (a_this, (const guchar *) "could not recognize next production", CR_ERROR); 02707 02708 if (PRIVATE (a_this)->sac_handler 02709 && PRIVATE (a_this)->sac_handler->unrecoverable_error) { 02710 PRIVATE (a_this)->sac_handler-> 02711 unrecoverable_error (PRIVATE (a_this)->sac_handler); 02712 } 02713 02714 cr_parser_dump_err_stack (a_this, TRUE); 02715 02716 return status; 02717 02718 error: 02719 02720 if (token) { 02721 cr_token_destroy (token); 02722 token = NULL; 02723 } 02724 02725 if (PRIVATE (a_this)->sac_handler 02726 && PRIVATE (a_this)->sac_handler->unrecoverable_error) { 02727 PRIVATE (a_this)->sac_handler-> 02728 unrecoverable_error (PRIVATE (a_this)->sac_handler); 02729 } 02730 02731 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 02732 02733 return status; 02734 } 02735 02736 /**************************************** 02737 *Public CRParser Methods 02738 ****************************************/ 02739 02740 /** 02741 * cr_parser_new: 02742 * @a_tknzr: the tokenizer to use for the parsing. 02743 * 02744 *Creates a new parser to parse data 02745 *coming the input stream given in parameter. 02746 * 02747 *Returns the newly created instance of #CRParser, 02748 *or NULL if an error occurred. 02749 */ 02750 CRParser * 02751 cr_parser_new (CRTknzr * a_tknzr) 02752 { 02753 CRParser *result = NULL; 02754 enum CRStatus status = CR_OK; 02755 02756 result = g_malloc0 (sizeof (CRParser)); 02757 02758 PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv)); 02759 02760 if (a_tknzr) { 02761 status = cr_parser_set_tknzr (result, a_tknzr); 02762 } 02763 02764 g_return_val_if_fail (status == CR_OK, NULL); 02765 02766 return result; 02767 } 02768 02769 /** 02770 * cr_parser_new_from_buf: 02771 *@a_buf: the buffer to parse. 02772 *@a_len: the length of the data in the buffer. 02773 *@a_enc: the encoding of the input buffer a_buf. 02774 *@a_free_buf: if set to TRUE, a_buf will be freed 02775 *during the destruction of the newly built instance 02776 *of #CRParser. If set to FALSE, it is up to the caller to 02777 *eventually free it. 02778 * 02779 *Instanciates a new parser from a memory buffer. 02780 * 02781 *Returns the newly built parser, or NULL if an error arises. 02782 */ 02783 CRParser * 02784 cr_parser_new_from_buf (guchar * a_buf, 02785 gulong a_len, 02786 enum CREncoding a_enc, 02787 gboolean a_free_buf) 02788 { 02789 CRParser *result = NULL; 02790 CRInput *input = NULL; 02791 02792 g_return_val_if_fail (a_buf && a_len, NULL); 02793 02794 input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf); 02795 g_return_val_if_fail (input, NULL); 02796 02797 result = cr_parser_new_from_input (input); 02798 if (!result) { 02799 cr_input_destroy (input); 02800 input = NULL; 02801 return NULL; 02802 } 02803 return result; 02804 } 02805 02806 /** 02807 * cr_parser_new_from_input: 02808 * @a_input: the parser input stream to use. 02809 * 02810 * Returns a newly built parser input. 02811 */ 02812 CRParser * 02813 cr_parser_new_from_input (CRInput * a_input) 02814 { 02815 CRParser *result = NULL; 02816 CRTknzr *tokenizer = NULL; 02817 02818 if (a_input) { 02819 tokenizer = cr_tknzr_new (a_input); 02820 g_return_val_if_fail (tokenizer, NULL); 02821 } 02822 02823 result = cr_parser_new (tokenizer); 02824 g_return_val_if_fail (result, NULL); 02825 02826 return result; 02827 } 02828 02829 /** 02830 * cr_parser_new_from_file: 02831 * @a_file_uri: the uri of the file to parse. 02832 * @a_enc: the file encoding to use. 02833 * 02834 * Returns the newly built parser. 02835 */ 02836 CRParser * 02837 cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc) 02838 { 02839 CRParser *result = NULL; 02840 CRTknzr *tokenizer = NULL; 02841 02842 tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc); 02843 if (!tokenizer) { 02844 cr_utils_trace_info ("Could not open input file"); 02845 return NULL; 02846 } 02847 02848 result = cr_parser_new (tokenizer); 02849 g_return_val_if_fail (result, NULL); 02850 return result; 02851 } 02852 02853 /** 02854 * cr_parser_set_sac_handler: 02855 *@a_this: the "this pointer" of the current instance of #CRParser. 02856 *@a_handler: the handler to set. 02857 * 02858 *Sets a SAC document handler to the parser. 02859 * 02860 *Returns CR_OK upon successfull completion, an error code otherwise. 02861 */ 02862 enum CRStatus 02863 cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler) 02864 { 02865 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 02866 02867 if (PRIVATE (a_this)->sac_handler) { 02868 cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); 02869 } 02870 02871 PRIVATE (a_this)->sac_handler = a_handler; 02872 cr_doc_handler_ref (a_handler); 02873 02874 return CR_OK; 02875 } 02876 02877 /** 02878 * cr_parser_get_sac_handler: 02879 *@a_this: the "this pointer" of the current instance of 02880 *#CRParser. 02881 *@a_handler: out parameter. The returned handler. 02882 * 02883 *Gets the SAC document handler. 02884 * 02885 *Returns CR_OK upon successfull completion, an error code 02886 *otherwise. 02887 */ 02888 enum CRStatus 02889 cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler) 02890 { 02891 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 02892 02893 *a_handler = PRIVATE (a_this)->sac_handler; 02894 02895 return CR_OK; 02896 } 02897 02898 /** 02899 * cr_parser_set_default_sac_handler: 02900 *@a_this: a pointer to the current instance of #CRParser. 02901 * 02902 *Sets the SAC handler associated to the current instance 02903 *of #CRParser to the default SAC handler. 02904 * 02905 *Returns CR_OK upon successfull completion, an error code otherwise. 02906 */ 02907 enum CRStatus 02908 cr_parser_set_default_sac_handler (CRParser * a_this) 02909 { 02910 CRDocHandler *default_sac_handler = NULL; 02911 enum CRStatus status = CR_ERROR; 02912 02913 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 02914 02915 default_sac_handler = cr_doc_handler_new (); 02916 02917 cr_doc_handler_set_default_sac_handler (default_sac_handler); 02918 02919 status = cr_parser_set_sac_handler (a_this, default_sac_handler); 02920 02921 if (status != CR_OK) { 02922 cr_doc_handler_destroy (default_sac_handler); 02923 default_sac_handler = NULL; 02924 } 02925 02926 return status; 02927 } 02928 02929 /** 02930 * cr_parser_set_use_core_grammar: 02931 * @a_this: the current instance of #CRParser. 02932 * @a_use_core_grammar: where to parse against the css core grammar. 02933 * 02934 * Returns CR_OK upon succesful completion, an error code otherwise. 02935 */ 02936 enum CRStatus 02937 cr_parser_set_use_core_grammar (CRParser * a_this, 02938 gboolean a_use_core_grammar) 02939 { 02940 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 02941 02942 PRIVATE (a_this)->use_core_grammar = a_use_core_grammar; 02943 02944 return CR_OK; 02945 } 02946 02947 /** 02948 * cr_parser_get_use_core_grammar: 02949 * @a_this: the current instance of #CRParser. 02950 * @a_use_core_grammar: wether to use the core grammar or not. 02951 * 02952 * Returns CR_OK upon succesful completion, an error code otherwise. 02953 */ 02954 enum CRStatus 02955 cr_parser_get_use_core_grammar (CRParser const * a_this, 02956 gboolean * a_use_core_grammar) 02957 { 02958 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 02959 02960 *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar; 02961 02962 return CR_OK; 02963 } 02964 02965 /** 02966 * cr_parser_parse_file: 02967 *@a_this: a pointer to the current instance of #CRParser. 02968 *@a_file_uri: the uri to the file to load. For the time being, 02969 *@a_enc: the encoding of the file to parse. 02970 *only local files are supported. 02971 * 02972 *Parses a the given in parameter. 02973 * 02974 *Returns CR_OK upon successfull completion, an error code otherwise. 02975 */ 02976 enum CRStatus 02977 cr_parser_parse_file (CRParser * a_this, 02978 const guchar * a_file_uri, enum CREncoding a_enc) 02979 { 02980 enum CRStatus status = CR_ERROR; 02981 CRTknzr *tknzr = NULL; 02982 02983 g_return_val_if_fail (a_this && PRIVATE (a_this) 02984 && a_file_uri, CR_BAD_PARAM_ERROR); 02985 02986 tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc); 02987 02988 g_return_val_if_fail (tknzr != NULL, CR_ERROR); 02989 02990 status = cr_parser_set_tknzr (a_this, tknzr); 02991 g_return_val_if_fail (status == CR_OK, CR_ERROR); 02992 02993 status = cr_parser_parse (a_this); 02994 02995 return status; 02996 } 02997 02998 /** 02999 * cr_parser_parse_expr: 03000 * @a_this: the current instance of #CRParser. 03001 * @a_expr: out parameter. the parsed expression. 03002 * 03003 *Parses an expression as defined by the css2 spec in appendix 03004 *D.1: 03005 *expr: term [ operator term ]* 03006 * 03007 * 03008 * Returns CR_OK upon successful completion, an error code otherwise. 03009 */ 03010 enum CRStatus 03011 cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr) 03012 { 03013 enum CRStatus status = CR_ERROR; 03014 CRInputPos init_pos; 03015 CRTerm *expr = NULL, 03016 *expr2 = NULL; 03017 guchar next_byte = 0; 03018 gulong nb_terms = 0; 03019 03020 g_return_val_if_fail (a_this && PRIVATE (a_this) 03021 && a_expr, CR_BAD_PARAM_ERROR); 03022 03023 RECORD_INITIAL_POS (a_this, &init_pos); 03024 03025 status = cr_parser_parse_term (a_this, &expr); 03026 03027 CHECK_PARSING_STATUS (status, FALSE); 03028 03029 for (;;) { 03030 guchar operator = 0; 03031 03032 status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, 03033 1, &next_byte); 03034 if (status != CR_OK) { 03035 if (status == CR_END_OF_INPUT_ERROR) { 03036 /* 03037 if (!nb_terms) 03038 { 03039 goto error ; 03040 } 03041 */ 03042 status = CR_OK; 03043 break; 03044 } else { 03045 goto error; 03046 } 03047 } 03048 03049 if (next_byte == '/' || next_byte == ',') { 03050 READ_NEXT_BYTE (a_this, &operator); 03051 } 03052 03053 cr_parser_try_to_skip_spaces_and_comments (a_this); 03054 03055 status = cr_parser_parse_term (a_this, &expr2); 03056 03057 if (status != CR_OK || expr2 == NULL) { 03058 status = CR_OK; 03059 break; 03060 } 03061 03062 switch (operator) { 03063 case '/': 03064 expr2->the_operator = DIVIDE; 03065 break; 03066 case ',': 03067 expr2->the_operator = COMMA; 03068 03069 default: 03070 break; 03071 } 03072 03073 expr = cr_term_append_term (expr, expr2); 03074 expr2 = NULL; 03075 operator = 0; 03076 nb_terms++; 03077 } 03078 03079 if (status == CR_OK) { 03080 *a_expr = cr_term_append_term (*a_expr, expr); 03081 expr = NULL; 03082 03083 cr_parser_clear_errors (a_this); 03084 return CR_OK; 03085 } 03086 03087 error: 03088 03089 if (expr) { 03090 cr_term_destroy (expr); 03091 expr = NULL; 03092 } 03093 03094 if (expr2) { 03095 cr_term_destroy (expr2); 03096 expr2 = NULL; 03097 } 03098 03099 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03100 03101 return status; 03102 } 03103 03104 /** 03105 * cr_parser_parse_prio: 03106 *@a_this: the current instance of #CRParser. 03107 *@a_prio: a string representing the priority. 03108 *Today, only "!important" is returned as only this 03109 *priority is defined by css2. 03110 * 03111 *Parses a declaration priority as defined by 03112 *the css2 grammar in appendix C: 03113 *prio: IMPORTANT_SYM S* 03114 * 03115 * Returns CR_OK upon successful completion, an error code otherwise. 03116 */ 03117 enum CRStatus 03118 cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio) 03119 { 03120 enum CRStatus status = CR_ERROR; 03121 CRInputPos init_pos; 03122 CRToken *token = NULL; 03123 03124 g_return_val_if_fail (a_this && PRIVATE (a_this) 03125 && a_prio 03126 && *a_prio == NULL, CR_BAD_PARAM_ERROR); 03127 03128 RECORD_INITIAL_POS (a_this, &init_pos); 03129 03130 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 03131 if (status == CR_END_OF_INPUT_ERROR) { 03132 goto error; 03133 } 03134 ENSURE_PARSING_COND (status == CR_OK 03135 && token && token->type == IMPORTANT_SYM_TK); 03136 03137 cr_parser_try_to_skip_spaces_and_comments (a_this); 03138 *a_prio = cr_string_new_from_string ("!important"); 03139 cr_token_destroy (token); 03140 token = NULL; 03141 return CR_OK; 03142 03143 error: 03144 if (token) { 03145 cr_token_destroy (token); 03146 token = NULL; 03147 } 03148 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03149 03150 return status; 03151 } 03152 03153 /** 03154 * cr_parser_parse_declaration: 03155 *@a_this: the "this pointer" of the current instance of #CRParser. 03156 *@a_property: the successfully parsed property. The caller 03157 * *must* free the returned pointer. 03158 *@a_expr: the expression that represents the attribute value. 03159 *The caller *must* free the returned pointer. 03160 * 03161 *TODO: return the parsed priority, so that 03162 *upper layers can take benefit from it. 03163 *Parses a "declaration" as defined by the css2 spec in appendix D.1: 03164 *declaration ::= [property ':' S* expr prio?]? 03165 * 03166 *Returns CR_OK upon successfull completion, an error code otherwise. 03167 */ 03168 enum CRStatus 03169 cr_parser_parse_declaration (CRParser * a_this, 03170 CRString ** a_property, 03171 CRTerm ** a_expr, gboolean * a_important) 03172 { 03173 enum CRStatus status = CR_ERROR; 03174 CRInputPos init_pos; 03175 guint32 cur_char = 0; 03176 CRTerm *expr = NULL; 03177 CRString *prio = NULL; 03178 03179 g_return_val_if_fail (a_this && PRIVATE (a_this) 03180 && a_property && a_expr 03181 && a_important, CR_BAD_PARAM_ERROR); 03182 03183 RECORD_INITIAL_POS (a_this, &init_pos); 03184 03185 status = cr_parser_parse_property (a_this, a_property); 03186 03187 if (status == CR_END_OF_INPUT_ERROR) 03188 goto error; 03189 03190 CHECK_PARSING_STATUS_ERR 03191 (a_this, status, FALSE, 03192 (const guchar *) "while parsing declaration: next property is malformed", 03193 CR_SYNTAX_ERROR); 03194 03195 READ_NEXT_CHAR (a_this, &cur_char); 03196 03197 if (cur_char != ':') { 03198 status = CR_PARSING_ERROR; 03199 cr_parser_push_error 03200 (a_this, 03201 (const guchar *) "while parsing declaration: this char must be ':'", 03202 CR_SYNTAX_ERROR); 03203 goto error; 03204 } 03205 03206 cr_parser_try_to_skip_spaces_and_comments (a_this); 03207 03208 status = cr_parser_parse_expr (a_this, &expr); 03209 03210 CHECK_PARSING_STATUS_ERR 03211 (a_this, status, FALSE, 03212 (const guchar *) "while parsing declaration: next expression is malformed", 03213 CR_SYNTAX_ERROR); 03214 03215 cr_parser_try_to_skip_spaces_and_comments (a_this); 03216 status = cr_parser_parse_prio (a_this, &prio); 03217 if (prio) { 03218 cr_string_destroy (prio); 03219 prio = NULL; 03220 *a_important = TRUE; 03221 } else { 03222 *a_important = FALSE; 03223 } 03224 if (*a_expr) { 03225 cr_term_append_term (*a_expr, expr); 03226 expr = NULL; 03227 } else { 03228 *a_expr = expr; 03229 expr = NULL; 03230 } 03231 03232 cr_parser_clear_errors (a_this); 03233 return CR_OK; 03234 03235 error: 03236 03237 if (expr) { 03238 cr_term_destroy (expr); 03239 expr = NULL; 03240 } 03241 03242 if (*a_property) { 03243 cr_string_destroy (*a_property); 03244 *a_property = NULL; 03245 } 03246 03247 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03248 03249 return status; 03250 } 03251 03252 /** 03253 * cr_parser_parse_statement_core: 03254 *@a_this: the current instance of #CRParser. 03255 * 03256 *Parses a statement as defined by the css core grammar in 03257 *chapter 4.1 of the css2 spec. 03258 *statement : ruleset | at-rule; 03259 * 03260 *Returns CR_OK upon successfull completion, an error code otherwise. 03261 */ 03262 enum CRStatus 03263 cr_parser_parse_statement_core (CRParser * a_this) 03264 { 03265 CRToken *token = NULL; 03266 CRInputPos init_pos; 03267 enum CRStatus status = CR_ERROR; 03268 03269 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 03270 03271 RECORD_INITIAL_POS (a_this, &init_pos); 03272 03273 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 03274 03275 ENSURE_PARSING_COND (status == CR_OK && token); 03276 03277 switch (token->type) { 03278 case ATKEYWORD_TK: 03279 case IMPORT_SYM_TK: 03280 case PAGE_SYM_TK: 03281 case MEDIA_SYM_TK: 03282 case FONT_FACE_SYM_TK: 03283 case CHARSET_SYM_TK: 03284 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 03285 token = NULL; 03286 status = cr_parser_parse_atrule_core (a_this); 03287 CHECK_PARSING_STATUS (status, TRUE); 03288 break; 03289 03290 default: 03291 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 03292 token = NULL; 03293 status = cr_parser_parse_ruleset_core (a_this); 03294 cr_parser_clear_errors (a_this); 03295 CHECK_PARSING_STATUS (status, TRUE); 03296 } 03297 03298 return CR_OK; 03299 03300 error: 03301 if (token) { 03302 cr_token_destroy (token); 03303 token = NULL; 03304 } 03305 03306 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03307 03308 return status; 03309 } 03310 03311 /** 03312 * cr_parser_parse_ruleset: 03313 *@a_this: the "this pointer" of the current instance of #CRParser. 03314 * 03315 *Parses a "ruleset" as defined in the css2 spec at appendix D.1. 03316 *ruleset ::= selector [ ',' S* selector ]* 03317 *'{' S* declaration? [ ';' S* declaration? ]* '}' S*; 03318 * 03319 *This methods calls the the SAC handler on the relevant SAC handler 03320 *callbacks whenever it encounters some specific constructions. 03321 *See the documentation of #CRDocHandler (the SAC handler) to know 03322 *when which SAC handler is called. 03323 * 03324 *Returns CR_OK upon successfull completion, an error code otherwise. 03325 */ 03326 enum CRStatus 03327 cr_parser_parse_ruleset (CRParser * a_this) 03328 { 03329 enum CRStatus status = CR_OK; 03330 CRInputPos init_pos; 03331 guint32 cur_char = 0, 03332 next_char = 0; 03333 CRString *property = NULL; 03334 CRTerm *expr = NULL; 03335 CRSimpleSel *simple_sels = NULL; 03336 CRSelector *selector = NULL; 03337 gboolean start_selector = FALSE, 03338 is_important = FALSE; 03339 CRParsingLocation end_parsing_location; 03340 03341 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 03342 03343 RECORD_INITIAL_POS (a_this, &init_pos); 03344 03345 status = cr_parser_parse_selector (a_this, &selector); 03346 CHECK_PARSING_STATUS (status, FALSE); 03347 03348 READ_NEXT_CHAR (a_this, &cur_char); 03349 03350 ENSURE_PARSING_COND_ERR 03351 (a_this, cur_char == '{', 03352 (const guchar *) "while parsing rulset: current char should be '{'", 03353 CR_SYNTAX_ERROR); 03354 03355 if (PRIVATE (a_this)->sac_handler 03356 && PRIVATE (a_this)->sac_handler->start_selector) { 03357 /* 03358 *the selector is ref counted so that the parser's user 03359 *can choose to keep it. 03360 */ 03361 if (selector) { 03362 cr_selector_ref (selector); 03363 } 03364 03365 PRIVATE (a_this)->sac_handler->start_selector 03366 (PRIVATE (a_this)->sac_handler, selector); 03367 start_selector = TRUE; 03368 } 03369 03370 cr_parser_try_to_skip_spaces_and_comments (a_this); 03371 03372 PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE; 03373 03374 status = cr_parser_parse_declaration (a_this, &property, 03375 &expr, 03376 &is_important); 03377 if (expr) { 03378 cr_term_ref (expr); 03379 } 03380 if (status == CR_OK 03381 && PRIVATE (a_this)->sac_handler 03382 && PRIVATE (a_this)->sac_handler->property) { 03383 PRIVATE (a_this)->sac_handler->property 03384 (PRIVATE (a_this)->sac_handler, property, expr, 03385 is_important); 03386 } 03387 if (status == CR_OK) { 03388 /* 03389 *free the allocated 03390 *'property' and 'term' before parsing 03391 *next declarations. 03392 */ 03393 if (property) { 03394 cr_string_destroy (property); 03395 property = NULL; 03396 } 03397 if (expr) { 03398 cr_term_unref (expr); 03399 expr = NULL; 03400 } 03401 } else {/*status != CR_OK*/ 03402 guint32 c = 0 ; 03403 /* 03404 *test if we have reached '}', which 03405 *would mean that we are parsing an empty ruleset (eg. x{ }) 03406 *In that case, goto end_of_ruleset. 03407 */ 03408 status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ; 03409 if (status == CR_OK && c == '}') { 03410 status = CR_OK ; 03411 goto end_of_ruleset ; 03412 } 03413 } 03414 CHECK_PARSING_STATUS_ERR 03415 (a_this, status, FALSE, 03416 (const guchar *) "while parsing ruleset: next construction should be a declaration", 03417 CR_SYNTAX_ERROR); 03418 03419 for (;;) { 03420 PEEK_NEXT_CHAR (a_this, &next_char); 03421 if (next_char != ';') 03422 break; 03423 03424 /*consume the ';' char */ 03425 READ_NEXT_CHAR (a_this, &cur_char); 03426 03427 cr_parser_try_to_skip_spaces_and_comments (a_this); 03428 03429 status = cr_parser_parse_declaration (a_this, &property, 03430 &expr, &is_important); 03431 03432 if (expr) { 03433 cr_term_ref (expr); 03434 } 03435 if (status == CR_OK 03436 && PRIVATE (a_this)->sac_handler 03437 && PRIVATE (a_this)->sac_handler->property) { 03438 PRIVATE (a_this)->sac_handler->property 03439 (PRIVATE (a_this)->sac_handler, 03440 property, expr, is_important); 03441 } 03442 if (property) { 03443 cr_string_destroy (property); 03444 property = NULL; 03445 } 03446 if (expr) { 03447 cr_term_unref (expr); 03448 expr = NULL; 03449 } 03450 } 03451 03452 end_of_ruleset: 03453 cr_parser_try_to_skip_spaces_and_comments (a_this); 03454 cr_parser_get_parsing_location (a_this, &end_parsing_location); 03455 READ_NEXT_CHAR (a_this, &cur_char); 03456 ENSURE_PARSING_COND_ERR 03457 (a_this, cur_char == '}', 03458 (const guchar *) "while parsing rulset: current char must be a '}'", 03459 CR_SYNTAX_ERROR); 03460 03461 selector->location = end_parsing_location; 03462 if (PRIVATE (a_this)->sac_handler 03463 && PRIVATE (a_this)->sac_handler->end_selector) { 03464 PRIVATE (a_this)->sac_handler->end_selector 03465 (PRIVATE (a_this)->sac_handler, selector); 03466 start_selector = FALSE; 03467 } 03468 03469 if (expr) { 03470 cr_term_unref (expr); 03471 expr = NULL; 03472 } 03473 03474 if (simple_sels) { 03475 cr_simple_sel_destroy (simple_sels); 03476 simple_sels = NULL; 03477 } 03478 03479 if (selector) { 03480 cr_selector_unref (selector); 03481 selector = NULL; 03482 } 03483 03484 cr_parser_clear_errors (a_this); 03485 PRIVATE (a_this)->state = RULESET_PARSED_STATE; 03486 03487 return CR_OK; 03488 03489 error: 03490 if (start_selector == TRUE 03491 && PRIVATE (a_this)->sac_handler 03492 && PRIVATE (a_this)->sac_handler->error) { 03493 PRIVATE (a_this)->sac_handler->error 03494 (PRIVATE (a_this)->sac_handler); 03495 } 03496 if (expr) { 03497 cr_term_unref (expr); 03498 expr = NULL; 03499 } 03500 if (simple_sels) { 03501 cr_simple_sel_destroy (simple_sels); 03502 simple_sels = NULL; 03503 } 03504 if (property) { 03505 cr_string_destroy (property); 03506 } 03507 if (selector) { 03508 cr_selector_unref (selector); 03509 selector = NULL; 03510 } 03511 03512 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03513 03514 return status; 03515 } 03516 03517 /** 03518 * cr_parser_parse_import: 03519 *@a_this: the "this pointer" of the current instance 03520 *of #CRParser. 03521 *@a_media_list: out parameter. A linked list of 03522 *#CRString 03523 *Each CRString is a string that contains 03524 *a 'medium' declaration part of the successfully 03525 *parsed 'import' declaration. 03526 *@a_import_string: out parameter. 03527 *A string that contains the 'import 03528 *string". The import string can be either an uri (if it starts with 03529 *the substring "uri(") or a any other css2 string. Note that 03530 * *a_import_string must be initially set to NULL or else, this function 03531 *will return CR_BAD_PARAM_ERROR. 03532 *@a_location: the location (line, column) where the import has been parsed 03533 * 03534 *Parses an 'import' declaration as defined in the css2 spec 03535 *in appendix D.1: 03536 * 03537 *import ::= 03538 *\@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S* 03539 * 03540 *Returns CR_OK upon sucessfull completion, an error code otherwise. 03541 */ 03542 enum CRStatus 03543 cr_parser_parse_import (CRParser * a_this, 03544 GList ** a_media_list, 03545 CRString ** a_import_string, 03546 CRParsingLocation *a_location) 03547 { 03548 enum CRStatus status = CR_OK; 03549 CRInputPos init_pos; 03550 guint32 cur_char = 0, 03551 next_char = 0; 03552 CRString *medium = NULL; 03553 03554 g_return_val_if_fail (a_this 03555 && a_import_string 03556 && (*a_import_string == NULL), 03557 CR_BAD_PARAM_ERROR); 03558 03559 RECORD_INITIAL_POS (a_this, &init_pos); 03560 03561 if (BYTE (a_this, 1, NULL) == '@' 03562 && BYTE (a_this, 2, NULL) == 'i' 03563 && BYTE (a_this, 3, NULL) == 'm' 03564 && BYTE (a_this, 4, NULL) == 'p' 03565 && BYTE (a_this, 5, NULL) == 'o' 03566 && BYTE (a_this, 6, NULL) == 'r' 03567 && BYTE (a_this, 7, NULL) == 't') { 03568 SKIP_CHARS (a_this, 1); 03569 if (a_location) { 03570 cr_parser_get_parsing_location 03571 (a_this, a_location) ; 03572 } 03573 SKIP_CHARS (a_this, 6); 03574 status = CR_OK; 03575 } else { 03576 status = CR_PARSING_ERROR; 03577 goto error; 03578 } 03579 03580 cr_parser_try_to_skip_spaces_and_comments (a_this); 03581 03582 PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE; 03583 03584 PEEK_NEXT_CHAR (a_this, &next_char); 03585 03586 if (next_char == '"' || next_char == '\'') { 03587 status = cr_parser_parse_string (a_this, a_import_string); 03588 03589 CHECK_PARSING_STATUS (status, FALSE); 03590 } else { 03591 status = cr_parser_parse_uri (a_this, a_import_string); 03592 03593 CHECK_PARSING_STATUS (status, FALSE); 03594 } 03595 03596 cr_parser_try_to_skip_spaces_and_comments (a_this); 03597 03598 status = cr_parser_parse_ident (a_this, &medium); 03599 03600 if (status == CR_OK && medium) { 03601 *a_media_list = g_list_append (*a_media_list, medium); 03602 medium = NULL; 03603 } 03604 03605 cr_parser_try_to_skip_spaces_and_comments (a_this); 03606 03607 for (; status == CR_OK;) { 03608 if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, 03609 &next_char)) != CR_OK) { 03610 if (status == CR_END_OF_INPUT_ERROR) { 03611 status = CR_OK; 03612 goto okay; 03613 } 03614 goto error; 03615 } 03616 03617 if (next_char == ',') { 03618 READ_NEXT_CHAR (a_this, &cur_char); 03619 } else { 03620 break; 03621 } 03622 03623 cr_parser_try_to_skip_spaces_and_comments (a_this); 03624 03625 status = cr_parser_parse_ident (a_this, &medium); 03626 03627 cr_parser_try_to_skip_spaces_and_comments (a_this); 03628 03629 if ((status == CR_OK) && medium) { 03630 *a_media_list = g_list_append (*a_media_list, medium); 03631 03632 medium = NULL; 03633 } 03634 03635 CHECK_PARSING_STATUS (status, FALSE); 03636 cr_parser_try_to_skip_spaces_and_comments (a_this); 03637 } 03638 cr_parser_try_to_skip_spaces_and_comments (a_this); 03639 READ_NEXT_CHAR (a_this, &cur_char); 03640 ENSURE_PARSING_COND (cur_char == ';'); 03641 cr_parser_try_to_skip_spaces_and_comments (a_this); 03642 okay: 03643 cr_parser_clear_errors (a_this); 03644 PRIVATE (a_this)->state = IMPORT_PARSED_STATE; 03645 03646 return CR_OK; 03647 03648 error: 03649 03650 if (*a_media_list) { 03651 GList *cur = NULL; 03652 03653 /* 03654 *free each element of *a_media_list. 03655 *Note that each element of *a_medium list *must* 03656 *be a GString* or else, the code that is coming next 03657 *will corrupt the memory and lead to hard to debug 03658 *random crashes. 03659 *This is where C++ and its compile time 03660 *type checking mecanism (through STL containers) would 03661 *have prevented us to go through this hassle. 03662 */ 03663 for (cur = *a_media_list; cur; cur = cur->next) { 03664 if (cur->data) { 03665 cr_string_destroy (cur->data); 03666 } 03667 } 03668 03669 g_list_free (*a_media_list); 03670 *a_media_list = NULL; 03671 } 03672 03673 if (*a_import_string) { 03674 cr_string_destroy (*a_import_string); 03675 *a_import_string = NULL; 03676 } 03677 03678 if (medium) { 03679 cr_string_destroy (medium); 03680 medium = NULL; 03681 } 03682 03683 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03684 03685 return status; 03686 } 03687 03688 /** 03689 * cr_parser_parse_media: 03690 *@a_this: the "this pointer" of the current instance of #CRParser. 03691 * 03692 *Parses a 'media' declaration as specified in the css2 spec at 03693 *appendix D.1: 03694 * 03695 *media ::= \@media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S* 03696 * 03697 *Note that this function calls the required sac handlers during the parsing 03698 *to notify media productions. See #CRDocHandler to know the callback called 03699 *during \@media parsing. 03700 * 03701 *Returns CR_OK upon successfull completion, an error code otherwise. 03702 */ 03703 enum CRStatus 03704 cr_parser_parse_media (CRParser * a_this) 03705 { 03706 enum CRStatus status = CR_OK; 03707 CRInputPos init_pos; 03708 CRToken *token = NULL; 03709 guint32 next_char = 0, 03710 cur_char = 0; 03711 CRString *medium = NULL; 03712 GList *media_list = NULL; 03713 CRParsingLocation location = {0} ; 03714 03715 g_return_val_if_fail (a_this 03716 && PRIVATE (a_this), 03717 CR_BAD_PARAM_ERROR); 03718 03719 RECORD_INITIAL_POS (a_this, &init_pos); 03720 03721 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 03722 &token); 03723 ENSURE_PARSING_COND (status == CR_OK 03724 && token 03725 && token->type == MEDIA_SYM_TK); 03726 cr_parsing_location_copy (&location, &token->location) ; 03727 cr_token_destroy (token); 03728 token = NULL; 03729 03730 cr_parser_try_to_skip_spaces_and_comments (a_this); 03731 03732 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 03733 ENSURE_PARSING_COND (status == CR_OK 03734 && token && token->type == IDENT_TK); 03735 03736 medium = token->u.str; 03737 token->u.str = NULL; 03738 cr_token_destroy (token); 03739 token = NULL; 03740 03741 if (medium) { 03742 media_list = g_list_append (media_list, medium); 03743 medium = NULL; 03744 } 03745 03746 for (; status == CR_OK;) { 03747 cr_parser_try_to_skip_spaces_and_comments (a_this); 03748 PEEK_NEXT_CHAR (a_this, &next_char); 03749 03750 if (next_char == ',') { 03751 READ_NEXT_CHAR (a_this, &cur_char); 03752 } else { 03753 break; 03754 } 03755 03756 cr_parser_try_to_skip_spaces_and_comments (a_this); 03757 03758 status = cr_parser_parse_ident (a_this, &medium); 03759 03760 CHECK_PARSING_STATUS (status, FALSE); 03761 03762 if (medium) { 03763 media_list = g_list_append (media_list, medium); 03764 medium = NULL; 03765 } 03766 } 03767 03768 READ_NEXT_CHAR (a_this, &cur_char); 03769 03770 ENSURE_PARSING_COND (cur_char == '{'); 03771 03772 /* 03773 *call the SAC handler api here. 03774 */ 03775 if (PRIVATE (a_this)->sac_handler 03776 && PRIVATE (a_this)->sac_handler->start_media) { 03777 PRIVATE (a_this)->sac_handler->start_media 03778 (PRIVATE (a_this)->sac_handler, media_list, 03779 &location); 03780 } 03781 03782 cr_parser_try_to_skip_spaces_and_comments (a_this); 03783 03784 PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE; 03785 03786 for (; status == CR_OK;) { 03787 status = cr_parser_parse_ruleset (a_this); 03788 cr_parser_try_to_skip_spaces_and_comments (a_this); 03789 } 03790 03791 READ_NEXT_CHAR (a_this, &cur_char); 03792 03793 ENSURE_PARSING_COND (cur_char == '}'); 03794 03795 /* 03796 *call the right SAC handler api here. 03797 */ 03798 if (PRIVATE (a_this)->sac_handler 03799 && PRIVATE (a_this)->sac_handler->end_media) { 03800 PRIVATE (a_this)->sac_handler->end_media 03801 (PRIVATE (a_this)->sac_handler, media_list); 03802 } 03803 03804 cr_parser_try_to_skip_spaces_and_comments (a_this); 03805 03806 /* 03807 *Then, free the data structures passed to 03808 *the last call to the SAC handler. 03809 */ 03810 if (medium) { 03811 cr_string_destroy (medium); 03812 medium = NULL; 03813 } 03814 03815 if (media_list) { 03816 GList *cur = NULL; 03817 03818 for (cur = media_list; cur; cur = cur->next) { 03819 cr_string_destroy (cur->data); 03820 } 03821 03822 g_list_free (media_list); 03823 media_list = NULL; 03824 } 03825 03826 cr_parser_clear_errors (a_this); 03827 PRIVATE (a_this)->state = MEDIA_PARSED_STATE; 03828 03829 return CR_OK; 03830 03831 error: 03832 03833 if (token) { 03834 cr_token_destroy (token); 03835 token = NULL; 03836 } 03837 03838 if (medium) { 03839 cr_string_destroy (medium); 03840 medium = NULL; 03841 } 03842 03843 if (media_list) { 03844 GList *cur = NULL; 03845 03846 for (cur = media_list; cur; cur = cur->next) { 03847 cr_string_destroy (cur->data); 03848 } 03849 03850 g_list_free (media_list); 03851 media_list = NULL; 03852 } 03853 03854 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 03855 03856 return status; 03857 } 03858 03859 /** 03860 * cr_parser_parse_page: 03861 *@a_this: the "this pointer" of the current instance of #CRParser. 03862 * 03863 *Parses '\@page' rule as specified in the css2 spec in appendix D.1: 03864 *page ::= PAGE_SYM S* IDENT? pseudo_page? S* 03865 *'{' S* declaration [ ';' S* declaration ]* '}' S* 03866 * 03867 *This function also calls the relevant SAC handlers whenever it 03868 *encounters a construction that must 03869 *be reported to the calling application. 03870 * 03871 *Returns CR_OK upon successfull completion, an error code otherwise. 03872 */ 03873 enum CRStatus 03874 cr_parser_parse_page (CRParser * a_this) 03875 { 03876 enum CRStatus status = CR_OK; 03877 CRInputPos init_pos; 03878 CRToken *token = NULL; 03879 CRTerm *css_expression = NULL; 03880 CRString *page_selector = NULL, 03881 *page_pseudo_class = NULL, 03882 *property = NULL; 03883 gboolean important = TRUE; 03884 CRParsingLocation location = {0} ; 03885 03886 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 03887 03888 RECORD_INITIAL_POS (a_this, &init_pos); 03889 03890 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 03891 &token) ; 03892 ENSURE_PARSING_COND (status == CR_OK 03893 && token 03894 && token->type == PAGE_SYM_TK); 03895 03896 cr_parsing_location_copy (&location, &token->location) ; 03897 cr_token_destroy (token); 03898 token = NULL; 03899 03900 cr_parser_try_to_skip_spaces_and_comments (a_this); 03901 03902 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 03903 ENSURE_PARSING_COND (status == CR_OK && token); 03904 03905 if (token->type == IDENT_TK) { 03906 page_selector = token->u.str; 03907 token->u.str = NULL; 03908 cr_token_destroy (token); 03909 token = NULL; 03910 } else { 03911 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 03912 token = NULL; 03913 } 03914 03915 /* 03916 *try to parse pseudo_page 03917 */ 03918 cr_parser_try_to_skip_spaces_and_comments (a_this); 03919 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 03920 ENSURE_PARSING_COND (status == CR_OK && token); 03921 03922 if (token->type == DELIM_TK && token->u.unichar == ':') { 03923 cr_token_destroy (token); 03924 token = NULL; 03925 status = cr_parser_parse_ident (a_this, &page_pseudo_class); 03926 CHECK_PARSING_STATUS (status, FALSE); 03927 } else { 03928 cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 03929 token = NULL; 03930 } 03931 03932 /* 03933 *parse_block 03934 * 03935 */ 03936 cr_parser_try_to_skip_spaces_and_comments (a_this); 03937 03938 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 03939 03940 ENSURE_PARSING_COND (status == CR_OK && token 03941 && token->type == CBO_TK); 03942 03943 cr_token_destroy (token); 03944 token = NULL; 03945 03946 /* 03947 *Call the appropriate SAC handler here. 03948 */ 03949 if (PRIVATE (a_this)->sac_handler 03950 && PRIVATE (a_this)->sac_handler->start_page) { 03951 PRIVATE (a_this)->sac_handler->start_page 03952 (PRIVATE (a_this)->sac_handler, 03953 page_selector, page_pseudo_class, 03954 &location); 03955 } 03956 cr_parser_try_to_skip_spaces_and_comments (a_this); 03957 03958 PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE; 03959 03960 status = cr_parser_parse_declaration (a_this, &property, 03961 &css_expression, 03962 &important); 03963 ENSURE_PARSING_COND (status == CR_OK); 03964 03965 /* 03966 *call the relevant SAC handler here... 03967 */ 03968 if (PRIVATE (a_this)->sac_handler 03969 && PRIVATE (a_this)->sac_handler->property) { 03970 if (css_expression) 03971 cr_term_ref (css_expression); 03972 03973 PRIVATE (a_this)->sac_handler->property 03974 (PRIVATE (a_this)->sac_handler, 03975 property, css_expression, important); 03976 } 03977 /* 03978 *... and free the data structure passed to that last 03979 *SAC handler. 03980 */ 03981 if (property) { 03982 cr_string_destroy (property); 03983 property = NULL; 03984 } 03985 if (css_expression) { 03986 cr_term_unref (css_expression); 03987 css_expression = NULL; 03988 } 03989 03990 for (;;) { 03991 /*parse the other ';' separated declarations */ 03992 if (token) { 03993 cr_token_destroy (token); 03994 token = NULL; 03995 } 03996 status = cr_tknzr_get_next_token 03997 (PRIVATE (a_this)->tknzr, &token); 03998 03999 ENSURE_PARSING_COND (status == CR_OK && token); 04000 04001 if (token->type != SEMICOLON_TK) { 04002 cr_tknzr_unget_token 04003 (PRIVATE (a_this)->tknzr, 04004 token); 04005 token = NULL ; 04006 break; 04007 } 04008 04009 cr_token_destroy (token); 04010 token = NULL; 04011 cr_parser_try_to_skip_spaces_and_comments (a_this); 04012 04013 status = cr_parser_parse_declaration (a_this, &property, 04014 &css_expression, 04015 &important); 04016 if (status != CR_OK) 04017 break ; 04018 04019 /* 04020 *call the relevant SAC handler here... 04021 */ 04022 if (PRIVATE (a_this)->sac_handler 04023 && PRIVATE (a_this)->sac_handler->property) { 04024 cr_term_ref (css_expression); 04025 PRIVATE (a_this)->sac_handler->property 04026 (PRIVATE (a_this)->sac_handler, 04027 property, css_expression, important); 04028 } 04029 /* 04030 *... and free the data structure passed to that last 04031 *SAC handler. 04032 */ 04033 if (property) { 04034 cr_string_destroy (property); 04035 property = NULL; 04036 } 04037 if (css_expression) { 04038 cr_term_unref (css_expression); 04039 css_expression = NULL; 04040 } 04041 } 04042 cr_parser_try_to_skip_spaces_and_comments 04043 (a_this) ; 04044 if (token) { 04045 cr_token_destroy (token) ; 04046 token = NULL ; 04047 } 04048 04049 status = cr_tknzr_get_next_token 04050 (PRIVATE (a_this)->tknzr, &token); 04051 ENSURE_PARSING_COND (status == CR_OK 04052 && token 04053 && token->type == CBC_TK) ; 04054 cr_token_destroy (token) ; 04055 token = NULL ; 04056 /* 04057 *call the relevant SAC handler here. 04058 */ 04059 if (PRIVATE (a_this)->sac_handler 04060 && PRIVATE (a_this)->sac_handler->end_page) { 04061 PRIVATE (a_this)->sac_handler->end_page 04062 (PRIVATE (a_this)->sac_handler, 04063 page_selector, page_pseudo_class); 04064 } 04065 04066 if (page_selector) { 04067 cr_string_destroy (page_selector); 04068 page_selector = NULL; 04069 } 04070 04071 if (page_pseudo_class) { 04072 cr_string_destroy (page_pseudo_class); 04073 page_pseudo_class = NULL; 04074 } 04075 04076 cr_parser_try_to_skip_spaces_and_comments (a_this); 04077 04078 /*here goes the former implem of this function ... */ 04079 04080 cr_parser_clear_errors (a_this); 04081 PRIVATE (a_this)->state = PAGE_PARSED_STATE; 04082 04083 return CR_OK; 04084 04085 error: 04086 if (token) { 04087 cr_token_destroy (token); 04088 token = NULL; 04089 } 04090 if (page_selector) { 04091 cr_string_destroy (page_selector); 04092 page_selector = NULL; 04093 } 04094 if (page_pseudo_class) { 04095 cr_string_destroy (page_pseudo_class); 04096 page_pseudo_class = NULL; 04097 } 04098 if (property) { 04099 cr_string_destroy (property); 04100 property = NULL; 04101 } 04102 if (css_expression) { 04103 cr_term_destroy (css_expression); 04104 css_expression = NULL; 04105 } 04106 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 04107 return status; 04108 } 04109 04110 /** 04111 * cr_parser_parse_charset: 04112 *@a_this: the "this pointer" of the current instance of #CRParser. 04113 *@a_value: out parameter. The actual parsed value of the charset 04114 *declararation. Note that for safety check reasons, *a_value must be 04115 *set to NULL. 04116 *@a_charset_sym_location: the parsing location of the charset rule 04117 * 04118 *Parses a charset declaration as defined implictly by the css2 spec in 04119 *appendix D.1: 04120 *charset ::= CHARSET_SYM S* STRING S* ';' 04121 * 04122 *Returns CR_OK upon successfull completion, an error code otherwise. 04123 */ 04124 enum CRStatus 04125 cr_parser_parse_charset (CRParser * a_this, CRString ** a_value, 04126 CRParsingLocation *a_charset_sym_location) 04127 { 04128 enum CRStatus status = CR_OK; 04129 CRInputPos init_pos; 04130 CRToken *token = NULL; 04131 CRString *charset_str = NULL; 04132 04133 g_return_val_if_fail (a_this && a_value 04134 && (*a_value == NULL), 04135 CR_BAD_PARAM_ERROR); 04136 04137 RECORD_INITIAL_POS (a_this, &init_pos); 04138 04139 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 04140 04141 ENSURE_PARSING_COND (status == CR_OK 04142 && token && token->type == CHARSET_SYM_TK); 04143 if (a_charset_sym_location) { 04144 cr_parsing_location_copy (a_charset_sym_location, 04145 &token->location) ; 04146 } 04147 cr_token_destroy (token); 04148 token = NULL; 04149 04150 PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE; 04151 04152 cr_parser_try_to_skip_spaces_and_comments (a_this); 04153 04154 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 04155 ENSURE_PARSING_COND (status == CR_OK 04156 && token && token->type == STRING_TK); 04157 charset_str = token->u.str; 04158 token->u.str = NULL; 04159 cr_token_destroy (token); 04160 token = NULL; 04161 04162 cr_parser_try_to_skip_spaces_and_comments (a_this); 04163 04164 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 04165 04166 ENSURE_PARSING_COND (status == CR_OK 04167 && token && token->type == SEMICOLON_TK); 04168 cr_token_destroy (token); 04169 token = NULL; 04170 04171 if (charset_str) { 04172 *a_value = charset_str; 04173 charset_str = NULL; 04174 } 04175 04176 PRIVATE (a_this)->state = CHARSET_PARSED_STATE; 04177 return CR_OK; 04178 04179 error: 04180 04181 if (token) { 04182 cr_token_destroy (token); 04183 token = NULL; 04184 } 04185 04186 if (*a_value) { 04187 cr_string_destroy (*a_value); 04188 *a_value = NULL; 04189 } 04190 04191 if (charset_str) { 04192 cr_string_destroy (charset_str); 04193 charset_str = NULL; 04194 } 04195 04196 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 04197 04198 return status; 04199 } 04200 04201 /** 04202 * cr_parser_parse_font_face: 04203 *@a_this: the current instance of #CRParser. 04204 * 04205 *Parses the "\@font-face" rule specified in the css1 spec in 04206 *appendix D.1: 04207 * 04208 *font_face ::= FONT_FACE_SYM S* 04209 *'{' S* declaration [ ';' S* declaration ]* '}' S* 04210 * 04211 *This function will call SAC handlers whenever it is necessary. 04212 * 04213 *Returns CR_OK upon successfull completion, an error code otherwise. 04214 */ 04215 enum CRStatus 04216 cr_parser_parse_font_face (CRParser * a_this) 04217 { 04218 enum CRStatus status = CR_ERROR; 04219 CRInputPos init_pos; 04220 CRString *property = NULL; 04221 CRTerm *css_expression = NULL; 04222 CRToken *token = NULL; 04223 gboolean important = FALSE; 04224 guint32 next_char = 0, 04225 cur_char = 0; 04226 CRParsingLocation location = {0} ; 04227 04228 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 04229 04230 RECORD_INITIAL_POS (a_this, &init_pos); 04231 04232 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 04233 ENSURE_PARSING_COND (status == CR_OK 04234 && token 04235 && token->type == FONT_FACE_SYM_TK); 04236 04237 cr_parser_try_to_skip_spaces_and_comments (a_this); 04238 if (token) { 04239 cr_parsing_location_copy (&location, 04240 &token->location) ; 04241 cr_token_destroy (token); 04242 token = NULL; 04243 } 04244 status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 04245 &token); 04246 ENSURE_PARSING_COND (status == CR_OK && token 04247 && token->type == CBO_TK); 04248 if (token) { 04249 cr_token_destroy (token); 04250 token = NULL; 04251 } 04252 /* 04253 *here, call the relevant SAC handler. 04254 */ 04255 if (PRIVATE (a_this)->sac_handler 04256 && PRIVATE (a_this)->sac_handler->start_font_face) { 04257 PRIVATE (a_this)->sac_handler->start_font_face 04258 (PRIVATE (a_this)->sac_handler, &location); 04259 } 04260 PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE; 04261 /* 04262 *and resume the parsing. 04263 */ 04264 cr_parser_try_to_skip_spaces_and_comments (a_this); 04265 status = cr_parser_parse_declaration (a_this, &property, 04266 &css_expression, &important); 04267 if (status == CR_OK) { 04268 /* 04269 *here, call the relevant SAC handler. 04270 */ 04271 cr_term_ref (css_expression); 04272 if (PRIVATE (a_this)->sac_handler && 04273 PRIVATE (a_this)->sac_handler->property) { 04274 PRIVATE (a_this)->sac_handler->property 04275 (PRIVATE (a_this)->sac_handler, 04276 property, css_expression, important); 04277 } 04278 ENSURE_PARSING_COND (css_expression && property); 04279 } 04280 /*free the data structures allocated during last parsing. */ 04281 if (property) { 04282 cr_string_destroy (property); 04283 property = NULL; 04284 } 04285 if (css_expression) { 04286 cr_term_unref (css_expression); 04287 css_expression = NULL; 04288 } 04289 for (;;) { 04290 PEEK_NEXT_CHAR (a_this, &next_char); 04291 if (next_char == ';') { 04292 READ_NEXT_CHAR (a_this, &cur_char); 04293 } else { 04294 break; 04295 } 04296 cr_parser_try_to_skip_spaces_and_comments (a_this); 04297 status = cr_parser_parse_declaration (a_this, 04298 &property, 04299 &css_expression, 04300 &important); 04301 if (status != CR_OK) 04302 break; 04303 /* 04304 *here, call the relevant SAC handler. 04305 */ 04306 cr_term_ref (css_expression); 04307 if (PRIVATE (a_this)->sac_handler->property) { 04308 PRIVATE (a_this)->sac_handler->property 04309 (PRIVATE (a_this)->sac_handler, 04310 property, css_expression, important); 04311 } 04312 /* 04313 *Then, free the data structures allocated during 04314 *last parsing. 04315 */ 04316 if (property) { 04317 cr_string_destroy (property); 04318 property = NULL; 04319 } 04320 if (css_expression) { 04321 cr_term_unref (css_expression); 04322 css_expression = NULL; 04323 } 04324 } 04325 cr_parser_try_to_skip_spaces_and_comments (a_this); 04326 READ_NEXT_CHAR (a_this, &cur_char); 04327 ENSURE_PARSING_COND (cur_char == '}'); 04328 /* 04329 *here, call the relevant SAC handler. 04330 */ 04331 if (PRIVATE (a_this)->sac_handler->end_font_face) { 04332 PRIVATE (a_this)->sac_handler->end_font_face 04333 (PRIVATE (a_this)->sac_handler); 04334 } 04335 cr_parser_try_to_skip_spaces_and_comments (a_this); 04336 04337 if (token) { 04338 cr_token_destroy (token); 04339 token = NULL; 04340 } 04341 cr_parser_clear_errors (a_this); 04342 PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE; 04343 return CR_OK; 04344 04345 error: 04346 if (token) { 04347 cr_token_destroy (token); 04348 token = NULL; 04349 } 04350 if (property) { 04351 cr_string_destroy (property); 04352 property = NULL; 04353 } 04354 if (css_expression) { 04355 cr_term_destroy (css_expression); 04356 css_expression = NULL; 04357 } 04358 cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos); 04359 return status; 04360 } 04361 04362 /** 04363 * cr_parser_parse: 04364 *@a_this: the current instance of #CRParser. 04365 * 04366 *Parses the data that comes from the 04367 *input previously associated to the current instance of 04368 *#CRParser. 04369 * 04370 *Returns CR_OK upon succesful completion, an error code otherwise. 04371 */ 04372 enum CRStatus 04373 cr_parser_parse (CRParser * a_this) 04374 { 04375 enum CRStatus status = CR_ERROR; 04376 04377 g_return_val_if_fail (a_this && PRIVATE (a_this) 04378 && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR); 04379 04380 if (PRIVATE (a_this)->use_core_grammar == FALSE) { 04381 status = cr_parser_parse_stylesheet (a_this); 04382 } else { 04383 status = cr_parser_parse_stylesheet_core (a_this); 04384 } 04385 04386 return status; 04387 } 04388 04389 /** 04390 * cr_parser_set_tknzr: 04391 * @a_this: the current instance of #CRParser; 04392 * @a_tknzr: the new tokenizer. 04393 * 04394 * Returns CR_OK upon successful completion, an error code otherwise. 04395 */ 04396 enum CRStatus 04397 cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr) 04398 { 04399 g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 04400 04401 if (PRIVATE (a_this)->tknzr) { 04402 cr_tknzr_unref (PRIVATE (a_this)->tknzr); 04403 } 04404 04405 PRIVATE (a_this)->tknzr = a_tknzr; 04406 04407 if (a_tknzr) 04408 cr_tknzr_ref (a_tknzr); 04409 04410 return CR_OK; 04411 } 04412 04413 /** 04414 * cr_parser_get_tknzr: 04415 *@a_this: the current instance of #CRParser 04416 *@a_tknzr: out parameter. The returned tokenizer 04417 * 04418 *Getter of the parser's underlying tokenizer 04419 * 04420 *Returns CR_OK upon succesful completion, an error code 04421 *otherwise 04422 */ 04423 enum CRStatus 04424 cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr) 04425 { 04426 g_return_val_if_fail (a_this && PRIVATE (a_this) 04427 && a_tknzr, CR_BAD_PARAM_ERROR); 04428 04429 *a_tknzr = PRIVATE (a_this)->tknzr; 04430 return CR_OK; 04431 } 04432 04433 /** 04434 * cr_parser_get_parsing_location: 04435 *@a_this: the current instance of #CRParser 04436 *@a_loc: the parsing location to get. 04437 * 04438 *Gets the current parsing location. 04439 * 04440 *Returns CR_OK upon succesful completion, an error code 04441 *otherwise. 04442 */ 04443 enum CRStatus 04444 cr_parser_get_parsing_location (CRParser const *a_this, 04445 CRParsingLocation *a_loc) 04446 { 04447 g_return_val_if_fail (a_this 04448 && PRIVATE (a_this) 04449 && a_loc, CR_BAD_PARAM_ERROR) ; 04450 04451 return cr_tknzr_get_parsing_location 04452 (PRIVATE (a_this)->tknzr, a_loc) ; 04453 } 04454 04455 /** 04456 * cr_parser_parse_buf: 04457 *@a_this: the current instance of #CRparser 04458 *@a_buf: the input buffer 04459 *@a_len: the length of the input buffer 04460 *@a_enc: the encoding of the buffer 04461 * 04462 *Parses a stylesheet from a buffer 04463 * 04464 *Returns CR_OK upon successful completion, an error code otherwise. 04465 */ 04466 enum CRStatus 04467 cr_parser_parse_buf (CRParser * a_this, 04468 const guchar * a_buf, 04469 gulong a_len, enum CREncoding a_enc) 04470 { 04471 enum CRStatus status = CR_ERROR; 04472 CRTknzr *tknzr = NULL; 04473 04474 g_return_val_if_fail (a_this && PRIVATE (a_this) 04475 && a_buf, CR_BAD_PARAM_ERROR); 04476 04477 tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE); 04478 04479 g_return_val_if_fail (tknzr != NULL, CR_ERROR); 04480 04481 status = cr_parser_set_tknzr (a_this, tknzr); 04482 g_return_val_if_fail (status == CR_OK, CR_ERROR); 04483 04484 status = cr_parser_parse (a_this); 04485 04486 return status; 04487 } 04488 04489 /** 04490 * cr_parser_destroy: 04491 *@a_this: the current instance of #CRParser to 04492 *destroy. 04493 * 04494 *Destroys the current instance 04495 *of #CRParser. 04496 */ 04497 void 04498 cr_parser_destroy (CRParser * a_this) 04499 { 04500 g_return_if_fail (a_this && PRIVATE (a_this)); 04501 04502 if (PRIVATE (a_this)->tknzr) { 04503 if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE) 04504 PRIVATE (a_this)->tknzr = NULL; 04505 } 04506 04507 if (PRIVATE (a_this)->sac_handler) { 04508 cr_doc_handler_unref (PRIVATE (a_this)->sac_handler); 04509 PRIVATE (a_this)->sac_handler = NULL; 04510 } 04511 04512 if (PRIVATE (a_this)->err_stack) { 04513 cr_parser_clear_errors (a_this); 04514 PRIVATE (a_this)->err_stack = NULL; 04515 } 04516 04517 if (PRIVATE (a_this)) { 04518 g_free (PRIVATE (a_this)); 04519 PRIVATE (a_this) = NULL; 04520 } 04521 04522 if (a_this) { 04523 g_free (a_this); 04524 a_this = NULL; /*useless. Just for the sake of coherence */ 04525 } 04526 }