"Initial commit to Gerrit"
[profile/ivi/libcroco.git] / src / cr-statement.c
1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  * This file is part of The Croco Library
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2.1 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  *
20  * Author: Dodji Seketeli.
21  * See COPYRIGHTS files for copyrights information.
22  */
23
24 #include <string.h>
25 #include "cr-statement.h"
26 #include "cr-parser.h"
27
28 /**
29  *@file
30  *Definition of the #CRStatement class.
31  */
32
33 #define DECLARATION_INDENT_NB 2
34
35 static void cr_statement_clear (CRStatement * a_this);
36
37 static void  
38 parse_font_face_start_font_face_cb (CRDocHandler * a_this,
39                                     CRParsingLocation *a_location)
40 {
41         CRStatement *stmt = NULL;
42         enum CRStatus status = CR_OK;
43
44         stmt = cr_statement_new_at_font_face_rule (NULL, NULL);
45         g_return_if_fail (stmt);
46
47         status = cr_doc_handler_set_ctxt (a_this, stmt);
48         g_return_if_fail (status == CR_OK);
49 }
50
51 static void
52 parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this)
53 {
54         CRStatement *stmt = NULL;
55         CRStatement **stmtptr = NULL;
56         enum CRStatus status = CR_OK;
57
58         g_return_if_fail (a_this);
59
60         stmtptr = &stmt;
61         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
62         if (status != CR_OK) {
63                 cr_utils_trace_info ("Couldn't get parsing context. "
64                                      "This may lead to some memory leaks.");
65                 return;
66         }
67         if (stmt) {
68                 cr_statement_destroy (stmt);
69                 cr_doc_handler_set_ctxt (a_this, NULL);
70                 return;
71         }
72 }
73
74 static void
75 parse_font_face_property_cb (CRDocHandler * a_this,
76                              CRString * a_name,
77                              CRTerm * a_value, gboolean a_important)
78 {
79         enum CRStatus status = CR_OK;
80         CRString *name = NULL;
81         CRDeclaration *decl = NULL;
82         CRStatement *stmt = NULL;
83         CRStatement **stmtptr = NULL;
84
85         g_return_if_fail (a_this && a_name);
86
87         stmtptr = &stmt;
88         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
89         g_return_if_fail (status == CR_OK && stmt);
90         g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT);
91
92         name = cr_string_dup (a_name) ;
93         g_return_if_fail (name);
94         decl = cr_declaration_new (stmt, name, a_value);
95         if (!decl) {
96                 cr_utils_trace_info ("cr_declaration_new () failed.");
97                 goto error;
98         }
99         name = NULL;
100
101         stmt->kind.font_face_rule->decl_list =
102                 cr_declaration_append (stmt->kind.font_face_rule->decl_list,
103                                        decl);
104         if (!stmt->kind.font_face_rule->decl_list)
105                 goto error;
106         decl = NULL;
107
108       error:
109         if (decl) {
110                 cr_declaration_unref (decl);
111                 decl = NULL;
112         }
113         if (name) {
114                 cr_string_destroy (name);
115                 name = NULL;
116         }
117 }
118
119 static void
120 parse_font_face_end_font_face_cb (CRDocHandler * a_this)
121 {
122         CRStatement *result = NULL;
123         CRStatement **resultptr = NULL;
124         enum CRStatus status = CR_OK;
125
126         g_return_if_fail (a_this);
127
128         resultptr = &result;
129         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr);
130         g_return_if_fail (status == CR_OK && result);
131         g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT);
132
133         status = cr_doc_handler_set_result (a_this, result);
134         g_return_if_fail (status == CR_OK);
135 }
136
137 static void
138 parse_page_start_page_cb (CRDocHandler * a_this,
139                           CRString * a_name, 
140                           CRString * a_pseudo_page,
141                           CRParsingLocation *a_location)
142 {
143         CRStatement *stmt = NULL;
144         enum CRStatus status = CR_OK;
145         CRString *page_name = NULL, *pseudo_name = NULL ;
146
147         if (a_name)
148                 page_name = cr_string_dup (a_name) ;
149         if (a_pseudo_page)
150                 pseudo_name = cr_string_dup (a_pseudo_page) ;
151
152         stmt = cr_statement_new_at_page_rule (NULL, NULL, 
153                                               page_name,
154                                               pseudo_name);
155         page_name = NULL ;
156         pseudo_name = NULL ;
157         g_return_if_fail (stmt);
158         status = cr_doc_handler_set_ctxt (a_this, stmt);
159         g_return_if_fail (status == CR_OK);
160 }
161
162 static void
163 parse_page_unrecoverable_error_cb (CRDocHandler * a_this)
164 {
165         CRStatement *stmt = NULL;
166         CRStatement **stmtptr = NULL;
167         enum CRStatus status = CR_OK;
168
169         g_return_if_fail (a_this);
170
171         stmtptr = &stmt;
172         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
173         if (status != CR_OK) {
174                 cr_utils_trace_info ("Couldn't get parsing context. "
175                                      "This may lead to some memory leaks.");
176                 return;
177         }
178         if (stmt) {
179                 cr_statement_destroy (stmt);
180                 stmt = NULL;
181                 cr_doc_handler_set_ctxt (a_this, NULL);
182         }
183 }
184
185 static void
186 parse_page_property_cb (CRDocHandler * a_this,
187                         CRString * a_name,
188                         CRTerm * a_expression, gboolean a_important)
189 {
190         CRString *name = NULL;
191         CRStatement *stmt = NULL;
192         CRStatement **stmtptr = NULL;
193         CRDeclaration *decl = NULL;
194         enum CRStatus status = CR_OK;
195
196         stmtptr = &stmt;
197         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
198         g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT);
199
200         name = cr_string_dup (a_name);
201         g_return_if_fail (name);
202
203         decl = cr_declaration_new (stmt, name, a_expression);
204         g_return_if_fail (decl);
205         decl->important = a_important;
206         stmt->kind.page_rule->decl_list =
207                 cr_declaration_append (stmt->kind.page_rule->decl_list, decl);
208         g_return_if_fail (stmt->kind.page_rule->decl_list);
209 }
210
211 static void
212 parse_page_end_page_cb (CRDocHandler * a_this,
213                         CRString * a_name, 
214                         CRString * a_pseudo_page)
215 {
216         enum CRStatus status = CR_OK;
217         CRStatement *stmt = NULL;
218         CRStatement **stmtptr = NULL;
219
220         stmtptr = &stmt;
221         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
222         g_return_if_fail (status == CR_OK && stmt);
223         g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT);
224
225         status = cr_doc_handler_set_result (a_this, stmt);
226         g_return_if_fail (status == CR_OK);
227 }
228
229 static void
230 parse_at_media_start_media_cb (CRDocHandler * a_this, 
231                                GList * a_media_list,
232                                CRParsingLocation *a_location)
233 {
234         enum CRStatus status = CR_OK;
235         CRStatement *at_media = NULL;
236         GList *media_list = NULL;
237
238         g_return_if_fail (a_this && a_this->priv);
239
240         if (a_media_list) {
241                 /*duplicate media list */
242                 media_list = cr_utils_dup_glist_of_cr_string 
243                         (a_media_list);
244         }
245
246         g_return_if_fail (media_list);
247
248         /*make sure cr_statement_new_at_media_rule works in this case. */
249         at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list);
250
251         status = cr_doc_handler_set_ctxt (a_this, at_media);
252         g_return_if_fail (status == CR_OK);
253         status = cr_doc_handler_set_result (a_this, at_media);
254         g_return_if_fail (status == CR_OK);
255 }
256
257 static void
258 parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this)
259 {
260         enum CRStatus status = CR_OK;
261         CRStatement *stmt = NULL;
262         CRStatement **stmtptr = NULL;
263
264         g_return_if_fail (a_this);
265
266         stmtptr = &stmt;
267         status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
268         if (status != CR_OK) {
269                 cr_utils_trace_info ("Couldn't get parsing context. "
270                                      "This may lead to some memory leaks.");
271                 return;
272         }
273         if (stmt) {
274                 cr_statement_destroy (stmt);
275                 stmt = NULL;
276                 cr_doc_handler_set_ctxt (a_this, NULL);
277                 cr_doc_handler_set_result (a_this, NULL);
278         }
279 }
280
281 static void
282 parse_at_media_start_selector_cb (CRDocHandler * a_this,
283                                   CRSelector * a_sellist)
284 {
285         enum CRStatus status = CR_OK;
286         CRStatement *at_media = NULL;
287         CRStatement **at_media_ptr = NULL;
288         CRStatement *ruleset = NULL;
289
290         g_return_if_fail (a_this && a_this->priv && a_sellist);
291
292         at_media_ptr = &at_media;
293         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr);
294         g_return_if_fail (status == CR_OK && at_media);
295         g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT);
296         ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media);
297         g_return_if_fail (ruleset);
298         status = cr_doc_handler_set_ctxt (a_this, ruleset);
299         g_return_if_fail (status == CR_OK);
300 }
301
302 static void
303 parse_at_media_property_cb (CRDocHandler * a_this,
304                             CRString * a_name, CRTerm * a_value,
305                             gboolean a_important)
306 {
307         enum CRStatus status = CR_OK;
308
309         /*
310          *the current ruleset stmt, child of the 
311          *current at-media being parsed.
312          */
313         CRStatement *stmt = NULL;
314         CRStatement **stmtptr = NULL;
315         CRDeclaration *decl = NULL;
316         CRString *name = NULL;
317
318         g_return_if_fail (a_this && a_name);
319
320         name = cr_string_dup (a_name) ;
321         g_return_if_fail (name);
322
323         stmtptr = &stmt;
324         status = cr_doc_handler_get_ctxt (a_this, 
325                                           (gpointer *) stmtptr);
326         g_return_if_fail (status == CR_OK && stmt);
327         g_return_if_fail (stmt->type == RULESET_STMT);
328
329         decl = cr_declaration_new (stmt, name, a_value);
330         g_return_if_fail (decl);
331         decl->important = a_important;
332         status = cr_statement_ruleset_append_decl (stmt, decl);
333         g_return_if_fail (status == CR_OK);
334 }
335
336 static void
337 parse_at_media_end_selector_cb (CRDocHandler * a_this, 
338                                 CRSelector * a_sellist)
339 {
340         enum CRStatus status = CR_OK;
341
342         /*
343          *the current ruleset stmt, child of the 
344          *current at-media being parsed.
345          */
346         CRStatement *stmt = NULL;
347         CRStatement **stmtptr = NULL;
348
349         g_return_if_fail (a_this && a_sellist);
350
351         stmtptr = &stmt;
352         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
353         g_return_if_fail (status == CR_OK && stmt
354                           && stmt->type == RULESET_STMT);
355         g_return_if_fail (stmt->kind.ruleset->parent_media_rule);
356
357         status = cr_doc_handler_set_ctxt
358                 (a_this, stmt->kind.ruleset->parent_media_rule);
359         g_return_if_fail (status == CR_OK);
360 }
361
362 static void
363 parse_at_media_end_media_cb (CRDocHandler * a_this, 
364                              GList * a_media_list)
365 {
366         enum CRStatus status = CR_OK;
367         CRStatement *at_media = NULL;
368         CRStatement **at_media_ptr = NULL;
369
370         g_return_if_fail (a_this && a_this->priv);
371
372         at_media_ptr = &at_media;
373         status = cr_doc_handler_get_ctxt (a_this, 
374                                           (gpointer *) at_media_ptr);
375         g_return_if_fail (status == CR_OK && at_media);
376         status = cr_doc_handler_set_result (a_this, at_media);
377 }
378
379 static void
380 parse_ruleset_start_selector_cb (CRDocHandler * a_this,
381                                  CRSelector * a_sellist)
382 {
383         CRStatement *ruleset = NULL;
384
385         g_return_if_fail (a_this && a_this->priv && a_sellist);
386
387         ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL);
388         g_return_if_fail (ruleset);
389
390         cr_doc_handler_set_result (a_this, ruleset);
391 }
392
393 static void
394 parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this)
395 {
396         CRStatement *stmt = NULL;
397         CRStatement **stmtptr = NULL;
398         enum CRStatus status = CR_OK;
399
400         stmtptr = &stmt;
401         status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
402         if (status != CR_OK) {
403                 cr_utils_trace_info ("Couldn't get parsing context. "
404                                      "This may lead to some memory leaks.");
405                 return;
406         }
407         if (stmt) {
408                 cr_statement_destroy (stmt);
409                 stmt = NULL;
410                 cr_doc_handler_set_result (a_this, NULL);
411         }
412 }
413
414 static void
415 parse_ruleset_property_cb (CRDocHandler * a_this,
416                            CRString * a_name,
417                            CRTerm * a_value, gboolean a_important)
418 {
419         enum CRStatus status = CR_OK;
420         CRStatement *ruleset = NULL;
421         CRStatement **rulesetptr = NULL;
422         CRDeclaration *decl = NULL;
423         CRString *stringue = NULL;
424
425         g_return_if_fail (a_this && a_this->priv && a_name);
426
427         stringue = cr_string_dup (a_name);
428         g_return_if_fail (stringue);
429
430         rulesetptr = &ruleset;
431         status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr);
432         g_return_if_fail (status == CR_OK
433                           && ruleset 
434                           && ruleset->type == RULESET_STMT);
435
436         decl = cr_declaration_new (ruleset, stringue, a_value);
437         g_return_if_fail (decl);
438         decl->important = a_important;
439         status = cr_statement_ruleset_append_decl (ruleset, decl);
440         g_return_if_fail (status == CR_OK);
441 }
442
443 static void
444 parse_ruleset_end_selector_cb (CRDocHandler * a_this, 
445                                CRSelector * a_sellist)
446 {
447         CRStatement *result = NULL;
448         CRStatement **resultptr = NULL;
449         enum CRStatus status = CR_OK;
450
451         g_return_if_fail (a_this && a_sellist);
452
453         resultptr = &result;
454         status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr);
455
456         g_return_if_fail (status == CR_OK
457                           && result 
458                           && result->type == RULESET_STMT);
459 }
460
461 static void
462 cr_statement_clear (CRStatement * a_this)
463 {
464         g_return_if_fail (a_this);
465
466         switch (a_this->type) {
467         case AT_RULE_STMT:
468                 break;
469         case RULESET_STMT:
470                 if (!a_this->kind.ruleset)
471                         return;
472                 if (a_this->kind.ruleset->sel_list) {
473                         cr_selector_unref (a_this->kind.ruleset->sel_list);
474                         a_this->kind.ruleset->sel_list = NULL;
475                 }
476                 if (a_this->kind.ruleset->decl_list) {
477                         cr_declaration_destroy
478                                 (a_this->kind.ruleset->decl_list);
479                         a_this->kind.ruleset->decl_list = NULL;
480                 }
481                 g_free (a_this->kind.ruleset);
482                 a_this->kind.ruleset = NULL;
483                 break;
484
485         case AT_IMPORT_RULE_STMT:
486                 if (!a_this->kind.import_rule)
487                         return;
488                 if (a_this->kind.import_rule->url) {
489                         cr_string_destroy 
490                                 (a_this->kind.import_rule->url) ;
491                         a_this->kind.import_rule->url = NULL;
492                 }
493                 g_free (a_this->kind.import_rule);
494                 a_this->kind.import_rule = NULL;
495                 break;
496
497         case AT_MEDIA_RULE_STMT:
498                 if (!a_this->kind.media_rule)
499                         return;
500                 if (a_this->kind.media_rule->rulesets) {
501                         cr_statement_destroy
502                                 (a_this->kind.media_rule->rulesets);
503                         a_this->kind.media_rule->rulesets = NULL;
504                 }
505                 if (a_this->kind.media_rule->media_list) {
506                         GList *cur = NULL;
507
508                         for (cur = a_this->kind.media_rule->media_list;
509                              cur; cur = cur->next) {
510                                 if (cur->data) {
511                                         cr_string_destroy ((CRString *) cur->data);
512                                         cur->data = NULL;
513                                 }
514
515                         }
516                         g_list_free (a_this->kind.media_rule->media_list);
517                         a_this->kind.media_rule->media_list = NULL;
518                 }
519                 g_free (a_this->kind.media_rule);
520                 a_this->kind.media_rule = NULL;
521                 break;
522
523         case AT_PAGE_RULE_STMT:
524                 if (!a_this->kind.page_rule)
525                         return;
526
527                 if (a_this->kind.page_rule->decl_list) {
528                         cr_declaration_destroy
529                                 (a_this->kind.page_rule->decl_list);
530                         a_this->kind.page_rule->decl_list = NULL;
531                 }
532                 if (a_this->kind.page_rule->name) {
533                         cr_string_destroy 
534                                 (a_this->kind.page_rule->name);
535                         a_this->kind.page_rule->name = NULL;
536                 }
537                 if (a_this->kind.page_rule->pseudo) {
538                         cr_string_destroy
539                                 (a_this->kind.page_rule->pseudo);
540                         a_this->kind.page_rule->pseudo = NULL;
541                 }
542                 g_free (a_this->kind.page_rule);
543                 a_this->kind.page_rule = NULL;
544                 break;
545
546         case AT_CHARSET_RULE_STMT:
547                 if (!a_this->kind.charset_rule)
548                         return;
549
550                 if (a_this->kind.charset_rule->charset) {
551                         cr_string_destroy
552                                 (a_this->kind.charset_rule->charset);
553                         a_this->kind.charset_rule->charset = NULL;
554                 }
555                 g_free (a_this->kind.charset_rule);
556                 a_this->kind.charset_rule = NULL;
557                 break;
558
559         case AT_FONT_FACE_RULE_STMT:
560                 if (!a_this->kind.font_face_rule)
561                         return;
562
563                 if (a_this->kind.font_face_rule->decl_list) {
564                         cr_declaration_unref
565                                 (a_this->kind.font_face_rule->decl_list);
566                         a_this->kind.font_face_rule->decl_list = NULL;
567                 }
568                 g_free (a_this->kind.font_face_rule);
569                 a_this->kind.font_face_rule = NULL;
570                 break;
571
572         default:
573                 break;
574         }
575 }
576
577 /**
578  * cr_statement_ruleset_to_string:
579  *
580  *@a_this: the current instance of #CRStatement
581  *@a_indent: the number of whitespace to use for indentation
582  *
583  *Serializes the ruleset statement into a string
584  *
585  *Returns the newly allocated serialised string. Must be freed
586  *by the caller, using g_free().
587  */
588 static gchar *
589 cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
590 {
591         GString *stringue = NULL;
592         gchar *tmp_str = NULL,
593                 *result = NULL;
594
595         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
596
597         stringue = g_string_new (NULL);
598
599         if (a_this->kind.ruleset->sel_list) {
600                 if (a_indent)
601                         cr_utils_dump_n_chars2 (' ', stringue, a_indent);
602
603                 tmp_str =
604                         cr_selector_to_string (a_this->kind.ruleset->
605                                                sel_list);
606                 if (tmp_str) {
607                         g_string_append (stringue, tmp_str);
608                         g_free (tmp_str);
609                         tmp_str = NULL;
610                 }
611         }
612         g_string_append (stringue, " {\n");
613         if (a_this->kind.ruleset->decl_list) {
614                 tmp_str = cr_declaration_list_to_string2
615                         (a_this->kind.ruleset->decl_list,
616                          a_indent + DECLARATION_INDENT_NB, TRUE);
617                 if (tmp_str) {
618                         g_string_append (stringue, tmp_str);
619                         g_free (tmp_str);
620                         tmp_str = NULL;
621                 }
622                 g_string_append (stringue, "\n");
623                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
624         }
625         g_string_append (stringue, "}");
626         result = stringue->str;
627
628         if (stringue) {
629                 g_string_free (stringue, FALSE);
630                 stringue = NULL;
631         }
632         if (tmp_str) {
633                 g_free (tmp_str);
634                 tmp_str = NULL;
635         }
636         return result;
637 }
638
639
640 /**
641  * cr_statement_font_face_rule_to_string:
642  *
643  *@a_this: the current instance of #CRStatement to consider
644  *It must be a font face rule statement.
645  *@a_indent: the number of white spaces of indentation.
646  *
647  *Serializes a font face rule statement into a string.
648  *
649  *Returns the serialized string. Must be deallocated by the caller
650  *using g_free().
651  */
652 static gchar *
653 cr_statement_font_face_rule_to_string (CRStatement const * a_this,
654                                        glong a_indent)
655 {
656         gchar *result = NULL, *tmp_str = NULL ;
657         GString *stringue = NULL ;
658
659         g_return_val_if_fail (a_this 
660                               && a_this->type == AT_FONT_FACE_RULE_STMT,
661                               NULL);
662
663         if (a_this->kind.font_face_rule->decl_list) {
664                 stringue = g_string_new (NULL) ;
665                 g_return_val_if_fail (stringue, NULL) ;
666                 if (a_indent)
667                         cr_utils_dump_n_chars2 (' ', stringue, 
668                                         a_indent);
669                 g_string_append (stringue, "@font-face {\n");
670                 tmp_str = cr_declaration_list_to_string2 
671                         (a_this->kind.font_face_rule->decl_list,
672                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
673                 if (tmp_str) {
674                         g_string_append (stringue,
675                                          tmp_str) ;
676                         g_free (tmp_str) ;
677                         tmp_str = NULL ;
678                 }
679                 g_string_append (stringue, "\n}");
680         }
681         if (stringue) {
682                 result = stringue->str ;
683                 g_string_free (stringue, FALSE) ;
684                 stringue = NULL ;
685         }
686         return result ;
687 }
688
689
690 /**
691  * cr_statement_charset_to_string:
692  *
693  *Serialises an \@charset statement into a string.
694  *@a_this: the statement to serialize.
695  *@a_indent: the number of indentation spaces
696  *
697  *Returns the serialized charset statement. Must be
698  *freed by the caller using g_free().
699  */
700 static gchar *
701 cr_statement_charset_to_string (CRStatement const *a_this,
702                                 gulong a_indent)
703 {
704         gchar *str = NULL ;
705         GString *stringue = NULL ;
706
707         g_return_val_if_fail (a_this
708                               && a_this->type == AT_CHARSET_RULE_STMT,
709                               NULL) ;
710
711         if (a_this->kind.charset_rule
712             && a_this->kind.charset_rule->charset
713             && a_this->kind.charset_rule->charset->stryng
714             && a_this->kind.charset_rule->charset->stryng->str) {
715                 str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
716                                  a_this->kind.charset_rule->charset->stryng->len);
717                 g_return_val_if_fail (str, NULL);
718                 stringue = g_string_new (NULL) ;
719                 g_return_val_if_fail (stringue, NULL) ;
720                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
721                 g_string_append_printf (stringue, 
722                                         "@charset \"%s\" ;", str);
723                 if (str) {
724                         g_free (str);
725                         str = NULL;
726                 }
727         }
728         if (stringue) {
729                 str = stringue->str ;
730                 g_string_free (stringue, FALSE) ;
731         }
732         return str ;
733 }
734
735
736 /**
737  * cr_statement_at_page_rule_to_string:
738  *
739  *Serialises the at page rule statement into a string
740  *@a_this: the current instance of #CRStatement. Must
741  *be an "\@page" rule statement.
742  *
743  *Returns the serialized string. Must be freed by the caller
744  */
745 static gchar *
746 cr_statement_at_page_rule_to_string (CRStatement const *a_this,
747                                      gulong a_indent)
748 {
749         GString *stringue = NULL;
750         gchar *result = NULL ;
751
752         stringue = g_string_new (NULL) ;
753
754         cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
755         g_string_append (stringue, "@page");
756         if (a_this->kind.page_rule->name
757             && a_this->kind.page_rule->name->stryng) {
758                 g_string_append_printf 
759                   (stringue, " %s",
760                    a_this->kind.page_rule->name->stryng->str) ;
761         } else {
762                 g_string_append (stringue, " ");
763         }
764         if (a_this->kind.page_rule->pseudo
765             && a_this->kind.page_rule->pseudo->stryng) {
766                 g_string_append_printf 
767                   (stringue,  " :%s",
768                    a_this->kind.page_rule->pseudo->stryng->str) ;
769         }
770         if (a_this->kind.page_rule->decl_list) {
771                 gchar *str = NULL ;
772                 g_string_append (stringue, " {\n");
773                 str = cr_declaration_list_to_string2
774                         (a_this->kind.page_rule->decl_list,
775                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
776                 if (str) {
777                         g_string_append (stringue, str) ;
778                         g_free (str) ;
779                         str = NULL ;
780                 }
781                 g_string_append (stringue, "\n}\n");
782         }
783         result = stringue->str ;
784         g_string_free (stringue, FALSE) ;
785         stringue = NULL ;
786         return result ;
787 }
788
789
790 /**
791  *Serializes an \@media statement.
792  *@param a_this the current instance of #CRStatement
793  *@param a_indent the number of spaces of indentation.
794  *@return the serialized \@media statement. Must be freed
795  *by the caller using g_free().
796  */
797 static gchar *
798 cr_statement_media_rule_to_string (CRStatement const *a_this,
799                                    gulong a_indent)
800 {
801         gchar *str = NULL ;
802         GString *stringue = NULL ;
803         GList const *cur = NULL;
804
805         g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
806                               NULL);
807
808         if (a_this->kind.media_rule) {
809                 stringue = g_string_new (NULL) ;                
810                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
811                 g_string_append (stringue, "@media");
812
813                 for (cur = a_this->kind.media_rule->media_list; cur;
814                      cur = cur->next) {
815                         if (cur->data) {
816                                 guchar *str = cr_string_dup2
817                                         ((CRString const *) cur->data);
818
819                                 if (str) {
820                                         if (cur->prev) {
821                                                 g_string_append
822                                                         (stringue, 
823                                                          ",");
824                                         }
825                                         g_string_append_printf 
826                                                 (stringue, 
827                                                  " %s", str);
828                                         g_free (str);
829                                         str = NULL;
830                                 }
831                         }
832                 }
833                 g_string_append (stringue, " {\n");
834                 str = cr_statement_list_to_string
835                         (a_this->kind.media_rule->rulesets,
836                          a_indent + DECLARATION_INDENT_NB) ;
837                 if (str) {
838                         g_string_append (stringue, str) ;
839                         g_free (str) ;
840                         str = NULL ;
841                 }
842                 g_string_append (stringue, "\n}");
843         }
844         if (stringue) {
845                 str = stringue->str ;
846                 g_string_free (stringue, FALSE) ;
847         }
848         return str ;
849 }
850
851
852 static gchar *
853 cr_statement_import_rule_to_string (CRStatement const *a_this,
854                                     gulong a_indent)
855 {
856         GString *stringue = NULL ;
857         guchar *str = NULL;
858
859         g_return_val_if_fail (a_this
860                               && a_this->type == AT_IMPORT_RULE_STMT
861                               && a_this->kind.import_rule,
862                               NULL) ;
863
864         if (a_this->kind.import_rule->url
865             && a_this->kind.import_rule->url->stryng) { 
866                 stringue = g_string_new (NULL) ;
867                 g_return_val_if_fail (stringue, NULL) ;
868                 str = g_strndup (a_this->kind.import_rule->url->stryng->str,
869                                  a_this->kind.import_rule->url->stryng->len);
870                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
871                 if (str) {
872                         g_string_append_printf (stringue,
873                                                 "@import url(\"%s\")", 
874                                                 str);
875                         g_free (str);
876                         str = NULL ;
877                 } else          /*there is no url, so no import rule, get out! */
878                         return NULL;
879
880                 if (a_this->kind.import_rule->media_list) {
881                         GList const *cur = NULL;
882
883                         for (cur = a_this->kind.import_rule->media_list;
884                              cur; cur = cur->next) {
885                                 if (cur->data) {
886                                         CRString const *crstr = cur->data;
887
888                                         if (cur->prev) {
889                                                 g_string_append 
890                                                         (stringue, ", ");
891                                         }
892                                         if (crstr 
893                                             && crstr->stryng
894                                             && crstr->stryng->str) {
895                                                 g_string_append_len 
896                                                         (stringue,
897                                                          crstr->stryng->str,
898                                                          crstr->stryng->len) ;
899                                         }
900                                 }
901                         }
902                 }
903                 g_string_append (stringue, " ;");
904         }
905         if (stringue) {
906                 str = stringue->str ;
907                 g_string_free (stringue, FALSE) ;
908                 stringue = NULL ;
909         }
910         return str ;
911 }
912
913
914 /*******************
915  *public functions
916  ******************/
917
918 /**
919  * cr_statement_does_buf_parses_against_core:
920  *
921  *@a_buf: the buffer to parse.
922  *@a_encoding: the character encoding of a_buf.
923  *
924  *Tries to parse a buffer and says whether if the content of the buffer
925  *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
926  *css spec) or not.
927  *
928  *Returns TRUE if the buffer parses against the core grammar, false otherwise.
929  */
930 gboolean
931 cr_statement_does_buf_parses_against_core (const guchar * a_buf,
932                                            enum CREncoding a_encoding)
933 {
934         CRParser *parser = NULL;
935         enum CRStatus status = CR_OK;
936         gboolean result = FALSE;
937
938         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
939                                          a_encoding, FALSE);
940         g_return_val_if_fail (parser, FALSE);
941
942         status = cr_parser_set_use_core_grammar (parser, TRUE);
943         if (status != CR_OK) {
944                 goto cleanup;
945         }
946
947         status = cr_parser_parse_statement_core (parser);
948         if (status == CR_OK) {
949                 result = TRUE;
950         }
951
952       cleanup:
953         if (parser) {
954                 cr_parser_destroy (parser);
955         }
956
957         return result;
958 }
959
960 /**
961  * cr_statement_parse_from_buf:
962  *
963  *@a_buf: the buffer to parse.
964  *@a_encoding: the character encoding of a_buf.
965  *
966  *Parses a buffer that contains a css statement and returns 
967  *an instance of #CRStatement in case of successful parsing.
968  *TODO: at support of "\@import" rules.
969  *
970  *Returns the newly built instance of #CRStatement in case
971  *of successful parsing, NULL otherwise.
972  */
973 CRStatement *
974 cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
975 {
976         CRStatement *result = NULL;
977
978         /*
979          *The strategy of this function is "brute force".
980          *It tries to parse all the types of CRStatement it knows about.
981          *I could do this a smarter way but I don't have the time now.
982          *I think I will revisit this when time of performances and
983          *pull based incremental parsing comes.
984          */
985
986         result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
987         if (!result) {
988                 result = cr_statement_at_charset_rule_parse_from_buf
989                         (a_buf, a_encoding);
990         } else {
991                 goto out;
992         }
993
994         if (!result) {
995                 result = cr_statement_at_media_rule_parse_from_buf
996                         (a_buf, a_encoding);
997         } else {
998                 goto out;
999         }
1000
1001         if (!result) {
1002                 result = cr_statement_at_charset_rule_parse_from_buf
1003                         (a_buf, a_encoding);
1004         } else {
1005                 goto out;
1006         }
1007
1008         if (!result) {
1009                 result = cr_statement_font_face_rule_parse_from_buf
1010                         (a_buf, a_encoding);
1011
1012         } else {
1013                 goto out;
1014         }
1015
1016         if (!result) {
1017                 result = cr_statement_at_page_rule_parse_from_buf
1018                         (a_buf, a_encoding);
1019         } else {
1020                 goto out;
1021         }
1022
1023         if (!result) {
1024                 result = cr_statement_at_import_rule_parse_from_buf
1025                         (a_buf, a_encoding);
1026         } else {
1027                 goto out;
1028         }
1029
1030       out:
1031         return result;
1032 }
1033
1034 /**
1035  * cr_statement_ruleset_parse_from_buf:
1036  *
1037  *@a_buf: the buffer to parse.
1038  *@a_enc: the character encoding of a_buf.
1039  *
1040  *Parses a buffer that contains a ruleset statement an instanciates
1041  *a #CRStatement of type RULESET_STMT.
1042  *
1043  *Returns the newly built instance of #CRStatement in case of successful parsing,
1044  *NULL otherwise.
1045  */
1046 CRStatement *
1047 cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
1048                                      enum CREncoding a_enc)
1049 {
1050         enum CRStatus status = CR_OK;
1051         CRStatement *result = NULL;
1052         CRStatement **resultptr = NULL;
1053         CRParser *parser = NULL;
1054         CRDocHandler *sac_handler = NULL;
1055
1056         g_return_val_if_fail (a_buf, NULL);
1057
1058         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 
1059                                          a_enc, FALSE);
1060
1061         g_return_val_if_fail (parser, NULL);
1062
1063         sac_handler = cr_doc_handler_new ();
1064         g_return_val_if_fail (parser, NULL);
1065
1066         sac_handler->start_selector = parse_ruleset_start_selector_cb;
1067         sac_handler->end_selector = parse_ruleset_end_selector_cb;
1068         sac_handler->property = parse_ruleset_property_cb;
1069         sac_handler->unrecoverable_error =
1070                 parse_ruleset_unrecoverable_error_cb;
1071
1072         cr_parser_set_sac_handler (parser, sac_handler);
1073         cr_parser_try_to_skip_spaces_and_comments (parser);
1074         status = cr_parser_parse_ruleset (parser);
1075         if (status != CR_OK) {
1076                 goto cleanup;
1077         }
1078
1079         resultptr = &result;
1080         status = cr_doc_handler_get_result (sac_handler,
1081                                             (gpointer *) resultptr);
1082         if (!((status == CR_OK) && result)) {
1083                 if (result) {
1084                         cr_statement_destroy (result);
1085                         result = NULL;
1086                 }
1087         }
1088
1089       cleanup:
1090         if (parser) {
1091                 cr_parser_destroy (parser);
1092                 parser = NULL;
1093                 sac_handler = NULL ;
1094         }
1095         if (sac_handler) {
1096                 cr_doc_handler_unref (sac_handler);
1097                 sac_handler = NULL;
1098         }
1099         return result;
1100 }
1101
1102 /**
1103  * cr_statement_new_ruleset:
1104  *
1105  *@a_sel_list: the list of #CRSimpleSel (selectors)
1106  *the rule applies to.
1107  *@a_decl_list: the list of instances of #CRDeclaration
1108  *that composes the ruleset.
1109  *@a_media_types: a list of instances of GString that
1110  *describe the media list this ruleset applies to.
1111  *
1112  *Creates a new instance of #CRStatement of type
1113  *#CRRulSet.
1114  *
1115  *Returns the new instance of #CRStatement or NULL if something
1116  *went wrong.
1117  */
1118 CRStatement *
1119 cr_statement_new_ruleset (CRStyleSheet * a_sheet,
1120                           CRSelector * a_sel_list,
1121                           CRDeclaration * a_decl_list,
1122                           CRStatement * a_parent_media_rule)
1123 {
1124         CRStatement *result = NULL;
1125
1126         g_return_val_if_fail (a_sel_list, NULL);
1127
1128         if (a_parent_media_rule) {
1129                 g_return_val_if_fail
1130                         (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
1131                          NULL);
1132                 g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
1133                                       NULL);
1134         }
1135
1136         result = g_try_malloc (sizeof (CRStatement));
1137
1138         if (!result) {
1139                 cr_utils_trace_info ("Out of memory");
1140                 return NULL;
1141         }
1142
1143         memset (result, 0, sizeof (CRStatement));
1144         result->type = RULESET_STMT;
1145         result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet));
1146
1147         if (!result->kind.ruleset) {
1148                 cr_utils_trace_info ("Out of memory");
1149                 if (result)
1150                         g_free (result);
1151                 return NULL;
1152         }
1153
1154         memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
1155         result->kind.ruleset->sel_list = a_sel_list;
1156         if (a_sel_list)
1157                 cr_selector_ref (a_sel_list);
1158         result->kind.ruleset->decl_list = a_decl_list;
1159
1160         if (a_parent_media_rule) {
1161                 result->kind.ruleset->parent_media_rule = a_parent_media_rule;
1162                 a_parent_media_rule->kind.media_rule->rulesets =
1163                         cr_statement_append
1164                         (a_parent_media_rule->kind.media_rule->rulesets,
1165                          result);
1166         }
1167
1168         cr_statement_set_parent_sheet (result, a_sheet);
1169
1170         return result;
1171 }
1172
1173 /**
1174  * cr_statement_at_media_rule_parse_from_buf:
1175  *
1176  *@a_buf: the input to parse.
1177  *@a_enc: the encoding of the buffer.
1178  *
1179  *Parses a buffer that contains an "\@media" declaration
1180  *and builds an \@media css statement.
1181  *
1182  *Returns the \@media statement, or NULL if the buffer could not
1183  *be successfully parsed.
1184  */
1185 CRStatement *
1186 cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
1187                                            enum CREncoding a_enc)
1188 {
1189         CRParser *parser = NULL;
1190         CRStatement *result = NULL;
1191         CRStatement **resultptr = NULL;
1192         CRDocHandler *sac_handler = NULL;
1193         enum CRStatus status = CR_OK;
1194
1195         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 
1196                                          a_enc, FALSE);
1197         if (!parser) {
1198                 cr_utils_trace_info ("Instanciation of the parser failed");
1199                 goto cleanup;
1200         }
1201
1202         sac_handler = cr_doc_handler_new ();
1203         if (!sac_handler) {
1204                 cr_utils_trace_info
1205                         ("Instanciation of the sac handler failed");
1206                 goto cleanup;
1207         }
1208
1209         sac_handler->start_media = parse_at_media_start_media_cb;
1210         sac_handler->start_selector = parse_at_media_start_selector_cb;
1211         sac_handler->property = parse_at_media_property_cb;
1212         sac_handler->end_selector = parse_at_media_end_selector_cb;
1213         sac_handler->end_media = parse_at_media_end_media_cb;
1214         sac_handler->unrecoverable_error =
1215                 parse_at_media_unrecoverable_error_cb;
1216
1217         status = cr_parser_set_sac_handler (parser, sac_handler);
1218         if (status != CR_OK)
1219                 goto cleanup;
1220
1221         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1222         if (status != CR_OK)
1223                 goto cleanup;
1224
1225         status = cr_parser_parse_media (parser);
1226         if (status != CR_OK)
1227                 goto cleanup;
1228
1229         resultptr = &result;
1230         status = cr_doc_handler_get_result (sac_handler,
1231                                             (gpointer *) resultptr);
1232         if (status != CR_OK)
1233                 goto cleanup;
1234
1235       cleanup:
1236
1237         if (parser) {
1238                 cr_parser_destroy (parser);
1239                 parser = NULL;
1240                 sac_handler = NULL ;
1241         }
1242         if (sac_handler) {
1243                 cr_doc_handler_unref (sac_handler);
1244                 sac_handler = NULL;
1245         }
1246
1247         return result;
1248 }
1249
1250 /**
1251  * cr_statement_new_at_media_rule:
1252  *
1253  *@a_ruleset: the ruleset statements contained
1254  *in the \@media rule.
1255  *@a_media: the media string list. A list of GString pointers.
1256  *
1257  *Instanciates an instance of #CRStatement of type
1258  *AT_MEDIA_RULE_STMT (\@media ruleset).
1259  *
1260  */
1261 CRStatement *
1262 cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
1263                                 CRStatement * a_rulesets, GList * a_media)
1264 {
1265         CRStatement *result = NULL,
1266                 *cur = NULL;
1267
1268         if (a_rulesets)
1269                 g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
1270
1271         result = g_try_malloc (sizeof (CRStatement));
1272
1273         if (!result) {
1274                 cr_utils_trace_info ("Out of memory");
1275                 return NULL;
1276         }
1277
1278         memset (result, 0, sizeof (CRStatement));
1279         result->type = AT_MEDIA_RULE_STMT;
1280
1281         result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule));
1282         if (!result->kind.media_rule) {
1283                 cr_utils_trace_info ("Out of memory");
1284                 g_free (result);
1285                 return NULL;
1286         }
1287         memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
1288         result->kind.media_rule->rulesets = a_rulesets;
1289         for (cur = a_rulesets; cur; cur = cur->next) {
1290                 if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
1291                         cr_utils_trace_info ("Bad parameter a_rulesets. "
1292                                              "It should be a list of "
1293                                              "correct ruleset statement only !");
1294                         goto error;
1295                 }
1296                 cur->kind.ruleset->parent_media_rule = result;
1297         }
1298
1299         result->kind.media_rule->media_list = a_media;
1300         if (a_sheet) {
1301                 cr_statement_set_parent_sheet (result, a_sheet);
1302         }
1303
1304         return result;
1305
1306       error:
1307         return NULL;
1308 }
1309
1310 /**
1311  * cr_statement_new_at_import_rule:
1312  *
1313  *@a_url: the url to connect to the get the file
1314  *to be imported.
1315  *@a_sheet: the imported parsed stylesheet.
1316  *
1317  *Creates a new instance of #CRStatment of type
1318  *#CRAtImportRule.
1319  *
1320  *Returns the newly built instance of #CRStatement.
1321  */
1322 CRStatement *
1323 cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
1324                                  CRString * a_url,
1325                                  GList * a_media_list,
1326                                  CRStyleSheet * a_imported_sheet)
1327 {
1328         CRStatement *result = NULL;
1329
1330         result = g_try_malloc (sizeof (CRStatement));
1331
1332         if (!result) {
1333                 cr_utils_trace_info ("Out of memory");
1334                 return NULL;
1335         }
1336
1337         memset (result, 0, sizeof (CRStatement));
1338         result->type = AT_IMPORT_RULE_STMT;
1339
1340         result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule));
1341
1342         if (!result->kind.import_rule) {
1343                 cr_utils_trace_info ("Out of memory");
1344                 g_free (result);
1345                 return NULL;
1346         }
1347
1348         memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
1349         result->kind.import_rule->url = a_url;
1350         result->kind.import_rule->media_list = a_media_list;
1351         result->kind.import_rule->sheet = a_imported_sheet;
1352         if (a_container_sheet)
1353                 cr_statement_set_parent_sheet (result, a_container_sheet);
1354
1355         return result;
1356 }
1357
1358 /**
1359  * cr_statement_at_import_rule_parse_from_buf:
1360  *
1361  *@a_buf: the buffer to parse.
1362  *@a_encoding: the encoding of a_buf.
1363  *
1364  *Parses a buffer that contains an "\@import" rule and
1365  *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
1366  *
1367  *Returns the newly built instance of #CRStatement in case of 
1368  *a successful parsing, NULL otherwise.
1369  */
1370 CRStatement *
1371 cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
1372                                             enum CREncoding a_encoding)
1373 {
1374         enum CRStatus status = CR_OK;
1375         CRParser *parser = NULL;
1376         CRStatement *result = NULL;
1377         GList *media_list = NULL;
1378         CRString *import_string = NULL;
1379         CRParsingLocation location = {0} ;
1380
1381         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1382                                          a_encoding, FALSE);
1383         if (!parser) {
1384                 cr_utils_trace_info ("Instanciation of parser failed.");
1385                 goto cleanup;
1386         }
1387
1388         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1389         if (status != CR_OK)
1390                 goto cleanup;
1391
1392         status = cr_parser_parse_import (parser,
1393                                          &media_list, 
1394                                          &import_string,
1395                                          &location);
1396         if (status != CR_OK || !import_string)
1397                 goto cleanup;
1398
1399         result = cr_statement_new_at_import_rule (NULL, import_string,
1400                                                   media_list, NULL);
1401         if (result) {
1402                 cr_parsing_location_copy (&result->location,
1403                                           &location) ;
1404                 import_string = NULL;
1405                 media_list = NULL;
1406         }
1407
1408  cleanup:
1409         if (parser) {
1410                 cr_parser_destroy (parser);
1411                 parser = NULL;
1412         }
1413         if (media_list) {
1414                 GList *cur = NULL;
1415
1416                 for (cur = media_list; media_list;
1417                      media_list = g_list_next (media_list)) {
1418                         if (media_list->data) {
1419                                 cr_string_destroy ((CRString*)media_list->data);
1420                                 media_list->data = NULL;
1421                         }
1422                 }
1423                 g_list_free (media_list);
1424                 media_list = NULL;
1425         }
1426         if (import_string) {
1427                 cr_string_destroy (import_string);
1428                 import_string = NULL;
1429         }
1430
1431         return result;
1432 }
1433
1434 /**
1435  * cr_statement_new_at_page_rule:
1436  *
1437  *@a_decl_list: a list of instances of #CRDeclarations
1438  *which is actually the list of declarations that applies to
1439  *this page rule.
1440  *@a_selector: the page rule selector.
1441  *
1442  *Creates a new instance of #CRStatement of type
1443  *#CRAtPageRule.
1444  *
1445  *Returns the newly built instance of #CRStatement or NULL
1446  *in case of error.
1447  */
1448 CRStatement *
1449 cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
1450                                CRDeclaration * a_decl_list,
1451                                CRString * a_name, CRString * a_pseudo)
1452 {
1453         CRStatement *result = NULL;
1454
1455         result = g_try_malloc (sizeof (CRStatement));
1456
1457         if (!result) {
1458                 cr_utils_trace_info ("Out of memory");
1459                 return NULL;
1460         }
1461
1462         memset (result, 0, sizeof (CRStatement));
1463         result->type = AT_PAGE_RULE_STMT;
1464
1465         result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule));
1466
1467         if (!result->kind.page_rule) {
1468                 cr_utils_trace_info ("Out of memory");
1469                 g_free (result);
1470                 return NULL;
1471         }
1472
1473         memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
1474         if (a_decl_list) {
1475                 result->kind.page_rule->decl_list = a_decl_list;
1476                 cr_declaration_ref (a_decl_list);
1477         }
1478         result->kind.page_rule->name = a_name;
1479         result->kind.page_rule->pseudo = a_pseudo;
1480         if (a_sheet)
1481                 cr_statement_set_parent_sheet (result, a_sheet);
1482
1483         return result;
1484 }
1485
1486 /**
1487  * cr_statement_at_page_rule_parse_from_buf:
1488  *
1489  *@a_buf: the character buffer to parse.
1490  *@a_encoding: the character encoding of a_buf.
1491  *
1492  *Parses a buffer that contains an "\@page" production and,
1493  *if the parsing succeeds, builds the page statement.
1494  *
1495  *Returns the newly built at page statement in case of successful parsing,
1496  *NULL otherwise.
1497  */
1498 CRStatement *
1499 cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
1500                                           enum CREncoding a_encoding)
1501 {
1502         enum CRStatus status = CR_OK;
1503         CRParser *parser = NULL;
1504         CRDocHandler *sac_handler = NULL;
1505         CRStatement *result = NULL;
1506         CRStatement **resultptr = NULL;
1507
1508         g_return_val_if_fail (a_buf, NULL);
1509
1510         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1511                                          a_encoding, FALSE);
1512         if (!parser) {
1513                 cr_utils_trace_info ("Instanciation of the parser failed.");
1514                 goto cleanup;
1515         }
1516
1517         sac_handler = cr_doc_handler_new ();
1518         if (!sac_handler) {
1519                 cr_utils_trace_info
1520                         ("Instanciation of the sac handler failed.");
1521                 goto cleanup;
1522         }
1523
1524         sac_handler->start_page = parse_page_start_page_cb;
1525         sac_handler->property = parse_page_property_cb;
1526         sac_handler->end_page = parse_page_end_page_cb;
1527         sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
1528
1529         status = cr_parser_set_sac_handler (parser, sac_handler);
1530         if (status != CR_OK)
1531                 goto cleanup;
1532
1533         /*Now, invoke the parser to parse the "@page production" */
1534         cr_parser_try_to_skip_spaces_and_comments (parser);
1535         if (status != CR_OK)
1536                 goto cleanup;
1537         status = cr_parser_parse_page (parser);
1538         if (status != CR_OK)
1539                 goto cleanup;
1540
1541         resultptr = &result;
1542         status = cr_doc_handler_get_result (sac_handler,
1543                                             (gpointer *) resultptr);
1544
1545       cleanup:
1546
1547         if (parser) {
1548                 cr_parser_destroy (parser);
1549                 parser = NULL;
1550                 sac_handler = NULL ;
1551         }
1552         if (sac_handler) {
1553                 cr_doc_handler_unref (sac_handler);
1554                 sac_handler = NULL;
1555         }
1556         return result;
1557 }
1558
1559 /**
1560  * cr_statement_new_at_charset_rule:
1561  *
1562  *@a_charset: the string representing the charset.
1563  *Note that the newly built instance of #CRStatement becomes
1564  *the owner of a_charset. The caller must not free a_charset !!!.
1565  *
1566  *Creates a new instance of #CRStatement of type
1567  *#CRAtCharsetRule.
1568  *
1569  *Returns the newly built instance of #CRStatement or NULL
1570  *if an error arises.
1571  */
1572 CRStatement *
1573 cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 
1574                                   CRString * a_charset)
1575 {
1576         CRStatement *result = NULL;
1577
1578         g_return_val_if_fail (a_charset, NULL);
1579
1580         result = g_try_malloc (sizeof (CRStatement));
1581
1582         if (!result) {
1583                 cr_utils_trace_info ("Out of memory");
1584                 return NULL;
1585         }
1586
1587         memset (result, 0, sizeof (CRStatement));
1588         result->type = AT_CHARSET_RULE_STMT;
1589
1590         result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule));
1591
1592         if (!result->kind.charset_rule) {
1593                 cr_utils_trace_info ("Out of memory");
1594                 g_free (result);
1595                 return NULL;
1596         }
1597         memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
1598         result->kind.charset_rule->charset = a_charset;
1599         cr_statement_set_parent_sheet (result, a_sheet);
1600
1601         return result;
1602 }
1603
1604 /**
1605  * cr_statement_at_charset_rule_parse_from_buf:
1606  *
1607  *@a_buf: the buffer to parse.
1608  *@a_encoding: the character encoding of the buffer.
1609  *
1610  *Parses a buffer that contains an '\@charset' rule and
1611  *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
1612  *
1613  *Returns the newly built instance of #CRStatement.
1614  */
1615 CRStatement *
1616 cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
1617                                              enum CREncoding a_encoding)
1618 {
1619         enum CRStatus status = CR_OK;
1620         CRParser *parser = NULL;
1621         CRStatement *result = NULL;
1622         CRString *charset = NULL;
1623
1624         g_return_val_if_fail (a_buf, NULL);
1625
1626         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1627                                          a_encoding, FALSE);
1628         if (!parser) {
1629                 cr_utils_trace_info ("Instanciation of the parser failed.");
1630                 goto cleanup;
1631         }
1632
1633         /*Now, invoke the parser to parse the "@charset production" */
1634         cr_parser_try_to_skip_spaces_and_comments (parser);
1635         if (status != CR_OK)
1636                 goto cleanup;
1637         status = cr_parser_parse_charset (parser, &charset, NULL);
1638         if (status != CR_OK || !charset)
1639                 goto cleanup;
1640
1641         result = cr_statement_new_at_charset_rule (NULL, charset);
1642         if (result)
1643                 charset = NULL;
1644
1645       cleanup:
1646
1647         if (parser) {
1648                 cr_parser_destroy (parser);
1649                 parser = NULL;
1650         }
1651         if (charset) {
1652                 cr_string_destroy (charset);
1653         }
1654
1655         return result;
1656 }
1657
1658 /**
1659  * cr_statement_new_at_font_face_rule:
1660  *
1661  *@a_font_decls: a list of instances of #CRDeclaration. Each declaration
1662  *is actually a font declaration.
1663  *
1664  *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
1665  *
1666  *Returns the newly built instance of #CRStatement.
1667  */
1668 CRStatement *
1669 cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
1670                                     CRDeclaration * a_font_decls)
1671 {
1672         CRStatement *result = NULL;
1673
1674         result = g_try_malloc (sizeof (CRStatement));
1675
1676         if (!result) {
1677                 cr_utils_trace_info ("Out of memory");
1678                 return NULL;
1679         }
1680         memset (result, 0, sizeof (CRStatement));
1681         result->type = AT_FONT_FACE_RULE_STMT;
1682
1683         result->kind.font_face_rule = g_try_malloc
1684                 (sizeof (CRAtFontFaceRule));
1685
1686         if (!result->kind.font_face_rule) {
1687                 cr_utils_trace_info ("Out of memory");
1688                 g_free (result);
1689                 return NULL;
1690         }
1691         memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
1692
1693         result->kind.font_face_rule->decl_list = a_font_decls;
1694         if (a_sheet)
1695                 cr_statement_set_parent_sheet (result, a_sheet);
1696
1697         return result;
1698 }
1699
1700 /**
1701  * cr_statement_font_face_rule_parse_from_buf:
1702  *
1703  *
1704  *@a_buf: the buffer to parse.
1705  *@a_encoding: the character encoding of a_buf.
1706  *
1707  *Parses a buffer that contains an "\@font-face" rule and builds
1708  *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
1709  *
1710  *Returns the newly built instance of #CRStatement in case of successufull
1711  *parsing, NULL otherwise.
1712  */
1713 CRStatement *
1714 cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
1715                                             enum CREncoding a_encoding)
1716 {
1717         CRStatement *result = NULL;
1718         CRStatement **resultptr = NULL;
1719         CRParser *parser = NULL;
1720         CRDocHandler *sac_handler = NULL;
1721         enum CRStatus status = CR_OK;
1722
1723         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1724                                          a_encoding, FALSE);
1725         if (!parser)
1726                 goto cleanup;
1727
1728         sac_handler = cr_doc_handler_new ();
1729         if (!sac_handler)
1730                 goto cleanup;
1731
1732         /*
1733          *set sac callbacks here
1734          */
1735         sac_handler->start_font_face = parse_font_face_start_font_face_cb;
1736         sac_handler->property = parse_font_face_property_cb;
1737         sac_handler->end_font_face = parse_font_face_end_font_face_cb;
1738         sac_handler->unrecoverable_error =
1739                 parse_font_face_unrecoverable_error_cb;
1740
1741         status = cr_parser_set_sac_handler (parser, sac_handler);
1742         if (status != CR_OK)
1743                 goto cleanup;
1744
1745         /*
1746          *cleanup spaces of comment that may be there before the real
1747          *"@font-face" thing.
1748          */
1749         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1750         if (status != CR_OK)
1751                 goto cleanup;
1752
1753         status = cr_parser_parse_font_face (parser);
1754         if (status != CR_OK)
1755                 goto cleanup;
1756
1757         resultptr = &result;
1758         status = cr_doc_handler_get_result (sac_handler,
1759                                             (gpointer *) resultptr);
1760         if (status != CR_OK || !result)
1761                 goto cleanup;
1762
1763       cleanup:
1764         if (parser) {
1765                 cr_parser_destroy (parser);
1766                 parser = NULL;
1767                 sac_handler = NULL ;
1768         }
1769         if (sac_handler) {
1770                 cr_doc_handler_unref (sac_handler);
1771                 sac_handler = NULL;
1772         }
1773         return result;
1774 }
1775
1776 /**
1777  * cr_statement_set_parent_sheet:
1778  *
1779  *@a_this: the current instance of #CRStatement.
1780  *@a_sheet: the sheet that contains the current statement.
1781  *
1782  *Sets the container stylesheet.
1783  *
1784  *Returns CR_OK upon successful completion, an error code otherwise.
1785  */
1786 enum CRStatus
1787 cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
1788 {
1789         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
1790         a_this->parent_sheet = a_sheet;
1791         return CR_OK;
1792 }
1793
1794 /**
1795  * cr_statement_get_parent_sheet:
1796  *
1797  *@a_this: the current #CRStatement.
1798  *@a_sheet: out parameter. A pointer to the sheets that
1799  *
1800  *Gets the sheets that contains the current statement.
1801  *
1802  *Returns CR_OK upon successful completion, an error code otherwise.
1803  */
1804 enum CRStatus
1805 cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
1806 {
1807         g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
1808         *a_sheet = a_this->parent_sheet;
1809         return CR_OK;
1810 }
1811
1812 /**
1813  * cr_statement_append:
1814  *
1815  *@a_this: the current instance of the statement list.
1816  *@a_new: a_new the new instance of #CRStatement to append.
1817  *
1818  *Appends a new statement to the statement list.
1819  *
1820  *Returns the new list statement list, or NULL in cas of failure.
1821  */
1822 CRStatement *
1823 cr_statement_append (CRStatement * a_this, CRStatement * a_new)
1824 {
1825         CRStatement *cur = NULL;
1826
1827         g_return_val_if_fail (a_new, NULL);
1828
1829         if (!a_this) {
1830                 return a_new;
1831         }
1832
1833         /*walk forward in the current list to find the tail list element */
1834         for (cur = a_this; cur && cur->next; cur = cur->next) ;
1835
1836         cur->next = a_new;
1837         a_new->prev = cur;
1838
1839         return a_this;
1840 }
1841
1842 /**
1843  * cr_statement_prepend:
1844  *
1845  *@a_this: the current instance of #CRStatement.
1846  *@a_new: the new statement to prepend.
1847  *
1848  *Prepends the an instance of #CRStatement to
1849  *the current statement list.
1850  *
1851  *Returns the new list with the new statement prepended,
1852  *or NULL in case of an error.
1853  */
1854 CRStatement *
1855 cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
1856 {
1857         CRStatement *cur = NULL;
1858
1859         g_return_val_if_fail (a_new, NULL);
1860
1861         if (!a_this)
1862                 return a_new;
1863
1864         a_new->next = a_this;
1865         a_this->prev = a_new;
1866
1867         /*walk backward in the prepended list to find the head list element */
1868         for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
1869
1870         return cur;
1871 }
1872
1873 /**
1874  * cr_statement_unlink:
1875  *
1876  *@a_this: the current statements list.
1877  *@a_to_unlink: the statement to unlink from the list.
1878  *
1879  *Unlinks a statement from the statements list.
1880  *
1881  *Returns the new list where a_to_unlink has been unlinked
1882  *from, or NULL in case of error.
1883  */
1884 CRStatement *
1885 cr_statement_unlink (CRStatement * a_stmt)
1886 {
1887         CRStatement *result = a_stmt;
1888
1889         g_return_val_if_fail (result, NULL);
1890
1891         /**
1892          *Some sanity checks first
1893          */
1894         if (a_stmt->next) {
1895                 g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
1896         }
1897         if (a_stmt->prev) {
1898                 g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
1899         }
1900
1901         /**
1902          *Now, the real unlinking job.
1903          */
1904         if (a_stmt->next) {
1905                 a_stmt->next->prev = a_stmt->prev;
1906         }
1907         if (a_stmt->prev) {
1908                 a_stmt->prev->next = a_stmt->next;
1909         }
1910
1911         if (a_stmt->parent_sheet
1912             && a_stmt->parent_sheet->statements == a_stmt) {
1913                 a_stmt->parent_sheet->statements =
1914                         a_stmt->parent_sheet->statements->next;
1915         }
1916
1917         a_stmt->next = NULL;
1918         a_stmt->prev = NULL;
1919         a_stmt->parent_sheet = NULL;
1920
1921         return result;
1922 }
1923
1924 /**
1925  * cr_statement_nr_rules:
1926  *
1927  *@a_this: the current instance of #CRStatement.
1928  *
1929  *Gets the number of rules in the statement list;
1930  *
1931  *Returns number of rules in the statement list.
1932  */
1933 gint
1934 cr_statement_nr_rules (CRStatement const * a_this)
1935 {
1936         CRStatement const *cur = NULL;
1937         int nr = 0;
1938
1939         g_return_val_if_fail (a_this, -1);
1940
1941         for (cur = a_this; cur; cur = cur->next)
1942                 nr++;
1943         return nr;
1944 }
1945
1946 /**
1947  * cr_statement_get_from_list:
1948  *
1949  *@a_this: the current instance of #CRStatement.
1950  *@itemnr: the index into the statement list.
1951  *
1952  *Use an index to get a CRStatement from the statement list.
1953  *
1954  *Returns CRStatement at position itemnr, if itemnr > number of statements - 1,
1955  *it will return NULL.
1956  */
1957 CRStatement *
1958 cr_statement_get_from_list (CRStatement * a_this, int itemnr)
1959 {
1960         CRStatement *cur = NULL;
1961         int nr = 0;
1962
1963         g_return_val_if_fail (a_this, NULL);
1964
1965         for (cur = a_this; cur; cur = cur->next)
1966                 if (nr++ == itemnr)
1967                         return cur;
1968         return NULL;
1969 }
1970
1971 /**
1972  * cr_statement_ruleset_set_sel_list:
1973  *
1974  *@a_this: the current ruleset statement.
1975  *@a_sel_list: the selector list to set. Note
1976  *that this function increments the ref count of a_sel_list.
1977  *The sel list will be destroyed at the destruction of the
1978  *current instance of #CRStatement.
1979  *
1980  *Sets a selector list to a ruleset statement.
1981  *
1982  *Returns CR_OK upon successful completion, an error code otherwise.
1983  */
1984 enum CRStatus
1985 cr_statement_ruleset_set_sel_list (CRStatement * a_this,
1986                                    CRSelector * a_sel_list)
1987 {
1988         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
1989                               CR_BAD_PARAM_ERROR);
1990
1991         if (a_this->kind.ruleset->sel_list)
1992                 cr_selector_unref (a_this->kind.ruleset->sel_list);
1993
1994         a_this->kind.ruleset->sel_list = a_sel_list;
1995
1996         if (a_sel_list)
1997                 cr_selector_ref (a_sel_list);
1998
1999         return CR_OK;
2000 }
2001
2002 /**
2003  * cr_statement_ruleset_get_declarations:
2004  *
2005  *@a_this: the current instance of #CRStatement.
2006  *@a_decl_list: out parameter. A pointer to the the returned
2007  *list of declaration. Must not be NULL.
2008  *
2009  *Gets a pointer to the list of declaration contained
2010  *in the ruleset statement.
2011  *
2012  *Returns CR_OK upon successful completion, an error code if something
2013  *bad happened.
2014  */
2015 enum CRStatus
2016 cr_statement_ruleset_get_declarations (CRStatement * a_this,
2017                                        CRDeclaration ** a_decl_list)
2018 {
2019         g_return_val_if_fail (a_this
2020                               && a_this->type == RULESET_STMT
2021                               && a_this->kind.ruleset
2022                               && a_decl_list, CR_BAD_PARAM_ERROR);
2023
2024         *a_decl_list = a_this->kind.ruleset->decl_list;
2025
2026         return CR_OK;
2027 }
2028
2029 /**
2030  * cr_statement_ruleset_get_sel_list:
2031  *
2032  *@a_this: the current ruleset statement.
2033  *@a_list: out parameter. The returned selector list,
2034  *if and only if the function returned CR_OK.
2035  *
2036  *Gets a pointer to the selector list contained in
2037  *the current ruleset statement.
2038  *
2039  *Returns CR_OK upon successful completion, an error code otherwise.
2040  */
2041 enum CRStatus
2042 cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list)
2043 {
2044         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
2045                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
2046
2047         *a_list = a_this->kind.ruleset->sel_list;
2048
2049         return CR_OK;
2050 }
2051
2052 /**
2053  * cr_statement_ruleset_set_decl_list:
2054  *
2055  *@a_this: the current ruleset statement.
2056  *@a_list: the declaration list to be added to the current
2057  *ruleset statement.
2058  *
2059  *Sets a declaration list to the current ruleset statement.
2060  *
2061  *Returns CR_OK upon successful completion, an error code otherwise.
2062  */
2063 enum CRStatus
2064 cr_statement_ruleset_set_decl_list (CRStatement * a_this,
2065                                     CRDeclaration * a_list)
2066 {
2067         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
2068                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
2069
2070         if (a_this->kind.ruleset->decl_list == a_list)
2071                 return CR_OK;
2072
2073         if (a_this->kind.ruleset->sel_list) {
2074                 cr_declaration_destroy (a_this->kind.ruleset->decl_list);
2075         }
2076
2077         a_this->kind.ruleset->sel_list = NULL;
2078
2079         return CR_OK;
2080 }
2081
2082 /**
2083  * cr_statement_ruleset_append_decl2:
2084  *
2085  *@a_this: the current statement.
2086  *@a_prop: the property of the declaration.
2087  *@a_value: the value of the declaration.
2088  *
2089  *Appends a declaration to the current ruleset statement.
2090  *
2091  *Returns CR_OK upon successful completion, an error code
2092  *otherwise.
2093  */
2094 enum CRStatus
2095 cr_statement_ruleset_append_decl2 (CRStatement * a_this,
2096                                    CRString * a_prop, 
2097                                    CRTerm * a_value)
2098 {
2099         CRDeclaration *new_decls = NULL;
2100
2101         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
2102                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
2103
2104         new_decls = cr_declaration_append2
2105                 (a_this->kind.ruleset->decl_list, 
2106                  a_prop, a_value);
2107         g_return_val_if_fail (new_decls, CR_ERROR);
2108         a_this->kind.ruleset->decl_list = new_decls;
2109
2110         return CR_OK;
2111 }
2112
2113 /**
2114  * cr_statement_ruleset_append_decl:
2115  *
2116  *Appends a declaration to the current statement.
2117  *
2118  *@a_this: the current statement.
2119  *@a_declaration: the declaration to append.
2120  *
2121  *Returns CR_OK upon sucessful completion, an error code
2122  *otherwise.
2123  */
2124 enum CRStatus
2125 cr_statement_ruleset_append_decl (CRStatement * a_this,
2126                                   CRDeclaration * a_decl)
2127 {
2128         CRDeclaration *new_decls = NULL;
2129
2130         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
2131                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
2132
2133         new_decls = cr_declaration_append
2134                 (a_this->kind.ruleset->decl_list, a_decl);
2135         g_return_val_if_fail (new_decls, CR_ERROR);
2136         a_this->kind.ruleset->decl_list = new_decls;
2137
2138         return CR_OK;
2139 }
2140
2141 /**
2142  * cr_statement_at_import_rule_set_imported_sheet:
2143  *
2144  *Sets a stylesheet to the current \@import rule.
2145  *@a_this: the current \@import rule.
2146  *@a_sheet: the stylesheet. The stylesheet is owned
2147  *by the current instance of #CRStatement, that is, the 
2148  *stylesheet will be destroyed when the current instance
2149  *of #CRStatement is destroyed.
2150  *
2151  *Returns CR_OK upon successful completion, an error code otherwise.
2152  */
2153 enum CRStatus
2154 cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
2155                                                 CRStyleSheet * a_sheet)
2156 {
2157         g_return_val_if_fail (a_this
2158                               && a_this->type == AT_IMPORT_RULE_STMT
2159                               && a_this->kind.import_rule,
2160                               CR_BAD_PARAM_ERROR);
2161
2162         a_this->kind.import_rule->sheet = a_sheet;
2163
2164         return CR_OK;
2165 }
2166
2167 /**
2168  * cr_statement_at_import_rule_get_imported_sheet:
2169  *
2170  *@a_this: the current \@import rule statement.
2171  *@a_sheet: out parameter. The returned stylesheet if and
2172  *only if the function returns CR_OK.
2173  *
2174  *Gets the stylesheet contained by the \@import rule statement.
2175  *Returns CR_OK upon sucessful completion, an error code otherwise.
2176  */
2177 enum CRStatus
2178 cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
2179                                                 CRStyleSheet ** a_sheet)
2180 {
2181         g_return_val_if_fail (a_this
2182                               && a_this->type == AT_IMPORT_RULE_STMT
2183                               && a_this->kind.import_rule,
2184                               CR_BAD_PARAM_ERROR);
2185         *a_sheet = a_this->kind.import_rule->sheet;
2186         return CR_OK;
2187
2188 }
2189
2190 /**
2191  * cr_statement_at_import_rule_set_url:
2192  *
2193  *@a_this: the current \@import rule statement.
2194  *@a_url: the url to set.
2195  *
2196  *Sets an url to the current \@import rule statement.
2197  *
2198  *Returns CR_OK upon successful completion, an error code otherwise.
2199  */
2200 enum CRStatus
2201 cr_statement_at_import_rule_set_url (CRStatement * a_this, 
2202                                      CRString * a_url)
2203 {
2204         g_return_val_if_fail (a_this
2205                               && a_this->type == AT_IMPORT_RULE_STMT
2206                               && a_this->kind.import_rule,
2207                               CR_BAD_PARAM_ERROR);
2208
2209         if (a_this->kind.import_rule->url) {
2210                 cr_string_destroy (a_this->kind.import_rule->url);
2211         }
2212
2213         a_this->kind.import_rule->url = a_url;
2214
2215         return CR_OK;
2216 }
2217
2218 /**
2219  * cr_statement_at_import_rule_get_url:
2220  *
2221  *@a_this: the current \@import rule statement.
2222  *@a_url: out parameter. The returned url if
2223  *and only if the function returned CR_OK.
2224  *
2225  *Gets the url of the \@import rule statement.
2226  *Returns CR_OK upon successful completion, an error code otherwise.
2227  */
2228 enum CRStatus
2229 cr_statement_at_import_rule_get_url (CRStatement const * a_this,
2230                                      CRString ** a_url)
2231 {
2232         g_return_val_if_fail (a_this
2233                               && a_this->type == AT_IMPORT_RULE_STMT
2234                               && a_this->kind.import_rule,
2235                               CR_BAD_PARAM_ERROR);
2236
2237         *a_url = a_this->kind.import_rule->url;
2238
2239         return CR_OK;
2240 }
2241
2242 /**
2243  * cr_statement_at_media_nr_rules:
2244  *
2245  *@a_this: the current instance of #CRStatement.
2246  *
2247  *Returns the number of rules in the media rule;
2248  */
2249 int
2250 cr_statement_at_media_nr_rules (CRStatement const * a_this)
2251 {
2252         g_return_val_if_fail (a_this
2253                               && a_this->type == AT_MEDIA_RULE_STMT
2254                               && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
2255
2256         return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
2257 }
2258
2259 /**
2260  * cr_statement_at_media_get_from_list:
2261  *
2262  *@a_this: the current instance of #CRStatement.
2263  *@itemnr: the index into the media rule list of rules.
2264  *
2265  *Use an index to get a CRStatement from the media rule list of rules.
2266  *
2267  *Returns CRStatement at position itemnr, if itemnr > number of rules - 1,
2268  *it will return NULL.
2269  */
2270 CRStatement *
2271 cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
2272 {
2273         g_return_val_if_fail (a_this
2274                               && a_this->type == AT_MEDIA_RULE_STMT
2275                               && a_this->kind.media_rule, NULL);
2276
2277         return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
2278                                            itemnr);
2279 }
2280
2281 /**
2282  * cr_statement_at_page_rule_set_declarations:
2283  *
2284  *@a_this: the current \@page rule statement.
2285  *@a_decl_list: the declaration list to add. Will be freed
2286  *by the current instance of #CRStatement when it is destroyed.
2287  *
2288  *Sets a declaration list to the current \@page rule statement.
2289  *
2290  *Returns CR_OK upon successful completion, an error code otherwise.
2291  */
2292 enum CRStatus
2293 cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
2294                                             CRDeclaration * a_decl_list)
2295 {
2296         g_return_val_if_fail (a_this
2297                               && a_this->type == AT_PAGE_RULE_STMT
2298                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
2299
2300         if (a_this->kind.page_rule->decl_list) {
2301                 cr_declaration_unref (a_this->kind.page_rule->decl_list);
2302         }
2303
2304         a_this->kind.page_rule->decl_list = a_decl_list;
2305
2306         if (a_decl_list) {
2307                 cr_declaration_ref (a_decl_list);
2308         }
2309
2310         return CR_OK;
2311 }
2312
2313 /**
2314  * cr_statement_at_page_rule_get_declarations:
2315  *
2316  *@a_this: the current \@page rule statement.
2317  *@a_decl_list: out parameter. The returned declaration list.
2318  *
2319  *Gets the declaration list associated to the current \@page rule
2320  *statement.
2321  *
2322  *Returns CR_OK upon successful completion, an error code otherwise.
2323  */
2324 enum CRStatus
2325 cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
2326                                             CRDeclaration ** a_decl_list)
2327 {
2328         g_return_val_if_fail (a_this
2329                               && a_this->type == AT_PAGE_RULE_STMT
2330                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
2331
2332         *a_decl_list = a_this->kind.page_rule->decl_list;
2333
2334         return CR_OK;
2335 }
2336
2337 /**
2338  * cr_statement_at_charset_rule_set_charset:
2339  *
2340  *
2341  *@a_this: the current \@charset rule statement.
2342  *@a_charset: the charset to set.
2343  *
2344  *Sets the charset of the current \@charset rule statement.
2345  *
2346  *Returns CR_OK upon successful completion, an error code otherwise.
2347  */
2348 enum CRStatus
2349 cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
2350                                           CRString * a_charset)
2351 {
2352         g_return_val_if_fail (a_this
2353                               && a_this->type == AT_CHARSET_RULE_STMT
2354                               && a_this->kind.charset_rule,
2355                               CR_BAD_PARAM_ERROR);
2356
2357         if (a_this->kind.charset_rule->charset) {
2358                 cr_string_destroy (a_this->kind.charset_rule->charset);
2359         }
2360         a_this->kind.charset_rule->charset = a_charset;
2361         return CR_OK;
2362 }
2363
2364 /**
2365  * cr_statement_at_charset_rule_get_charset:
2366  *@a_this: the current \@charset rule statement.
2367  *@a_charset: out parameter. The returned charset string if
2368  *and only if the function returned CR_OK.
2369  *
2370  *Gets the charset string associated to the current
2371  *\@charset rule statement.
2372  *
2373  * Returns CR_OK upon successful completion, an error code otherwise.
2374  */
2375 enum CRStatus
2376 cr_statement_at_charset_rule_get_charset (CRStatement const * a_this,
2377                                           CRString ** a_charset)
2378 {
2379         g_return_val_if_fail (a_this
2380                               && a_this->type == AT_CHARSET_RULE_STMT
2381                               && a_this->kind.charset_rule,
2382                               CR_BAD_PARAM_ERROR);
2383
2384         *a_charset = a_this->kind.charset_rule->charset;
2385
2386         return CR_OK;
2387 }
2388
2389 /**
2390  * cr_statement_at_font_face_rule_set_decls:
2391  *
2392  *@a_this: the current \@font-face rule statement.
2393  *@a_decls: the declarations list to set.
2394  *
2395  *Sets a declaration list to the current \@font-face rule statement.
2396  *
2397  *Returns CR_OK upon successful completion, an error code otherwise.
2398  */
2399 enum CRStatus
2400 cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
2401                                           CRDeclaration * a_decls)
2402 {
2403         g_return_val_if_fail (a_this
2404                               && a_this->type == AT_FONT_FACE_RULE_STMT
2405                               && a_this->kind.font_face_rule,
2406                               CR_BAD_PARAM_ERROR);
2407
2408         if (a_this->kind.font_face_rule->decl_list) {
2409                 cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
2410         }
2411
2412         a_this->kind.font_face_rule->decl_list = a_decls;
2413         cr_declaration_ref (a_decls);
2414
2415         return CR_OK;
2416 }
2417
2418 /**
2419  * cr_statement_at_font_face_rule_get_decls:
2420  *
2421  *@a_this: the current \@font-face rule statement.
2422  *@a_decls: out parameter. The returned declaration list if
2423  *and only if this function returns CR_OK.
2424  *
2425  *Gets the declaration list associated to the current instance
2426  *of \@font-face rule statement.
2427  *
2428  *Returns CR_OK upon successful completion, an error code otherwise.
2429  */
2430 enum CRStatus
2431 cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
2432                                           CRDeclaration ** a_decls)
2433 {
2434         g_return_val_if_fail (a_this
2435                               && a_this->type == AT_FONT_FACE_RULE_STMT
2436                               && a_this->kind.font_face_rule,
2437                               CR_BAD_PARAM_ERROR);
2438
2439         *a_decls = a_this->kind.font_face_rule->decl_list;
2440
2441         return CR_OK;
2442 }
2443
2444 /**
2445  * cr_statement_at_font_face_rule_add_decl:
2446  *
2447  *@a_this: the current \@font-face rule statement.
2448  *@a_prop: the property of the declaration.
2449  *@a_value: the value of the declaration.
2450  *
2451  *Adds a declaration to the current \@font-face rule
2452  *statement.
2453  *
2454  *Returns CR_OK upon successful completion, an error code otherwise.
2455  */
2456 enum CRStatus
2457 cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
2458                                          CRString * a_prop, CRTerm * a_value)
2459 {
2460         CRDeclaration *decls = NULL;
2461
2462         g_return_val_if_fail (a_this
2463                               && a_this->type == AT_FONT_FACE_RULE_STMT
2464                               && a_this->kind.font_face_rule,
2465                               CR_BAD_PARAM_ERROR);
2466
2467         decls = cr_declaration_append2
2468                 (a_this->kind.font_face_rule->decl_list, 
2469                  a_prop, a_value);
2470
2471         g_return_val_if_fail (decls, CR_ERROR);
2472
2473         if (a_this->kind.font_face_rule->decl_list == NULL)
2474                 cr_declaration_ref (decls);
2475
2476         a_this->kind.font_face_rule->decl_list = decls;
2477
2478         return CR_OK;
2479 }
2480
2481
2482 /**
2483  * cr_statement_to_string:
2484  *
2485  *@a_this: the current statement to serialize
2486  *@a_indent: the number of white space of indentation.
2487  *
2488  *Serializes a css statement into a string
2489  *
2490  *Returns the serialized statement. Must be freed by the caller
2491  *using g_free().
2492  */
2493 gchar *
2494 cr_statement_to_string (CRStatement const * a_this, gulong a_indent)
2495 {
2496         gchar *str = NULL ;
2497
2498         if (!a_this)
2499                 return NULL;
2500
2501         switch (a_this->type) {
2502         case RULESET_STMT:
2503                 str = cr_statement_ruleset_to_string 
2504                         (a_this, a_indent);
2505                 break;
2506
2507         case AT_FONT_FACE_RULE_STMT:
2508                 str = cr_statement_font_face_rule_to_string 
2509                         (a_this, a_indent) ;
2510                 break;
2511
2512         case AT_CHARSET_RULE_STMT:
2513                 str = cr_statement_charset_to_string
2514                         (a_this, a_indent);                
2515                 break;
2516
2517         case AT_PAGE_RULE_STMT:
2518                 str = cr_statement_at_page_rule_to_string
2519                         (a_this, a_indent);
2520                 break;
2521
2522         case AT_MEDIA_RULE_STMT:
2523                 str = cr_statement_media_rule_to_string
2524                         (a_this, a_indent);
2525                 break;
2526
2527         case AT_IMPORT_RULE_STMT:
2528                 str = cr_statement_import_rule_to_string
2529                         (a_this, a_indent);
2530                 break;
2531
2532         default:
2533                 cr_utils_trace_info ("Statement unrecognized");
2534                 break;
2535         }
2536         return str ;
2537 }
2538
2539 gchar*
2540 cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent)
2541 {
2542         CRStatement const *cur_stmt = NULL ;
2543         GString *stringue = NULL ;
2544         gchar *str = NULL ;
2545
2546         g_return_val_if_fail (a_this, NULL) ;
2547
2548         stringue = g_string_new (NULL) ;
2549         if (!stringue) {
2550                 cr_utils_trace_info ("Out of memory") ;
2551                 return NULL ;
2552         }
2553         for (cur_stmt = a_this ; cur_stmt;
2554              cur_stmt = cur_stmt->next) {
2555                 str = cr_statement_to_string (cur_stmt, a_indent) ;
2556                 if (str) {
2557                         if (!cur_stmt->prev) {
2558                                 g_string_append (stringue, str) ;
2559                         } else {
2560                                 g_string_append_printf 
2561                                         (stringue, "\n%s", str) ;
2562                         }
2563                         g_free (str) ;
2564                         str = NULL ;
2565                 }                
2566         }
2567         str = stringue->str ;
2568         g_string_free (stringue, FALSE) ;
2569         return str ;
2570 }
2571
2572 /**
2573  * cr_statement_dump:
2574  *
2575  *@a_this: the current css2 statement.
2576  *@a_fp: the destination file pointer.
2577  *@a_indent: the number of white space indentation characters.
2578  *
2579  *Dumps the css2 statement to a file.
2580  */
2581 void
2582 cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
2583 {
2584         gchar *str = NULL ;
2585
2586         if (!a_this)
2587                 return;
2588
2589         str = cr_statement_to_string (a_this, a_indent) ;
2590         if (str) {
2591                 fprintf (a_fp, "%s",str) ;
2592                 g_free (str) ;
2593                 str = NULL ;
2594         }
2595 }
2596
2597 /**
2598  * cr_statement_dump_ruleset:
2599  *
2600  *@a_this: the current instance of #CRStatement.
2601  *@a_fp: the destination file pointer.
2602  *@a_indent: the number of indentation white spaces to add.
2603  *
2604  *Dumps a ruleset statement to a file.
2605  */
2606 void
2607 cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent)
2608 {
2609         guchar *str = NULL;
2610
2611         g_return_if_fail (a_fp && a_this);
2612         str = cr_statement_ruleset_to_string (a_this, a_indent);
2613         if (str) {
2614                 fprintf (a_fp, str);
2615                 g_free (str);
2616                 str = NULL;
2617         }
2618 }
2619
2620 /**
2621  * cr_statement_dump_font_face_rule:
2622  *
2623  *@a_this: the current instance of font face rule statement.
2624  *@a_fp: the destination file pointer.
2625  *@a_indent: the number of white space indentation.
2626  *
2627  *Dumps a font face rule statement to a file.
2628  */
2629 void
2630 cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp,
2631                                   glong a_indent)
2632 {
2633         gchar *str = NULL ;
2634         g_return_if_fail (a_this 
2635                           && a_this->type == AT_FONT_FACE_RULE_STMT);
2636
2637         str = cr_statement_font_face_rule_to_string (a_this,
2638                                                      a_indent) ;
2639         if (str) {
2640                 fprintf (a_fp, "%s", str) ;
2641                 g_free (str) ;
2642                 str = NULL ;
2643         }
2644 }
2645
2646 /**
2647  * cr_statement_dump_charset:
2648  *
2649  *@a_this: the current instance of the \@charset rule statement.
2650  *@a_fp: the destination file pointer.
2651  *@a_indent: the number of indentation white spaces.
2652  *
2653  *Dumps an \@charset rule statement to a file.
2654  */
2655 void
2656 cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
2657 {
2658         guchar *str = NULL;
2659
2660         g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
2661
2662         str = cr_statement_charset_to_string (a_this,
2663                                               a_indent) ;
2664         if (str) {
2665                 fprintf (a_fp, str) ;
2666                 g_free (str) ;
2667                 str = NULL ;
2668         }
2669 }
2670
2671
2672 /**
2673  * cr_statement_dump_page:
2674  *
2675  *@a_this: the statement to dump on stdout.
2676  *@a_fp: the destination file pointer.
2677  *@a_indent: the number of indentation white spaces.
2678  *
2679  *Dumps an \@page rule statement on stdout.
2680  */
2681 void
2682 cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
2683 {
2684         guchar *str = NULL;
2685
2686         g_return_if_fail (a_this
2687                           && a_this->type == AT_PAGE_RULE_STMT
2688                           && a_this->kind.page_rule);
2689
2690         str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
2691         if (str) {
2692                 fprintf (a_fp, str);
2693                 g_free (str) ;
2694                 str = NULL ; 
2695         }
2696 }
2697
2698
2699 /**
2700  * cr_statement_dump_media_rule:
2701  *
2702  *@a_this: the statement to dump.
2703  *@a_fp: the destination file pointer
2704  *@a_indent: the number of white spaces indentation.
2705  *
2706  *Dumps an \@media rule statement to a file.
2707  */
2708 void
2709 cr_statement_dump_media_rule (CRStatement const * a_this,
2710                               FILE * a_fp,
2711                               gulong a_indent)
2712 {
2713         gchar *str = NULL ;
2714         g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
2715
2716         str = cr_statement_media_rule_to_string (a_this, a_indent) ;
2717         if (str) {
2718                 fprintf (a_fp, str) ;
2719                 g_free (str) ;
2720                 str = NULL ;
2721         }
2722 }
2723
2724 /**
2725  * cr_statement_dump_import_rule:
2726  *
2727  *@a_fp: the destination file pointer.
2728  *@a_indent: the number of white space indentations.
2729  *
2730  *Dumps an \@import rule statement to a file.
2731  */
2732 void
2733 cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
2734                                gulong a_indent)
2735 {
2736         gchar *str = NULL ;
2737         g_return_if_fail (a_this
2738                           && a_this->type == AT_IMPORT_RULE_STMT
2739                           && a_fp
2740                           && a_this->kind.import_rule);
2741
2742         str = cr_statement_import_rule_to_string (a_this, a_indent) ;
2743         if (str) {
2744                 fprintf (a_fp, str) ;
2745                 g_free (str) ;
2746                 str = NULL ;
2747         }
2748 }
2749
2750 /**
2751  * cr_statement_destroy:
2752  *
2753  * @a_this: the current instance of #CRStatement.
2754  *
2755  *Destructor of #CRStatement.
2756  */
2757 void
2758 cr_statement_destroy (CRStatement * a_this)
2759 {
2760         CRStatement *cur = NULL;
2761
2762         g_return_if_fail (a_this);
2763
2764         /*go get the tail of the list */
2765         for (cur = a_this; cur && cur->next; cur = cur->next) {
2766                 cr_statement_clear (cur);
2767         }
2768
2769         if (cur)
2770                 cr_statement_clear (cur);
2771
2772         if (cur->prev == NULL) {
2773                 g_free (a_this);
2774                 return;
2775         }
2776
2777         /*walk backward and free next element */
2778         for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
2779                 if (cur->next) {
2780                         g_free (cur->next);
2781                         cur->next = NULL;
2782                 }
2783         }
2784
2785         if (!cur)
2786                 return;
2787
2788         /*free the one remaining list */
2789         if (cur->next) {
2790                 g_free (cur->next);
2791                 cur->next = NULL;
2792         }
2793
2794         g_free (cur);
2795         cur = NULL;
2796 }