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