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