Code

* src/dialogs/layers-panel.cpp: Compile fix from Mathieu Dimanche.
[inkscape.git] / src / libcroco / cr-statement.c
1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
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  */
24 #include <string.h>
25 #include "cr-statement.h"
26 #include "cr-parser.h"
28 #define UNUSED(_param) ((void)(_param))
30 /**
31  *@file
32  *Definition of the #CRStatement class.
33  */
35 #define DECLARATION_INDENT_NB 2
37 static void cr_statement_clear (CRStatement * a_this);
39 static void  
40 parse_font_face_start_font_face_cb (CRDocHandler * a_this,
41                                     CRParsingLocation * a_location)
42 {
43         CRStatement *stmt = NULL;
44         enum CRStatus status = CR_OK;
46         UNUSED(a_location);
48         stmt = cr_statement_new_at_font_face_rule (NULL, NULL);
49         g_return_if_fail (stmt);
51         status = cr_doc_handler_set_ctxt (a_this, stmt);
52         g_return_if_fail (status == CR_OK);
53 }
55 static void
56 parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this)
57 {
58         CRStatement *stmt = NULL;
59         CRStatement **stmtptr = NULL;
60         enum CRStatus status = CR_OK;
62         g_return_if_fail (a_this);
64         stmtptr = &stmt;
65         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
66         if (status != CR_OK) {
67                 cr_utils_trace_info ("Couldn't get parsing context. "
68                                      "This may lead to some memory leaks.");
69                 return;
70         }
71         if (stmt) {
72                 cr_statement_destroy (stmt);
73                 cr_doc_handler_set_ctxt (a_this, NULL);
74                 return;
75         }
76 }
78 static void
79 parse_font_face_property_cb (CRDocHandler * a_this,
80                              CRString * a_name,
81                              CRTerm * a_value, gboolean a_important)
82 {
83         enum CRStatus status = CR_OK;
84         CRString *name = NULL;
85         CRDeclaration *decl = NULL;
86         CRStatement *stmt = NULL;
87         CRStatement **stmtptr = NULL;
89         UNUSED(a_important);
91         g_return_if_fail (a_this && a_name);
93         stmtptr = &stmt;
94         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
95         g_return_if_fail (status == CR_OK && stmt);
96         g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT);
98         name = cr_string_dup (a_name) ;
99         g_return_if_fail (name);
100         decl = cr_declaration_new (stmt, name, a_value);
101         if (!decl) {
102                 cr_utils_trace_info ("cr_declaration_new () failed.");
103                 goto error;
104         }
105         name = NULL;
107         stmt->kind.font_face_rule->decl_list =
108                 cr_declaration_append (stmt->kind.font_face_rule->decl_list,
109                                        decl);
110         if (!stmt->kind.font_face_rule->decl_list)
111                 goto error;
112         decl = NULL;
114       error:
115         if (decl) {
116                 cr_declaration_unref (decl);
117                 decl = NULL;
118         }
119         if (name) {
120                 cr_string_destroy (name);
121                 name = NULL;
122         }
125 static void
126 parse_font_face_end_font_face_cb (CRDocHandler * a_this)
128         CRStatement *result = NULL;
129         CRStatement **resultptr = NULL;
130         enum CRStatus status = CR_OK;
132         g_return_if_fail (a_this);
134         resultptr = &result;
135         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr);
136         g_return_if_fail (status == CR_OK && result);
137         g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT);
139         status = cr_doc_handler_set_result (a_this, result);
140         g_return_if_fail (status == CR_OK);
143 static void
144 parse_page_start_page_cb (CRDocHandler * a_this,
145                           CRString * a_name, 
146                           CRString * a_pseudo_page,
147                           CRParsingLocation * a_location)
149         CRStatement *stmt = NULL;
150         enum CRStatus status = CR_OK;
151         CRString *page_name = NULL, *pseudo_name = NULL ;
153         UNUSED(a_location);
155         if (a_name)
156                 page_name = cr_string_dup (a_name) ;
157         if (a_pseudo_page)
158                 pseudo_name = cr_string_dup (a_pseudo_page) ;
160         stmt = cr_statement_new_at_page_rule (NULL, NULL, 
161                                               page_name,
162                                               pseudo_name);
163         page_name = NULL ;
164         pseudo_name = NULL ;
165         g_return_if_fail (stmt);
166         status = cr_doc_handler_set_ctxt (a_this, stmt);
167         g_return_if_fail (status == CR_OK);
170 static void
171 parse_page_unrecoverable_error_cb (CRDocHandler * a_this)
173         CRStatement *stmt = NULL;
174         CRStatement **stmtptr = NULL;
175         enum CRStatus status = CR_OK;
177         g_return_if_fail (a_this);
179         stmtptr = &stmt;
180         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
181         if (status != CR_OK) {
182                 cr_utils_trace_info ("Couldn't get parsing context. "
183                                      "This may lead to some memory leaks.");
184                 return;
185         }
186         if (stmt) {
187                 cr_statement_destroy (stmt);
188                 stmt = NULL;
189                 cr_doc_handler_set_ctxt (a_this, NULL);
190         }
193 static void
194 parse_page_property_cb (CRDocHandler * a_this,
195                         CRString * a_name,
196                         CRTerm * a_expression, gboolean a_important)
198         CRString *name = NULL;
199         CRStatement *stmt = NULL;
200         CRStatement **stmtptr = NULL;
201         CRDeclaration *decl = NULL;
202         enum CRStatus status = CR_OK;
204         stmtptr = &stmt;
205         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
206         g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT);
208         name = cr_string_dup (a_name);
209         g_return_if_fail (name);
211         decl = cr_declaration_new (stmt, name, a_expression);
212         g_return_if_fail (decl);
213         decl->important = a_important;
214         stmt->kind.page_rule->decl_list =
215                 cr_declaration_append (stmt->kind.page_rule->decl_list, decl);
216         g_return_if_fail (stmt->kind.page_rule->decl_list);
219 static void
220 parse_page_end_page_cb (CRDocHandler * a_this,
221                         CRString * a_name, 
222                         CRString * a_pseudo_page)
224         enum CRStatus status = CR_OK;
225         CRStatement *stmt = NULL;
226         CRStatement **stmtptr = NULL;
228         UNUSED(a_name);
229         UNUSED(a_pseudo_page);
231         stmtptr = &stmt;
232         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
233         g_return_if_fail (status == CR_OK && stmt);
234         g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT);
236         status = cr_doc_handler_set_result (a_this, stmt);
237         g_return_if_fail (status == CR_OK);
240 static void
241 parse_at_media_start_media_cb (CRDocHandler * a_this, 
242                                GList * a_media_list,
243                                CRParsingLocation * a_location)
245         enum CRStatus status = CR_OK;
246         CRStatement *at_media = NULL;
247         GList *media_list = NULL;
249         UNUSED(a_location);
251         g_return_if_fail (a_this && a_this->priv);
253         if (a_media_list) {
254                 /*duplicate media list */
255                 media_list = cr_utils_dup_glist_of_cr_string 
256                         (a_media_list);
257         }
259         g_return_if_fail (media_list);
261         /*make sure cr_statement_new_at_media_rule works in this case. */
262         at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list);
264         status = cr_doc_handler_set_ctxt (a_this, at_media);
265         g_return_if_fail (status == CR_OK);
266         status = cr_doc_handler_set_result (a_this, at_media);
267         g_return_if_fail (status == CR_OK);
270 static void
271 parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this)
273         enum CRStatus status = CR_OK;
274         CRStatement *stmt = NULL;
275         CRStatement **stmtptr = NULL;
277         g_return_if_fail (a_this);
279         stmtptr = &stmt;
280         status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
281         if (status != CR_OK) {
282                 cr_utils_trace_info ("Couldn't get parsing context. "
283                                      "This may lead to some memory leaks.");
284                 return;
285         }
286         if (stmt) {
287                 cr_statement_destroy (stmt);
288                 stmt = NULL;
289                 cr_doc_handler_set_ctxt (a_this, NULL);
290                 cr_doc_handler_set_result (a_this, NULL);
291         }
294 static void
295 parse_at_media_start_selector_cb (CRDocHandler * a_this,
296                                   CRSelector * a_sellist)
298         enum CRStatus status = CR_OK;
299         CRStatement *at_media = NULL;
300         CRStatement **at_media_ptr = NULL;
301         CRStatement *ruleset = NULL;
303         g_return_if_fail (a_this && a_this->priv && a_sellist);
305         at_media_ptr = &at_media;
306         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr);
307         g_return_if_fail (status == CR_OK && at_media);
308         g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT);
309         ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media);
310         g_return_if_fail (ruleset);
311         status = cr_doc_handler_set_ctxt (a_this, ruleset);
312         g_return_if_fail (status == CR_OK);
315 static void
316 parse_at_media_property_cb (CRDocHandler * a_this,
317                             CRString * a_name, CRTerm * a_value,
318                             gboolean a_important)
320         enum CRStatus status = CR_OK;
322         /*
323          *the current ruleset stmt, child of the 
324          *current at-media being parsed.
325          */
326         CRStatement *stmt = NULL;
327         CRStatement **stmtptr = NULL;
328         CRDeclaration *decl = NULL;
329         CRString *name = NULL;
331         g_return_if_fail (a_this && a_name);
333         name = cr_string_dup (a_name) ;
334         g_return_if_fail (name);
336         stmtptr = &stmt;
337         status = cr_doc_handler_get_ctxt (a_this, 
338                                           (gpointer *) stmtptr);
339         g_return_if_fail (status == CR_OK && stmt);
340         g_return_if_fail (stmt->type == RULESET_STMT);
342         decl = cr_declaration_new (stmt, name, a_value);
343         g_return_if_fail (decl);
344         decl->important = a_important;
345         status = cr_statement_ruleset_append_decl (stmt, decl);
346         g_return_if_fail (status == CR_OK);
349 static void
350 parse_at_media_end_selector_cb (CRDocHandler * a_this, 
351                                 CRSelector * a_sellist)
353         enum CRStatus status = CR_OK;
355         /*
356          *the current ruleset stmt, child of the 
357          *current at-media being parsed.
358          */
359         CRStatement *stmt = NULL;
360         CRStatement **stmtptr = NULL;
362         g_return_if_fail (a_this && a_sellist);
364         stmtptr = &stmt;
365         status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
366         g_return_if_fail (status == CR_OK && stmt
367                           && stmt->type == RULESET_STMT);
368         g_return_if_fail (stmt->kind.ruleset->parent_media_rule);
370         status = cr_doc_handler_set_ctxt
371                 (a_this, stmt->kind.ruleset->parent_media_rule);
372         g_return_if_fail (status == CR_OK);
375 static void
376 parse_at_media_end_media_cb (CRDocHandler * a_this, 
377                              GList * a_media_list)
379         enum CRStatus status = CR_OK;
380         CRStatement *at_media = NULL;
381         CRStatement **at_media_ptr = NULL;
383         UNUSED(a_media_list);
385         g_return_if_fail (a_this && a_this->priv);
387         at_media_ptr = &at_media;
388         status = cr_doc_handler_get_ctxt (a_this, 
389                                           (gpointer *) at_media_ptr);
390         g_return_if_fail (status == CR_OK && at_media);
391         status = cr_doc_handler_set_result (a_this, at_media);
394 static void
395 parse_ruleset_start_selector_cb (CRDocHandler * a_this,
396                                  CRSelector * a_sellist)
398         CRStatement *ruleset = NULL;
400         g_return_if_fail (a_this && a_this->priv && a_sellist);
402         ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL);
403         g_return_if_fail (ruleset);
405         cr_doc_handler_set_result (a_this, ruleset);
408 static void
409 parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this)
411         CRStatement *stmt = NULL;
412         CRStatement **stmtptr = NULL;
413         enum CRStatus status = CR_OK;
415         stmtptr = &stmt;
416         status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
417         if (status != CR_OK) {
418                 cr_utils_trace_info ("Couldn't get parsing context. "
419                                      "This may lead to some memory leaks.");
420                 return;
421         }
422         if (stmt) {
423                 cr_statement_destroy (stmt);
424                 stmt = NULL;
425                 cr_doc_handler_set_result (a_this, NULL);
426         }
429 static void
430 parse_ruleset_property_cb (CRDocHandler * a_this,
431                            CRString * a_name,
432                            CRTerm * a_value, gboolean a_important)
434         enum CRStatus status = CR_OK;
435         CRStatement *ruleset = NULL;
436         CRStatement **rulesetptr = NULL;
437         CRDeclaration *decl = NULL;
438         CRString *stringue = NULL;
440         g_return_if_fail (a_this && a_this->priv && a_name);
442         stringue = cr_string_dup (a_name);
443         g_return_if_fail (stringue);
445         rulesetptr = &ruleset;
446         status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr);
447         g_return_if_fail (status == CR_OK
448                           && ruleset 
449                           && ruleset->type == RULESET_STMT);
451         decl = cr_declaration_new (ruleset, stringue, a_value);
452         g_return_if_fail (decl);
453         decl->important = a_important;
454         status = cr_statement_ruleset_append_decl (ruleset, decl);
455         g_return_if_fail (status == CR_OK);
458 static void
459 parse_ruleset_end_selector_cb (CRDocHandler * a_this, 
460                                CRSelector * a_sellist)
462         CRStatement *result = NULL;
463         CRStatement **resultptr = NULL;
464         enum CRStatus status = CR_OK;
466         g_return_if_fail (a_this && a_sellist);
468         resultptr = &result;
469         status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr);
471         g_return_if_fail (status == CR_OK
472                           && result 
473                           && result->type == RULESET_STMT);
476 static void
477 cr_statement_clear (CRStatement * a_this)
479         g_return_if_fail (a_this);
481         switch (a_this->type) {
482         case AT_RULE_STMT:
483                 break;
484         case RULESET_STMT:
485                 if (!a_this->kind.ruleset)
486                         return;
487                 if (a_this->kind.ruleset->sel_list) {
488                         cr_selector_unref (a_this->kind.ruleset->sel_list);
489                         a_this->kind.ruleset->sel_list = NULL;
490                 }
491                 if (a_this->kind.ruleset->decl_list) {
492                         cr_declaration_destroy
493                                 (a_this->kind.ruleset->decl_list);
494                         a_this->kind.ruleset->decl_list = NULL;
495                 }
496                 g_free (a_this->kind.ruleset);
497                 a_this->kind.ruleset = NULL;
498                 break;
500         case AT_IMPORT_RULE_STMT:
501                 if (!a_this->kind.import_rule)
502                         return;
503                 if (a_this->kind.import_rule->url) {
504                         cr_string_destroy 
505                                 (a_this->kind.import_rule->url) ;
506                         a_this->kind.import_rule->url = NULL;
507                 }
508                 g_free (a_this->kind.import_rule);
509                 a_this->kind.import_rule = NULL;
510                 break;
512         case AT_MEDIA_RULE_STMT:
513                 if (!a_this->kind.media_rule)
514                         return;
515                 if (a_this->kind.media_rule->rulesets) {
516                         cr_statement_destroy
517                                 (a_this->kind.media_rule->rulesets);
518                         a_this->kind.media_rule->rulesets = NULL;
519                 }
520                 if (a_this->kind.media_rule->media_list) {
521                         GList *cur = NULL;
523                         for (cur = a_this->kind.media_rule->media_list;
524                              cur; cur = cur->next) {
525                                 if (cur->data) {
526                                         cr_string_destroy ((CRString *) cur->data);
527                                         cur->data = NULL;
528                                 }
530                         }
531                         g_list_free (a_this->kind.media_rule->media_list);
532                         a_this->kind.media_rule->media_list = NULL;
533                 }
534                 g_free (a_this->kind.media_rule);
535                 a_this->kind.media_rule = NULL;
536                 break;
538         case AT_PAGE_RULE_STMT:
539                 if (!a_this->kind.page_rule)
540                         return;
542                 if (a_this->kind.page_rule->decl_list) {
543                         cr_declaration_destroy
544                                 (a_this->kind.page_rule->decl_list);
545                         a_this->kind.page_rule->decl_list = NULL;
546                 }
547                 if (a_this->kind.page_rule->name) {
548                         cr_string_destroy 
549                                 (a_this->kind.page_rule->name);
550                         a_this->kind.page_rule->name = NULL;
551                 }
552                 if (a_this->kind.page_rule->pseudo) {
553                         cr_string_destroy
554                                 (a_this->kind.page_rule->pseudo);
555                         a_this->kind.page_rule->pseudo = NULL;
556                 }
557                 g_free (a_this->kind.page_rule);
558                 a_this->kind.page_rule = NULL;
559                 break;
561         case AT_CHARSET_RULE_STMT:
562                 if (!a_this->kind.charset_rule)
563                         return;
565                 if (a_this->kind.charset_rule->charset) {
566                         cr_string_destroy
567                                 (a_this->kind.charset_rule->charset);
568                         a_this->kind.charset_rule->charset = NULL;
569                 }
570                 g_free (a_this->kind.charset_rule);
571                 a_this->kind.charset_rule = NULL;
572                 break;
574         case AT_FONT_FACE_RULE_STMT:
575                 if (!a_this->kind.font_face_rule)
576                         return;
578                 if (a_this->kind.font_face_rule->decl_list) {
579                         cr_declaration_unref
580                                 (a_this->kind.font_face_rule->decl_list);
581                         a_this->kind.font_face_rule->decl_list = NULL;
582                 }
583                 g_free (a_this->kind.font_face_rule);
584                 a_this->kind.font_face_rule = NULL;
585                 break;
587         default:
588                 break;
589         }
592 /**
593  *Serializes the ruleset statement into a string
594  *@param a_this the current instance of #CRStatement
595  *@param a_indent the number of whitespace to use for indentation
596  *@return the newly allocated serialised string. Must be freed
597  *by the caller, using g_free().
598  */
599 static gchar *
600 cr_statement_ruleset_to_string (CRStatement * a_this, glong a_indent)
602         GString *stringue = NULL;
603         gchar *tmp_str = NULL,
604                 *result = NULL;
606         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
608         stringue = g_string_new (NULL);
610         if (a_this->kind.ruleset->sel_list) {
611                 if (a_indent)
612                         cr_utils_dump_n_chars2 (' ', stringue, a_indent);
614                 tmp_str =
615                         cr_selector_to_string (a_this->kind.ruleset->
616                                                sel_list);
617                 if (tmp_str) {
618                         g_string_append (stringue, tmp_str);
619                         g_free (tmp_str);
620                         tmp_str = NULL;
621                 }
622         }
623         g_string_append (stringue, " {\n");
624         if (a_this->kind.ruleset->decl_list) {
625                 tmp_str = cr_declaration_list_to_string2
626                         (a_this->kind.ruleset->decl_list,
627                          a_indent + DECLARATION_INDENT_NB, TRUE);
628                 if (tmp_str) {
629                         g_string_append (stringue, tmp_str);
630                         g_free (tmp_str);
631                         tmp_str = NULL;
632                 }
633                 g_string_append (stringue, "\n");
634                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
635         }
636         g_string_append (stringue, "}");
637         result = stringue->str;
639         if (stringue) {
640                 g_string_free (stringue, FALSE);
641                 stringue = NULL;
642         }
643         if (tmp_str) {
644                 g_free (tmp_str);
645                 tmp_str = NULL;
646         }
647         return result;
651 /**
652  *Serializes a font face rule statement into a string.
653  *@param a_this the current instance of #CRStatement to consider
654  *It must be a font face rule statement.
655  *@param a_indent the number of white spaces of indentation.
656  *@return the serialized string. Must be deallocated by the caller
657  *using g_free().
658  */
659 static gchar *
660 cr_statement_font_face_rule_to_string (CRStatement * a_this, 
661                                        glong a_indent)
663         gchar *result = NULL, *tmp_str = NULL ;
664         GString *stringue = NULL ;
666         g_return_val_if_fail (a_this 
667                               && a_this->type == AT_FONT_FACE_RULE_STMT,
668                               NULL);
670         if (a_this->kind.font_face_rule->decl_list) {
671                 stringue = g_string_new (NULL) ;
672                 g_return_val_if_fail (stringue, NULL) ;
673                 if (a_indent)
674                         cr_utils_dump_n_chars2 (' ', stringue, 
675                                         a_indent);
676                 g_string_append (stringue, "@font-face {\n");
677                 tmp_str = cr_declaration_list_to_string2 
678                         (a_this->kind.font_face_rule->decl_list,
679                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
680                 if (tmp_str) {
681                         g_string_append (stringue,
682                                          tmp_str) ;
683                         g_free (tmp_str) ;
684                         tmp_str = NULL ;
685                 }
686                 g_string_append (stringue, "\n}");
687         }
688         if (stringue) {
689                 result = stringue->str ;
690                 g_string_free (stringue, FALSE) ;
691                 stringue = NULL ;
692         }
693         return result ;
697 /**
698  *Serialises an @charset statement into a string.
699  *@param a_this the statement to serialize.
700  *@return the serialized charset statement. Must be
701  *freed by the caller using g_free().
702  */
703 static gchar *
704 cr_statement_charset_to_string (CRStatement *a_this, 
705                                 gulong a_indent)
707         gchar *str = NULL ;
708         GString *stringue = NULL ;
710         g_return_val_if_fail (a_this
711                               && a_this->type == AT_CHARSET_RULE_STMT,
712                               NULL) ;
714         if (a_this->kind.charset_rule
715             && a_this->kind.charset_rule->charset
716             && a_this->kind.charset_rule->charset->stryng
717             && a_this->kind.charset_rule->charset->stryng->str) {
718                 str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
719                                  a_this->kind.charset_rule->charset->stryng->len);
720                 g_return_val_if_fail (str, NULL);
721                 stringue = g_string_new (NULL) ;
722                 g_return_val_if_fail (stringue, NULL) ;
723                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
724                 g_string_append_printf (stringue, 
725                                         "@charset \"%s\" ;", str);
726                 if (str) {
727                         g_free (str);
728                         str = NULL;
729                 }
730         }
731         if (stringue) {
732                 str = stringue->str ;
733                 g_string_free (stringue, FALSE) ;
734         }
735         return str ;
739 /**
740  *Serialises the at page rule statement into a string
741  *@param a_this the current instance of #CRStatement. Must
742  *be an "@page" rule statement.
743  *@return the serialized string. Must be freed by the caller
744  */
745 static gchar *
746 cr_statement_at_page_rule_to_string (CRStatement *a_this,
747                                      gulong a_indent)
749         GString *stringue = NULL;
750         gchar *result = NULL ;
752         stringue = g_string_new (NULL) ;
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 ;
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 *a_this,
799                                    gulong a_indent)
801         gchar *str = NULL ;
802         GString *stringue = NULL ;
803         GList *cur = NULL;
805         g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
806                               NULL);
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");
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 *) cur->data);
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 ;
852 static gchar *
853 cr_statement_import_rule_to_string (CRStatement *a_this,
854                                     gulong a_indent)
856         GString *stringue = NULL ;
857         guchar *str = NULL;
859         g_return_val_if_fail (a_this
860                               && a_this->type == AT_IMPORT_RULE_STMT
861                               && a_this->kind.import_rule,
862                               NULL) ;
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;
880                 if (a_this->kind.import_rule->media_list) {
881                         GList *cur = NULL;
883                         for (cur = a_this->kind.import_rule->media_list;
884                              cur; cur = cur->next) {
885                                 if (cur->data) {
886                                         CRString *crstr = cur->data;
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 ;
914 /*******************
915  *public functions
916  ******************/
918 /**
919  *Tries to parse a buffer and says whether if the content of the buffer
920  *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
921  *css spec) or not.
922  *@param a_buf the buffer to parse.
923  *@param a_encoding the character encoding of a_buf.
924  *@return TRUE if the buffer parses against the core grammar, false otherwise.
925  */
926 gboolean
927 cr_statement_does_buf_parses_against_core (const guchar * a_buf,
928                                            enum CREncoding a_encoding)
930         CRParser *parser = NULL;
931         enum CRStatus status = CR_OK;
932         gboolean result = FALSE;
934         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
935                                          a_encoding, FALSE);
936         g_return_val_if_fail (parser, FALSE);
938         status = cr_parser_set_use_core_grammar (parser, TRUE);
939         if (status != CR_OK) {
940                 goto cleanup;
941         }
943         status = cr_parser_parse_statement_core (parser);
944         if (status == CR_OK) {
945                 result = TRUE;
946         }
948       cleanup:
949         if (parser) {
950                 cr_parser_destroy (parser);
951         }
953         return result;
956 /**
957  *Parses a buffer that contains a css statement and returns 
958  *an instance of #CRStatement in case of successfull parsing.
959  *TODO: at support of "@import" rules.
960  *@param a_buf the buffer to parse.
961  *@param a_encoding the character encoding of a_buf.
962  *@return the newly built instance of #CRStatement in case
963  *of successfull parsing, NULL otherwise.
964  */
965 CRStatement *
966 cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
968         CRStatement *result = NULL;
970         /*
971          *The strategy of this function is "brute force".
972          *It tries to parse all the types of #CRStatement it knows about.
973          *I could do this a smarter way but I don't have the time now.
974          *I think I will revisit this when time of performances and
975          *pull based incremental parsing comes.
976          */
978         result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
979         if (!result) {
980                 result = cr_statement_at_charset_rule_parse_from_buf
981                         (a_buf, a_encoding);
982         } else {
983                 goto out;
984         }
986         if (!result) {
987                 result = cr_statement_at_media_rule_parse_from_buf
988                         (a_buf, a_encoding);
989         } else {
990                 goto out;
991         }
993         if (!result) {
994                 result = cr_statement_at_charset_rule_parse_from_buf
995                         (a_buf, a_encoding);
996         } else {
997                 goto out;
998         }
1000         if (!result) {
1001                 result = cr_statement_font_face_rule_parse_from_buf
1002                         (a_buf, a_encoding);
1004         } else {
1005                 goto out;
1006         }
1008         if (!result) {
1009                 result = cr_statement_at_page_rule_parse_from_buf
1010                         (a_buf, a_encoding);
1011         } else {
1012                 goto out;
1013         }
1015         if (!result) {
1016                 result = cr_statement_at_import_rule_parse_from_buf
1017                         (a_buf, a_encoding);
1018         } else {
1019                 goto out;
1020         }
1022       out:
1023         return result;
1026 /**
1027  *Parses a buffer that contains a ruleset statement and instanciates
1028  *a #CRStatement of type RULESET_STMT.
1029  *@param a_buf the buffer to parse.
1030  *@param a_enc the character encoding of a_buf.
1031  *@param the newly built instance of #CRStatement in case of successful parsing,
1032  *NULL otherwise.
1033  */
1034 CRStatement *
1035 cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
1036                                      enum CREncoding a_enc)
1038         enum CRStatus status = CR_OK;
1039         CRStatement *result = NULL;
1040         CRStatement **resultptr = NULL;
1041         CRParser *parser = NULL;
1042         CRDocHandler *sac_handler = NULL;
1044         g_return_val_if_fail (a_buf, NULL);
1046         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 
1047                                          a_enc, FALSE);
1049         g_return_val_if_fail (parser, NULL);
1051         sac_handler = cr_doc_handler_new ();
1052         g_return_val_if_fail (sac_handler, NULL);
1054         sac_handler->start_selector = parse_ruleset_start_selector_cb;
1055         sac_handler->end_selector = parse_ruleset_end_selector_cb;
1056         sac_handler->property = parse_ruleset_property_cb;
1057         sac_handler->unrecoverable_error =
1058                 parse_ruleset_unrecoverable_error_cb;
1060         cr_parser_set_sac_handler (parser, sac_handler);
1061         cr_parser_try_to_skip_spaces_and_comments (parser);
1062         status = cr_parser_parse_ruleset (parser);
1063         if (status != CR_OK) {
1064                 goto cleanup;
1065         }
1067         resultptr = &result;
1068         status = cr_doc_handler_get_result (sac_handler,
1069                                             (gpointer *) resultptr);
1070         if (!((status == CR_OK) && result)) {
1071                 if (result) {
1072                         cr_statement_destroy (result);
1073                         result = NULL;
1074                 }
1075         }
1077       cleanup:
1078         if (parser) {
1079                 cr_parser_destroy (parser);
1080                 parser = NULL;
1081                 sac_handler = NULL ;
1082         }
1083         if (sac_handler) {
1084                 cr_doc_handler_unref (sac_handler);
1085                 sac_handler = NULL;
1086         }
1087         return result;
1090 /**
1091  *Creates a new instance of #CRStatement of type
1092  *#CRRulSet.
1093  *@param a_sel_list the list of #CRSimpleSel (selectors)
1094  *the rule applies to.
1095  *@param a_decl_list the list of instances of #CRDeclaration
1096  *that composes the ruleset.
1097  *@param a_media_types a list of instances of GString that
1098  *describe the media list this ruleset applies to.
1099  *@return the new instance of #CRStatement or NULL if something
1100  *went wrong.
1101  */
1102 CRStatement *
1103 cr_statement_new_ruleset (CRStyleSheet * a_sheet,
1104                           CRSelector * a_sel_list,
1105                           CRDeclaration * a_decl_list,
1106                           CRStatement * a_parent_media_rule)
1108         CRStatement *result = NULL;
1110         g_return_val_if_fail (a_sel_list, NULL);
1112         if (a_parent_media_rule) {
1113                 g_return_val_if_fail
1114                         (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
1115                          NULL);
1116                 g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
1117                                       NULL);
1118         }
1120         result = g_try_malloc (sizeof (CRStatement));
1122         if (!result) {
1123                 cr_utils_trace_info ("Out of memory");
1124                 return NULL;
1125         }
1127         memset (result, 0, sizeof (CRStatement));
1128         result->type = RULESET_STMT;
1129         result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet));
1131         if (!result->kind.ruleset) {
1132                 cr_utils_trace_info ("Out of memory");
1133                 if (result)
1134                         g_free (result);
1135                 return NULL;
1136         }
1138         memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
1139         result->kind.ruleset->sel_list = a_sel_list;
1140         if (a_sel_list)
1141                 cr_selector_ref (a_sel_list);
1142         result->kind.ruleset->decl_list = a_decl_list;
1144         if (a_parent_media_rule) {
1145                 result->kind.ruleset->parent_media_rule = a_parent_media_rule;
1146                 a_parent_media_rule->kind.media_rule->rulesets =
1147                         cr_statement_append
1148                         (a_parent_media_rule->kind.media_rule->rulesets,
1149                          result);
1150         }
1152         cr_statement_set_parent_sheet (result, a_sheet);
1154         return result;
1157 /**
1158  *Parses a buffer that contains an "@media" declaration
1159  *and builds an @media css statement.
1160  *@param a_buf the input to parse.
1161  *@param a_enc the encoding of the buffer.
1162  *@return the @media statement, or NULL if the buffer could not
1163  *be successfully parsed.
1164  */
1165 CRStatement *
1166 cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
1167                                            enum CREncoding a_enc)
1169         CRParser *parser = NULL;
1170         CRStatement *result = NULL;
1171         CRStatement **resultptr = NULL;
1172         CRDocHandler *sac_handler = NULL;
1173         enum CRStatus status = CR_OK;
1175         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf), 
1176                                          a_enc, FALSE);
1177         if (!parser) {
1178                 cr_utils_trace_info ("Instanciation of the parser failed");
1179                 goto cleanup;
1180         }
1182         sac_handler = cr_doc_handler_new ();
1183         if (!sac_handler) {
1184                 cr_utils_trace_info
1185                         ("Instanciation of the sac handler failed");
1186                 goto cleanup;
1187         }
1189         sac_handler->start_media = parse_at_media_start_media_cb;
1190         sac_handler->start_selector = parse_at_media_start_selector_cb;
1191         sac_handler->property = parse_at_media_property_cb;
1192         sac_handler->end_selector = parse_at_media_end_selector_cb;
1193         sac_handler->end_media = parse_at_media_end_media_cb;
1194         sac_handler->unrecoverable_error =
1195                 parse_at_media_unrecoverable_error_cb;
1197         status = cr_parser_set_sac_handler (parser, sac_handler);
1198         if (status != CR_OK)
1199                 goto cleanup;
1201         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1202         if (status != CR_OK)
1203                 goto cleanup;
1205         status = cr_parser_parse_media (parser);
1206         if (status != CR_OK)
1207                 goto cleanup;
1209         resultptr = &result;
1210         status = cr_doc_handler_get_result (sac_handler,
1211                                             (gpointer *) resultptr);
1212         if (status != CR_OK)
1213                 goto cleanup;
1215       cleanup:
1217         if (parser) {
1218                 cr_parser_destroy (parser);
1219                 parser = NULL;
1220                 sac_handler = NULL ;
1221         }
1222         if (sac_handler) {
1223                 cr_doc_handler_unref (sac_handler);
1224                 sac_handler = NULL;
1225         }
1227         return result;
1230 /**
1231  *Instanciates an instance of #CRStatement of type
1232  *AT_MEDIA_RULE_STMT (@media ruleset).
1233  *@param a_ruleset the ruleset statements contained
1234  *in the @media rule.
1235  *@param a_media, the media string list. A list of GString pointers.
1236  */
1237 CRStatement *
1238 cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
1239                                 CRStatement * a_rulesets, GList * a_media)
1241         CRStatement *result = NULL,
1242                 *cur = NULL;
1244         if (a_rulesets)
1245                 g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
1247         result = g_try_malloc (sizeof (CRStatement));
1249         if (!result) {
1250                 cr_utils_trace_info ("Out of memory");
1251                 return NULL;
1252         }
1254         memset (result, 0, sizeof (CRStatement));
1255         result->type = AT_MEDIA_RULE_STMT;
1257         result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule));
1258         if (!result->kind.media_rule) {
1259                 cr_utils_trace_info ("Out of memory");
1260                 g_free (result);
1261                 return NULL;
1262         }
1263         memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
1264         result->kind.media_rule->rulesets = a_rulesets;
1265         for (cur = a_rulesets; cur; cur = cur->next) {
1266                 if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
1267                         cr_utils_trace_info ("Bad parameter a_rulesets. "
1268                                              "It should be a list of "
1269                                              "correct ruleset statement only !");
1270                         goto error;
1271                 }
1272                 cur->kind.ruleset->parent_media_rule = result;
1273         }
1275         result->kind.media_rule->media_list = a_media;
1276         if (a_sheet) {
1277                 cr_statement_set_parent_sheet (result, a_sheet);
1278         }
1280         return result;
1282       error:
1283         return NULL;
1286 /**
1287  *Creates a new instance of #CRStatment of type
1288  *#CRAtImportRule.
1289  *@param a_url the url to connect to the get the file
1290  *to be imported.
1291  *@param a_sheet the imported parsed stylesheet.
1292  *@return the newly built instance of #CRStatement.
1293  */
1294 CRStatement *
1295 cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
1296                                  CRString * a_url,
1297                                  GList * a_media_list,
1298                                  CRStyleSheet * a_imported_sheet)
1300         CRStatement *result = NULL;
1302         result = g_try_malloc (sizeof (CRStatement));
1304         if (!result) {
1305                 cr_utils_trace_info ("Out of memory");
1306                 return NULL;
1307         }
1309         memset (result, 0, sizeof (CRStatement));
1310         result->type = AT_IMPORT_RULE_STMT;
1312         result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule));
1314         if (!result->kind.import_rule) {
1315                 cr_utils_trace_info ("Out of memory");
1316                 g_free (result);
1317                 return NULL;
1318         }
1320         memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
1321         result->kind.import_rule->url = a_url;
1322         result->kind.import_rule->media_list = a_media_list;
1323         result->kind.import_rule->sheet = a_imported_sheet;
1324         if (a_container_sheet)
1325                 cr_statement_set_parent_sheet (result, a_container_sheet);
1327         return result;
1330 /**
1331  *Parses a buffer that contains an "@import" rule and
1332  *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
1333  *@param a_buf the buffer to parse.
1334  *@param a_encoding the encoding of a_buf.
1335  *@return the newly built instance of #CRStatement in case of 
1336  *a successfull parsing, NULL otherwise.
1337  */
1338 CRStatement *
1339 cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
1340                                             enum CREncoding a_encoding)
1342         enum CRStatus status = CR_OK;
1343         CRParser *parser = NULL;
1344         CRStatement *result = NULL;
1345         GList *media_list = NULL;
1346         CRString *import_string = NULL;
1347         CRParsingLocation location = {0,0,0} ;
1349         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1350                                          a_encoding, FALSE);
1351         if (!parser) {
1352                 cr_utils_trace_info ("Instanciation of parser failed.");
1353                 goto cleanup;
1354         }
1356         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1357         if (status != CR_OK)
1358                 goto cleanup;
1360         status = cr_parser_parse_import (parser,
1361                                          &media_list, 
1362                                          &import_string,
1363                                          &location);
1364         if (status != CR_OK || !import_string)
1365                 goto cleanup;
1367         result = cr_statement_new_at_import_rule (NULL, import_string,
1368                                                   media_list, NULL);
1369         if (result) {
1370                 cr_parsing_location_copy (&result->location,
1371                                           &location) ;
1372                 import_string = NULL;
1373                 media_list = NULL;
1374         }
1376  cleanup:
1377         if (parser) {
1378                 cr_parser_destroy (parser);
1379                 parser = NULL;
1380         }
1381         if (media_list) {
1382                 GList *cur = NULL;
1384                 for (cur = media_list; media_list;
1385                      media_list = g_list_next (media_list)) {
1386                         if (media_list->data) {
1387                                 cr_string_destroy ((CRString*)media_list->data);
1388                                 media_list->data = NULL;
1389                         }
1390                 }
1391                 g_list_free (media_list);
1392                 media_list = NULL;
1393         }
1394         if (import_string) {
1395                 cr_string_destroy (import_string);
1396                 import_string = NULL;
1397         }
1399         return result;
1402 /**
1403  *Creates a new instance of #CRStatement of type
1404  *#CRAtPageRule.
1405  *@param a_decl_list a list of instances of #CRDeclarations
1406  *which is actually the list of declarations that applies to
1407  *this page rule.
1408  *@param a_selector the page rule selector.
1409  *@return the newly built instance of #CRStatement or NULL
1410  *in case of error.
1411  */
1412 CRStatement *
1413 cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
1414                                CRDeclaration * a_decl_list,
1415                                CRString * a_name, CRString * a_pseudo)
1417         CRStatement *result = NULL;
1419         result = g_try_malloc (sizeof (CRStatement));
1421         if (!result) {
1422                 cr_utils_trace_info ("Out of memory");
1423                 return NULL;
1424         }
1426         memset (result, 0, sizeof (CRStatement));
1427         result->type = AT_PAGE_RULE_STMT;
1429         result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule));
1431         if (!result->kind.page_rule) {
1432                 cr_utils_trace_info ("Out of memory");
1433                 g_free (result);
1434                 return NULL;
1435         }
1437         memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
1438         if (a_decl_list) {
1439                 result->kind.page_rule->decl_list = a_decl_list;
1440                 cr_declaration_ref (a_decl_list);
1441         }
1442         result->kind.page_rule->name = a_name;
1443         result->kind.page_rule->pseudo = a_pseudo;
1444         if (a_sheet)
1445                 cr_statement_set_parent_sheet (result, a_sheet);
1447         return result;
1450 /**
1451  *Parses a buffer that contains an "@page" production and,
1452  *if the parsing succeeds, builds the page statement.
1453  *@param a_buf the character buffer to parse.
1454  *@param a_encoding the character encoding of a_buf.
1455  *@return the newly built at page statement in case of successfull parsing,
1456  *NULL otherwise.
1457  */
1458 CRStatement *
1459 cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
1460                                           enum CREncoding a_encoding)
1462         enum CRStatus status = CR_OK;
1463         CRParser *parser = NULL;
1464         CRDocHandler *sac_handler = NULL;
1465         CRStatement *result = NULL;
1466         CRStatement **resultptr = NULL;
1468         g_return_val_if_fail (a_buf, NULL);
1470         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1471                                          a_encoding, FALSE);
1472         if (!parser) {
1473                 cr_utils_trace_info ("Instanciation of the parser failed.");
1474                 goto cleanup;
1475         }
1477         sac_handler = cr_doc_handler_new ();
1478         if (!sac_handler) {
1479                 cr_utils_trace_info
1480                         ("Instanciation of the sac handler failed.");
1481                 goto cleanup;
1482         }
1484         sac_handler->start_page = parse_page_start_page_cb;
1485         sac_handler->property = parse_page_property_cb;
1486         sac_handler->end_page = parse_page_end_page_cb;
1487         sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
1489         status = cr_parser_set_sac_handler (parser, sac_handler);
1490         if (status != CR_OK)
1491                 goto cleanup;
1493         /*Now, invoke the parser to parse the "@page production" */
1494         cr_parser_try_to_skip_spaces_and_comments (parser);
1495         if (status != CR_OK)
1496                 goto cleanup;
1497         status = cr_parser_parse_page (parser);
1498         if (status != CR_OK)
1499                 goto cleanup;
1501         resultptr = &result;
1502         status = cr_doc_handler_get_result (sac_handler,
1503                                             (gpointer *) resultptr);
1505       cleanup:
1507         if (parser) {
1508                 cr_parser_destroy (parser);
1509                 parser = NULL;
1510                 sac_handler = NULL ;
1511         }
1512         if (sac_handler) {
1513                 cr_doc_handler_unref (sac_handler);
1514                 sac_handler = NULL;
1515         }
1516         return result;
1519 /**
1520  *Creates a new instance of #CRStatement of type
1521  *#CRAtCharsetRule.
1522  *@param a_charset the string representing the charset.
1523  *Note that the newly built instance of #CRStatement becomes
1524  *the owner of a_charset. The caller must not free a_charset !!!.
1525  *@return the newly built instance of #CRStatement or NULL
1526  *if an error arises.
1527  */
1528 CRStatement *
1529 cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 
1530                                   CRString * a_charset)
1532         CRStatement *result = NULL;
1534         g_return_val_if_fail (a_charset, NULL);
1536         result = g_try_malloc (sizeof (CRStatement));
1538         if (!result) {
1539                 cr_utils_trace_info ("Out of memory");
1540                 return NULL;
1541         }
1543         memset (result, 0, sizeof (CRStatement));
1544         result->type = AT_CHARSET_RULE_STMT;
1546         result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule));
1548         if (!result->kind.charset_rule) {
1549                 cr_utils_trace_info ("Out of memory");
1550                 g_free (result);
1551                 return NULL;
1552         }
1553         memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
1554         result->kind.charset_rule->charset = a_charset;
1555         cr_statement_set_parent_sheet (result, a_sheet);
1557         return result;
1560 /**
1561  *Parses a buffer that contains an '@charset' rule and
1562  *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
1563  *@param a_buf the buffer to parse.
1564  *@param the character encoding of the buffer.
1565  *@return the newly built instance of #CRStatement.
1566  */
1567 CRStatement *
1568 cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
1569                                              enum CREncoding a_encoding)
1571         enum CRStatus status = CR_OK;
1572         CRParser *parser = NULL;
1573         CRStatement *result = NULL;
1574         CRString *charset = NULL;
1576         g_return_val_if_fail (a_buf, NULL);
1578         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1579                                          a_encoding, FALSE);
1580         if (!parser) {
1581                 cr_utils_trace_info ("Instanciation of the parser failed.");
1582                 goto cleanup;
1583         }
1585         /*Now, invoke the parser to parse the "@charset production" */
1586         cr_parser_try_to_skip_spaces_and_comments (parser);
1587         if (status != CR_OK)
1588                 goto cleanup;
1589         status = cr_parser_parse_charset (parser, &charset, NULL);
1590         if (status != CR_OK || !charset)
1591                 goto cleanup;
1593         result = cr_statement_new_at_charset_rule (NULL, charset);
1594         if (result)
1595                 charset = NULL;
1597       cleanup:
1599         if (parser) {
1600                 cr_parser_destroy (parser);
1601                 parser = NULL;
1602         }
1603         if (charset) {
1604                 cr_string_destroy (charset);
1605         }
1607         return result;
1610 /**
1611  *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
1612  *@param a_font_decls a list of instances of #CRDeclaration. Each declaration
1613  *is actually a font declaration.
1614  *@return the newly built instance of #CRStatement.
1615  */
1616 CRStatement *
1617 cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
1618                                     CRDeclaration * a_font_decls)
1620         CRStatement *result = NULL;
1622         result = g_try_malloc (sizeof (CRStatement));
1624         if (!result) {
1625                 cr_utils_trace_info ("Out of memory");
1626                 return NULL;
1627         }
1628         memset (result, 0, sizeof (CRStatement));
1629         result->type = AT_FONT_FACE_RULE_STMT;
1631         result->kind.font_face_rule = g_try_malloc
1632                 (sizeof (CRAtFontFaceRule));
1634         if (!result->kind.font_face_rule) {
1635                 cr_utils_trace_info ("Out of memory");
1636                 g_free (result);
1637                 return NULL;
1638         }
1639         memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
1641         result->kind.font_face_rule->decl_list = a_font_decls;
1642         if (a_sheet)
1643                 cr_statement_set_parent_sheet (result, a_sheet);
1645         return result;
1648 /**
1649  *Parses a buffer that contains an "@font-face" rule and builds
1650  *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
1651  *@param a_buf the buffer to parse.
1652  *@param a_encoding the character encoding of a_buf.
1653  *@return the newly built instance of #CRStatement in case of successufull
1654  *parsing, NULL otherwise.
1655  */
1656 CRStatement *
1657 cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
1658                                             enum CREncoding a_encoding)
1660         CRStatement *result = NULL;
1661         CRStatement **resultptr = NULL;
1662         CRParser *parser = NULL;
1663         CRDocHandler *sac_handler = NULL;
1664         enum CRStatus status = CR_OK;
1666         parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen (a_buf),
1667                                          a_encoding, FALSE);
1668         if (!parser)
1669                 goto cleanup;
1671         sac_handler = cr_doc_handler_new ();
1672         if (!sac_handler)
1673                 goto cleanup;
1675         /*
1676          *set sac callbacks here
1677          */
1678         sac_handler->start_font_face = parse_font_face_start_font_face_cb;
1679         sac_handler->property = parse_font_face_property_cb;
1680         sac_handler->end_font_face = parse_font_face_end_font_face_cb;
1681         sac_handler->unrecoverable_error =
1682                 parse_font_face_unrecoverable_error_cb;
1684         status = cr_parser_set_sac_handler (parser, sac_handler);
1685         if (status != CR_OK)
1686                 goto cleanup;
1688         /*
1689          *cleanup spaces of comment that may be there before the real
1690          *"@font-face" thing.
1691          */
1692         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1693         if (status != CR_OK)
1694                 goto cleanup;
1696         status = cr_parser_parse_font_face (parser);
1697         if (status != CR_OK)
1698                 goto cleanup;
1700         resultptr = &result;
1701         status = cr_doc_handler_get_result (sac_handler,
1702                                             (gpointer *) resultptr);
1703         if (status != CR_OK || !result)
1704                 goto cleanup;
1706       cleanup:
1707         if (parser) {
1708                 cr_parser_destroy (parser);
1709                 parser = NULL;
1710                 sac_handler = NULL ;
1711         }
1712         if (sac_handler) {
1713                 cr_doc_handler_unref (sac_handler);
1714                 sac_handler = NULL;
1715         }
1716         return result;
1719 /**
1720  *Sets the container stylesheet.
1721  *@param a_this the current instance of #CRStatement.
1722  *@param a_sheet the sheet that contains the current statement.
1723  *@return CR_OK upon successfull completion, an errror code otherwise.
1724  */
1725 enum CRStatus
1726 cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
1728         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
1729         a_this->parent_sheet = a_sheet;
1730         return CR_OK;
1733 /**
1734  *Gets the sheets that contains the current statement.
1735  *@param a_this the current #CRStatement.
1736  *@param a_sheet out parameter. A pointer to the sheets that
1737  *@return CR_OK upon successfull completion, an error code otherwise.
1738  */
1739 enum CRStatus
1740 cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
1742         g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
1743         *a_sheet = a_this->parent_sheet;
1744         return CR_OK;
1747 /**
1748  *Appends a new statement to the statement list.
1749  *@param a_this the current instance of the statement list.
1750  *@param a_this a_new the new instance of #CRStatement to append.
1751  *@return the new list statement list, or NULL in cas of failure.
1752  */
1753 CRStatement *
1754 cr_statement_append (CRStatement * a_this, CRStatement * a_new)
1756         CRStatement *cur = NULL;
1758         g_return_val_if_fail (a_new, NULL);
1760         if (!a_this) {
1761                 return a_new;
1762         }
1764         /*walk forward in the current list to find the tail list element */
1765         for (cur = a_this; cur && cur->next; cur = cur->next) ;
1767         cur->next = a_new;
1768         a_new->prev = cur;
1770         return a_this;
1773 /**
1774  *Prepends the an instance of #CRStatement to
1775  *the current statement list.
1776  *@param a_this the current instance of #CRStatement.
1777  *@param a_new the new statement to prepend.
1778  *@return the new list with the new statement prepended,
1779  *or NULL in case of an error.
1780  */
1781 CRStatement *
1782 cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
1784         CRStatement *cur = NULL;
1786         g_return_val_if_fail (a_new, NULL);
1788         if (!a_this)
1789                 return a_new;
1791         a_new->next = a_this;
1792         a_this->prev = a_new;
1794         /*walk backward in the prepended list to find the head list element */
1795         for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
1797         return cur;
1800 /**
1801  *Unlinks a statement from the statements list.
1802  *@param a_this the current statements list.
1803  *@param a_to_unlink the statement to unlink from the list.
1804  *@return the new list where a_to_unlink has been unlinked
1805  *from, or NULL in case of error.
1806  */
1807 CRStatement *
1808 cr_statement_unlink (CRStatement * a_stmt)
1810         CRStatement *result = a_stmt;
1812         g_return_val_if_fail (result, NULL);
1814         /**
1815          *Some sanity checks first
1816          */
1817         if (a_stmt->next) {
1818                 g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
1819         }
1820         if (a_stmt->prev) {
1821                 g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
1822         }
1824         /**
1825          *Now, the real unlinking job.
1826          */
1827         if (a_stmt->next) {
1828                 a_stmt->next->prev = a_stmt->prev;
1829         }
1830         if (a_stmt->prev) {
1831                 a_stmt->prev->next = a_stmt->next;
1832         }
1834         if (a_stmt->parent_sheet
1835             && a_stmt->parent_sheet->statements == a_stmt) {
1836                 a_stmt->parent_sheet->statements =
1837                         a_stmt->parent_sheet->statements->next;
1838         }
1840         a_stmt->next = NULL;
1841         a_stmt->prev = NULL;
1842         a_stmt->parent_sheet = NULL;
1844         return result;
1847 /**
1848  *Return the number of rules in the statement list;
1849  *@param a_this the current instance of #CRStatement.
1850  *@return number of rules in the statement list.
1851  */
1852 gint
1853 cr_statement_nr_rules (CRStatement * a_this)
1855         CRStatement *cur = NULL;
1856         int nr = 0;
1858         g_return_val_if_fail (a_this, -1);
1860         for (cur = a_this; cur; cur = cur->next)
1861                 nr++;
1862         return nr;
1865 /**
1866  *Use an index to get a CRStatement from the statement list.
1867  *@param a_this the current instance of #CRStatement.
1868  *@param itemnr the index into the statement list.
1869  *@return CRStatement at position itemnr, if itemnr > number of statements - 1,
1870  *it will return NULL.
1871  */
1872 CRStatement *
1873 cr_statement_get_from_list (CRStatement * a_this, int itemnr)
1875         CRStatement *cur = NULL;
1876         int nr = 0;
1878         g_return_val_if_fail (a_this, NULL);
1880         for (cur = a_this; cur; cur = cur->next)
1881                 if (nr++ == itemnr)
1882                         return cur;
1883         return NULL;
1886 /**
1887  *Sets a selector list to a ruleset statement.
1888  *@param a_this the current ruleset statement.
1889  *@param a_sel_list the selector list to set. Note
1890  *that this function increments the ref count of a_sel_list.
1891  *The sel list will be destroyed at the destruction of the
1892  *current instance of #CRStatement.
1893  *@return CR_OK upon successfull completion, an error code otherwise.
1894  */
1895 enum CRStatus
1896 cr_statement_ruleset_set_sel_list (CRStatement * a_this,
1897                                    CRSelector * a_sel_list)
1899         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
1900                               CR_BAD_PARAM_ERROR);
1902         if (a_this->kind.ruleset->sel_list)
1903                 cr_selector_unref (a_this->kind.ruleset->sel_list);
1905         a_this->kind.ruleset->sel_list = a_sel_list;
1907         if (a_sel_list)
1908                 cr_selector_ref (a_sel_list);
1910         return CR_OK;
1913 /**
1914  *Gets a pointer to the list of declaration contained
1915  *in the ruleset statement.
1916  *@param a_this the current instance of #CRStatement.
1917  *@a_decl_list out parameter. A pointer to the the returned
1918  *list of declaration. Must not be NULL.
1919  *@return CR_OK upon successfull completion, an error code if something
1920  *bad happened.
1921  */
1922 enum CRStatus
1923 cr_statement_ruleset_get_declarations (CRStatement * a_this,
1924                                        CRDeclaration ** a_decl_list)
1926         g_return_val_if_fail (a_this
1927                               && a_this->type == RULESET_STMT
1928                               && a_this->kind.ruleset
1929                               && a_decl_list, CR_BAD_PARAM_ERROR);
1931         *a_decl_list = a_this->kind.ruleset->decl_list;
1933         return CR_OK;
1936 /**
1937  *Gets a pointer to the selector list contained in
1938  *the current ruleset statement.
1939  *@param a_this the current ruleset statement.
1940  *@param a_list out parameter. The returned selector list,
1941  *if and only if the function returned CR_OK.
1942  *@return CR_OK upon successfull completion, an error code otherwise.
1943  */
1944 enum CRStatus
1945 cr_statement_ruleset_get_sel_list (CRStatement * a_this, CRSelector ** a_list)
1947         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
1948                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
1950         *a_list = a_this->kind.ruleset->sel_list;
1952         return CR_OK;
1955 /**
1956  *Sets a declaration list to the current ruleset statement.
1957  *@param a_this the current ruleset statement.
1958  *@param a_list the declaration list to be added to the current
1959  *ruleset statement.
1960  *@return CR_OK upon successfull completion, an error code otherwise.
1961  */
1962 enum CRStatus
1963 cr_statement_ruleset_set_decl_list (CRStatement * a_this,
1964                                     CRDeclaration * a_list)
1966         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
1967                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
1969         if (a_this->kind.ruleset->decl_list == a_list)
1970                 return CR_OK;
1972         if (a_this->kind.ruleset->sel_list) {
1973                 cr_declaration_destroy (a_this->kind.ruleset->decl_list);
1974         }
1976         a_this->kind.ruleset->sel_list = NULL;
1978         return CR_OK;
1981 /**
1982  *Appends a declaration to the current ruleset statement.
1983  *@param a_this the current statement.
1984  *@param a_prop the property of the declaration.
1985  *@param a_value the value of the declaration.
1986  *@return CR_OK uppon successfull completion, an error code
1987  *otherwise.
1988  */
1989 enum CRStatus
1990 cr_statement_ruleset_append_decl2 (CRStatement * a_this,
1991                                    CRString * a_prop, 
1992                                    CRTerm * a_value)
1994         CRDeclaration *new_decls = NULL;
1996         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
1997                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
1999         new_decls = cr_declaration_append2
2000                 (a_this->kind.ruleset->decl_list, 
2001                  a_prop, a_value);
2002         g_return_val_if_fail (new_decls, CR_ERROR);
2003         a_this->kind.ruleset->decl_list = new_decls;
2005         return CR_OK;
2008 /**
2009  *Appends a declaration to the current statement.
2010  *@param a_this the current statement.
2011  *@param a_declaration the declaration to append.
2012  *@return CR_OK upon sucessfull completion, an error code
2013  *otherwise.
2014  */
2015 enum CRStatus
2016 cr_statement_ruleset_append_decl (CRStatement * a_this,
2017                                   CRDeclaration * a_decl)
2019         CRDeclaration *new_decls = NULL;
2021         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
2022                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
2024         new_decls = cr_declaration_append
2025                 (a_this->kind.ruleset->decl_list, a_decl);
2026         g_return_val_if_fail (new_decls, CR_ERROR);
2027         a_this->kind.ruleset->decl_list = new_decls;
2029         return CR_OK;
2032 /**
2033  *Sets a stylesheet to the current @import rule.
2034  *@param a_this the current @import rule.
2035  *@param a_sheet the stylesheet. The stylesheet is owned
2036  *by the current instance of #CRStatement, that is, the 
2037  *stylesheet will be destroyed when the current instance
2038  *of #CRStatement will be destroyed.
2039  *@return CR_OK upon successfull completion, an error code otherwise.
2040  */
2041 enum CRStatus
2042 cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
2043                                                 CRStyleSheet * a_sheet)
2045         g_return_val_if_fail (a_this
2046                               && a_this->type == AT_IMPORT_RULE_STMT
2047                               && a_this->kind.import_rule,
2048                               CR_BAD_PARAM_ERROR);
2050         a_this->kind.import_rule->sheet = a_sheet;
2052         return CR_OK;
2055 /**
2056  *Gets the stylesheet contained by the @import rule statement.
2057  *@param a_this the current @import rule statement.
2058  *@param a_sheet out parameter. The returned stylesheet if and
2059  *only if the function returns CR_OK.
2060  *@return CR_OK upon sucessfull completion, an error code otherwise.
2061  */
2062 enum CRStatus
2063 cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
2064                                                 CRStyleSheet ** a_sheet)
2066         g_return_val_if_fail (a_this
2067                               && a_this->type == AT_IMPORT_RULE_STMT
2068                               && a_this->kind.import_rule,
2069                               CR_BAD_PARAM_ERROR);
2070         *a_sheet = a_this->kind.import_rule->sheet;
2071         return CR_OK;
2075 /**
2076  *Sets an url to the current @import rule statement.
2077  *@param a_this the current @import rule statement.
2078  *@param a_url the url to set.
2079  *@return CR_OK upon successfull completion, an error code otherwise.
2080  */
2081 enum CRStatus
2082 cr_statement_at_import_rule_set_url (CRStatement * a_this, 
2083                                      CRString * a_url)
2085         g_return_val_if_fail (a_this
2086                               && a_this->type == AT_IMPORT_RULE_STMT
2087                               && a_this->kind.import_rule,
2088                               CR_BAD_PARAM_ERROR);
2090         if (a_this->kind.import_rule->url) {
2091                 cr_string_destroy (a_this->kind.import_rule->url);
2092         }
2094         a_this->kind.import_rule->url = a_url;
2096         return CR_OK;
2099 /**
2100  *Gets the url of the @import rule statement.
2101  *@param the current @import rule statement.
2102  *@param a_url out parameter. The returned url if
2103  *and only if the function returned CR_OK.
2104  */
2105 enum CRStatus
2106 cr_statement_at_import_rule_get_url (CRStatement * a_this, 
2107                                      CRString ** a_url)
2109         g_return_val_if_fail (a_this
2110                               && a_this->type == AT_IMPORT_RULE_STMT
2111                               && a_this->kind.import_rule,
2112                               CR_BAD_PARAM_ERROR);
2114         *a_url = a_this->kind.import_rule->url;
2116         return CR_OK;
2119 /**
2120  *Return the number of rules in the media rule;
2121  *@param a_this the current instance of #CRStatement.
2122  *@return number of rules in the media rule.
2123  */
2124 int
2125 cr_statement_at_media_nr_rules (CRStatement * a_this)
2127         g_return_val_if_fail (a_this
2128                               && a_this->type == AT_MEDIA_RULE_STMT
2129                               && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
2131         return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
2134 /**
2135  *Use an index to get a CRStatement from the media rule list of rules.
2136  *@param a_this the current instance of #CRStatement.
2137  *@param itemnr the index into the media rule list of rules.
2138  *@return CRStatement at position itemnr, if itemnr > number of rules - 1,
2139  *it will return NULL.
2140  */
2141 CRStatement *
2142 cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
2144         g_return_val_if_fail (a_this
2145                               && a_this->type == AT_MEDIA_RULE_STMT
2146                               && a_this->kind.media_rule, NULL);
2148         return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
2149                                            itemnr);
2152 /**
2153  *Sets a declaration list to the current @page rule statement.
2154  *@param a_this the current @page rule statement.
2155  *@param a_decl_list the declaration list to add. Will be freed
2156  *by the current instance of #CRStatement when it is destroyed.
2157  *@return CR_OK upon successfull completion, an error code otherwise.
2158  */
2159 enum CRStatus
2160 cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
2161                                             CRDeclaration * a_decl_list)
2163         g_return_val_if_fail (a_this
2164                               && a_this->type == AT_PAGE_RULE_STMT
2165                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
2167         if (a_this->kind.page_rule->decl_list) {
2168                 cr_declaration_unref (a_this->kind.page_rule->decl_list);
2169         }
2171         a_this->kind.page_rule->decl_list = a_decl_list;
2173         if (a_decl_list) {
2174                 cr_declaration_ref (a_decl_list);
2175         }
2177         return CR_OK;
2180 /**
2181  *Gets the declaration list associated to the current @page rule
2182  *statement.
2183  *@param a_this the current  @page rule statement.
2184  *@param a_decl_list out parameter. The returned declaration list.
2185  *@return CR_OK upon successfull completion, an error code otherwise.
2186  */
2187 enum CRStatus
2188 cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
2189                                             CRDeclaration ** a_decl_list)
2191         g_return_val_if_fail (a_this
2192                               && a_this->type == AT_PAGE_RULE_STMT
2193                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
2195         *a_decl_list = a_this->kind.page_rule->decl_list;
2197         return CR_OK;
2200 /**
2201  *Sets the charset of the current @charset rule statement.
2202  *@param a_this the current @charset rule statement.
2203  *@param a_charset the charset to set.
2204  *@return CR_OK upon successfull completion, an error code otherwise.
2205  */
2206 enum CRStatus
2207 cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
2208                                           CRString * a_charset)
2210         g_return_val_if_fail (a_this
2211                               && a_this->type == AT_CHARSET_RULE_STMT
2212                               && a_this->kind.charset_rule,
2213                               CR_BAD_PARAM_ERROR);
2215         if (a_this->kind.charset_rule->charset) {
2216                 cr_string_destroy (a_this->kind.charset_rule->charset);
2217         }
2218         a_this->kind.charset_rule->charset = a_charset;
2219         return CR_OK;
2222 /**
2223  *Gets the charset string associated to the current
2224  *@charset rule statement.
2225  *@param a_this the current @charset rule statement.
2226  *@param a_charset out parameter. The returned charset string if
2227  *and only if the function returned CR_OK.
2228  */
2229 enum CRStatus
2230 cr_statement_at_charset_rule_get_charset (CRStatement * a_this,
2231                                           CRString ** a_charset)
2233         g_return_val_if_fail (a_this
2234                               && a_this->type == AT_CHARSET_RULE_STMT
2235                               && a_this->kind.charset_rule,
2236                               CR_BAD_PARAM_ERROR);
2238         *a_charset = a_this->kind.charset_rule->charset;
2240         return CR_OK;
2243 /**
2244  *Sets a declaration list to the current @font-face rule statement.
2245  *@param a_this the current @font-face rule statement.
2246  *@param a_decls the declarations list to set.
2247  *@return CR_OK upon successfull completion, an error code otherwise.
2248  */
2249 enum CRStatus
2250 cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
2251                                           CRDeclaration * a_decls)
2253         g_return_val_if_fail (a_this
2254                               && a_this->type == AT_FONT_FACE_RULE_STMT
2255                               && a_this->kind.font_face_rule,
2256                               CR_BAD_PARAM_ERROR);
2258         if (a_this->kind.font_face_rule->decl_list) {
2259                 cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
2260         }
2262         a_this->kind.font_face_rule->decl_list = a_decls;
2263         cr_declaration_ref (a_decls);
2265         return CR_OK;
2268 /**
2269  *Gets the declaration list associated to the current instance
2270  *of @font-face rule statement.
2271  *@param a_this the current @font-face rule statement.
2272  *@param a_decls out parameter. The returned declaration list if
2273  *and only if this function returns CR_OK.
2274  *@return CR_OK upon successfull completion, an error code otherwise.
2275  */
2276 enum CRStatus
2277 cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
2278                                           CRDeclaration ** a_decls)
2280         g_return_val_if_fail (a_this
2281                               && a_this->type == AT_FONT_FACE_RULE_STMT
2282                               && a_this->kind.font_face_rule,
2283                               CR_BAD_PARAM_ERROR);
2285         *a_decls = a_this->kind.font_face_rule->decl_list;
2287         return CR_OK;
2290 /**
2291  *Adds a declaration to the current @font-face rule
2292  *statement.
2293  *@param a_this the current @font-face rule statement.
2294  *@param a_prop the property of the declaration.
2295  *@param a_value the value of the declaration.
2296  *@return CR_OK upon successfull completion, an error code otherwise.
2297  */
2298 enum CRStatus
2299 cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
2300                                          CRString * a_prop, CRTerm * a_value)
2302         CRDeclaration *decls = NULL;
2304         g_return_val_if_fail (a_this
2305                               && a_this->type == AT_FONT_FACE_RULE_STMT
2306                               && a_this->kind.font_face_rule,
2307                               CR_BAD_PARAM_ERROR);
2309         decls = cr_declaration_append2
2310                 (a_this->kind.font_face_rule->decl_list, 
2311                  a_prop, a_value);
2313         g_return_val_if_fail (decls, CR_ERROR);
2315         if (a_this->kind.font_face_rule->decl_list == NULL)
2316                 cr_declaration_ref (decls);
2318         a_this->kind.font_face_rule->decl_list = decls;
2320         return CR_OK;
2323 /**
2324  *Serializes a css statement into a string
2325  *@param a_this the current statement to serialize
2326  *@param a_indent the number of white space of indentation.
2327  *@return the serialized statement. Must be freed by the caller
2328  *using g_free().
2329  */
2330 gchar *
2331 cr_statement_to_string (CRStatement * a_this, gulong a_indent)
2333         gchar *str = NULL ;
2335         if (!a_this)
2336                 return NULL;
2338         switch (a_this->type) {
2339         case RULESET_STMT:
2340                 str = cr_statement_ruleset_to_string 
2341                         (a_this, a_indent);
2342                 break;
2344         case AT_FONT_FACE_RULE_STMT:
2345                 str = cr_statement_font_face_rule_to_string 
2346                         (a_this, a_indent) ;
2347                 break;
2349         case AT_CHARSET_RULE_STMT:
2350                 str = cr_statement_charset_to_string
2351                         (a_this, a_indent);                
2352                 break;
2354         case AT_PAGE_RULE_STMT:
2355                 str = cr_statement_at_page_rule_to_string
2356                         (a_this, a_indent);
2357                 break;
2359         case AT_MEDIA_RULE_STMT:
2360                 str = cr_statement_media_rule_to_string
2361                         (a_this, a_indent);
2362                 break;
2364         case AT_IMPORT_RULE_STMT:
2365                 str = cr_statement_import_rule_to_string
2366                         (a_this, a_indent);
2367                 break;
2369         default:
2370                 cr_utils_trace_info ("Statement unrecognized");
2371                 break;
2372         }
2373         return str ;
2376 gchar*
2377 cr_statement_list_to_string (CRStatement *a_this, gulong a_indent)
2379         CRStatement *cur_stmt = NULL ;
2380         GString *stringue = NULL ;
2381         gchar *str = NULL ;
2383         g_return_val_if_fail (a_this, NULL) ;
2385         stringue = g_string_new (NULL) ;
2386         if (!stringue) {
2387                 cr_utils_trace_info ("Out of memory") ;
2388                 return NULL ;
2389         }
2390         for (cur_stmt = a_this ; cur_stmt;
2391              cur_stmt = cur_stmt->next) {
2392                 str = cr_statement_to_string (cur_stmt, a_indent) ;
2393                 if (str) {
2394                         if (!cur_stmt->prev) {
2395                                 g_string_append (stringue, str) ;
2396                         } else {
2397                                 g_string_append_printf 
2398                                         (stringue, "\n%s", str) ;
2399                         }
2400                         g_free (str) ;
2401                         str = NULL ;
2402                 }                
2403         }
2404         str = stringue->str ;
2405         g_string_free (stringue, FALSE) ;
2406         return str ;
2409 /**
2410  *Dumps the css2 statement to a file.
2411  *@param a_this the current css2 statement.
2412  *@param a_fp the destination file pointer.
2413  *@param a_indent the number of white space indentation characters.
2414  */
2415 void
2416 cr_statement_dump (CRStatement * a_this, FILE * a_fp, gulong a_indent)
2418         gchar *str = NULL ;
2420         if (!a_this)
2421                 return;
2423         str = cr_statement_to_string (a_this, a_indent) ;
2424         if (str) {
2425                 fprintf (a_fp, "%s",str) ;
2426                 g_free (str) ;
2427                 str = NULL ;
2428         }
2431 /**
2432  *Dumps a ruleset statement to a file.
2433  *@param a_this the current instance of #CRStatement.
2434  *@param a_fp the destination file pointer.
2435  *@param a_indent the number of indentation white spaces to add.
2436  */
2437 void
2438 cr_statement_dump_ruleset (CRStatement * a_this, FILE * a_fp, glong a_indent)
2440         guchar *str = NULL;
2442         g_return_if_fail (a_fp && a_this);
2443         str = cr_statement_ruleset_to_string (a_this, a_indent);
2444         if (str) {
2445                 fprintf (a_fp, str);
2446                 g_free (str);
2447                 str = NULL;
2448         }
2451 /**
2452  *Dumps a font face rule statement to a file.
2453  *@param a_this the current instance of font face rule statement.
2454  *@param a_fp the destination file pointer.
2455  *@param a_indent the number of white space indentation.
2456  */
2457 void
2458 cr_statement_dump_font_face_rule (CRStatement * a_this, FILE * a_fp,
2459                                   glong a_indent)
2461         gchar *str = NULL ;
2462         g_return_if_fail (a_this 
2463                           && a_this->type == AT_FONT_FACE_RULE_STMT);
2465         str = cr_statement_font_face_rule_to_string (a_this,
2466                                                      a_indent) ;
2467         if (str) {
2468                 fprintf (a_fp, "%s", str) ;
2469                 g_free (str) ;
2470                 str = NULL ;
2471         }
2474 /**
2475  *Dumps an @charset rule statement to a file.
2476  *@param a_this the current instance of the @charset rule statement.
2477  *@param a_fp the destination file pointer.
2478  *@param a_indent the number of indentation white spaces.
2479  */
2480 void
2481 cr_statement_dump_charset (CRStatement * a_this, FILE * a_fp, gulong a_indent)
2483         guchar *str = NULL;
2485         g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
2487         str = cr_statement_charset_to_string (a_this,
2488                                               a_indent) ;
2489         if (str) {
2490                 fprintf (a_fp, str) ;
2491                 g_free (str) ;
2492                 str = NULL ;
2493         }
2497 /**
2498  *Dumps an @page rule statement on stdout.
2499  *@param a_this the statement to dump on stdout.
2500  *@param a_fp the destination file pointer.
2501  *@param a_indent the number of indentation white spaces.
2502  */
2503 void
2504 cr_statement_dump_page (CRStatement * a_this, FILE * a_fp, gulong a_indent)
2506         guchar *str = NULL;
2508         g_return_if_fail (a_this
2509                           && a_this->type == AT_PAGE_RULE_STMT
2510                           && a_this->kind.page_rule);
2512         str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
2513         if (str) {
2514                 fprintf (a_fp, str);
2515                 g_free (str) ;
2516                 str = NULL ; 
2517         }
2521 /**
2522  *Dumps an @media rule statement to a file.
2523  *@param a_this the statement to dump.
2524  *@param a_fp the destination file pointer
2525  *@param a_indent the number of white spaces indentation.
2526  */
2527 void
2528 cr_statement_dump_media_rule (CRStatement * a_this, 
2529                               FILE * a_fp,
2530                               gulong a_indent)
2532         gchar *str = NULL ;
2533         g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
2535         str = cr_statement_media_rule_to_string (a_this, a_indent) ;
2536         if (str) {
2537                 fprintf (a_fp, str) ;
2538                 g_free (str) ;
2539                 str = NULL ;
2540         }
2543 /**
2544  *Dumps an @import rule statement to a file.
2545  *@param a_fp the destination file pointer.
2546  *@param a_indent the number of white space indentations.
2547  */
2548 void
2549 cr_statement_dump_import_rule (CRStatement * a_this, FILE * a_fp,
2550                                gulong a_indent)
2552         gchar *str = NULL ;
2553         g_return_if_fail (a_this
2554                           && a_this->type == AT_IMPORT_RULE_STMT
2555                           && a_fp
2556                           && a_this->kind.import_rule);
2558         str = cr_statement_import_rule_to_string (a_this, a_indent) ;
2559         if (str) {
2560                 fprintf (a_fp, str) ;
2561                 g_free (str) ;
2562                 str = NULL ;
2563         }
2566 /**
2567  *Destructor of #CRStatement.
2568  */
2569 void
2570 cr_statement_destroy (CRStatement * a_this)
2572         CRStatement *cur = NULL;
2574         g_return_if_fail (a_this);
2576         /*go get the tail of the list */
2577         for (cur = a_this; cur && cur->next; cur = cur->next) {
2578                 cr_statement_clear (cur);
2579         }
2581         if (cur)
2582                 cr_statement_clear (cur);
2584         if (cur->prev == NULL) {
2585                 g_free (a_this);
2586                 return;
2587         }
2589         /*walk backward and free next element */
2590         for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
2591                 if (cur->next) {
2592                         g_free (cur->next);
2593                         cur->next = NULL;
2594                 }
2595         }
2597         if (!cur)
2598                 return;
2600         /*free the one remaining list */
2601         if (cur->next) {
2602                 g_free (cur->next);
2603                 cur->next = NULL;
2604         }
2606         g_free (cur);
2607         cur = NULL;