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