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