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

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