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