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