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

cr-tknzr.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  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of version 2.1 of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00018  * USA
00019  *
00020  * Author: Dodji Seketeli
00021  * See the COPYRIGHTS file for copyrights information.
00022  */
00023 
00024 /**
00025  *@file
00026  *The definition of the #CRTknzr (tokenizer)
00027  *class.
00028  */
00029 
00030 #include "string.h"
00031 #include "cr-tknzr.h"
00032 #include "cr-doc-handler.h"
00033 
00034 struct _CRTknzrPriv {
00035         /**The parser input stream of bytes*/
00036         CRInput *input;
00037 
00038         /**
00039          *A cache where tknzr_unget_token()
00040          *puts back the token. tknzr_get_next_token()
00041          *first look in this cache, and if and 
00042          *only if it's empty, fetches the next token
00043          *from the input stream.
00044          */
00045         CRToken *token_cache;
00046 
00047         /**
00048          *The position of the end of the previous token
00049          *or char fetched.
00050          */
00051         CRInputPos prev_pos;
00052 
00053         CRDocHandler *sac_handler;
00054 
00055         /**
00056          *The reference count of the current instance
00057          *of #CRTknzr. Is manipulated by cr_tknzr_ref()
00058          *and cr_tknzr_unref().
00059          */
00060         glong ref_count;
00061 };
00062 
00063 #define PRIVATE(obj) ((obj)->priv)
00064 
00065 /**
00066  *return TRUE if the character is a number ([0-9]), FALSE otherwise
00067  *@param a_char the char to test.
00068  */
00069 #define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
00070 
00071 /**
00072  *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
00073  *
00074  *@param status the status (of type enum CRStatus) to test.
00075  *@param is_exception if set to FALSE, the final status returned the
00076  *current function will be CR_PARSING_ERROR. If set to TRUE, the
00077  *current status will be the current value of the 'status' variable.
00078  *
00079  */
00080 #define CHECK_PARSING_STATUS(status, is_exception) \
00081 if ((status) != CR_OK) \
00082 { \
00083         if (is_exception == FALSE) \
00084         { \
00085                 status = CR_PARSING_ERROR ; \
00086         } \
00087         goto error ; \
00088 }
00089 
00090 /**
00091  *Peeks the next char from the input stream of the current tokenizer.
00092  *invokes CHECK_PARSING_STATUS on the status returned by
00093  *cr_tknzr_input_peek_char().
00094  *
00095  *@param the current instance of #CRTkzr.
00096  *@param to_char a pointer to the char where to store the
00097  *char peeked.
00098  */
00099 #define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \
00100 {\
00101 status = cr_tknzr_peek_char  (a_tknzr, a_to_char) ; \
00102 CHECK_PARSING_STATUS (status, TRUE) \
00103 }
00104 
00105 /**
00106  *Reads the next char from the input stream of the current parser.
00107  *In case of error, jumps to the "error:" label located in the
00108  *function where this macro is called.
00109  *@param parser the curent instance of #CRTknzr
00110  *@param to_char a pointer to the guint32 char where to store
00111  *the character read.
00112  */
00113 #define READ_NEXT_CHAR(a_tknzr, to_char) \
00114 status = cr_tknzr_read_char (a_tknzr, to_char) ;\
00115 CHECK_PARSING_STATUS (status, TRUE)
00116 
00117 /**
00118  *Gets information about the current position in
00119  *the input of the parser.
00120  *In case of failure, this macro returns from the 
00121  *calling function and
00122  *returns a status code of type enum #CRStatus.
00123  *@param parser the current instance of #CRTknzr.
00124  *@param pos out parameter. A pointer to the position 
00125  *inside the current parser input. Must
00126  */
00127 #define RECORD_INITIAL_POS(a_tknzr, a_pos) \
00128 status = cr_input_get_cur_pos (PRIVATE  \
00129 (a_tknzr)->input, a_pos) ; \
00130 g_return_val_if_fail (status == CR_OK, status)
00131 
00132 /**
00133  *Gets the address of the current byte inside the
00134  *parser input.
00135  *@param parser the current instance of #CRTknzr.
00136  *@param addr out parameter a pointer (guchar*)
00137  *to where the address  must be put.
00138  */
00139 #define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \
00140 status = cr_input_get_cur_byte_addr \
00141             (PRIVATE (a_tknzr)->input, a_addr) ; \
00142 CHECK_PARSING_STATUS (status, TRUE)
00143 
00144 /**
00145  *Peeks a byte from the topmost parser input at
00146  *a given offset from the current position.
00147  *If it fails, goto the "error:" label.
00148  *
00149  *@param a_parser the current instance of #CRTknzr.
00150  *@param a_offset the offset of the byte to peek, the
00151  *current byte having the offset '0'.
00152  *@param a_byte_ptr out parameter a pointer (guchar*) to
00153  *where the peeked char is to be stored.
00154  */
00155 #define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \
00156 status = cr_tknzr_peek_byte (a_tknzr, \
00157                              a_offset, \
00158                              a_byte_ptr) ; \
00159 CHECK_PARSING_STATUS (status, TRUE) ;
00160 
00161 #define BYTE(a_input, a_n, a_eof) \
00162 cr_input_peek_byte2 (a_input, a_n, a_eof)
00163 
00164 /**
00165  *Reads a byte from the topmost parser input
00166  *steam.
00167  *If it fails, goto the "error" label.
00168  *@param a_parser the current instance of #CRTknzr.
00169  *@param a_byte_ptr the guchar * where to put the read char.
00170  */
00171 #define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \
00172 status = \
00173 cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\
00174 CHECK_PARSING_STATUS (status, TRUE) ;
00175 
00176 /**
00177  *Skips a given number of byte in the topmost
00178  *parser input. Don't update line and column number.
00179  *In case of error, jumps to the "error:" label
00180  *of the surrounding function.
00181  *@param a_parser the current instance of #CRTknzr.
00182  *@param a_nb_bytes the number of bytes to skip.
00183  */
00184 #define SKIP_BYTES(a_tknzr, a_nb_bytes) \
00185 status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \
00186                                      CR_SEEK_CUR, a_nb_bytes) ; \
00187 CHECK_PARSING_STATUS (status, TRUE) ;
00188 
00189 /**
00190  *Skip utf8 encoded characters.
00191  *Updates line and column numbers.
00192  *@param a_parser the current instance of #CRTknzr.
00193  *@param a_nb_chars the number of chars to skip. Must be of
00194  *type glong.
00195  */
00196 #define SKIP_CHARS(a_tknzr, a_nb_chars) \
00197 { \
00198 glong nb_chars = a_nb_chars ; \
00199 status = cr_input_consume_chars \
00200      (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \
00201 CHECK_PARSING_STATUS (status, TRUE) ; \
00202 }
00203 
00204 /**
00205  *Tests the condition and if it is false, sets
00206  *status to "CR_PARSING_ERROR" and goto the 'error'
00207  *label.
00208  *@param condition the condition to test.
00209  */
00210 #define ENSURE_PARSING_COND(condition) \
00211 if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
00212 
00213 static enum CRStatus  cr_tknzr_parse_nl (CRTknzr * a_this, 
00214                                          guchar ** a_start, 
00215                                          guchar ** a_end,
00216                                          CRParsingLocation *a_location);
00217 
00218 static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this, 
00219                                        guchar ** a_start, 
00220                                        guchar ** a_end,
00221                                        CRParsingLocation *a_location) ;
00222 
00223 static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this, 
00224                                                     guint32 * a_unicode,
00225                                                     CRParsingLocation *a_location) ;
00226 
00227 static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this, 
00228                                             guint32 * a_esc_code,
00229                                             CRParsingLocation *a_location);
00230 
00231 static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this, 
00232                                             CRString ** a_str);
00233 
00234 static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this, 
00235                                              CRString ** a_comment);
00236 
00237 static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this, 
00238                                              guint32 * a_char, 
00239                                              CRParsingLocation *a_location);
00240 
00241 static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this,
00242                                          CRNum ** a_num);
00243 
00244 /**********************************
00245  *PRIVATE methods
00246  **********************************/
00247 
00248 /**
00249  *Parses a "w" as defined by the css spec at [4.1.1]:
00250  * w ::= [ \t\r\n\f]*
00251  *
00252  *@param a_this the current instance of #CRTknzr.
00253  *@param a_start out param. Upon successfull completion, points
00254  *to the beginning of the parsed white space, points to NULL otherwise.
00255  *Can also point to NULL is there is no white space actually.
00256  *@param a_end out param. Upon successfull completion, points
00257  *to the end of the parsed white space, points to NULL otherwise.
00258  *Can also point to NULL is there is no white space actually.
00259  */
00260 static enum CRStatus
00261 cr_tknzr_parse_w (CRTknzr * a_this, 
00262                   guchar ** a_start, 
00263                   guchar ** a_end, 
00264                   CRParsingLocation *a_location)
00265 {
00266         guint32 cur_char = 0;
00267         CRInputPos init_pos;
00268         enum CRStatus status = CR_OK;
00269 
00270         g_return_val_if_fail (a_this && PRIVATE (a_this)
00271                               && PRIVATE (a_this)->input
00272                               && a_start && a_end, 
00273                               CR_BAD_PARAM_ERROR);
00274 
00275         RECORD_INITIAL_POS (a_this, &init_pos);
00276 
00277         *a_start = NULL;
00278         *a_end = NULL;
00279 
00280         READ_NEXT_CHAR (a_this, &cur_char);
00281 
00282         if (cr_utils_is_white_space (cur_char) == FALSE) {
00283                 status = CR_PARSING_ERROR;
00284                 goto error;
00285         }
00286         if (a_location) {
00287                 cr_tknzr_get_parsing_location (a_this, 
00288                                                a_location) ;
00289         }
00290         RECORD_CUR_BYTE_ADDR (a_this, a_start);
00291         *a_end = *a_start;
00292 
00293         for (;;) {
00294                 gboolean is_eof = FALSE;
00295 
00296                 cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof);
00297                 if (is_eof)
00298                         break;
00299 
00300                 status = cr_tknzr_peek_char (a_this, &cur_char);
00301                 if (status == CR_END_OF_INPUT_ERROR) {
00302                         status = CR_OK;
00303                         break;
00304                 } else if (status != CR_OK) {
00305                         goto error;
00306                 }
00307 
00308                 if (cr_utils_is_white_space (cur_char) == TRUE) {
00309                         READ_NEXT_CHAR (a_this, &cur_char);
00310                         RECORD_CUR_BYTE_ADDR (a_this, a_end);
00311                 } else {
00312                         break;
00313                 }
00314         }
00315 
00316         return CR_OK;
00317 
00318       error:
00319         cr_tknzr_set_cur_pos (a_this, &init_pos);
00320 
00321         return status;
00322 }
00323 
00324 /**
00325  *Parses a newline as defined in the css2 spec:
00326  * nl   ::=    \n|\r\n|\r|\f
00327  *
00328  *@param a_this the "this pointer" of the current instance of #CRTknzr.
00329  *@param a_start a pointer to the first character of the successfully 
00330  *parsed string.
00331  *@param a_end a pointer to the last character of the successfully parsed
00332  *string.
00333  *@result CR_OK uppon successfull completion, an error code otherwise.
00334  */
00335 static enum CRStatus
00336 cr_tknzr_parse_nl (CRTknzr * a_this, 
00337                    guchar ** a_start, 
00338                    guchar ** a_end, 
00339                    CRParsingLocation *a_location)
00340 {
00341         CRInputPos init_pos;
00342         guchar next_chars[2] = { 0 };
00343         enum CRStatus status = CR_PARSING_ERROR;
00344 
00345         g_return_val_if_fail (a_this && PRIVATE (a_this)
00346                               && a_start && a_end, CR_BAD_PARAM_ERROR);
00347 
00348         RECORD_INITIAL_POS (a_this, &init_pos);
00349 
00350         PEEK_BYTE (a_this, 1, &next_chars[0]);
00351         PEEK_BYTE (a_this, 2, &next_chars[1]);
00352 
00353         if ((next_chars[0] == '\r' && next_chars[1] == '\n')) {
00354                 SKIP_BYTES (a_this, 1);
00355                 if (a_location) {
00356                         cr_tknzr_get_parsing_location 
00357                                 (a_this, a_location) ;
00358                 }
00359                 SKIP_CHARS (a_this, 1);
00360 
00361                 RECORD_CUR_BYTE_ADDR (a_this, a_end);
00362 
00363                 status = CR_OK;
00364         } else if (next_chars[0] == '\n'
00365                    || next_chars[0] == '\r' || next_chars[0] == '\f') {
00366                 SKIP_CHARS (a_this, 1);
00367                 if (a_location) {
00368                         cr_tknzr_get_parsing_location 
00369                                 (a_this, a_location) ;
00370                 }
00371                 RECORD_CUR_BYTE_ADDR (a_this, a_start);
00372                 *a_end = *a_start;
00373                 status = CR_OK;
00374         } else {
00375                 status = CR_PARSING_ERROR;
00376                 goto error;
00377         }
00378         return CR_OK ;
00379 
00380  error:
00381         cr_tknzr_set_cur_pos (a_this, &init_pos) ;
00382         return status;
00383 }
00384 
00385 /**
00386  *Go ahead in the parser input, skipping all the spaces.
00387  *If the next char if not a white space, this function does nothing.
00388  *In any cases, it stops when it encounters a non white space character.
00389  *
00390  *@param a_this the current instance of #CRTknzr.
00391  *@return CR_OK upon successfull completion, an error code otherwise.
00392  */
00393 static enum CRStatus
00394 cr_tknzr_try_to_skip_spaces (CRTknzr * a_this)
00395 {
00396         enum CRStatus status = CR_ERROR;
00397         guint32 cur_char = 0;
00398 
00399         g_return_val_if_fail (a_this && PRIVATE (a_this)
00400                               && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
00401 
00402         status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char);
00403 
00404         if (status != CR_OK) {
00405                 if (status == CR_END_OF_INPUT_ERROR)
00406                         return CR_OK;
00407                 return status;
00408         }
00409 
00410         if (cr_utils_is_white_space (cur_char) == TRUE) {
00411                 glong nb_chars = -1; /*consume all spaces */
00412 
00413                 status = cr_input_consume_white_spaces
00414                         (PRIVATE (a_this)->input, &nb_chars);
00415         }
00416 
00417         return status;
00418 }
00419 
00420 /**
00421  *Parses a "comment" as defined in the css spec at [4.1.1]:
00422  *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ .
00423  *This complex regexp is just to say that comments start
00424  *with the two chars '/''*' and ends with the two chars '*''/'.
00425  *It also means that comments cannot be nested.
00426  *So based on that, I've just tried to implement the parsing function
00427  *simply and in a straight forward manner.
00428  */
00429 static enum CRStatus
00430 cr_tknzr_parse_comment (CRTknzr * a_this, 
00431                         CRString ** a_comment)
00432 {
00433         enum CRStatus status = CR_OK;
00434         CRInputPos init_pos;
00435         guint32 cur_char = 0, next_char= 0;
00436         CRString *comment = NULL;
00437         CRParsingLocation loc = {0} ;
00438 
00439         g_return_val_if_fail (a_this && PRIVATE (a_this)
00440                               && PRIVATE (a_this)->input, 
00441                               CR_BAD_PARAM_ERROR);
00442 
00443         RECORD_INITIAL_POS (a_this, &init_pos);        
00444         READ_NEXT_CHAR (a_this, &cur_char) ;        
00445         ENSURE_PARSING_COND (cur_char == '/');
00446         cr_tknzr_get_parsing_location (a_this, &loc) ;
00447 
00448         READ_NEXT_CHAR (a_this, &cur_char);
00449         ENSURE_PARSING_COND (cur_char == '*');
00450         comment = cr_string_new ();
00451         for (;;) {
00452                 READ_NEXT_CHAR (a_this, &cur_char);
00453 
00454                 /*make sure there are no nested comments */
00455                 if (cur_char == '/') {
00456                         READ_NEXT_CHAR (a_this, &cur_char);
00457                         ENSURE_PARSING_COND (cur_char != '*');
00458                         g_string_append_c (comment->stryng, '/');
00459                         g_string_append_unichar (comment->stryng, 
00460                                                  cur_char);
00461                         continue;
00462                 }
00463 
00464                 /*Detect the end of the comments region */
00465                 if (cur_char == '*') {
00466                         PEEK_NEXT_CHAR (a_this, &next_char);
00467 
00468                         if (next_char == '/') {
00469                                 /*
00470                                  *end of comments region
00471                                  *Now, call the right SAC callback.
00472                                  */
00473                                 SKIP_CHARS (a_this, 1) ;
00474                                 status = CR_OK;
00475                                 break;
00476                         } else {
00477                                 g_string_append_c (comment->stryng, 
00478                                                    '*');
00479                         }
00480                 }
00481                 g_string_append_unichar (comment->stryng, cur_char);
00482         }
00483 
00484         if (status == CR_OK) {
00485                 cr_parsing_location_copy (&comment->location, 
00486                                           &loc) ;
00487                 *a_comment = comment;                
00488                 return CR_OK;
00489         }
00490  error:
00491 
00492         if (comment) {
00493                 cr_string_destroy (comment);
00494                 comment = NULL;
00495         }
00496 
00497         cr_tknzr_set_cur_pos (a_this, &init_pos);
00498 
00499         return status;
00500 }
00501 
00502 /**
00503  *Parses an 'unicode' escape sequence defined
00504  *in css spec at chap 4.1.1:
00505  *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]?
00506  *@param a_this the current instance of #CRTknzr.
00507  *@param a_start out parameter. A pointer to the start
00508  *of the unicode escape sequence. Must *NOT* be deleted by
00509  *the caller.
00510  *@param a_end out parameter. A pointer to the last character
00511  *of the unicode escape sequence. Must *NOT* be deleted by the caller.
00512  *@return CR_OK if parsing succeded, an error code otherwise.
00513  *Error code can be either CR_PARSING_ERROR if the string 
00514  *parsed just doesn't
00515  *respect the production or another error if a 
00516  *lower level error occured.
00517  */
00518 static enum CRStatus
00519 cr_tknzr_parse_unicode_escape (CRTknzr * a_this, 
00520                                guint32 * a_unicode,
00521                                CRParsingLocation *a_location)
00522 {
00523         guint32 cur_char;
00524         CRInputPos init_pos;
00525         glong occur = 0;
00526         guint32 unicode = 0;
00527         guchar *tmp_char_ptr1 = NULL,
00528                 *tmp_char_ptr2 = NULL;
00529         enum CRStatus status = CR_OK;
00530 
00531         g_return_val_if_fail (a_this && PRIVATE (a_this)
00532                               && a_unicode, CR_BAD_PARAM_ERROR);
00533 
00534         /*first, let's backup the current position pointer */
00535         RECORD_INITIAL_POS (a_this, &init_pos);
00536 
00537         READ_NEXT_CHAR (a_this, &cur_char);
00538 
00539         if (cur_char != '\\') {
00540                 status = CR_PARSING_ERROR;
00541                 goto error;
00542         }
00543         if (a_location) {
00544                 cr_tknzr_get_parsing_location 
00545                         (a_this, a_location) ;
00546         }
00547         PEEK_NEXT_CHAR (a_this, &cur_char);
00548 
00549         for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9')
00550                                       || (cur_char >= 'a' && cur_char <= 'f')
00551                                       || (cur_char >= 'A' && cur_char <= 'F'))
00552              && occur < 6; occur++) {
00553                 gint cur_char_val = 0;
00554 
00555                 READ_NEXT_CHAR (a_this, &cur_char);
00556 
00557                 if ((cur_char >= '0' && cur_char <= '9')) {
00558                         cur_char_val = (cur_char - '0');
00559                 } else if ((cur_char >= 'a' && cur_char <= 'f')) {
00560                         cur_char_val = 10 + (cur_char - 'a');
00561                 } else if ((cur_char >= 'A' && cur_char <= 'F')) {
00562                         cur_char_val = 10 + (cur_char - 'A');
00563                 }
00564 
00565                 unicode = unicode * 10 + cur_char_val;
00566 
00567                 PEEK_NEXT_CHAR (a_this, &cur_char);
00568         }
00569 
00570         if (occur == 5) {
00571                 /*
00572                  *the unicode escape is 6 digit length
00573                  */
00574 
00575                 /*
00576                  *parse one space that may 
00577                  *appear just after the unicode
00578                  *escape.
00579                  */
00580                 cr_tknzr_parse_w (a_this, &tmp_char_ptr1, 
00581                                   &tmp_char_ptr2, NULL);
00582                 status = CR_OK;
00583         } else {
00584                 /*
00585                  *The unicode escape is less than
00586                  *6 digit length. The character
00587                  *that comes right after the escape
00588                  *must be a white space.
00589                  */
00590                 status = cr_tknzr_parse_w (a_this, &tmp_char_ptr1,
00591                                            &tmp_char_ptr2, NULL);
00592         }
00593 
00594         if (status == CR_OK) {
00595                 *a_unicode = unicode;
00596                 return CR_OK;
00597         }
00598 
00599       error:
00600         /*
00601          *restore the initial position pointer backuped at
00602          *the beginning of this function.
00603          */
00604         cr_tknzr_set_cur_pos (a_this, &init_pos);
00605 
00606         return status;
00607 }
00608 
00609 /**
00610  *parses an escape sequence as defined by the css spec:
00611  *escape ::= {unicode}|\\[ -~\200-\4177777]
00612  *@param a_this the current instance of #CRTknzr .
00613  */
00614 static enum CRStatus
00615 cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code,
00616                        CRParsingLocation *a_location)
00617 {
00618         enum CRStatus status = CR_OK;
00619         guint32 cur_char = 0;
00620         CRInputPos init_pos;
00621         guchar next_chars[2];
00622 
00623         g_return_val_if_fail (a_this && PRIVATE (a_this)
00624                               && a_esc_code, CR_BAD_PARAM_ERROR);
00625 
00626         RECORD_INITIAL_POS (a_this, &init_pos);
00627 
00628         PEEK_BYTE (a_this, 1, &next_chars[0]);
00629         PEEK_BYTE (a_this, 2, &next_chars[1]);
00630 
00631         if (next_chars[0] != '\\') {
00632                 status = CR_PARSING_ERROR;
00633                 goto error;
00634         }
00635 
00636         if ((next_chars[1] >= '0' && next_chars[1] <= '9')
00637             || (next_chars[1] >= 'a' && next_chars[1] <= 'f')
00638             || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) {
00639                 status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code, 
00640                                                         a_location);
00641         } else {
00642                 /*consume the '\' char */
00643                 READ_NEXT_CHAR (a_this, &cur_char);
00644                 if (a_location) {
00645                         cr_tknzr_get_parsing_location (a_this, 
00646                                                        a_location) ;
00647                 }
00648                 /*then read the char after the '\' */
00649                 READ_NEXT_CHAR (a_this, &cur_char);
00650 
00651                 if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) {
00652                         status = CR_PARSING_ERROR;
00653                         goto error;
00654                 }
00655                 *a_esc_code = cur_char;
00656 
00657         }
00658         if (status == CR_OK) {
00659                 return CR_OK;
00660         }
00661  error:
00662         cr_tknzr_set_cur_pos (a_this, &init_pos);
00663         return status;
00664 }
00665 
00666 /**
00667  *Parses a string type as defined in css spec [4.1.1]:
00668  *
00669  *string ::= {string1}|{string2}
00670  *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
00671  *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
00672  *
00673  *@param a_this the current instance of #CRTknzr.
00674  *@param a_start out parameter. Upon successfull completion, 
00675  *points to the beginning of the string, points to an undefined value
00676  *otherwise.
00677  *@param a_end out parameter. Upon successfull completion, points to
00678  *the beginning of the string, points to an undefined value otherwise.
00679  *@return CR_OK upon successfull completion, an error code otherwise.
00680  */
00681 static enum CRStatus
00682 cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str)
00683 {
00684         guint32 cur_char = 0,
00685                 delim = 0;
00686         CRInputPos init_pos;
00687         enum CRStatus status = CR_OK;
00688         CRString *str = NULL;
00689 
00690         g_return_val_if_fail (a_this && PRIVATE (a_this)
00691                               && PRIVATE (a_this)->input
00692                               && a_str, CR_BAD_PARAM_ERROR);
00693 
00694         RECORD_INITIAL_POS (a_this, &init_pos);
00695         READ_NEXT_CHAR (a_this, &cur_char);
00696 
00697         if (cur_char == '"')
00698                 delim = '"';
00699         else if (cur_char == '\'')
00700                 delim = '\'';
00701         else {
00702                 status = CR_PARSING_ERROR;
00703                 goto error;
00704         }
00705         str = cr_string_new ();
00706         if (str) {
00707                 cr_tknzr_get_parsing_location 
00708                         (a_this, &str->location) ;
00709         }
00710         for (;;) {
00711                 guchar next_chars[2] = { 0 };
00712 
00713                 PEEK_BYTE (a_this, 1, &next_chars[0]);
00714                 PEEK_BYTE (a_this, 2, &next_chars[1]);
00715 
00716                 if (next_chars[0] == '\\') {
00717                         guchar *tmp_char_ptr1 = NULL,
00718                                 *tmp_char_ptr2 = NULL;
00719                         guint32 esc_code = 0;
00720 
00721                         if (next_chars[1] == '\'' || next_chars[1] == '"') {
00722                                 g_string_append_unichar (str->stryng, 
00723                                                          next_chars[1]);
00724                                 SKIP_BYTES (a_this, 2);
00725                                 status = CR_OK;
00726                         } else {
00727                                 status = cr_tknzr_parse_escape
00728                                         (a_this, &esc_code, NULL);
00729 
00730                                 if (status == CR_OK) {
00731                                         g_string_append_unichar
00732                                                 (str->stryng, 
00733                                                  esc_code);
00734                                 }
00735                         }
00736 
00737                         if (status != CR_OK) {
00738                                 /*
00739                                  *consume the '\' char, and try to parse
00740                                  *a newline.
00741                                  */
00742                                 READ_NEXT_CHAR (a_this, &cur_char);
00743 
00744                                 status = cr_tknzr_parse_nl
00745                                         (a_this, &tmp_char_ptr1,
00746                                          &tmp_char_ptr2, NULL);
00747                         }
00748 
00749                         CHECK_PARSING_STATUS (status, FALSE);
00750                 } else if (strchr ("\t !#$%&", next_chars[0])
00751                            || (next_chars[0] >= '(' && next_chars[0] <= '~')) {
00752                         READ_NEXT_CHAR (a_this, &cur_char);
00753                         g_string_append_unichar (str->stryng, 
00754                                                  cur_char);
00755                         status = CR_OK;
00756                 }
00757 
00758                 else if (cr_utils_is_nonascii (next_chars[0])) {
00759                         READ_NEXT_CHAR (a_this, &cur_char);
00760                         g_string_append_unichar (str->stryng, cur_char);
00761                 } else if (next_chars[0] == delim) {
00762                         READ_NEXT_CHAR (a_this, &cur_char);
00763                         break;
00764                 } else {
00765                         status = CR_PARSING_ERROR;
00766                         goto error;
00767                 }
00768         }
00769 
00770         if (status == CR_OK) {
00771                 if (*a_str == NULL) {
00772                         *a_str = str;
00773                         str = NULL;
00774                 } else {
00775                         (*a_str)->stryng = g_string_append_len
00776                                 ((*a_str)->stryng,
00777                                  str->stryng->str, 
00778                                  str->stryng->len);
00779                         cr_string_destroy (str);
00780                 }
00781                 return CR_OK;
00782         }
00783 
00784  error:
00785 
00786         if (str) {
00787                 cr_string_destroy (str) ;
00788                 str = NULL;
00789         }
00790         cr_tknzr_set_cur_pos (a_this, &init_pos);
00791         return status;
00792 }
00793 
00794 /**
00795  *Parses the an nmstart as defined by the css2 spec [4.1.1]:
00796  * nmstart [a-zA-Z]|{nonascii}|{escape}
00797  *
00798  *@param a_this the current instance of #CRTknzr.
00799  *@param a_start out param. A pointer to the starting point of
00800  *the token.
00801  *@param a_end out param. A pointer to the ending point of the
00802  *token.
00803  *@param a_char out param. The actual parsed nmchar.
00804  *@return CR_OK upon successfull completion, 
00805  *an error code otherwise.
00806  */
00807 static enum CRStatus
00808 cr_tknzr_parse_nmstart (CRTknzr * a_this, 
00809                         guint32 * a_char,
00810                         CRParsingLocation *a_location)
00811 {
00812         CRInputPos init_pos;
00813         enum CRStatus status = CR_OK;
00814         guint32 cur_char = 0,
00815                 next_char = 0;
00816 
00817         g_return_val_if_fail (a_this && PRIVATE (a_this)
00818                               && PRIVATE (a_this)->input
00819                               && a_char, CR_BAD_PARAM_ERROR);
00820 
00821         RECORD_INITIAL_POS (a_this, &init_pos);
00822 
00823         PEEK_NEXT_CHAR (a_this, &next_char);
00824 
00825         if (next_char == '\\') {
00826                 status = cr_tknzr_parse_escape (a_this, a_char,
00827                                                 a_location);
00828 
00829                 if (status != CR_OK)
00830                         goto error;
00831 
00832         } else if (cr_utils_is_nonascii (next_char) == TRUE
00833                    || ((next_char >= 'a') && (next_char <= 'z'))
00834                    || ((next_char >= 'A') && (next_char <= 'Z'))
00835                 ) {
00836                 READ_NEXT_CHAR (a_this, &cur_char);
00837                 if (a_location) {
00838                         cr_tknzr_get_parsing_location (a_this, 
00839                                                        a_location) ;
00840                 }
00841                 *a_char = cur_char;
00842                 status = CR_OK;
00843         } else {
00844                 status = CR_PARSING_ERROR;
00845                 goto error;
00846         }
00847 
00848         return CR_OK;
00849 
00850  error:        
00851         cr_tknzr_set_cur_pos (a_this, &init_pos);
00852 
00853         return status;
00854 
00855 }
00856 
00857 /**
00858  *Parses an nmchar as described in the css spec at
00859  *chap 4.1.1:
00860  *nmchar ::= [a-z0-9-]|{nonascii}|{escape}
00861  *
00862  *Humm, I have added the possibility for nmchar to
00863  *contain upper case letters.
00864  *
00865  *@param a_this the current instance of #CRTknzr.
00866  *@param a_start out param. A pointer to the starting point of
00867  *the token.
00868  *@param a_end out param. A pointer to the ending point of the
00869  *token.
00870  *@param a_char out param. The actual parsed nmchar.
00871  *@return CR_OK upon successfull completion, 
00872  *an error code otherwise.
00873  */
00874 static enum CRStatus
00875 cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char,
00876                        CRParsingLocation *a_location)
00877 {
00878         guint32 cur_char = 0,
00879                 next_char = 0;
00880         enum CRStatus status = CR_OK;
00881         CRInputPos init_pos;
00882 
00883         g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
00884                               CR_BAD_PARAM_ERROR);
00885 
00886         RECORD_INITIAL_POS (a_this, &init_pos);
00887 
00888         status = cr_input_peek_char (PRIVATE (a_this)->input, 
00889                                      &next_char) ;
00890         if (status != CR_OK)
00891                 goto error;
00892 
00893         if (next_char == '\\') {
00894                 status = cr_tknzr_parse_escape (a_this, a_char, 
00895                                                 a_location);
00896 
00897                 if (status != CR_OK)
00898                         goto error;
00899 
00900         } else if (cr_utils_is_nonascii (next_char) == TRUE
00901                    || ((next_char >= 'a') && (next_char <= 'z'))
00902                    || ((next_char >= 'A') && (next_char <= 'Z'))
00903                    || ((next_char >= '0') && (next_char <= '9'))
00904                    || (next_char == '-')
00905                    || (next_char == '_') /*'_' not allowed by the spec. */
00906                 ) {
00907                 READ_NEXT_CHAR (a_this, &cur_char);
00908                 *a_char = cur_char;
00909                 status = CR_OK;
00910                 if (a_location) {
00911                         cr_tknzr_get_parsing_location
00912                                 (a_this, a_location) ;
00913                 }
00914         } else {
00915                 status = CR_PARSING_ERROR;
00916                 goto error;
00917         }
00918         return CR_OK;
00919 
00920  error:
00921         cr_tknzr_set_cur_pos (a_this, &init_pos);
00922         return status;
00923 }
00924 
00925 /**
00926  *Parses an "ident" as defined in css spec [4.1.1]:
00927  *ident ::= {nmstart}{nmchar}*
00928  *
00929  *Actually parses it using the css3 grammar:
00930  *ident ::= -?{nmstart}{nmchar}*
00931  *@param a_this the currens instance of #CRTknzr.
00932  *
00933  *@param a_str a pointer to parsed ident. If *a_str is NULL,
00934  *this function allocates a new instance of CRString. If not, 
00935  *the function just appends the parsed string to the one passed.
00936  *In both cases it is up to the caller to free *a_str.
00937  *
00938  *@return CR_OK upon successfull completion, an error code 
00939  *otherwise.
00940  */
00941 static enum CRStatus
00942 cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str)
00943 {
00944         guint32 tmp_char = 0;
00945         CRString *stringue = NULL ;
00946         CRInputPos init_pos;
00947         enum CRStatus status = CR_OK;
00948         gboolean location_is_set = FALSE ;
00949 
00950         g_return_val_if_fail (a_this && PRIVATE (a_this)
00951                               && PRIVATE (a_this)->input
00952                               && a_str, CR_BAD_PARAM_ERROR);
00953 
00954         RECORD_INITIAL_POS (a_this, &init_pos);
00955         PEEK_NEXT_CHAR (a_this, &tmp_char) ;
00956         stringue = cr_string_new () ;
00957         g_return_val_if_fail (stringue, 
00958                               CR_OUT_OF_MEMORY_ERROR) ;
00959 
00960         if (tmp_char == '-') {
00961                 READ_NEXT_CHAR (a_this, &tmp_char) ;
00962                 cr_tknzr_get_parsing_location
00963                         (a_this, &stringue->location) ;
00964                 location_is_set = TRUE ;
00965                 g_string_append_unichar (stringue->stryng, 
00966                                          tmp_char) ;
00967         }
00968         status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL);
00969         if (status != CR_OK) {
00970                 status = CR_PARSING_ERROR;
00971                 goto end ;
00972         }
00973         if (location_is_set == FALSE) {
00974                 cr_tknzr_get_parsing_location 
00975                         (a_this, &stringue->location) ;
00976                 location_is_set = TRUE ;
00977         }
00978         g_string_append_unichar (stringue->stryng, tmp_char);
00979         for (;;) {
00980                 status = cr_tknzr_parse_nmchar (a_this, 
00981                                                 &tmp_char, 
00982                                                 NULL);
00983                 if (status != CR_OK) {
00984                         status = CR_OK ;
00985                         break;
00986                 }
00987                 g_string_append_unichar (stringue->stryng, tmp_char);
00988         }
00989         if (status == CR_OK) {
00990                 if (!*a_str) {
00991                         *a_str = stringue ;
00992                 
00993                 } else {
00994                         g_string_append_len ((*a_str)->stryng, 
00995                                              stringue->stryng->str, 
00996                                              stringue->stryng->len) ;
00997                         cr_string_destroy (stringue) ;
00998                 }
00999                 stringue = NULL ;
01000         }
01001 
01002  error:
01003  end:
01004         if (stringue) {
01005                 cr_string_destroy (stringue) ;
01006                 stringue = NULL ;
01007         }
01008         if (status != CR_OK ) {
01009                 cr_tknzr_set_cur_pos (a_this, &init_pos) ;
01010         }
01011         return status ;
01012 }
01013 
01014 
01015 /**
01016  *Parses a "name" as defined by css spec [4.1.1]:
01017  *name ::= {nmchar}+
01018  *
01019  *@param a_this the current instance of #CRTknzr.
01020  *
01021  *@param a_str out parameter. A pointer to the successfully parsed
01022  *name. If *a_str is set to NULL, this function allocates a new instance
01023  *of CRString. If not, it just appends the parsed name to the passed *a_str.
01024  *In both cases, it is up to the caller to free *a_str.
01025  *
01026  *@return CR_OK upon successfull completion, an error code otherwise.
01027  */
01028 static enum CRStatus
01029 cr_tknzr_parse_name (CRTknzr * a_this, 
01030                      CRString ** a_str)
01031 {
01032         guint32 tmp_char = 0;
01033         CRInputPos init_pos;
01034         enum CRStatus status = CR_OK;
01035         gboolean str_needs_free = FALSE,
01036                 is_first_nmchar=TRUE ;
01037         glong i = 0;
01038         CRParsingLocation loc = {0} ;
01039 
01040         g_return_val_if_fail (a_this && PRIVATE (a_this)
01041                               && PRIVATE (a_this)->input
01042                               && a_str,
01043                               CR_BAD_PARAM_ERROR) ;
01044 
01045         RECORD_INITIAL_POS (a_this, &init_pos);
01046 
01047         if (*a_str == NULL) {
01048                 *a_str = cr_string_new ();
01049                 str_needs_free = TRUE;
01050         }
01051         for (i = 0;; i++) {
01052                 if (is_first_nmchar == TRUE) {
01053                         status = cr_tknzr_parse_nmchar 
01054                                 (a_this, &tmp_char,
01055                                  &loc) ;
01056                         is_first_nmchar = FALSE ;
01057                 } else {
01058                         status = cr_tknzr_parse_nmchar 
01059                                 (a_this, &tmp_char, NULL) ;
01060                 }
01061                 if (status != CR_OK)
01062                         break;                
01063                 g_string_append_unichar ((*a_str)->stryng, 
01064                                          tmp_char);
01065         }
01066         if (i > 0) {
01067                 cr_parsing_location_copy 
01068                         (&(*a_str)->location, &loc) ;
01069                 return CR_OK;
01070         }
01071         if (str_needs_free == TRUE && *a_str) {
01072                 cr_string_destroy (*a_str);
01073                 *a_str = NULL;
01074         }
01075         cr_tknzr_set_cur_pos (a_this, &init_pos);
01076         return CR_PARSING_ERROR;
01077 }
01078 
01079 /**
01080  *Parses a "hash" as defined by the css spec in [4.1.1]:
01081  *HASH ::= #{name}
01082  */
01083 static enum CRStatus
01084 cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str)
01085 {
01086         guint32 cur_char = 0;
01087         CRInputPos init_pos;
01088         enum CRStatus status = CR_OK;
01089         gboolean str_needs_free = FALSE;
01090         CRParsingLocation loc = {0} ;
01091 
01092         g_return_val_if_fail (a_this && PRIVATE (a_this)
01093                               && PRIVATE (a_this)->input,
01094                               CR_BAD_PARAM_ERROR);
01095 
01096         RECORD_INITIAL_POS (a_this, &init_pos);
01097         READ_NEXT_CHAR (a_this, &cur_char);
01098         if (cur_char != '#') {
01099                 status = CR_PARSING_ERROR;
01100                 goto error;
01101         }
01102         if (*a_str == NULL) {
01103                 *a_str = cr_string_new ();
01104                 str_needs_free = TRUE;
01105         }
01106         cr_tknzr_get_parsing_location (a_this,
01107                                        &loc) ;
01108         status = cr_tknzr_parse_name (a_this, a_str);
01109         cr_parsing_location_copy (&(*a_str)->location, &loc) ;
01110         if (status != CR_OK) {
01111                 goto error;
01112         }
01113         return CR_OK;
01114 
01115  error:
01116         if (str_needs_free == TRUE && *a_str) {
01117                 cr_string_destroy (*a_str);
01118                 *a_str = NULL;
01119         }
01120 
01121         cr_tknzr_set_cur_pos (a_this, &init_pos);
01122         return status;
01123 }
01124 
01125 /**
01126  *Parses an uri as defined by the css spec [4.1.1]:
01127  * URI ::= url\({w}{string}{w}\)
01128  *         |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
01129  *
01130  *@param a_this the current instance of #CRTknzr.
01131  *@param a_str the successfully parsed url.
01132  *@return CR_OK upon successfull completion, an error code otherwise.
01133  */
01134 static enum CRStatus
01135 cr_tknzr_parse_uri (CRTknzr * a_this, 
01136                     CRString ** a_str)
01137 {
01138         guint32 cur_char = 0;
01139         CRInputPos init_pos;
01140         enum CRStatus status = CR_PARSING_ERROR;
01141         guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL;
01142         CRString *str = NULL;
01143         CRParsingLocation location = {0} ;
01144 
01145         g_return_val_if_fail (a_this 
01146                               && PRIVATE (a_this)
01147                               && PRIVATE (a_this)->input
01148                               && a_str, 
01149                               CR_BAD_PARAM_ERROR);
01150 
01151         RECORD_INITIAL_POS (a_this, &init_pos);
01152 
01153         PEEK_BYTE (a_this, 1, &tab[0]);
01154         PEEK_BYTE (a_this, 2, &tab[1]);
01155         PEEK_BYTE (a_this, 3, &tab[2]);
01156         PEEK_BYTE (a_this, 4, &tab[3]);
01157 
01158         if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') {
01159                 status = CR_PARSING_ERROR;
01160                 goto error;
01161         }
01162         /*
01163          *Here, we want to skip 4 bytes ('u''r''l''(').
01164          *But we also need to keep track of the parsing location
01165          *of the 'u'. So, we skip 1 byte, we record the parsing
01166          *location, then we skip the 3 remaining bytes.
01167          */
01168         SKIP_CHARS (a_this, 1);
01169         cr_tknzr_get_parsing_location (a_this, &location) ;
01170         SKIP_CHARS (a_this, 3);
01171         cr_tknzr_try_to_skip_spaces (a_this);
01172         status = cr_tknzr_parse_string (a_this, a_str);
01173 
01174         if (status == CR_OK) {
01175                 guint32 next_char = 0;
01176                 status = cr_tknzr_parse_w (a_this, &tmp_ptr1, 
01177                                            &tmp_ptr2, NULL);
01178                 cr_tknzr_try_to_skip_spaces (a_this);
01179                 PEEK_NEXT_CHAR (a_this, &next_char);
01180                 if (next_char == ')') {
01181                         READ_NEXT_CHAR (a_this, &cur_char);
01182                         status = CR_OK;
01183                 } else {
01184                         status = CR_PARSING_ERROR;
01185                 }
01186         }
01187         if (status != CR_OK) {
01188                 str = cr_string_new ();
01189                 for (;;) {
01190                         guint32 next_char = 0;
01191                         PEEK_NEXT_CHAR (a_this, &next_char);
01192                         if (strchr ("!#$%&", next_char)
01193                             || (next_char >= '*' && next_char <= '~')
01194                             || (cr_utils_is_nonascii (next_char) == TRUE)) {
01195                                 READ_NEXT_CHAR (a_this, &cur_char);
01196                                 g_string_append_unichar 
01197                                         (str->stryng, cur_char);
01198                                 status = CR_OK;
01199                         } else {
01200                                 guint32 esc_code = 0;
01201                                 status = cr_tknzr_parse_escape
01202                                         (a_this, &esc_code, NULL);
01203                                 if (status == CR_OK) {
01204                                         g_string_append_unichar
01205                                                 (str->stryng, 
01206                                                  esc_code);
01207                                 } else {
01208                                         status = CR_OK;
01209                                         break;
01210                                 }
01211                         }
01212                 }
01213                 cr_tknzr_try_to_skip_spaces (a_this);
01214                 READ_NEXT_CHAR (a_this, &cur_char);
01215                 if (cur_char == ')') {
01216                         status = CR_OK;
01217                 } else {
01218                         status = CR_PARSING_ERROR;
01219                         goto error;
01220                 }
01221                 if (str) {                        
01222                         if (*a_str == NULL) {
01223                                 *a_str = str;
01224                                 str = NULL;
01225                         } else {
01226                                 g_string_append_len
01227                                         ((*a_str)->stryng,
01228                                          str->stryng->str,
01229                                          str->stryng->len);
01230                                 cr_string_destroy (str);
01231                         }                        
01232                 }
01233         }
01234 
01235         cr_parsing_location_copy
01236                 (&(*a_str)->location,
01237                  &location) ;
01238         return CR_OK ;
01239  error:
01240         if (str) {
01241                 cr_string_destroy (str);
01242                 str = NULL;
01243         }
01244         cr_tknzr_set_cur_pos (a_this, &init_pos);
01245         return status;
01246 }
01247 
01248 /**
01249  *parses an RGB as defined in the css2 spec.
01250  *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')'
01251  *
01252  *@param a_this the "this pointer" of the current instance of
01253  *@param a_rgb out parameter the parsed rgb.
01254  *@return CR_OK upon successfull completion, an error code otherwise.
01255  */
01256 static enum CRStatus
01257 cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb)
01258 {
01259         enum CRStatus status = CR_OK;
01260         CRInputPos init_pos;
01261         CRNum *num = NULL;
01262         guchar next_bytes[3] = { 0 }, cur_byte = 0;
01263         glong red = 0,
01264                 green = 0,
01265                 blue = 0,
01266                 i = 0;
01267         gboolean is_percentage = FALSE;
01268         CRParsingLocation location = {0} ;
01269 
01270         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
01271 
01272         RECORD_INITIAL_POS (a_this, &init_pos);
01273 
01274         PEEK_BYTE (a_this, 1, &next_bytes[0]);
01275         PEEK_BYTE (a_this, 2, &next_bytes[1]);
01276         PEEK_BYTE (a_this, 3, &next_bytes[2]);
01277 
01278         if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R'))
01279             && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G'))
01280             && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) {
01281                 SKIP_CHARS (a_this, 1);
01282                 cr_tknzr_get_parsing_location (a_this, &location) ;
01283                 SKIP_CHARS (a_this, 2);
01284         } else {
01285                 status = CR_PARSING_ERROR;
01286                 goto error;
01287         }
01288         READ_NEXT_BYTE (a_this, &cur_byte);
01289         ENSURE_PARSING_COND (cur_byte == '(');
01290 
01291         cr_tknzr_try_to_skip_spaces (a_this);
01292         status = cr_tknzr_parse_num (a_this, &num);
01293         ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
01294 
01295         red = num->val;
01296         cr_num_destroy (num);
01297         num = NULL;
01298 
01299         PEEK_BYTE (a_this, 1, &next_bytes[0]);
01300         if (next_bytes[0] == '%') {
01301                 SKIP_CHARS (a_this, 1);
01302                 is_percentage = TRUE;
01303         }
01304         cr_tknzr_try_to_skip_spaces (a_this);
01305 
01306         for (i = 0; i < 2; i++) {
01307                 READ_NEXT_BYTE (a_this, &cur_byte);
01308                 ENSURE_PARSING_COND (cur_byte == ',');
01309 
01310                 cr_tknzr_try_to_skip_spaces (a_this);
01311                 status = cr_tknzr_parse_num (a_this, &num);
01312                 ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
01313 
01314                 PEEK_BYTE (a_this, 1, &next_bytes[0]);
01315                 if (next_bytes[0] == '%') {
01316                         SKIP_CHARS (a_this, 1);
01317                         is_percentage = 1;
01318                 }
01319 
01320                 if (i == 0) {
01321                         green = num->val;
01322                 } else if (i == 1) {
01323                         blue = num->val;
01324                 }
01325 
01326                 if (num) {
01327                         cr_num_destroy (num);
01328                         num = NULL;
01329                 }
01330                 cr_tknzr_try_to_skip_spaces (a_this);
01331         }
01332 
01333         READ_NEXT_BYTE (a_this, &cur_byte);
01334         if (*a_rgb == NULL) {
01335                 *a_rgb = cr_rgb_new_with_vals (red, green, blue,
01336                                                is_percentage);
01337 
01338                 if (*a_rgb == NULL) {
01339                         status = CR_ERROR;
01340                         goto error;
01341                 }
01342                 status = CR_OK;
01343         } else {
01344                 (*a_rgb)->red = red;
01345                 (*a_rgb)->green = green;
01346                 (*a_rgb)->blue = blue;
01347                 (*a_rgb)->is_percentage = is_percentage;
01348 
01349                 status = CR_OK;
01350         }
01351 
01352         if (status == CR_OK) {
01353                 if (a_rgb && *a_rgb) {
01354                         cr_parsing_location_copy 
01355                                 (&(*a_rgb)->location, 
01356                                  &location) ;
01357                 }
01358                 return CR_OK;
01359         }
01360 
01361  error:
01362         if (num) {
01363                 cr_num_destroy (num);
01364                 num = NULL;
01365         }
01366 
01367         cr_tknzr_set_cur_pos (a_this, &init_pos);
01368         return CR_OK;
01369 }
01370 
01371 /**
01372  *Parses a atkeyword as defined by the css spec in [4.1.1]:
01373  *ATKEYWORD ::= @{ident}
01374  *
01375  *@param a_this the "this pointer" of the current instance of
01376  *#CRTknzr.
01377  *
01378  *@param a_str out parameter. The parsed atkeyword. If *a_str is
01379  *set to NULL this function allocates a new instance of CRString and
01380  *sets it to the parsed atkeyword. If not, this function just appends
01381  *the parsed atkeyword to the end of *a_str. In both cases it is up to
01382  *the caller to free *a_str.
01383  *
01384  *@return CR_OK upon successfull completion, an error code otherwise.
01385  */
01386 static enum CRStatus
01387 cr_tknzr_parse_atkeyword (CRTknzr * a_this, 
01388                           CRString ** a_str)
01389 {
01390         guint32 cur_char = 0;
01391         CRInputPos init_pos;
01392         gboolean str_needs_free = FALSE;
01393         enum CRStatus status = CR_OK;
01394 
01395         g_return_val_if_fail (a_this && PRIVATE (a_this)
01396                               && PRIVATE (a_this)->input
01397                               && a_str, CR_BAD_PARAM_ERROR);
01398 
01399         RECORD_INITIAL_POS (a_this, &init_pos);
01400 
01401         READ_NEXT_CHAR (a_this, &cur_char);
01402 
01403         if (cur_char != '@') {
01404                 status = CR_PARSING_ERROR;
01405                 goto error;
01406         }
01407 
01408         if (*a_str == NULL) {
01409                 *a_str = cr_string_new ();
01410                 str_needs_free = TRUE;
01411         }
01412         status = cr_tknzr_parse_ident (a_this, a_str);
01413         if (status != CR_OK) {
01414                 goto error;
01415         }
01416         return CR_OK;
01417  error:
01418 
01419         if (str_needs_free == TRUE && *a_str) {
01420                 cr_string_destroy (*a_str);
01421                 *a_str = NULL;
01422         }
01423         cr_tknzr_set_cur_pos (a_this, &init_pos);
01424         return status;
01425 }
01426 
01427 static enum CRStatus
01428 cr_tknzr_parse_important (CRTknzr * a_this,
01429                           CRParsingLocation *a_location)
01430 {
01431         guint32 cur_char = 0;
01432         CRInputPos init_pos;
01433         enum CRStatus status = CR_OK;
01434 
01435         g_return_val_if_fail (a_this && PRIVATE (a_this)
01436                               && PRIVATE (a_this)->input,
01437                               CR_BAD_PARAM_ERROR);
01438 
01439         RECORD_INITIAL_POS (a_this, &init_pos);
01440         READ_NEXT_CHAR (a_this, &cur_char);
01441         ENSURE_PARSING_COND (cur_char == '!');
01442         if (a_location) {
01443                 cr_tknzr_get_parsing_location (a_this, 
01444                                                a_location) ;
01445         }
01446         cr_tknzr_try_to_skip_spaces (a_this);
01447 
01448         if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i'
01449             && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm'
01450             && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p'
01451             && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o'
01452             && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r'
01453             && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't'
01454             && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a'
01455             && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n'
01456             && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') {
01457                 SKIP_BYTES (a_this, 9);
01458                 if (a_location) {
01459                         cr_tknzr_get_parsing_location (a_this,
01460                                                        a_location) ;
01461                 }
01462                 return CR_OK;
01463         } else {
01464                 status = CR_PARSING_ERROR;
01465         }
01466 
01467  error:
01468         cr_tknzr_set_cur_pos (a_this, &init_pos);
01469 
01470         return status;
01471 }
01472 
01473 /**
01474  *Parses a num as defined in the css spec [4.1.1]:
01475  *[0-9]+|[0-9]*\.[0-9]+
01476  *@param a_this the current instance of #CRTknzr.
01477  *@param a_num out parameter. The parsed number.
01478  *@return CR_OK upon successfull completion, 
01479  *an error code otherwise.
01480  */
01481 static enum CRStatus
01482 cr_tknzr_parse_num (CRTknzr * a_this, 
01483                     CRNum ** a_num)
01484 {
01485         enum CRStatus status = CR_PARSING_ERROR;
01486         enum CRNumType val_type = NUM_GENERIC;
01487         gboolean parsing_dec = FALSE,
01488                 parsed = FALSE;
01489         guint32 cur_char = 0,
01490                 int_part = 0,
01491                 dec_part = 0,
01492                 next_char = 0;
01493         CRInputPos init_pos;
01494         CRParsingLocation location = {0} ;
01495 
01496         g_return_val_if_fail (a_this && PRIVATE (a_this)
01497                               && PRIVATE (a_this)->input, 
01498                               CR_BAD_PARAM_ERROR);
01499 
01500         RECORD_INITIAL_POS (a_this, &init_pos);
01501         READ_NEXT_CHAR (a_this, &cur_char);        
01502         if (IS_NUM (cur_char) == TRUE) {
01503                 int_part = int_part * 10 + (cur_char - '0');
01504 
01505                 parsed = TRUE;
01506         } else if (cur_char == '.') {
01507                 parsing_dec = TRUE;
01508         } else {
01509                 status = CR_PARSING_ERROR;
01510                 goto error;
01511         }
01512         cr_tknzr_get_parsing_location (a_this, &location) ;
01513 
01514         for (;;) {
01515                 status = cr_tknzr_peek_char (a_this, &next_char);
01516                 if (status != CR_OK) {
01517                         if (status == CR_END_OF_INPUT_ERROR)
01518                                 status = CR_OK;
01519                         break;
01520                 }
01521                 if (next_char == '.') {
01522                         if (parsing_dec == TRUE) {
01523                                 status = CR_PARSING_ERROR;
01524                                 goto error;
01525                         }
01526 
01527                         READ_NEXT_CHAR (a_this, &cur_char);
01528                         parsing_dec = TRUE;
01529                         parsed = TRUE;
01530                 } else if (IS_NUM (next_char) == TRUE) {
01531                         READ_NEXT_CHAR (a_this, &cur_char);
01532                         parsed = TRUE;
01533 
01534                         if (parsing_dec == FALSE) {
01535                                 int_part = int_part * 10 + (cur_char - '0');
01536                         } else {
01537                                 dec_part = dec_part * 10 + (cur_char - '0');
01538                         }
01539                 } else {
01540                         break;
01541                 }
01542         }
01543 
01544         if (parsed == FALSE) {
01545                 status = CR_PARSING_ERROR;
01546         }
01547 
01548         /*
01549          *Now, set the output param values.
01550          */
01551         if (status == CR_OK) {
01552                 gdouble val = 0.0;
01553 
01554                 val = int_part;
01555                 val += cr_utils_n_to_0_dot_n (dec_part);
01556                 if (*a_num == NULL) {
01557                         *a_num = cr_num_new_with_val (val, val_type);
01558 
01559                         if (*a_num == NULL) {
01560                                 status = CR_ERROR;
01561                                 goto error;
01562                         }
01563                 } else {
01564                         (*a_num)->val = val;
01565                         (*a_num)->type = val_type;
01566                 }
01567                 cr_parsing_location_copy (&(*a_num)->location,
01568                                           &location) ;
01569                 return CR_OK;
01570         }
01571 
01572  error:
01573 
01574         cr_tknzr_set_cur_pos (a_this, &init_pos);
01575 
01576         return status;
01577 }
01578 
01579 /*********************************************
01580  *PUBLIC methods
01581  ********************************************/
01582 
01583 CRTknzr *
01584 cr_tknzr_new (CRInput * a_input)
01585 {
01586         CRTknzr *result = NULL;
01587 
01588         result = g_try_malloc (sizeof (CRTknzr));
01589 
01590         if (result == NULL) {
01591                 cr_utils_trace_info ("Out of memory");
01592                 return NULL;
01593         }
01594 
01595         memset (result, 0, sizeof (CRTknzr));
01596 
01597         result->priv = g_try_malloc (sizeof (CRTknzrPriv));
01598 
01599         if (result->priv == NULL) {
01600                 cr_utils_trace_info ("Out of memory");
01601 
01602                 if (result) {
01603                         g_free (result);
01604                         result = NULL;
01605                 }
01606 
01607                 return NULL;
01608         }
01609         memset (result->priv, 0, sizeof (CRTknzrPriv));
01610         if (a_input)
01611                 cr_tknzr_set_input (result, a_input);
01612         return result;
01613 }
01614 
01615 CRTknzr *
01616 cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len,
01617                        enum CREncoding a_enc, 
01618                        gboolean a_free_at_destroy)
01619 {
01620         CRTknzr *result = NULL;
01621         CRInput *input = NULL;
01622 
01623         input = cr_input_new_from_buf (a_buf, a_len, a_enc,
01624                                        a_free_at_destroy);
01625 
01626         g_return_val_if_fail (input != NULL, NULL);
01627 
01628         result = cr_tknzr_new (input);
01629 
01630         return result;
01631 }
01632 
01633 CRTknzr *
01634 cr_tknzr_new_from_uri (const guchar * a_file_uri, 
01635                        enum CREncoding a_enc)
01636 {
01637         CRTknzr *result = NULL;
01638         CRInput *input = NULL;
01639 
01640         input = cr_input_new_from_uri (a_file_uri, a_enc);
01641         g_return_val_if_fail (input != NULL, NULL);
01642 
01643         result = cr_tknzr_new (input);
01644 
01645         return result;
01646 }
01647 
01648 void
01649 cr_tknzr_ref (CRTknzr * a_this)
01650 {
01651         g_return_if_fail (a_this && PRIVATE (a_this));
01652 
01653         PRIVATE (a_this)->ref_count++;
01654 }
01655 
01656 gboolean
01657 cr_tknzr_unref (CRTknzr * a_this)
01658 {
01659         g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
01660 
01661         if (PRIVATE (a_this)->ref_count > 0) {
01662                 PRIVATE (a_this)->ref_count--;
01663         }
01664 
01665         if (PRIVATE (a_this)->ref_count == 0) {
01666                 cr_tknzr_destroy (a_this);
01667                 return TRUE;
01668         }
01669 
01670         return FALSE;
01671 }
01672 
01673 enum CRStatus
01674 cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input)
01675 {
01676         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
01677 
01678         if (PRIVATE (a_this)->input) {
01679                 cr_input_unref (PRIVATE (a_this)->input);
01680         }
01681 
01682         PRIVATE (a_this)->input = a_input;
01683 
01684         cr_input_ref (PRIVATE (a_this)->input);
01685 
01686         return CR_OK;
01687 }
01688 
01689 enum CRStatus
01690 cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input)
01691 {
01692         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
01693 
01694         *a_input = PRIVATE (a_this)->input;
01695 
01696         return CR_OK;
01697 }
01698 
01699 /*********************************
01700  *Tokenizer input handling routines
01701  *********************************/
01702 
01703 /**
01704  *Reads the next byte from the parser input stream.
01705  *@param a_this the "this pointer" of the current instance of
01706  *#CRParser.
01707  *@param a_byte out parameter the place where to store the byte
01708  *read.
01709  *@return CR_OK upon successfull completion, an error 
01710  *code otherwise.
01711  */
01712 enum CRStatus
01713 cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte)
01714 {
01715         g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
01716 
01717         return cr_input_read_byte (PRIVATE (a_this)->input, a_byte);
01718 
01719 }
01720 
01721 /**
01722  *Reads the next char from the parser input stream.
01723  *@param a_this the current instance of #CRTknzr.
01724  *@param a_char out parameter. The read char.
01725  *@return CR_OK upon successfull completion, an error code
01726  *otherwise.
01727  */
01728 enum CRStatus
01729 cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char)
01730 {
01731         g_return_val_if_fail (a_this && PRIVATE (a_this)
01732                               && PRIVATE (a_this)->input
01733                               && a_char, CR_BAD_PARAM_ERROR);
01734 
01735         if (PRIVATE (a_this)->token_cache) {
01736                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01737                                       &PRIVATE (a_this)->prev_pos);
01738                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01739                 PRIVATE (a_this)->token_cache = NULL;
01740         }
01741 
01742         return cr_input_read_char (PRIVATE (a_this)->input, a_char);
01743 }
01744 
01745 /**
01746  *Peeks a char from the parser input stream.
01747  *To "peek a char" means reads the next char without consuming it.
01748  *Subsequent calls to this function return the same char.
01749  *@param a_this the current instance of #CRTknzr.
01750  *@param a_char out parameter. The peeked char uppon successfull completion.
01751  *@return CR_OK upon successfull completion, an error code otherwise.
01752  */
01753 enum CRStatus
01754 cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char)
01755 {
01756         g_return_val_if_fail (a_this && PRIVATE (a_this)
01757                               && PRIVATE (a_this)->input
01758                               && a_char, CR_BAD_PARAM_ERROR);
01759 
01760         if (PRIVATE (a_this)->token_cache) {
01761                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01762                                       &PRIVATE (a_this)->prev_pos);
01763                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01764                 PRIVATE (a_this)->token_cache = NULL;
01765         }
01766 
01767         return cr_input_peek_char (PRIVATE (a_this)->input, a_char);
01768 }
01769 
01770 /**
01771  *Peeks a byte ahead at a given postion in the parser input stream.
01772  *@param a_this the current instance of #CRTknzr.
01773  *@param a_offset the offset of the peeked byte starting from the current
01774  *byte in the parser input stream.
01775  *@param a_byte out parameter. The peeked byte upon 
01776  *successfull completion.
01777  *@return CR_OK upon successfull completion, an error code otherwise.
01778  */
01779 enum CRStatus
01780 cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte)
01781 {
01782         g_return_val_if_fail (a_this && PRIVATE (a_this)
01783                               && PRIVATE (a_this)->input && a_byte,
01784                               CR_BAD_PARAM_ERROR);
01785 
01786         if (PRIVATE (a_this)->token_cache) {
01787                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01788                                       &PRIVATE (a_this)->prev_pos);
01789                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01790                 PRIVATE (a_this)->token_cache = NULL;
01791         }
01792 
01793         return cr_input_peek_byte (PRIVATE (a_this)->input,
01794                                    CR_SEEK_CUR, a_offset, a_byte);
01795 }
01796 
01797 /**
01798  *Same as cr_tknzr_peek_byte() but this api returns the byte peeked.
01799  *@param a_this the current instance of #CRTknzr.
01800  *@param a_offset the offset of the peeked byte starting from the current
01801  *byte in the parser input stream.
01802  *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of
01803  *file, FALE otherwise. If the caller sets it to NULL, this parameter 
01804  *is just ignored.
01805  *@return the peeked byte.
01806  */
01807 guchar
01808 cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof)
01809 {
01810         g_return_val_if_fail (a_this && PRIVATE (a_this)
01811                               && PRIVATE (a_this)->input, 0);
01812 
01813         return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof);
01814 }
01815 
01816 /**
01817  *Gets the number of bytes left in the topmost input stream
01818  *associated to this parser.
01819  *@param a_this the current instance of #CRTknzr
01820  *@return the number of bytes left or -1 in case of error.
01821  */
01822 glong
01823 cr_tknzr_get_nb_bytes_left (CRTknzr * a_this)
01824 {
01825         g_return_val_if_fail (a_this && PRIVATE (a_this)
01826                               && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
01827 
01828         if (PRIVATE (a_this)->token_cache) {
01829                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01830                                       &PRIVATE (a_this)->prev_pos);
01831                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01832                 PRIVATE (a_this)->token_cache = NULL;
01833         }
01834 
01835         return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input);
01836 }
01837 
01838 enum CRStatus
01839 cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
01840 {
01841         g_return_val_if_fail (a_this && PRIVATE (a_this)
01842                               && PRIVATE (a_this)->input
01843                               && a_pos, CR_BAD_PARAM_ERROR);
01844 
01845         if (PRIVATE (a_this)->token_cache) {
01846                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01847                                       &PRIVATE (a_this)->prev_pos);
01848                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01849                 PRIVATE (a_this)->token_cache = NULL;
01850         }
01851 
01852         return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos);
01853 }
01854 
01855 enum CRStatus 
01856 cr_tknzr_get_parsing_location (CRTknzr *a_this,
01857                                CRParsingLocation *a_loc)
01858 {
01859         g_return_val_if_fail (a_this 
01860                               && PRIVATE (a_this)
01861                               && a_loc,
01862                               CR_BAD_PARAM_ERROR) ;
01863 
01864         return cr_input_get_parsing_location 
01865                 (PRIVATE (a_this)->input, a_loc) ;
01866 }
01867 
01868 enum CRStatus
01869 cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr)
01870 {
01871         g_return_val_if_fail (a_this && PRIVATE (a_this)
01872                               && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
01873         if (PRIVATE (a_this)->token_cache) {
01874                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01875                                       &PRIVATE (a_this)->prev_pos);
01876                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01877                 PRIVATE (a_this)->token_cache = NULL;
01878         }
01879 
01880         return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr);
01881 }
01882 
01883 enum CRStatus
01884 cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos)
01885 {
01886         g_return_val_if_fail (a_this && PRIVATE (a_this)
01887                               && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
01888 
01889         if (PRIVATE (a_this)->token_cache) {
01890                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01891                                       &PRIVATE (a_this)->prev_pos);
01892                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01893                 PRIVATE (a_this)->token_cache = NULL;
01894         }
01895 
01896         return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos);
01897 }
01898 
01899 enum CRStatus
01900 cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char)
01901 {
01902         g_return_val_if_fail (a_this && PRIVATE (a_this)
01903                               && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
01904 
01905         if (PRIVATE (a_this)->token_cache) {
01906                 cr_input_set_cur_pos (PRIVATE (a_this)->input,
01907                                       &PRIVATE (a_this)->prev_pos);
01908                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01909                 PRIVATE (a_this)->token_cache = NULL;
01910         }
01911 
01912         return cr_input_consume_chars (PRIVATE (a_this)->input,
01913                                        a_char, a_nb_char);
01914 }
01915 
01916 enum CRStatus
01917 cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
01918 {
01919         g_return_val_if_fail (a_this && PRIVATE (a_this)
01920                               && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
01921 
01922         if (PRIVATE (a_this)->token_cache) {
01923                 cr_token_destroy (PRIVATE (a_this)->token_cache);
01924                 PRIVATE (a_this)->token_cache = NULL;
01925         }
01926 
01927         return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos);
01928 }
01929 
01930 enum CRStatus
01931 cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token)
01932 {
01933         g_return_val_if_fail (a_this && PRIVATE (a_this)
01934                               && PRIVATE (a_this)->token_cache == NULL,
01935                               CR_BAD_PARAM_ERROR);
01936 
01937         PRIVATE (a_this)->token_cache = a_token;
01938 
01939         return CR_OK;
01940 }
01941 
01942 /**
01943  *Returns the next token of the input stream.
01944  *This method is really central. Each parsing
01945  *method calls it.
01946  *@param a_this the current tokenizer.
01947  *@param a_tk out parameter. The returned token.
01948  *for the sake of mem leak avoidance, *a_tk must
01949  *be NULL.
01950  *@param CR_OK upon successfull completion, an error code
01951  *otherwise.
01952  */
01953 enum CRStatus
01954 cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk)
01955 {
01956         enum CRStatus status = CR_OK;
01957         CRToken *token = NULL;
01958         CRInputPos init_pos;
01959         guint32 next_char = 0;
01960         guchar next_bytes[4] = { 0 };
01961         gboolean reached_eof = FALSE;
01962         CRInput *input = NULL;
01963         CRString *str = NULL;
01964         CRRgb *rgb = NULL;
01965         CRParsingLocation location = {0} ;
01966 
01967         g_return_val_if_fail (a_this && PRIVATE (a_this)
01968                               && a_tk && *a_tk == NULL
01969                               && PRIVATE (a_this)->input, 
01970                               CR_BAD_PARAM_ERROR);
01971 
01972         if (PRIVATE (a_this)->token_cache) {
01973                 *a_tk = PRIVATE (a_this)->token_cache;
01974                 PRIVATE (a_this)->token_cache = NULL;
01975                 return CR_OK;
01976         }
01977 
01978         RECORD_INITIAL_POS (a_this, &init_pos);
01979 
01980         status = cr_input_get_end_of_file
01981                 (PRIVATE (a_this)->input, &reached_eof);
01982         ENSURE_PARSING_COND (status == CR_OK);
01983 
01984         if (reached_eof == TRUE) {
01985                 status = CR_END_OF_INPUT_ERROR;
01986                 goto error;
01987         }
01988 
01989         input = PRIVATE (a_this)->input;
01990 
01991         PEEK_NEXT_CHAR (a_this, &next_char);
01992         token = cr_token_new ();
01993         ENSURE_PARSING_COND (token);
01994 
01995         switch (next_char) {
01996         case '@':
01997                 {
01998                         if (BYTE (input, 2, NULL) == 'f'
01999                             && BYTE (input, 3, NULL) == 'o'
02000                             && BYTE (input, 4, NULL) == 'n'
02001                             && BYTE (input, 5, NULL) == 't'
02002                             && BYTE (input, 6, NULL) == '-'
02003                             && BYTE (input, 7, NULL) == 'f'
02004                             && BYTE (input, 8, NULL) == 'a'
02005                             && BYTE (input, 9, NULL) == 'c'
02006                             && BYTE (input, 10, NULL) == 'e') {
02007                                 SKIP_CHARS (a_this, 1);
02008                                 cr_tknzr_get_parsing_location 
02009                                         (a_this, &location) ;
02010                                 SKIP_CHARS (a_this, 9);
02011                                 status = cr_token_set_font_face_sym (token);
02012                                 CHECK_PARSING_STATUS (status, TRUE);
02013                                 cr_parsing_location_copy (&token->location,
02014                                                           &location) ;
02015                                 goto done;
02016                         }
02017 
02018                         if (BYTE (input, 2, NULL) == 'c'
02019                             && BYTE (input, 3, NULL) == 'h'
02020                             && BYTE (input, 4, NULL) == 'a'
02021                             && BYTE (input, 5, NULL) == 'r'
02022                             && BYTE (input, 6, NULL) == 's'
02023                             && BYTE (input, 7, NULL) == 'e'
02024                             && BYTE (input, 8, NULL) == 't') {
02025                                 SKIP_CHARS (a_this, 1);
02026                                 cr_tknzr_get_parsing_location
02027                                         (a_this, &location) ;
02028                                 SKIP_CHARS (a_this, 7);
02029                                 status = cr_token_set_charset_sym (token);
02030                                 CHECK_PARSING_STATUS (status, TRUE);
02031                                 cr_parsing_location_copy (&token->location,
02032                                                           &location) ;
02033                                 goto done;
02034                         }
02035 
02036                         if (BYTE (input, 2, NULL) == 'i'
02037                             && BYTE (input, 3, NULL) == 'm'
02038                             && BYTE (input, 4, NULL) == 'p'
02039                             && BYTE (input, 5, NULL) == 'o'
02040                             && BYTE (input, 6, NULL) == 'r'
02041                             && BYTE (input, 7, NULL) == 't') {
02042                                 SKIP_CHARS (a_this, 1);
02043                                 cr_tknzr_get_parsing_location 
02044                                         (a_this, &location) ;
02045                                 SKIP_CHARS (a_this, 6);
02046                                 status = cr_token_set_import_sym (token);
02047                                 CHECK_PARSING_STATUS (status, TRUE);
02048                                 cr_parsing_location_copy (&token->location,
02049                                                           &location) ;
02050                                 goto done;
02051                         }
02052 
02053                         if (BYTE (input, 2, NULL) == 'm'
02054                             && BYTE (input, 3, NULL) == 'e'
02055                             && BYTE (input, 4, NULL) == 'd'
02056                             && BYTE (input, 5, NULL) == 'i'
02057                             && BYTE (input, 6, NULL) == 'a') {
02058                                 SKIP_CHARS (a_this, 1);
02059                                 cr_tknzr_get_parsing_location (a_this, 
02060                                                                &location) ;
02061                                 SKIP_CHARS (a_this, 5);
02062                                 status = cr_token_set_media_sym (token);
02063                                 CHECK_PARSING_STATUS (status, TRUE);
02064                                 cr_parsing_location_copy (&token->location, 
02065                                                           &location) ;
02066                                 goto done;
02067                         }
02068 
02069                         if (BYTE (input, 2, NULL) == 'p'
02070                             && BYTE (input, 3, NULL) == 'a'
02071                             && BYTE (input, 4, NULL) == 'g'
02072                             && BYTE (input, 5, NULL) == 'e') {
02073                                 SKIP_CHARS (a_this, 1);
02074                                 cr_tknzr_get_parsing_location (a_this, 
02075                                                                &location) ;
02076                                 SKIP_CHARS (a_this, 4);
02077                                 status = cr_token_set_page_sym (token);
02078                                 CHECK_PARSING_STATUS (status, TRUE);
02079                                 cr_parsing_location_copy (&token->location, 
02080                                                           &location) ;
02081                                 goto done;
02082                         }
02083                         status = cr_tknzr_parse_atkeyword (a_this, &str);
02084                         if (status == CR_OK) {
02085                                 status = cr_token_set_atkeyword (token, str);
02086                                 CHECK_PARSING_STATUS (status, TRUE);
02087                                 if (str) {
02088                                         cr_parsing_location_copy (&token->location, 
02089                                                                   &str->location) ;
02090                                 }
02091                                 goto done;
02092                         }
02093                 }
02094                 break;
02095 
02096         case 'u':
02097 
02098                 if (BYTE (input, 2, NULL) == 'r'
02099                     && BYTE (input, 3, NULL) == 'l'
02100                     && BYTE (input, 4, NULL) == '(') {
02101                         CRString *str = NULL;
02102 
02103                         status = cr_tknzr_parse_uri (a_this, &str);
02104                         if (status == CR_OK) {
02105                                 status = cr_token_set_uri (token, str);
02106                                 CHECK_PARSING_STATUS (status, TRUE);
02107                                 if (str) {
02108                                         cr_parsing_location_copy (&token->location,
02109                                                                   &str->location) ;
02110                                 }
02111                                 goto done;
02112                         }
02113                 } else {
02114                         status = cr_tknzr_parse_ident (a_this, &str);
02115                         if (status == CR_OK && str) {
02116                                 status = cr_token_set_ident (token, str);
02117                                 CHECK_PARSING_STATUS (status, TRUE);
02118                                 if (str) {
02119                                         cr_parsing_location_copy (&token->location, 
02120                                                                   &str->location) ;
02121                                 }
02122                                 goto done;
02123                         }
02124                 }
02125                 break;
02126 
02127         case 'r':
02128                 if (BYTE (input, 2, NULL) == 'g'
02129                     && BYTE (input, 3, NULL) == 'b'
02130                     && BYTE (input, 4, NULL) == '(') {
02131                         status = cr_tknzr_parse_rgb (a_this, &rgb);
02132                         if (status == CR_OK && rgb) {
02133                                 status = cr_token_set_rgb (token, rgb);
02134                                 CHECK_PARSING_STATUS (status, TRUE);
02135                                 if (rgb) {
02136                                         cr_parsing_location_copy (&token->location, 
02137                                                                   &rgb->location) ;
02138                                 }
02139                                 rgb = NULL;
02140                                 goto done;
02141                         }
02142 
02143                 } else {
02144                         status = cr_tknzr_parse_ident (a_this, &str);
02145                         if (status == CR_OK) {
02146                                 status = cr_token_set_ident (token, str);
02147                                 CHECK_PARSING_STATUS (status, TRUE);
02148                                 if (str) {
02149                                         cr_parsing_location_copy (&token->location, 
02150                                                                   &str->location) ;
02151                                 }
02152                                 str = NULL;
02153                                 goto done;
02154                         }
02155                 }
02156                 break;
02157 
02158         case '<':
02159                 if (BYTE (input, 2, NULL) == '-'
02160                     && BYTE (input, 3, NULL) == '-') {
02161                         SKIP_CHARS (a_this, 1);
02162                         cr_tknzr_get_parsing_location (a_this, 
02163                                                        &location) ;
02164                         SKIP_CHARS (a_this, 2);
02165                         status = cr_token_set_cdo (token);
02166                         CHECK_PARSING_STATUS (status, TRUE);
02167                         cr_parsing_location_copy (&token->location, 
02168                                                   &location) ;
02169                         goto done;
02170                 }
02171                 break;
02172 
02173         case '-':
02174                 if (BYTE (input, 2, NULL) == '-'
02175                     && BYTE (input, 3, NULL) == '>') {
02176                         SKIP_CHARS (a_this, 1);
02177                         cr_tknzr_get_parsing_location (a_this, 
02178                                                        &location) ;
02179                         SKIP_CHARS (a_this, 2);
02180                         status = cr_token_set_cdc (token);
02181                         CHECK_PARSING_STATUS (status, TRUE);
02182                         cr_parsing_location_copy (&token->location, 
02183                                                   &location) ;
02184                         goto done;
02185                 } else {
02186                         status = cr_tknzr_parse_ident
02187                                 (a_this, &str);
02188                         if (status == CR_OK) {
02189                                 cr_token_set_ident
02190                                         (token, str);
02191                                 if (str) {
02192                                         cr_parsing_location_copy (&token->location, 
02193                                                                   &str->location) ;
02194                                 }
02195                                 goto done;
02196                         }
02197                 }
02198                 break;
02199 
02200         case '~':
02201                 if (BYTE (input, 2, NULL) == '=') {
02202                         SKIP_CHARS (a_this, 1);
02203                         cr_tknzr_get_parsing_location (a_this, 
02204                                                        &location) ;
02205                         SKIP_CHARS (a_this, 1);
02206                         status = cr_token_set_includes (token);
02207                         CHECK_PARSING_STATUS (status, TRUE);
02208                         cr_parsing_location_copy (&token->location, 
02209                                                   &location) ;
02210                         goto done;
02211                 }
02212                 break;
02213 
02214         case '|':
02215                 if (BYTE (input, 2, NULL) == '=') {
02216                         SKIP_CHARS (a_this, 1);
02217                         cr_tknzr_get_parsing_location (a_this, 
02218                                                        &location) ;
02219                         SKIP_CHARS (a_this, 1);
02220                         status = cr_token_set_dashmatch (token);
02221                         CHECK_PARSING_STATUS (status, TRUE);
02222                         cr_parsing_location_copy (&token->location,
02223                                                   &location) ;
02224                         goto done;
02225                 }
02226                 break;
02227 
02228         case '/':
02229                 if (BYTE (input, 2, NULL) == '*') {
02230                         status = cr_tknzr_parse_comment (a_this, &str);
02231 
02232                         if (status == CR_OK) {
02233                                 status = cr_token_set_comment (token, str);
02234                                 str = NULL;
02235                                 CHECK_PARSING_STATUS (status, TRUE);
02236                                 if (str) {
02237                                         cr_parsing_location_copy (&token->location, 
02238                                                                   &str->location) ;
02239                                 }
02240                                 goto done;
02241                         }
02242                 }
02243                 break ;
02244 
02245         case ';':
02246                 SKIP_CHARS (a_this, 1);
02247                 cr_tknzr_get_parsing_location (a_this, 
02248                                                &location) ;
02249                 status = cr_token_set_semicolon (token);
02250                 CHECK_PARSING_STATUS (status, TRUE);
02251                 cr_parsing_location_copy (&token->location, 
02252                                           &location) ;
02253                 goto done;
02254 
02255         case '{':
02256                 SKIP_CHARS (a_this, 1);
02257                 cr_tknzr_get_parsing_location (a_this, 
02258                                                &location) ;
02259                 status = cr_token_set_cbo (token);
02260                 CHECK_PARSING_STATUS (status, TRUE);
02261                 cr_tknzr_get_parsing_location (a_this, 
02262                                                &location) ;
02263                 goto done;
02264 
02265         case '}':
02266                 SKIP_CHARS (a_this, 1);
02267                 cr_tknzr_get_parsing_location (a_this, 
02268                                                &location) ;
02269                 status = cr_token_set_cbc (token);
02270                 CHECK_PARSING_STATUS (status, TRUE);
02271                 cr_parsing_location_copy (&token->location, 
02272                                           &location) ;
02273                 goto done;
02274 
02275         case '(':
02276                 SKIP_CHARS (a_this, 1);
02277                 cr_tknzr_get_parsing_location (a_this, 
02278                                                &location) ;
02279                 status = cr_token_set_po (token);
02280                 CHECK_PARSING_STATUS (status, TRUE);
02281                 cr_parsing_location_copy (&token->location, 
02282                                           &location) ;
02283                 goto done;
02284 
02285         case ')':
02286                 SKIP_CHARS (a_this, 1);
02287                 cr_tknzr_get_parsing_location (a_this, 
02288                                                &location) ;
02289                 status = cr_token_set_pc (token);
02290                 CHECK_PARSING_STATUS (status, TRUE);
02291                 cr_parsing_location_copy (&token->location, 
02292                                           &location) ;
02293                 goto done;
02294 
02295         case '[':
02296                 SKIP_CHARS (a_this, 1);
02297                 cr_tknzr_get_parsing_location (a_this, 
02298                                                &location) ;
02299                 status = cr_token_set_bo (token);
02300                 CHECK_PARSING_STATUS (status, TRUE);
02301                 cr_parsing_location_copy (&token->location, 
02302                                           &location) ;
02303                 goto done;
02304 
02305         case ']':
02306                 SKIP_CHARS (a_this, 1);
02307                 cr_tknzr_get_parsing_location (a_this, 
02308                                                &location) ;
02309                 status = cr_token_set_bc (token);
02310                 CHECK_PARSING_STATUS (status, TRUE);
02311                 cr_parsing_location_copy (&token->location, 
02312                                           &location) ;
02313                 goto done;
02314 
02315         case ' ':
02316         case '\t':
02317         case '\n':
02318         case '\f':
02319         case '\r':
02320                 {
02321                         guchar *start = NULL,
02322                                 *end = NULL;
02323 
02324                         status = cr_tknzr_parse_w (a_this, &start, 
02325                                                    &end, &location);
02326                         if (status == CR_OK) {
02327                                 status = cr_token_set_s (token);
02328                                 CHECK_PARSING_STATUS (status, TRUE);
02329                                 cr_tknzr_get_parsing_location (a_this, 
02330                                                                &location) ;
02331                                 goto done;
02332                         }
02333                 }
02334                 break;
02335 
02336         case '#':
02337                 {
02338                         status = cr_tknzr_parse_hash (a_this, &str);
02339                         if (status == CR_OK && str) {
02340                                 status = cr_token_set_hash (token, str);
02341                                 CHECK_PARSING_STATUS (status, TRUE);
02342                                 if (str) {
02343                                         cr_parsing_location_copy (&token->location,
02344                                                                   &str->location) ;
02345                                 }
02346                                 str = NULL;
02347                                 goto done;
02348                         }
02349                 }
02350                 break;
02351 
02352         case '\'':
02353         case '"':
02354                 status = cr_tknzr_parse_string (a_this, &str);
02355                 if (status == CR_OK && str) {
02356                         status = cr_token_set_string (token, str);
02357                         CHECK_PARSING_STATUS (status, TRUE);
02358                         if (str) {
02359                                 cr_parsing_location_copy (&token->location, 
02360                                                           &str->location) ;
02361                         }
02362                         str = NULL;
02363                         goto done;
02364                 }
02365                 break;
02366 
02367         case '!':
02368                 status = cr_tknzr_parse_important (a_this, &location);
02369                 if (status == CR_OK) {
02370                         status = cr_token_set_important_sym (token);
02371                         CHECK_PARSING_STATUS (status, TRUE);
02372                         cr_parsing_location_copy (&token->location, 
02373                                                   &location) ;
02374                         goto done;
02375                 }
02376                 break;
02377 
02378         case '0':
02379         case '1':
02380         case '2':
02381         case '3':
02382         case '4':
02383         case '5':
02384         case '6':
02385         case '7':
02386         case '8':
02387         case '9':
02388         case '.':
02389                 {
02390                         CRNum *num = NULL;
02391 
02392                         status = cr_tknzr_parse_num (a_this, &num);
02393                         if (status == CR_OK && num) {
02394                                 next_bytes[0] = BYTE (input, 1, NULL);
02395                                 next_bytes[1] = BYTE (input, 2, NULL);
02396                                 next_bytes[2] = BYTE (input, 3, NULL);
02397                                 next_bytes[3] = BYTE (input, 3, NULL);
02398 
02399                                 if (next_bytes[0] == 'e'
02400                                     && next_bytes[1] == 'm') {
02401                                         num->type = NUM_LENGTH_EM;
02402                                         status = cr_token_set_ems (token,
02403                                                                    num);
02404                                         num = NULL;
02405                                         SKIP_CHARS (a_this, 2);
02406                                 } else if (next_bytes[0] == 'e'
02407                                            && next_bytes[1] == 'x') {
02408                                         num->type = NUM_LENGTH_EX;
02409                                         status = cr_token_set_exs (token,
02410                                                                    num);
02411                                         num = NULL;
02412                                         SKIP_CHARS (a_this, 2);
02413                                 } else if (next_bytes[0] == 'p'
02414                                            && next_bytes[1] == 'x') {
02415                                         num->type = NUM_LENGTH_PX;
02416                                         status = cr_token_set_length
02417                                                 (token, num, LENGTH_PX_ET);
02418                                         num = NULL;
02419                                         SKIP_CHARS (a_this, 2);
02420                                 } else if (next_bytes[0] == 'c'
02421                                            && next_bytes[1] == 'm') {
02422                                         num->type = NUM_LENGTH_CM;
02423                                         status = cr_token_set_length
02424                                                 (token, num, LENGTH_CM_ET);
02425                                         num = NULL;
02426                                         SKIP_CHARS (a_this, 2);
02427                                 } else if (next_bytes[0] == 'm'
02428                                            && next_bytes[1] == 'm') {
02429                                         num->type = NUM_LENGTH_MM;
02430                                         status = cr_token_set_length
02431                                                 (token, num, LENGTH_MM_ET);
02432                                         num = NULL;
02433                                         SKIP_CHARS (a_this, 2);
02434                                 } else if (next_bytes[0] == 'i'
02435                                            && next_bytes[1] == 'n') {
02436                                         num->type = NUM_LENGTH_IN;
02437                                         status = cr_token_set_length
02438                                                 (token, num, LENGTH_IN_ET);
02439                                         num = NULL;
02440                                         SKIP_CHARS (a_this, 2);
02441                                 } else if (next_bytes[0] == 'p'
02442                                            && next_bytes[1] == 't') {
02443                                         num->type = NUM_LENGTH_PT;
02444                                         status = cr_token_set_length
02445                                                 (token, num, LENGTH_PT_ET);
02446                                         num = NULL;
02447                                         SKIP_CHARS (a_this, 2);
02448                                 } else if (next_bytes[0] == 'p'
02449                                            && next_bytes[1] == 'c') {
02450                                         num->type = NUM_LENGTH_PC;
02451                                         status = cr_token_set_length
02452                                                 (token, num, LENGTH_PC_ET);
02453                                         num = NULL;
02454                                         SKIP_CHARS (a_this, 2);
02455                                 } else if (next_bytes[0] == 'd'
02456                                            && next_bytes[1] == 'e'
02457                                            && next_bytes[2] == 'g') {
02458                                         num->type = NUM_ANGLE_DEG;
02459                                         status = cr_token_set_angle
02460                                                 (token, num, ANGLE_DEG_ET);
02461                                         num = NULL;
02462                                         SKIP_CHARS (a_this, 3);
02463                                 } else if (next_bytes[0] == 'r'
02464                                            && next_bytes[1] == 'a'
02465                                            && next_bytes[2] == 'd') {
02466                                         num->type = NUM_ANGLE_RAD;
02467                                         status = cr_token_set_angle
02468                                                 (token, num, ANGLE_RAD_ET);
02469                                         num = NULL;
02470                                         SKIP_CHARS (a_this, 3);
02471                                 } else if (next_bytes[0] == 'g'
02472                                            && next_bytes[1] == 'r'
02473                                            && next_bytes[2] == 'a'
02474                                            && next_bytes[3] == 'd') {
02475                                         num->type = NUM_ANGLE_GRAD;
02476                                         status = cr_token_set_angle
02477                                                 (token, num, ANGLE_GRAD_ET);
02478                                         num = NULL;
02479                                         SKIP_CHARS (a_this, 4);
02480                                 } else if (next_bytes[0] == 'm'
02481                                            && next_bytes[1] == 's') {
02482                                         num->type = NUM_TIME_MS;
02483                                         status = cr_token_set_time
02484                                                 (token, num, TIME_MS_ET);
02485                                         num = NULL;
02486                                         SKIP_CHARS (a_this, 2);
02487                                 } else if (next_bytes[0] == 's') {
02488                                         num->type = NUM_TIME_S;
02489                                         status = cr_token_set_time
02490                                                 (token, num, TIME_S_ET);
02491                                         num = NULL;
02492                                         SKIP_CHARS (a_this, 1);
02493                                 } else if (next_bytes[0] == 'H'
02494                                            && next_bytes[1] == 'z') {
02495                                         num->type = NUM_FREQ_HZ;
02496                                         status = cr_token_set_freq
02497                                                 (token, num, FREQ_HZ_ET);
02498                                         num = NULL;
02499                                         SKIP_CHARS (a_this, 2);
02500                                 } else if (next_bytes[0] == 'k'
02501                                            && next_bytes[1] == 'H'
02502                                            && next_bytes[2] == 'z') {
02503                                         num->type = NUM_FREQ_KHZ;
02504                                         status = cr_token_set_freq
02505                                                 (token, num, FREQ_KHZ_ET);
02506                                         num = NULL;
02507                                         SKIP_CHARS (a_this, 3);
02508                                 } else if (next_bytes[0] == '%') {
02509                                         num->type = NUM_PERCENTAGE;
02510                                         status = cr_token_set_percentage
02511                                                 (token, num);
02512                                         num = NULL;
02513                                         SKIP_CHARS (a_this, 1);
02514                                 } else {
02515                                         status = cr_tknzr_parse_ident (a_this,
02516                                                                        &str);
02517                                         if (status == CR_OK && str) {
02518                                                 num->type = NUM_UNKNOWN_TYPE;
02519                                                 status = cr_token_set_dimen
02520                                                         (token, num, str);
02521                                                 num = NULL;
02522                                                 CHECK_PARSING_STATUS (status,
02523                                                                       TRUE);
02524                                                 str = NULL;
02525                                         } else {
02526                                                 status = cr_token_set_number
02527                                                         (token, num);
02528                                                 num = NULL;
02529                                                 CHECK_PARSING_STATUS (status, CR_OK);
02530                                                 str = NULL;
02531                                         }
02532                                 }
02533                                 if (token && token->u.num) {
02534                                         cr_parsing_location_copy (&token->location,
02535                                                                   &token->u.num->location) ;
02536                                 } else {
02537                                         status = CR_ERROR ;
02538                                 }
02539                                 goto done ;
02540                         }
02541                 }
02542                 break;
02543 
02544         default:
02545                 /*process the fallback cases here */
02546 
02547                 if (next_char == '\\'
02548                     || (cr_utils_is_nonascii (next_bytes[0]) == TRUE)
02549                     || ((next_char >= 'a') && (next_char <= 'z'))
02550                     || ((next_char >= 'A') && (next_char <= 'Z'))) {
02551                         status = cr_tknzr_parse_ident (a_this, &str);
02552                         if (status == CR_OK && str) {
02553                                 guint32 next_c = 0;
02554 
02555                                 status = cr_input_peek_char
02556                                         (PRIVATE (a_this)->input, &next_c);
02557 
02558                                 if (status == CR_OK && next_c == '(') {
02559 
02560                                         SKIP_CHARS (a_this, 1);
02561                                         status = cr_token_set_function
02562                                                 (token, str);
02563                                         CHECK_PARSING_STATUS (status, TRUE);
02564                                         /*ownership is transfered
02565                                          *to token by cr_token_set_function.
02566                                          */
02567                                         if (str) {
02568                                                 cr_parsing_location_copy (&token->location, 
02569                                                                           &str->location) ;
02570                                         }
02571                                         str = NULL;
02572                                 } else {
02573                                         status = cr_token_set_ident (token,
02574                                                                      str);
02575                                         CHECK_PARSING_STATUS (status, TRUE);
02576                                         if (str) {
02577                                                 cr_parsing_location_copy (&token->location, 
02578                                                                           &str->location) ;
02579                                         }
02580                                         str = NULL;
02581                                 }
02582                                 goto done;
02583                         } else {
02584                                 if (str) {
02585                                         cr_string_destroy (str);
02586                                         str = NULL;
02587                                 }
02588                         }
02589                 }
02590                 break;
02591         }
02592 
02593         READ_NEXT_CHAR (a_this, &next_char);
02594         cr_tknzr_get_parsing_location (a_this, 
02595                                        &location) ;
02596         status = cr_token_set_delim (token, next_char);
02597         CHECK_PARSING_STATUS (status, TRUE);
02598         cr_parsing_location_copy (&token->location, 
02599                                   &location) ;
02600  done:
02601 
02602         if (status == CR_OK && token) {
02603                 *a_tk = token;
02604                 /*
02605                  *store the previous position input stream pos.
02606                  */
02607                 memmove (&PRIVATE (a_this)->prev_pos,
02608                          &init_pos, sizeof (CRInputPos));
02609                 return CR_OK;
02610         }
02611 
02612  error:
02613         if (token) {
02614                 cr_token_destroy (token);
02615                 token = NULL;
02616         }
02617 
02618         if (str) {
02619                 cr_string_destroy (str);
02620                 str = NULL;
02621         }
02622         cr_tknzr_set_cur_pos (a_this, &init_pos);
02623         return status;
02624 
02625 }
02626 
02627 enum CRStatus
02628 cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type,
02629                       enum CRTokenExtraType a_et, gpointer a_res,
02630                       gpointer a_extra_res)
02631 {
02632         enum CRStatus status = CR_OK;
02633         CRToken *token = NULL;
02634 
02635         g_return_val_if_fail (a_this && PRIVATE (a_this)
02636                               && PRIVATE (a_this)->input
02637                               && a_res, CR_BAD_PARAM_ERROR);
02638 
02639         status = cr_tknzr_get_next_token (a_this, &token);
02640         if (status != CR_OK)
02641                 return status;
02642         if (token == NULL)
02643                 return CR_PARSING_ERROR;
02644 
02645         if (token->type == a_type) {
02646                 switch (a_type) {
02647                 case NO_TK:
02648                 case S_TK:
02649                 case CDO_TK:
02650                 case CDC_TK:
02651                 case INCLUDES_TK:
02652                 case DASHMATCH_TK:
02653                 case IMPORT_SYM_TK:
02654                 case PAGE_SYM_TK:
02655                 case MEDIA_SYM_TK:
02656                 case FONT_FACE_SYM_TK:
02657                 case CHARSET_SYM_TK:
02658                 case IMPORTANT_SYM_TK:
02659                         status = CR_OK;
02660                         break;
02661 
02662                 case STRING_TK:
02663                 case IDENT_TK:
02664                 case HASH_TK:
02665                 case ATKEYWORD_TK:
02666                 case FUNCTION_TK:
02667                 case COMMENT_TK:
02668                 case URI_TK:
02669                         *((CRString **) a_res) = token->u.str;
02670                         token->u.str = NULL;
02671                         status = CR_OK;
02672                         break;
02673 
02674                 case EMS_TK:
02675                 case EXS_TK:
02676                 case PERCENTAGE_TK:
02677                 case NUMBER_TK:
02678                         *((CRNum **) a_res) = token->u.num;
02679                         token->u.num = NULL;
02680                         status = CR_OK;
02681                         break;
02682 
02683                 case LENGTH_TK:
02684                 case ANGLE_TK:
02685                 case TIME_TK:
02686                 case FREQ_TK:
02687                         if (token->extra_type == a_et) {
02688                                 *((CRNum **) a_res) = token->u.num;
02689                                 token->u.num = NULL;
02690                                 status = CR_OK;
02691                         }
02692                         break;
02693 
02694                 case DIMEN_TK:
02695                         *((CRNum **) a_res) = token->u.num;
02696                         if (a_extra_res == NULL) {
02697                                 status = CR_BAD_PARAM_ERROR;
02698                                 goto error;
02699                         }
02700 
02701                         *((CRString **) a_extra_res) = token->dimen;
02702                         token->u.num = NULL;
02703                         token->dimen = NULL;
02704                         status = CR_OK;
02705                         break;
02706 
02707                 case DELIM_TK:
02708                         *((guint32 *) a_res) = token->u.unichar;
02709                         status = CR_OK;
02710                         break;
02711 
02712                 case UNICODERANGE_TK:
02713                 default:
02714                         status = CR_PARSING_ERROR;
02715                         break;
02716                 }
02717 
02718                 cr_token_destroy (token);
02719                 token = NULL;
02720         } else {
02721                 cr_tknzr_unget_token (a_this, token);
02722                 token = NULL;
02723                 status = CR_PARSING_ERROR;
02724         }
02725 
02726         return status;
02727 
02728       error:
02729 
02730         if (token) {
02731                 cr_tknzr_unget_token (a_this, token);
02732                 token = NULL;
02733         }
02734 
02735         return status;
02736 }
02737 
02738 void
02739 cr_tknzr_destroy (CRTknzr * a_this)
02740 {
02741         g_return_if_fail (a_this);
02742 
02743         if (PRIVATE (a_this) && PRIVATE (a_this)->input) {
02744                 if (cr_input_unref (PRIVATE (a_this)->input)
02745                     == TRUE) {
02746                         PRIVATE (a_this)->input = NULL;
02747                 }
02748         }
02749 
02750         if (PRIVATE (a_this)->token_cache) {
02751                 cr_token_destroy (PRIVATE (a_this)->token_cache);
02752                 PRIVATE (a_this)->token_cache = NULL;
02753         }
02754 
02755         if (PRIVATE (a_this)) {
02756                 g_free (PRIVATE (a_this));
02757                 PRIVATE (a_this) = NULL;
02758         }
02759 
02760         g_free (a_this);
02761 }

Generated on Fri Oct 29 08:29:12 2004 for Libcroco by  doxygen 1.3.9.1