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