Code

Node tool: special case node duplication for endnodes - select new endnode
[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         gchar *tmp_str = NULL,
603                 *result = NULL;
605         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
607         GString *stringue = (GString *)g_string_new (NULL);
609         if (a_this->kind.ruleset->sel_list) {
610                 if (a_indent)
611                         cr_utils_dump_n_chars2 (' ', stringue, a_indent);
613                 tmp_str = (gchar *)
614                         cr_selector_to_string (a_this->kind.ruleset->
615                                                sel_list);
616                 if (tmp_str) {
617                         g_string_append (stringue, tmp_str);
618                         g_free (tmp_str);
619                         tmp_str = NULL;
620                 }
621         }
622         g_string_append (stringue, " {\n");
623         if (a_this->kind.ruleset->decl_list) {
624                 tmp_str = (gchar *)cr_declaration_list_to_string2
625                         (a_this->kind.ruleset->decl_list,
626                          a_indent + DECLARATION_INDENT_NB, TRUE);
627                 if (tmp_str) {
628                         g_string_append (stringue, tmp_str);
629                         g_free (tmp_str);
630                         tmp_str = NULL;
631                 }
632                 g_string_append (stringue, "\n");
633                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
634         }
635         g_string_append (stringue, "}");
636         result = stringue->str;
638         if (stringue) {
639                 g_string_free (stringue, FALSE);
640                 stringue = NULL;
641         }
642         if (tmp_str) {
643                 g_free (tmp_str);
644                 tmp_str = NULL;
645         }
646         return result;
650 /**
651  *Serializes a font face rule statement into a string.
652  *@param a_this the current instance of #CRStatement to consider
653  *It must be a font face rule statement.
654  *@param a_indent the number of white spaces of indentation.
655  *@return the serialized string. Must be deallocated by the caller
656  *using g_free().
657  */
658 static gchar *
659 cr_statement_font_face_rule_to_string (CRStatement * a_this, 
660                                        glong a_indent)
662         gchar *result = NULL, *tmp_str = NULL ;
663         GString *stringue = NULL ;
665         g_return_val_if_fail (a_this 
666                               && a_this->type == AT_FONT_FACE_RULE_STMT,
667                               NULL);
669         if (a_this->kind.font_face_rule->decl_list) {
670                 stringue = (GString *)g_string_new (NULL) ;
671                 g_return_val_if_fail (stringue, NULL) ;
672                 if (a_indent)
673                         cr_utils_dump_n_chars2 (' ', stringue, 
674                                         a_indent);
675                 g_string_append (stringue, "@font-face {\n");
676                 tmp_str = (gchar *)cr_declaration_list_to_string2 
677                         (a_this->kind.font_face_rule->decl_list,
678                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
679                 if (tmp_str) {
680                         g_string_append (stringue,
681                                          tmp_str) ;
682                         g_free (tmp_str) ;
683                         tmp_str = NULL ;
684                 }
685                 g_string_append (stringue, "\n}");
686         }
687         if (stringue) {
688                 result = stringue->str ;
689                 g_string_free (stringue, FALSE) ;
690                 stringue = NULL ;
691         }
692         return result ;
696 /**
697  *Serialises an @charset statement into a string.
698  *@param a_this the statement to serialize.
699  *@return the serialized charset statement. Must be
700  *freed by the caller using g_free().
701  */
702 static gchar *
703 cr_statement_charset_to_string (CRStatement *a_this, 
704                                 gulong a_indent)
706         gchar *str = NULL ;
707         GString *stringue = NULL ;
709         g_return_val_if_fail (a_this
710                               && a_this->type == AT_CHARSET_RULE_STMT,
711                               NULL) ;
713         if (a_this->kind.charset_rule
714             && a_this->kind.charset_rule->charset
715             && a_this->kind.charset_rule->charset->stryng
716             && a_this->kind.charset_rule->charset->stryng->str) {
717                 str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
718                                  a_this->kind.charset_rule->charset->stryng->len);
719                 g_return_val_if_fail (str, NULL);
720                 stringue = g_string_new (NULL) ;
721                 g_return_val_if_fail (stringue, NULL) ;
722                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
723                 g_string_append_printf (stringue, 
724                                         "@charset \"%s\" ;", str);
725                 if (str) {
726                         g_free (str);
727                         str = NULL;
728                 }
729         }
730         if (stringue) {
731                 str = stringue->str ;
732                 g_string_free (stringue, FALSE) ;
733         }
734         return str ;
738 /**
739  *Serialises the at page rule statement into a string
740  *@param a_this the current instance of #CRStatement. Must
741  *be an "@page" rule statement.
742  *@return the serialized string. Must be freed by the caller
743  */
744 static gchar *
745 cr_statement_at_page_rule_to_string (CRStatement *a_this,
746                                      gulong a_indent)
748         gchar *result = NULL ;
750         GString *stringue = (GString *)g_string_new (NULL) ;
752         cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
753         g_string_append (stringue, "@page");
754         if (a_this->kind.page_rule->name
755             && a_this->kind.page_rule->name->stryng) {
756                 g_string_append_printf 
757                   (stringue, " %s",
758                    a_this->kind.page_rule->name->stryng->str) ;
759         } else {
760                 g_string_append (stringue, " ");
761         }
762         if (a_this->kind.page_rule->pseudo
763             && a_this->kind.page_rule->pseudo->stryng) {
764                 g_string_append_printf 
765                   (stringue,  " :%s",
766                    a_this->kind.page_rule->pseudo->stryng->str) ;
767         }
768         if (a_this->kind.page_rule->decl_list) {
769                 gchar *str = NULL ;
770                 g_string_append (stringue, " {\n");
771                 str = (gchar *)cr_declaration_list_to_string2
772                         (a_this->kind.page_rule->decl_list,
773                          a_indent + DECLARATION_INDENT_NB, TRUE) ;
774                 if (str) {
775                         g_string_append (stringue, str) ;
776                         g_free (str) ;
777                         str = NULL ;
778                 }
779                 g_string_append (stringue, "\n}\n");
780         }
781         result = stringue->str ;
782         g_string_free (stringue, FALSE) ;
783         stringue = NULL ;
784         return result ;
788 /**
789  *Serializes an @media statement.
790  *@param a_this the current instance of #CRStatement
791  *@param a_indent the number of spaces of indentation.
792  *@return the serialized @media statement. Must be freed
793  *by the caller using g_free().
794  */
795 static gchar *
796 cr_statement_media_rule_to_string (CRStatement *a_this,
797                                    gulong a_indent)
799         gchar *str = NULL ;
800         GString *stringue = NULL ;
801         GList *cur = NULL;
803         g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
804                               NULL);
806         if (a_this->kind.media_rule) {
807                 stringue = (GString *)g_string_new (NULL) ;                
808                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
809                 g_string_append (stringue, "@media");
811                 for (cur = a_this->kind.media_rule->media_list; cur;
812                      cur = cur->next) {
813                         if (cur->data) {
814                                 gchar *str = cr_string_dup2
815                                         ((CRString *) cur->data);
817                                 if (str) {
818                                         if (cur->prev) {
819                                                 g_string_append
820                                                         (stringue, 
821                                                          ",");
822                                         }
823                                         g_string_append_printf 
824                                                 (stringue, 
825                                                  " %s", str);
826                                         g_free (str);
827                                         str = NULL;
828                                 }
829                         }
830                 }
831                 g_string_append (stringue, " {\n");
832                 str = cr_statement_list_to_string
833                         (a_this->kind.media_rule->rulesets,
834                          a_indent + DECLARATION_INDENT_NB) ;
835                 if (str) {
836                         g_string_append (stringue, str) ;
837                         g_free (str) ;
838                         str = NULL ;
839                 }
840                 g_string_append (stringue, "\n}");
841         }
842         if (stringue) {
843                 str = stringue->str ;
844                 g_string_free (stringue, FALSE) ;
845         }
846         return str ;
850 static gchar *
851 cr_statement_import_rule_to_string (CRStatement *a_this,
852                                     gulong a_indent)
854         GString *stringue = NULL ;
855         gchar *str = NULL;
857         g_return_val_if_fail (a_this
858                               && a_this->type == AT_IMPORT_RULE_STMT
859                               && a_this->kind.import_rule,
860                               NULL) ;
862         if (a_this->kind.import_rule->url
863             && a_this->kind.import_rule->url->stryng) { 
864                 stringue = (GString *)g_string_new (NULL) ;
865                 g_return_val_if_fail (stringue, NULL) ;
866                 str = g_strndup (a_this->kind.import_rule->url->stryng->str,
867                                  a_this->kind.import_rule->url->stryng->len);
868                 cr_utils_dump_n_chars2 (' ', stringue, a_indent);
869                 if (str) {
870                         g_string_append_printf (stringue,
871                                                 "@import url(\"%s\")", 
872                                                 str);
873                         g_free (str);
874                         str = NULL ;
875                 } else          /*there is no url, so no import rule, get out! */
876                         return NULL;
878                 if (a_this->kind.import_rule->media_list) {
879                         GList *cur = NULL;
881                         for (cur = a_this->kind.import_rule->media_list;
882                              cur; cur = cur->next) {
883                                 if (cur->data) {
884                                         CRString *crstr = (CRString *)cur->data;
886                                         if (cur->prev) {
887                                                 g_string_append 
888                                                         (stringue, ", ");
889                                         }
890                                         if (crstr 
891                                             && crstr->stryng
892                                             && crstr->stryng->str) {
893                                                 g_string_append_len 
894                                                         (stringue,
895                                                          crstr->stryng->str,
896                                                          crstr->stryng->len) ;
897                                         }
898                                 }
899                         }
900                 }
901                 g_string_append (stringue, " ;");
902         }
903         if (stringue) {
904                 str = stringue->str ;
905                 g_string_free (stringue, FALSE) ;
906                 stringue = NULL ;
907         }
908         return str ;
912 /*******************
913  *public functions
914  ******************/
916 /**
917  *Tries to parse a buffer and says whether if the content of the buffer
918  *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
919  *css spec) or not.
920  *@param a_buf the buffer to parse.
921  *@param a_encoding the character encoding of a_buf.
922  *@return TRUE if the buffer parses against the core grammar, false otherwise.
923  */
924 gboolean
925 cr_statement_does_buf_parses_against_core (const guchar * a_buf,
926                                            enum CREncoding a_encoding)
928         CRParser *parser = NULL;
929         enum CRStatus status = CR_OK;
930         gboolean result = FALSE;
932         parser = cr_parser_new_from_buf ((guchar*)a_buf,
933                                                  strlen ((char *)a_buf),
934                                          a_encoding, FALSE);
935         g_return_val_if_fail (parser, FALSE);
937         status = cr_parser_set_use_core_grammar (parser, TRUE);
938         if (status != CR_OK) {
939                 goto cleanup;
940         }
942         status = cr_parser_parse_statement_core (parser);
943         if (status == CR_OK) {
944                 result = TRUE;
945         }
947       cleanup:
948         if (parser) {
949                 cr_parser_destroy (parser);
950         }
952         return result;
955 /**
956  *Parses a buffer that contains a css statement and returns 
957  *an instance of #CRStatement in case of successfull parsing.
958  *TODO: at support of "@import" rules.
959  *@param a_buf the buffer to parse.
960  *@param a_encoding the character encoding of a_buf.
961  *@return the newly built instance of #CRStatement in case
962  *of successfull parsing, NULL otherwise.
963  */
964 CRStatement *
965 cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
967         CRStatement *result = NULL;
969         /*
970          *The strategy of this function is "brute force".
971          *It tries to parse all the types of #CRStatement it knows about.
972          *I could do this a smarter way but I don't have the time now.
973          *I think I will revisit this when time of performances and
974          *pull based incremental parsing comes.
975          */
977         result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
978         if (!result) {
979                 result = cr_statement_at_charset_rule_parse_from_buf
980                         (a_buf, a_encoding);
981         } else {
982                 goto out;
983         }
985         if (!result) {
986                 result = cr_statement_at_media_rule_parse_from_buf
987                         (a_buf, a_encoding);
988         } else {
989                 goto out;
990         }
992         if (!result) {
993                 result = cr_statement_at_charset_rule_parse_from_buf
994                         (a_buf, a_encoding);
995         } else {
996                 goto out;
997         }
999         if (!result) {
1000                 result = cr_statement_font_face_rule_parse_from_buf
1001                         (a_buf, a_encoding);
1003         } else {
1004                 goto out;
1005         }
1007         if (!result) {
1008                 result = cr_statement_at_page_rule_parse_from_buf
1009                         (a_buf, a_encoding);
1010         } else {
1011                 goto out;
1012         }
1014         if (!result) {
1015                 result = cr_statement_at_import_rule_parse_from_buf
1016                         (a_buf, a_encoding);
1017         } else {
1018                 goto out;
1019         }
1021       out:
1022         return result;
1025 /**
1026  *Parses a buffer that contains a ruleset statement and instanciates
1027  *a #CRStatement of type RULESET_STMT.
1028  *@param a_buf the buffer to parse.
1029  *@param a_enc the character encoding of a_buf.
1030  *@param the newly built instance of #CRStatement in case of successful parsing,
1031  *NULL otherwise.
1032  */
1033 CRStatement *
1034 cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
1035                                      enum CREncoding a_enc)
1037         enum CRStatus status = CR_OK;
1038         CRStatement *result = NULL;
1039         CRStatement **resultptr = NULL;
1040         CRParser *parser = NULL;
1041         CRDocHandler *sac_handler = NULL;
1043         g_return_val_if_fail (a_buf, NULL);
1045         parser = cr_parser_new_from_buf ((guchar*)a_buf,
1046                                                  strlen ((char *)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         g_return_val_if_fail (a_sel_list, NULL);
1110         if (a_parent_media_rule) {
1111                 g_return_val_if_fail
1112                         (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
1113                          NULL);
1114                 g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
1115                                       NULL);
1116         }
1118         CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
1120         if (!result) {
1121                 cr_utils_trace_info ("Out of memory");
1122                 return NULL;
1123         }
1125         memset (result, 0, sizeof (CRStatement));
1126         result->type = RULESET_STMT;
1127         result->kind.ruleset = (CRRuleSet *)g_try_malloc (sizeof (CRRuleSet));
1129         if (!result->kind.ruleset) {
1130                 cr_utils_trace_info ("Out of memory");
1131                 if (result)
1132                         g_free (result);
1133                 return NULL;
1134         }
1136         memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
1137         result->kind.ruleset->sel_list = a_sel_list;
1138         if (a_sel_list)
1139                 cr_selector_ref (a_sel_list);
1140         result->kind.ruleset->decl_list = a_decl_list;
1142         if (a_parent_media_rule) {
1143                 result->kind.ruleset->parent_media_rule = a_parent_media_rule;
1144                 a_parent_media_rule->kind.media_rule->rulesets =
1145                         cr_statement_append
1146                         (a_parent_media_rule->kind.media_rule->rulesets,
1147                          result);
1148         }
1150         cr_statement_set_parent_sheet (result, a_sheet);
1152         return result;
1155 /**
1156  *Parses a buffer that contains an "@media" declaration
1157  *and builds an @media css statement.
1158  *@param a_buf the input to parse.
1159  *@param a_enc the encoding of the buffer.
1160  *@return the @media statement, or NULL if the buffer could not
1161  *be successfully parsed.
1162  */
1163 CRStatement *
1164 cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
1165                                            enum CREncoding a_enc)
1167         CRParser *parser = NULL;
1168         CRStatement *result = NULL;
1169         CRStatement **resultptr = NULL;
1170         CRDocHandler *sac_handler = NULL;
1171         enum CRStatus status = CR_OK;
1173         parser = cr_parser_new_from_buf ((guchar*)a_buf,
1174                                                  strlen ((char *)a_buf), 
1175                                          a_enc, FALSE);
1176         if (!parser) {
1177                 cr_utils_trace_info ("Instanciation of the parser failed");
1178                 goto cleanup;
1179         }
1181         sac_handler = cr_doc_handler_new ();
1182         if (!sac_handler) {
1183                 cr_utils_trace_info
1184                         ("Instanciation of the sac handler failed");
1185                 goto cleanup;
1186         }
1188         sac_handler->start_media = parse_at_media_start_media_cb;
1189         sac_handler->start_selector = parse_at_media_start_selector_cb;
1190         sac_handler->property = parse_at_media_property_cb;
1191         sac_handler->end_selector = parse_at_media_end_selector_cb;
1192         sac_handler->end_media = parse_at_media_end_media_cb;
1193         sac_handler->unrecoverable_error =
1194                 parse_at_media_unrecoverable_error_cb;
1196         status = cr_parser_set_sac_handler (parser, sac_handler);
1197         if (status != CR_OK)
1198                 goto cleanup;
1200         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1201         if (status != CR_OK)
1202                 goto cleanup;
1204         status = cr_parser_parse_media (parser);
1205         if (status != CR_OK)
1206                 goto cleanup;
1208         resultptr = &result;
1209         status = cr_doc_handler_get_result (sac_handler,
1210                                             (gpointer *) resultptr);
1211         if (status != CR_OK)
1212                 goto cleanup;
1214       cleanup:
1216         if (parser) {
1217                 cr_parser_destroy (parser);
1218                 parser = NULL;
1219                 sac_handler = NULL ;
1220         }
1221         if (sac_handler) {
1222                 cr_doc_handler_unref (sac_handler);
1223                 sac_handler = NULL;
1224         }
1226         return result;
1229 /**
1230  *Instanciates an instance of #CRStatement of type
1231  *AT_MEDIA_RULE_STMT (@media ruleset).
1232  *@param a_ruleset the ruleset statements contained
1233  *in the @media rule.
1234  *@param a_media, the media string list. A list of GString pointers.
1235  */
1236 CRStatement *
1237 cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
1238                                 CRStatement * a_rulesets, GList * a_media)
1240         CRStatement *cur = NULL;
1242         if (a_rulesets)
1243                 g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
1245         CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
1247         if (!result) {
1248                 cr_utils_trace_info ("Out of memory");
1249                 return NULL;
1250         }
1252         memset (result, 0, sizeof (CRStatement));
1253         result->type = AT_MEDIA_RULE_STMT;
1255         result->kind.media_rule = (CRAtMediaRule *)g_try_malloc (sizeof (CRAtMediaRule));
1256         if (!result->kind.media_rule) {
1257                 cr_utils_trace_info ("Out of memory");
1258                 g_free (result);
1259                 return NULL;
1260         }
1261         memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
1262         result->kind.media_rule->rulesets = a_rulesets;
1263         for (cur = a_rulesets; cur; cur = cur->next) {
1264                 if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
1265                         cr_utils_trace_info ("Bad parameter a_rulesets. "
1266                                              "It should be a list of "
1267                                              "correct ruleset statement only !");
1268                         goto error;
1269                 }
1270                 cur->kind.ruleset->parent_media_rule = result;
1271         }
1273         result->kind.media_rule->media_list = a_media;
1274         if (a_sheet) {
1275                 cr_statement_set_parent_sheet (result, a_sheet);
1276         }
1278         return result;
1280       error:
1281         return NULL;
1284 /**
1285  *Creates a new instance of #CRStatment of type
1286  *#CRAtImportRule.
1287  *@param a_url the url to connect to the get the file
1288  *to be imported.
1289  *@param a_sheet the imported parsed stylesheet.
1290  *@return the newly built instance of #CRStatement.
1291  */
1292 CRStatement *
1293 cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
1294                                  CRString * a_url,
1295                                  GList * a_media_list,
1296                                  CRStyleSheet * a_imported_sheet)
1298         CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
1300         if (!result) {
1301                 cr_utils_trace_info ("Out of memory");
1302                 return NULL;
1303         }
1305         memset (result, 0, sizeof (CRStatement));
1306         result->type = AT_IMPORT_RULE_STMT;
1308         result->kind.import_rule = (CRAtImportRule *)g_try_malloc (sizeof (CRAtImportRule));
1310         if (!result->kind.import_rule) {
1311                 cr_utils_trace_info ("Out of memory");
1312                 g_free (result);
1313                 return NULL;
1314         }
1316         memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
1317         result->kind.import_rule->url = a_url;
1318         result->kind.import_rule->media_list = a_media_list;
1319         result->kind.import_rule->sheet = a_imported_sheet;
1320         if (a_container_sheet)
1321                 cr_statement_set_parent_sheet (result, a_container_sheet);
1323         return result;
1326 /**
1327  *Parses a buffer that contains an "@import" rule and
1328  *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
1329  *@param a_buf the buffer to parse.
1330  *@param a_encoding the encoding of a_buf.
1331  *@return the newly built instance of #CRStatement in case of 
1332  *a successfull parsing, NULL otherwise.
1333  */
1334 CRStatement *
1335 cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
1336                                             enum CREncoding a_encoding)
1338         enum CRStatus status = CR_OK;
1339         CRParser *parser = NULL;
1340         CRStatement *result = NULL;
1341         GList *media_list = NULL;
1342         CRString *import_string = NULL;
1343         CRParsingLocation location = {0,0,0} ;
1345         parser = cr_parser_new_from_buf ((guchar*)a_buf,
1346                                                  strlen ((char *)a_buf),
1347                                          a_encoding, FALSE);
1348         if (!parser) {
1349                 cr_utils_trace_info ("Instanciation of parser failed.");
1350                 goto cleanup;
1351         }
1353         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1354         if (status != CR_OK)
1355                 goto cleanup;
1357         status = cr_parser_parse_import (parser,
1358                                          &media_list, 
1359                                          &import_string,
1360                                          &location);
1361         if (status != CR_OK || !import_string)
1362                 goto cleanup;
1364         result = cr_statement_new_at_import_rule (NULL, import_string,
1365                                                   media_list, NULL);
1366         if (result) {
1367                 cr_parsing_location_copy (&result->location,
1368                                           &location) ;
1369                 import_string = NULL;
1370                 media_list = NULL;
1371         }
1373  cleanup:
1374         if (parser) {
1375                 cr_parser_destroy (parser);
1376                 parser = NULL;
1377         }
1378         if (media_list) {
1379                 GList *cur = NULL;
1381                 for (cur = media_list; media_list;
1382                      media_list = g_list_next (media_list)) {
1383                         if (media_list->data) {
1384                                 cr_string_destroy ((CRString*)media_list->data);
1385                                 media_list->data = NULL;
1386                         }
1387                 }
1388                 g_list_free (media_list);
1389                 media_list = NULL;
1390         }
1391         if (import_string) {
1392                 cr_string_destroy (import_string);
1393                 import_string = NULL;
1394         }
1396         return result;
1399 /**
1400  *Creates a new instance of #CRStatement of type
1401  *#CRAtPageRule.
1402  *@param a_decl_list a list of instances of #CRDeclarations
1403  *which is actually the list of declarations that applies to
1404  *this page rule.
1405  *@param a_selector the page rule selector.
1406  *@return the newly built instance of #CRStatement or NULL
1407  *in case of error.
1408  */
1409 CRStatement *
1410 cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
1411                                CRDeclaration * a_decl_list,
1412                                CRString * a_name, CRString * a_pseudo)
1414         CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
1416         if (!result) {
1417                 cr_utils_trace_info ("Out of memory");
1418                 return NULL;
1419         }
1421         memset (result, 0, sizeof (CRStatement));
1422         result->type = AT_PAGE_RULE_STMT;
1424         result->kind.page_rule = (CRAtPageRule *)g_try_malloc (sizeof (CRAtPageRule));
1426         if (!result->kind.page_rule) {
1427                 cr_utils_trace_info ("Out of memory");
1428                 g_free (result);
1429                 return NULL;
1430         }
1432         memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
1433         if (a_decl_list) {
1434                 result->kind.page_rule->decl_list = a_decl_list;
1435                 cr_declaration_ref (a_decl_list);
1436         }
1437         result->kind.page_rule->name = a_name;
1438         result->kind.page_rule->pseudo = a_pseudo;
1439         if (a_sheet)
1440                 cr_statement_set_parent_sheet (result, a_sheet);
1442         return result;
1445 /**
1446  *Parses a buffer that contains an "@page" production and,
1447  *if the parsing succeeds, builds the page statement.
1448  *@param a_buf the character buffer to parse.
1449  *@param a_encoding the character encoding of a_buf.
1450  *@return the newly built at page statement in case of successfull parsing,
1451  *NULL otherwise.
1452  */
1453 CRStatement *
1454 cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
1455                                           enum CREncoding a_encoding)
1457         enum CRStatus status = CR_OK;
1458         CRDocHandler *sac_handler = NULL;
1459         CRStatement *result = NULL;
1460         CRStatement **resultptr = NULL;
1462         g_return_val_if_fail (a_buf, NULL);
1464         CRParser *parser = cr_parser_new_from_buf ((guchar*)a_buf, 
1465                                                  strlen ((char *)a_buf),
1466                                          a_encoding, FALSE);
1467         if (!parser) {
1468                 cr_utils_trace_info ("Instanciation of the parser failed.");
1469                 goto cleanup;
1470         }
1472         sac_handler = cr_doc_handler_new ();
1473         if (!sac_handler) {
1474                 cr_utils_trace_info
1475                         ("Instanciation of the sac handler failed.");
1476                 goto cleanup;
1477         }
1479         sac_handler->start_page = parse_page_start_page_cb;
1480         sac_handler->property = parse_page_property_cb;
1481         sac_handler->end_page = parse_page_end_page_cb;
1482         sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
1484         status = cr_parser_set_sac_handler (parser, sac_handler);
1485         if (status != CR_OK)
1486                 goto cleanup;
1488         /*Now, invoke the parser to parse the "@page production" */
1489         cr_parser_try_to_skip_spaces_and_comments (parser);
1490         if (status != CR_OK)
1491                 goto cleanup;
1492         status = cr_parser_parse_page (parser);
1493         if (status != CR_OK)
1494                 goto cleanup;
1496         resultptr = &result;
1497         status = cr_doc_handler_get_result (sac_handler,
1498                                             (gpointer *) resultptr);
1500       cleanup:
1502         if (parser) {
1503                 cr_parser_destroy (parser);
1504                 parser = NULL;
1505                 sac_handler = NULL ;
1506         }
1507         if (sac_handler) {
1508                 cr_doc_handler_unref (sac_handler);
1509                 sac_handler = NULL;
1510         }
1511         return result;
1514 /**
1515  *Creates a new instance of #CRStatement of type
1516  *#CRAtCharsetRule.
1517  *@param a_charset the string representing the charset.
1518  *Note that the newly built instance of #CRStatement becomes
1519  *the owner of a_charset. The caller must not free a_charset !!!.
1520  *@return the newly built instance of #CRStatement or NULL
1521  *if an error arises.
1522  */
1523 CRStatement *
1524 cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 
1525                                   CRString * a_charset)
1527         g_return_val_if_fail (a_charset, NULL);
1529         CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
1531         if (!result) {
1532                 cr_utils_trace_info ("Out of memory");
1533                 return NULL;
1534         }
1536         memset (result, 0, sizeof (CRStatement));
1537         result->type = AT_CHARSET_RULE_STMT;
1539         result->kind.charset_rule = (CRAtCharsetRule *)g_try_malloc (sizeof (CRAtCharsetRule));
1541         if (!result->kind.charset_rule) {
1542                 cr_utils_trace_info ("Out of memory");
1543                 g_free (result);
1544                 return NULL;
1545         }
1546         memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
1547         result->kind.charset_rule->charset = a_charset;
1548         cr_statement_set_parent_sheet (result, a_sheet);
1550         return result;
1553 /**
1554  *Parses a buffer that contains an '@charset' rule and
1555  *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
1556  *@param a_buf the buffer to parse.
1557  *@param the character encoding of the buffer.
1558  *@return the newly built instance of #CRStatement.
1559  */
1560 CRStatement *
1561 cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
1562                                              enum CREncoding a_encoding)
1564         enum CRStatus status = CR_OK;
1565         CRStatement *result = NULL;
1566         CRString *charset = NULL;
1568         g_return_val_if_fail (a_buf, NULL);
1570         CRParser *parser = cr_parser_new_from_buf ((guchar*)a_buf,
1571                                                  strlen ((char *)a_buf),
1572                                          a_encoding, FALSE);
1573         if (!parser) {
1574                 cr_utils_trace_info ("Instanciation of the parser failed.");
1575                 goto cleanup;
1576         }
1578         /*Now, invoke the parser to parse the "@charset production" */
1579         cr_parser_try_to_skip_spaces_and_comments (parser);
1580         if (status != CR_OK)
1581                 goto cleanup;
1582         status = cr_parser_parse_charset (parser, &charset, NULL);
1583         if (status != CR_OK || !charset)
1584                 goto cleanup;
1586         result = cr_statement_new_at_charset_rule (NULL, charset);
1587         if (result)
1588                 charset = NULL;
1590       cleanup:
1592         if (parser) {
1593                 cr_parser_destroy (parser);
1594                 parser = NULL;
1595         }
1596         if (charset) {
1597                 cr_string_destroy (charset);
1598         }
1600         return result;
1603 /**
1604  *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
1605  *@param a_font_decls a list of instances of #CRDeclaration. Each declaration
1606  *is actually a font declaration.
1607  *@return the newly built instance of #CRStatement.
1608  */
1609 CRStatement *
1610 cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
1611                                     CRDeclaration * a_font_decls)
1613         CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
1615         if (!result) {
1616                 cr_utils_trace_info ("Out of memory");
1617                 return NULL;
1618         }
1619         memset (result, 0, sizeof (CRStatement));
1620         result->type = AT_FONT_FACE_RULE_STMT;
1622         result->kind.font_face_rule = (CRAtFontFaceRule *)g_try_malloc
1623                 (sizeof (CRAtFontFaceRule));
1625         if (!result->kind.font_face_rule) {
1626                 cr_utils_trace_info ("Out of memory");
1627                 g_free (result);
1628                 return NULL;
1629         }
1630         memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
1632         result->kind.font_face_rule->decl_list = a_font_decls;
1633         if (a_sheet)
1634                 cr_statement_set_parent_sheet (result, a_sheet);
1636         return result;
1639 /**
1640  *Parses a buffer that contains an "@font-face" rule and builds
1641  *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
1642  *@param a_buf the buffer to parse.
1643  *@param a_encoding the character encoding of a_buf.
1644  *@return the newly built instance of #CRStatement in case of successufull
1645  *parsing, NULL otherwise.
1646  */
1647 CRStatement *
1648 cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
1649                                             enum CREncoding a_encoding)
1651         CRStatement *result = NULL;
1652         CRStatement **resultptr = NULL;
1653         CRDocHandler *sac_handler = NULL;
1654         enum CRStatus status = CR_OK;
1656         CRParser *parser = (CRParser *)cr_parser_new_from_buf (
1657                                                  (guchar*)a_buf,
1658                                                                                  strlen ((char *)a_buf),
1659                                          a_encoding, FALSE);
1660         if (!parser)
1661                 goto cleanup;
1663         sac_handler = cr_doc_handler_new ();
1664         if (!sac_handler)
1665                 goto cleanup;
1667         /*
1668          *set sac callbacks here
1669          */
1670         sac_handler->start_font_face = parse_font_face_start_font_face_cb;
1671         sac_handler->property = parse_font_face_property_cb;
1672         sac_handler->end_font_face = parse_font_face_end_font_face_cb;
1673         sac_handler->unrecoverable_error =
1674                 parse_font_face_unrecoverable_error_cb;
1676         status = cr_parser_set_sac_handler (parser, sac_handler);
1677         if (status != CR_OK)
1678                 goto cleanup;
1680         /*
1681          *cleanup spaces of comment that may be there before the real
1682          *"@font-face" thing.
1683          */
1684         status = cr_parser_try_to_skip_spaces_and_comments (parser);
1685         if (status != CR_OK)
1686                 goto cleanup;
1688         status = cr_parser_parse_font_face (parser);
1689         if (status != CR_OK)
1690                 goto cleanup;
1692         resultptr = &result;
1693         status = cr_doc_handler_get_result (sac_handler,
1694                                             (gpointer *) resultptr);
1695         if (status != CR_OK || !result)
1696                 goto cleanup;
1698       cleanup:
1699         if (parser) {
1700                 cr_parser_destroy (parser);
1701                 parser = NULL;
1702                 sac_handler = NULL ;
1703         }
1704         if (sac_handler) {
1705                 cr_doc_handler_unref (sac_handler);
1706                 sac_handler = NULL;
1707         }
1708         return result;
1711 /**
1712  *Sets the container stylesheet.
1713  *@param a_this the current instance of #CRStatement.
1714  *@param a_sheet the sheet that contains the current statement.
1715  *@return CR_OK upon successfull completion, an errror code otherwise.
1716  */
1717 enum CRStatus
1718 cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
1720         g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
1721         a_this->parent_sheet = a_sheet;
1722         return CR_OK;
1725 /**
1726  *Gets the sheets that contains the current statement.
1727  *@param a_this the current #CRStatement.
1728  *@param a_sheet out parameter. A pointer to the sheets that
1729  *@return CR_OK upon successfull completion, an error code otherwise.
1730  */
1731 enum CRStatus
1732 cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
1734         g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
1735         *a_sheet = a_this->parent_sheet;
1736         return CR_OK;
1739 /**
1740  *Appends a new statement to the statement list.
1741  *@param a_this the current instance of the statement list.
1742  *@param a_this a_new the new instance of #CRStatement to append.
1743  *@return the new list statement list, or NULL in cas of failure.
1744  */
1745 CRStatement *
1746 cr_statement_append (CRStatement * a_this, CRStatement * a_new)
1748         CRStatement *cur = NULL;
1750         g_return_val_if_fail (a_new, NULL);
1752         if (!a_this) {
1753                 return a_new;
1754         }
1756         /*walk forward in the current list to find the tail list element */
1757         for (cur = a_this; cur && cur->next; cur = cur->next) ;
1759         cur->next = a_new;
1760         a_new->prev = cur;
1762         return a_this;
1765 /**
1766  *Prepends the an instance of #CRStatement to
1767  *the current statement list.
1768  *@param a_this the current instance of #CRStatement.
1769  *@param a_new the new statement to prepend.
1770  *@return the new list with the new statement prepended,
1771  *or NULL in case of an error.
1772  */
1773 CRStatement *
1774 cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
1776         CRStatement *cur = NULL;
1778         g_return_val_if_fail (a_new, NULL);
1780         if (!a_this)
1781                 return a_new;
1783         a_new->next = a_this;
1784         a_this->prev = a_new;
1786         /*walk backward in the prepended list to find the head list element */
1787         for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
1789         return cur;
1792 /**
1793  *Unlinks a statement from the statements list.
1794  *@param a_this the current statements list.
1795  *@param a_to_unlink the statement to unlink from the list.
1796  *@return the new list where a_to_unlink has been unlinked
1797  *from, or NULL in case of error.
1798  */
1799 CRStatement *
1800 cr_statement_unlink (CRStatement * a_stmt)
1802         CRStatement *result = a_stmt;
1804         g_return_val_if_fail (result, NULL);
1806         /**
1807          *Some sanity checks first
1808          */
1809         if (a_stmt->next) {
1810                 g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
1811         }
1812         if (a_stmt->prev) {
1813                 g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
1814         }
1816         /**
1817          *Now, the real unlinking job.
1818          */
1819         if (a_stmt->next) {
1820                 a_stmt->next->prev = a_stmt->prev;
1821         }
1822         if (a_stmt->prev) {
1823                 a_stmt->prev->next = a_stmt->next;
1824         }
1826         if (a_stmt->parent_sheet
1827             && a_stmt->parent_sheet->statements == a_stmt) {
1828                 a_stmt->parent_sheet->statements =
1829                         a_stmt->parent_sheet->statements->next;
1830         }
1832         a_stmt->next = NULL;
1833         a_stmt->prev = NULL;
1834         a_stmt->parent_sheet = NULL;
1836         return result;
1839 /**
1840  *Return the number of rules in the statement list;
1841  *@param a_this the current instance of #CRStatement.
1842  *@return number of rules in the statement list.
1843  */
1844 gint
1845 cr_statement_nr_rules (CRStatement * a_this)
1847         CRStatement *cur = NULL;
1848         int nr = 0;
1850         g_return_val_if_fail (a_this, -1);
1852         for (cur = a_this; cur; cur = cur->next)
1853                 nr++;
1854         return nr;
1857 /**
1858  *Use an index to get a CRStatement from the statement list.
1859  *@param a_this the current instance of #CRStatement.
1860  *@param itemnr the index into the statement list.
1861  *@return CRStatement at position itemnr, if itemnr > number of statements - 1,
1862  *it will return NULL.
1863  */
1864 CRStatement *
1865 cr_statement_get_from_list (CRStatement * a_this, int itemnr)
1867         CRStatement *cur = NULL;
1868         int nr = 0;
1870         g_return_val_if_fail (a_this, NULL);
1872         for (cur = a_this; cur; cur = cur->next)
1873                 if (nr++ == itemnr)
1874                         return cur;
1875         return NULL;
1878 /**
1879  *Sets a selector list to a ruleset statement.
1880  *@param a_this the current ruleset statement.
1881  *@param a_sel_list the selector list to set. Note
1882  *that this function increments the ref count of a_sel_list.
1883  *The sel list will be destroyed at the destruction of the
1884  *current instance of #CRStatement.
1885  *@return CR_OK upon successfull completion, an error code otherwise.
1886  */
1887 enum CRStatus
1888 cr_statement_ruleset_set_sel_list (CRStatement * a_this,
1889                                    CRSelector * a_sel_list)
1891         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
1892                               CR_BAD_PARAM_ERROR);
1894         if (a_this->kind.ruleset->sel_list)
1895                 cr_selector_unref (a_this->kind.ruleset->sel_list);
1897         a_this->kind.ruleset->sel_list = a_sel_list;
1899         if (a_sel_list)
1900                 cr_selector_ref (a_sel_list);
1902         return CR_OK;
1905 /**
1906  *Gets a pointer to the list of declaration contained
1907  *in the ruleset statement.
1908  *@param a_this the current instance of #CRStatement.
1909  *@a_decl_list out parameter. A pointer to the the returned
1910  *list of declaration. Must not be NULL.
1911  *@return CR_OK upon successfull completion, an error code if something
1912  *bad happened.
1913  */
1914 enum CRStatus
1915 cr_statement_ruleset_get_declarations (CRStatement * a_this,
1916                                        CRDeclaration ** a_decl_list)
1918         g_return_val_if_fail (a_this
1919                               && a_this->type == RULESET_STMT
1920                               && a_this->kind.ruleset
1921                               && a_decl_list, CR_BAD_PARAM_ERROR);
1923         *a_decl_list = a_this->kind.ruleset->decl_list;
1925         return CR_OK;
1928 /**
1929  *Gets a pointer to the selector list contained in
1930  *the current ruleset statement.
1931  *@param a_this the current ruleset statement.
1932  *@param a_list out parameter. The returned selector list,
1933  *if and only if the function returned CR_OK.
1934  *@return CR_OK upon successfull completion, an error code otherwise.
1935  */
1936 enum CRStatus
1937 cr_statement_ruleset_get_sel_list (CRStatement * a_this, CRSelector ** a_list)
1939         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
1940                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
1942         *a_list = a_this->kind.ruleset->sel_list;
1944         return CR_OK;
1947 /**
1948  *Sets a declaration list to the current ruleset statement.
1949  *@param a_this the current ruleset statement.
1950  *@param a_list the declaration list to be added to the current
1951  *ruleset statement.
1952  *@return CR_OK upon successfull completion, an error code otherwise.
1953  */
1954 enum CRStatus
1955 cr_statement_ruleset_set_decl_list (CRStatement * a_this,
1956                                     CRDeclaration * a_list)
1958         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
1959                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
1961         if (a_this->kind.ruleset->decl_list == a_list)
1962                 return CR_OK;
1964         if (a_this->kind.ruleset->sel_list) {
1965                 cr_declaration_destroy (a_this->kind.ruleset->decl_list);
1966         }
1968         a_this->kind.ruleset->sel_list = NULL;
1970         return CR_OK;
1973 /**
1974  *Appends a declaration to the current ruleset statement.
1975  *@param a_this the current statement.
1976  *@param a_prop the property of the declaration.
1977  *@param a_value the value of the declaration.
1978  *@return CR_OK uppon successfull completion, an error code
1979  *otherwise.
1980  */
1981 enum CRStatus
1982 cr_statement_ruleset_append_decl2 (CRStatement * a_this,
1983                                    CRString * a_prop, 
1984                                    CRTerm * a_value)
1986         CRDeclaration *new_decls = NULL;
1988         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
1989                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
1991         new_decls = cr_declaration_append2
1992                 (a_this->kind.ruleset->decl_list, 
1993                  a_prop, a_value);
1994         g_return_val_if_fail (new_decls, CR_ERROR);
1995         a_this->kind.ruleset->decl_list = new_decls;
1997         return CR_OK;
2000 /**
2001  *Appends a declaration to the current statement.
2002  *@param a_this the current statement.
2003  *@param a_declaration the declaration to append.
2004  *@return CR_OK upon sucessfull completion, an error code
2005  *otherwise.
2006  */
2007 enum CRStatus
2008 cr_statement_ruleset_append_decl (CRStatement * a_this,
2009                                   CRDeclaration * a_decl)
2011         CRDeclaration *new_decls = NULL;
2013         g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
2014                               && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
2016         new_decls = cr_declaration_append
2017                 (a_this->kind.ruleset->decl_list, a_decl);
2018         g_return_val_if_fail (new_decls, CR_ERROR);
2019         a_this->kind.ruleset->decl_list = new_decls;
2021         return CR_OK;
2024 /**
2025  *Sets a stylesheet to the current @import rule.
2026  *@param a_this the current @import rule.
2027  *@param a_sheet the stylesheet. The stylesheet is owned
2028  *by the current instance of #CRStatement, that is, the 
2029  *stylesheet will be destroyed when the current instance
2030  *of #CRStatement will be destroyed.
2031  *@return CR_OK upon successfull completion, an error code otherwise.
2032  */
2033 enum CRStatus
2034 cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
2035                                                 CRStyleSheet * a_sheet)
2037         g_return_val_if_fail (a_this
2038                               && a_this->type == AT_IMPORT_RULE_STMT
2039                               && a_this->kind.import_rule,
2040                               CR_BAD_PARAM_ERROR);
2042         a_this->kind.import_rule->sheet = a_sheet;
2044         return CR_OK;
2047 /**
2048  *Gets the stylesheet contained by the @import rule statement.
2049  *@param a_this the current @import rule statement.
2050  *@param a_sheet out parameter. The returned stylesheet if and
2051  *only if the function returns CR_OK.
2052  *@return CR_OK upon sucessfull completion, an error code otherwise.
2053  */
2054 enum CRStatus
2055 cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
2056                                                 CRStyleSheet ** a_sheet)
2058         g_return_val_if_fail (a_this
2059                               && a_this->type == AT_IMPORT_RULE_STMT
2060                               && a_this->kind.import_rule,
2061                               CR_BAD_PARAM_ERROR);
2062         *a_sheet = a_this->kind.import_rule->sheet;
2063         return CR_OK;
2067 /**
2068  *Sets an url to the current @import rule statement.
2069  *@param a_this the current @import rule statement.
2070  *@param a_url the url to set.
2071  *@return CR_OK upon successfull completion, an error code otherwise.
2072  */
2073 enum CRStatus
2074 cr_statement_at_import_rule_set_url (CRStatement * a_this, 
2075                                      CRString * a_url)
2077         g_return_val_if_fail (a_this
2078                               && a_this->type == AT_IMPORT_RULE_STMT
2079                               && a_this->kind.import_rule,
2080                               CR_BAD_PARAM_ERROR);
2082         if (a_this->kind.import_rule->url) {
2083                 cr_string_destroy (a_this->kind.import_rule->url);
2084         }
2086         a_this->kind.import_rule->url = a_url;
2088         return CR_OK;
2091 /**
2092  *Gets the url of the @import rule statement.
2093  *@param the current @import rule statement.
2094  *@param a_url out parameter. The returned url if
2095  *and only if the function returned CR_OK.
2096  */
2097 enum CRStatus
2098 cr_statement_at_import_rule_get_url (CRStatement * a_this, 
2099                                      CRString ** a_url)
2101         g_return_val_if_fail (a_this
2102                               && a_this->type == AT_IMPORT_RULE_STMT
2103                               && a_this->kind.import_rule,
2104                               CR_BAD_PARAM_ERROR);
2106         *a_url = a_this->kind.import_rule->url;
2108         return CR_OK;
2111 /**
2112  *Return the number of rules in the media rule;
2113  *@param a_this the current instance of #CRStatement.
2114  *@return number of rules in the media rule.
2115  */
2116 int
2117 cr_statement_at_media_nr_rules (CRStatement * a_this)
2119         g_return_val_if_fail (a_this
2120                               && a_this->type == AT_MEDIA_RULE_STMT
2121                               && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
2123         return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
2126 /**
2127  *Use an index to get a CRStatement from the media rule list of rules.
2128  *@param a_this the current instance of #CRStatement.
2129  *@param itemnr the index into the media rule list of rules.
2130  *@return CRStatement at position itemnr, if itemnr > number of rules - 1,
2131  *it will return NULL.
2132  */
2133 CRStatement *
2134 cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
2136         g_return_val_if_fail (a_this
2137                               && a_this->type == AT_MEDIA_RULE_STMT
2138                               && a_this->kind.media_rule, NULL);
2140         return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
2141                                            itemnr);
2144 /**
2145  *Sets a declaration list to the current @page rule statement.
2146  *@param a_this the current @page rule statement.
2147  *@param a_decl_list the declaration list to add. Will be freed
2148  *by the current instance of #CRStatement when it is destroyed.
2149  *@return CR_OK upon successfull completion, an error code otherwise.
2150  */
2151 enum CRStatus
2152 cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
2153                                             CRDeclaration * a_decl_list)
2155         g_return_val_if_fail (a_this
2156                               && a_this->type == AT_PAGE_RULE_STMT
2157                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
2159         if (a_this->kind.page_rule->decl_list) {
2160                 cr_declaration_unref (a_this->kind.page_rule->decl_list);
2161         }
2163         a_this->kind.page_rule->decl_list = a_decl_list;
2165         if (a_decl_list) {
2166                 cr_declaration_ref (a_decl_list);
2167         }
2169         return CR_OK;
2172 /**
2173  *Gets the declaration list associated to the current @page rule
2174  *statement.
2175  *@param a_this the current  @page rule statement.
2176  *@param a_decl_list out parameter. The returned declaration list.
2177  *@return CR_OK upon successfull completion, an error code otherwise.
2178  */
2179 enum CRStatus
2180 cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
2181                                             CRDeclaration ** a_decl_list)
2183         g_return_val_if_fail (a_this
2184                               && a_this->type == AT_PAGE_RULE_STMT
2185                               && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
2187         *a_decl_list = a_this->kind.page_rule->decl_list;
2189         return CR_OK;
2192 /**
2193  *Sets the charset of the current @charset rule statement.
2194  *@param a_this the current @charset rule statement.
2195  *@param a_charset the charset to set.
2196  *@return CR_OK upon successfull completion, an error code otherwise.
2197  */
2198 enum CRStatus
2199 cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
2200                                           CRString * a_charset)
2202         g_return_val_if_fail (a_this
2203                               && a_this->type == AT_CHARSET_RULE_STMT
2204                               && a_this->kind.charset_rule,
2205                               CR_BAD_PARAM_ERROR);
2207         if (a_this->kind.charset_rule->charset) {
2208                 cr_string_destroy (a_this->kind.charset_rule->charset);
2209         }
2210         a_this->kind.charset_rule->charset = a_charset;
2211         return CR_OK;
2214 /**
2215  *Gets the charset string associated to the current
2216  *@charset rule statement.
2217  *@param a_this the current @charset rule statement.
2218  *@param a_charset out parameter. The returned charset string if
2219  *and only if the function returned CR_OK.
2220  */
2221 enum CRStatus
2222 cr_statement_at_charset_rule_get_charset (CRStatement * a_this,
2223                                           CRString ** a_charset)
2225         g_return_val_if_fail (a_this
2226                               && a_this->type == AT_CHARSET_RULE_STMT
2227                               && a_this->kind.charset_rule,
2228                               CR_BAD_PARAM_ERROR);
2230         *a_charset = a_this->kind.charset_rule->charset;
2232         return CR_OK;
2235 /**
2236  *Sets a declaration list to the current @font-face rule statement.
2237  *@param a_this the current @font-face rule statement.
2238  *@param a_decls the declarations list to set.
2239  *@return CR_OK upon successfull completion, an error code otherwise.
2240  */
2241 enum CRStatus
2242 cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
2243                                           CRDeclaration * a_decls)
2245         g_return_val_if_fail (a_this
2246                               && a_this->type == AT_FONT_FACE_RULE_STMT
2247                               && a_this->kind.font_face_rule,
2248                               CR_BAD_PARAM_ERROR);
2250         if (a_this->kind.font_face_rule->decl_list) {
2251                 cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
2252         }
2254         a_this->kind.font_face_rule->decl_list = a_decls;
2255         cr_declaration_ref (a_decls);
2257         return CR_OK;
2260 /**
2261  *Gets the declaration list associated to the current instance
2262  *of @font-face rule statement.
2263  *@param a_this the current @font-face rule statement.
2264  *@param a_decls out parameter. The returned declaration list if
2265  *and only if this function returns CR_OK.
2266  *@return CR_OK upon successfull completion, an error code otherwise.
2267  */
2268 enum CRStatus
2269 cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
2270                                           CRDeclaration ** a_decls)
2272         g_return_val_if_fail (a_this
2273                               && a_this->type == AT_FONT_FACE_RULE_STMT
2274                               && a_this->kind.font_face_rule,
2275                               CR_BAD_PARAM_ERROR);
2277         *a_decls = a_this->kind.font_face_rule->decl_list;
2279         return CR_OK;
2282 /**
2283  *Adds a declaration to the current @font-face rule
2284  *statement.
2285  *@param a_this the current @font-face rule statement.
2286  *@param a_prop the property of the declaration.
2287  *@param a_value the value of the declaration.
2288  *@return CR_OK upon successfull completion, an error code otherwise.
2289  */
2290 enum CRStatus
2291 cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
2292                                          CRString * a_prop, CRTerm * a_value)
2294         CRDeclaration *decls = NULL;
2296         g_return_val_if_fail (a_this
2297                               && a_this->type == AT_FONT_FACE_RULE_STMT
2298                               && a_this->kind.font_face_rule,
2299                               CR_BAD_PARAM_ERROR);
2301         decls = cr_declaration_append2
2302                 (a_this->kind.font_face_rule->decl_list, 
2303                  a_prop, a_value);
2305         g_return_val_if_fail (decls, CR_ERROR);
2307         if (a_this->kind.font_face_rule->decl_list == NULL)
2308                 cr_declaration_ref (decls);
2310         a_this->kind.font_face_rule->decl_list = decls;
2312         return CR_OK;
2315 /**
2316  *Serializes a css statement into a string
2317  *@param a_this the current statement to serialize
2318  *@param a_indent the number of white space of indentation.
2319  *@return the serialized statement. Must be freed by the caller
2320  *using g_free().
2321  */
2322 gchar *
2323 cr_statement_to_string (CRStatement * a_this, gulong a_indent)
2325         gchar *str = NULL ;
2327         if (!a_this)
2328                 return NULL;
2330         switch (a_this->type) {
2331         case RULESET_STMT:
2332                 str = cr_statement_ruleset_to_string 
2333                         (a_this, a_indent);
2334                 break;
2336         case AT_FONT_FACE_RULE_STMT:
2337                 str = cr_statement_font_face_rule_to_string 
2338                         (a_this, a_indent) ;
2339                 break;
2341         case AT_CHARSET_RULE_STMT:
2342                 str = cr_statement_charset_to_string
2343                         (a_this, a_indent);                
2344                 break;
2346         case AT_PAGE_RULE_STMT:
2347                 str = cr_statement_at_page_rule_to_string
2348                         (a_this, a_indent);
2349                 break;
2351         case AT_MEDIA_RULE_STMT:
2352                 str = cr_statement_media_rule_to_string
2353                         (a_this, a_indent);
2354                 break;
2356         case AT_IMPORT_RULE_STMT:
2357                 str = cr_statement_import_rule_to_string
2358                         (a_this, a_indent);
2359                 break;
2361         default:
2362                 cr_utils_trace_info ("Statement unrecognized");
2363                 break;
2364         }
2365         return str ;
2368 gchar*
2369 cr_statement_list_to_string (CRStatement *a_this, gulong a_indent)
2371         CRStatement *cur_stmt = NULL ;
2372         GString *stringue = NULL ;
2373         gchar *str = NULL ;
2375         g_return_val_if_fail (a_this, NULL) ;
2377         stringue = g_string_new (NULL) ;
2378         if (!stringue) {
2379                 cr_utils_trace_info ("Out of memory") ;
2380                 return NULL ;
2381         }
2382         for (cur_stmt = a_this ; cur_stmt;
2383              cur_stmt = cur_stmt->next) {
2384                 str = cr_statement_to_string (cur_stmt, a_indent) ;
2385                 if (str) {
2386                         if (!cur_stmt->prev) {
2387                                 g_string_append (stringue, str) ;
2388                         } else {
2389                                 g_string_append_printf 
2390                                         (stringue, "\n%s", str) ;
2391                         }
2392                         g_free (str) ;
2393                         str = NULL ;
2394                 }                
2395         }
2396         str = stringue->str ;
2397         g_string_free (stringue, FALSE) ;
2398         return str ;
2401 /**
2402  *Dumps the css2 statement to a file.
2403  *@param a_this the current css2 statement.
2404  *@param a_fp the destination file pointer.
2405  *@param a_indent the number of white space indentation characters.
2406  */
2407 void
2408 cr_statement_dump (CRStatement * a_this, FILE * a_fp, gulong a_indent)
2410         gchar *str = NULL ;
2412         if (!a_this)
2413                 return;
2415         str = cr_statement_to_string (a_this, a_indent) ;
2416         if (str) {
2417                 fprintf (a_fp, "%s",str) ;
2418                 g_free (str) ;
2419                 str = NULL ;
2420         }
2423 /**
2424  *Dumps a ruleset statement to a file.
2425  *@param a_this the current instance of #CRStatement.
2426  *@param a_fp the destination file pointer.
2427  *@param a_indent the number of indentation white spaces to add.
2428  */
2429 void
2430 cr_statement_dump_ruleset (CRStatement * a_this, FILE * a_fp, glong a_indent)
2432         g_return_if_fail (a_fp && a_this);
2433         gchar *str = cr_statement_ruleset_to_string (a_this, a_indent);
2434         if (str) {
2435                 fprintf (a_fp, "%s", str);
2436                 g_free (str);
2437                 str = NULL;
2438         }
2441 /**
2442  *Dumps a font face rule statement to a file.
2443  *@param a_this the current instance of font face rule statement.
2444  *@param a_fp the destination file pointer.
2445  *@param a_indent the number of white space indentation.
2446  */
2447 void
2448 cr_statement_dump_font_face_rule (CRStatement * a_this, FILE * a_fp,
2449                                   glong a_indent)
2451         gchar *str = NULL ;
2452         g_return_if_fail (a_this 
2453                           && a_this->type == AT_FONT_FACE_RULE_STMT);
2455         str = cr_statement_font_face_rule_to_string (a_this,
2456                                                      a_indent) ;
2457         if (str) {
2458                 fprintf (a_fp, "%s", str) ;
2459                 g_free (str) ;
2460                 str = NULL ;
2461         }
2464 /**
2465  *Dumps an @charset rule statement to a file.
2466  *@param a_this the current instance of the @charset rule statement.
2467  *@param a_fp the destination file pointer.
2468  *@param a_indent the number of indentation white spaces.
2469  */
2470 void
2471 cr_statement_dump_charset (CRStatement * a_this, FILE * a_fp, gulong a_indent)
2473         g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
2475         gchar *str = cr_statement_charset_to_string (a_this,
2476                                               a_indent) ;
2477         if (str) {
2478                 fprintf (a_fp, "%s", str) ;
2479                 g_free (str) ;
2480                 str = NULL ;
2481         }
2485 /**
2486  *Dumps an @page rule statement on stdout.
2487  *@param a_this the statement to dump on stdout.
2488  *@param a_fp the destination file pointer.
2489  *@param a_indent the number of indentation white spaces.
2490  */
2491 void
2492 cr_statement_dump_page (CRStatement * a_this, FILE * a_fp, gulong a_indent)
2494         g_return_if_fail (a_this
2495                           && a_this->type == AT_PAGE_RULE_STMT
2496                           && a_this->kind.page_rule);
2498         gchar *str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
2499         if (str) {
2500                 fprintf (a_fp, "%s", str);
2501                 g_free (str) ;
2502                 str = NULL ; 
2503         }
2507 /**
2508  *Dumps an @media rule statement to a file.
2509  *@param a_this the statement to dump.
2510  *@param a_fp the destination file pointer
2511  *@param a_indent the number of white spaces indentation.
2512  */
2513 void
2514 cr_statement_dump_media_rule (CRStatement * a_this, 
2515                               FILE * a_fp,
2516                               gulong a_indent)
2518         gchar *str = NULL ;
2519         g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
2521         str = cr_statement_media_rule_to_string (a_this, a_indent) ;
2522         if (str) {
2523                 fprintf (a_fp, "%s", str) ;
2524                 g_free (str) ;
2525                 str = NULL ;
2526         }
2529 /**
2530  *Dumps an @import rule statement to a file.
2531  *@param a_fp the destination file pointer.
2532  *@param a_indent the number of white space indentations.
2533  */
2534 void
2535 cr_statement_dump_import_rule (CRStatement * a_this, FILE * a_fp,
2536                                gulong a_indent)
2538         gchar *str = NULL ;
2539         g_return_if_fail (a_this
2540                           && a_this->type == AT_IMPORT_RULE_STMT
2541                           && a_fp
2542                           && a_this->kind.import_rule);
2544         str = cr_statement_import_rule_to_string (a_this, a_indent) ;
2545         if (str) {
2546                 fprintf (a_fp, "%s", str) ;
2547                 g_free (str) ;
2548                 str = NULL ;
2549         }
2552 /**
2553  *Destructor of #CRStatement.
2554  */
2555 void
2556 cr_statement_destroy (CRStatement * a_this)
2558         CRStatement *cur = NULL;
2560         g_return_if_fail (a_this);
2562         /*go get the tail of the list */
2563         for (cur = a_this; cur && cur->next; cur = cur->next) {
2564                 cr_statement_clear (cur);
2565         }
2567         if (cur)
2568                 cr_statement_clear (cur);
2570         if (cur->prev == NULL) {
2571                 g_free (a_this);
2572                 return;
2573         }
2575         /*walk backward and free next element */
2576         for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
2577                 if (cur->next) {
2578                         g_free (cur->next);
2579                         cur->next = NULL;
2580                 }
2581         }
2583         if (!cur)
2584                 return;
2586         /*free the one remaining list */
2587         if (cur->next) {
2588                 g_free (cur->next);
2589                 cur->next = NULL;
2590         }
2592         g_free (cur);
2593         cur = NULL;