Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

cr-parser.c

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

Generated on Wed Oct 1 01:36:47 2003 for Libcroco by doxygen 1.3.3