Libcroco
|
00001 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ 00002 00003 /* 00004 * This file is part of The Croco Library 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of version 2.1 of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00018 * USA 00019 * 00020 * Author: Dodji Seketeli. 00021 * See COPYRIGHTS files for copyrights information. 00022 */ 00023 00024 #include <string.h> 00025 #include "cr-statement.h" 00026 #include "cr-parser.h" 00027 00028 /** 00029 *@file 00030 *Definition of the #CRStatement class. 00031 */ 00032 00033 #define DECLARATION_INDENT_NB 2 00034 00035 static void cr_statement_clear (CRStatement * a_this); 00036 00037 static void 00038 parse_font_face_start_font_face_cb (CRDocHandler * a_this, 00039 CRParsingLocation *a_location) 00040 { 00041 CRStatement *stmt = NULL; 00042 enum CRStatus status = CR_OK; 00043 00044 stmt = cr_statement_new_at_font_face_rule (NULL, NULL); 00045 g_return_if_fail (stmt); 00046 00047 status = cr_doc_handler_set_ctxt (a_this, stmt); 00048 g_return_if_fail (status == CR_OK); 00049 } 00050 00051 static void 00052 parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this) 00053 { 00054 CRStatement *stmt = NULL; 00055 CRStatement **stmtptr = NULL; 00056 enum CRStatus status = CR_OK; 00057 00058 g_return_if_fail (a_this); 00059 00060 stmtptr = &stmt; 00061 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); 00062 if (status != CR_OK) { 00063 cr_utils_trace_info ("Couldn't get parsing context. " 00064 "This may lead to some memory leaks."); 00065 return; 00066 } 00067 if (stmt) { 00068 cr_statement_destroy (stmt); 00069 cr_doc_handler_set_ctxt (a_this, NULL); 00070 return; 00071 } 00072 } 00073 00074 static void 00075 parse_font_face_property_cb (CRDocHandler * a_this, 00076 CRString * a_name, 00077 CRTerm * a_value, gboolean a_important) 00078 { 00079 enum CRStatus status = CR_OK; 00080 CRString *name = NULL; 00081 CRDeclaration *decl = NULL; 00082 CRStatement *stmt = NULL; 00083 CRStatement **stmtptr = NULL; 00084 00085 g_return_if_fail (a_this && a_name); 00086 00087 stmtptr = &stmt; 00088 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); 00089 g_return_if_fail (status == CR_OK && stmt); 00090 g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT); 00091 00092 name = cr_string_dup (a_name) ; 00093 g_return_if_fail (name); 00094 decl = cr_declaration_new (stmt, name, a_value); 00095 if (!decl) { 00096 cr_utils_trace_info ("cr_declaration_new () failed."); 00097 goto error; 00098 } 00099 name = NULL; 00100 00101 stmt->kind.font_face_rule->decl_list = 00102 cr_declaration_append (stmt->kind.font_face_rule->decl_list, 00103 decl); 00104 if (!stmt->kind.font_face_rule->decl_list) 00105 goto error; 00106 decl = NULL; 00107 00108 error: 00109 if (decl) { 00110 cr_declaration_unref (decl); 00111 decl = NULL; 00112 } 00113 if (name) { 00114 cr_string_destroy (name); 00115 name = NULL; 00116 } 00117 } 00118 00119 static void 00120 parse_font_face_end_font_face_cb (CRDocHandler * a_this) 00121 { 00122 CRStatement *result = NULL; 00123 CRStatement **resultptr = NULL; 00124 enum CRStatus status = CR_OK; 00125 00126 g_return_if_fail (a_this); 00127 00128 resultptr = &result; 00129 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr); 00130 g_return_if_fail (status == CR_OK && result); 00131 g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT); 00132 00133 status = cr_doc_handler_set_result (a_this, result); 00134 g_return_if_fail (status == CR_OK); 00135 } 00136 00137 static void 00138 parse_page_start_page_cb (CRDocHandler * a_this, 00139 CRString * a_name, 00140 CRString * a_pseudo_page, 00141 CRParsingLocation *a_location) 00142 { 00143 CRStatement *stmt = NULL; 00144 enum CRStatus status = CR_OK; 00145 CRString *page_name = NULL, *pseudo_name = NULL ; 00146 00147 if (a_name) 00148 page_name = cr_string_dup (a_name) ; 00149 if (a_pseudo_page) 00150 pseudo_name = cr_string_dup (a_pseudo_page) ; 00151 00152 stmt = cr_statement_new_at_page_rule (NULL, NULL, 00153 page_name, 00154 pseudo_name); 00155 page_name = NULL ; 00156 pseudo_name = NULL ; 00157 g_return_if_fail (stmt); 00158 status = cr_doc_handler_set_ctxt (a_this, stmt); 00159 g_return_if_fail (status == CR_OK); 00160 } 00161 00162 static void 00163 parse_page_unrecoverable_error_cb (CRDocHandler * a_this) 00164 { 00165 CRStatement *stmt = NULL; 00166 CRStatement **stmtptr = NULL; 00167 enum CRStatus status = CR_OK; 00168 00169 g_return_if_fail (a_this); 00170 00171 stmtptr = &stmt; 00172 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); 00173 if (status != CR_OK) { 00174 cr_utils_trace_info ("Couldn't get parsing context. " 00175 "This may lead to some memory leaks."); 00176 return; 00177 } 00178 if (stmt) { 00179 cr_statement_destroy (stmt); 00180 stmt = NULL; 00181 cr_doc_handler_set_ctxt (a_this, NULL); 00182 } 00183 } 00184 00185 static void 00186 parse_page_property_cb (CRDocHandler * a_this, 00187 CRString * a_name, 00188 CRTerm * a_expression, gboolean a_important) 00189 { 00190 CRString *name = NULL; 00191 CRStatement *stmt = NULL; 00192 CRStatement **stmtptr = NULL; 00193 CRDeclaration *decl = NULL; 00194 enum CRStatus status = CR_OK; 00195 00196 stmtptr = &stmt; 00197 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); 00198 g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT); 00199 00200 name = cr_string_dup (a_name); 00201 g_return_if_fail (name); 00202 00203 decl = cr_declaration_new (stmt, name, a_expression); 00204 g_return_if_fail (decl); 00205 decl->important = a_important; 00206 stmt->kind.page_rule->decl_list = 00207 cr_declaration_append (stmt->kind.page_rule->decl_list, decl); 00208 g_return_if_fail (stmt->kind.page_rule->decl_list); 00209 } 00210 00211 static void 00212 parse_page_end_page_cb (CRDocHandler * a_this, 00213 CRString * a_name, 00214 CRString * a_pseudo_page) 00215 { 00216 enum CRStatus status = CR_OK; 00217 CRStatement *stmt = NULL; 00218 CRStatement **stmtptr = NULL; 00219 00220 stmtptr = &stmt; 00221 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); 00222 g_return_if_fail (status == CR_OK && stmt); 00223 g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT); 00224 00225 status = cr_doc_handler_set_result (a_this, stmt); 00226 g_return_if_fail (status == CR_OK); 00227 } 00228 00229 static void 00230 parse_at_media_start_media_cb (CRDocHandler * a_this, 00231 GList * a_media_list, 00232 CRParsingLocation *a_location) 00233 { 00234 enum CRStatus status = CR_OK; 00235 CRStatement *at_media = NULL; 00236 GList *media_list = NULL; 00237 00238 g_return_if_fail (a_this && a_this->priv); 00239 00240 if (a_media_list) { 00241 /*duplicate media list */ 00242 media_list = cr_utils_dup_glist_of_cr_string 00243 (a_media_list); 00244 } 00245 00246 g_return_if_fail (media_list); 00247 00248 /*make sure cr_statement_new_at_media_rule works in this case. */ 00249 at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list); 00250 00251 status = cr_doc_handler_set_ctxt (a_this, at_media); 00252 g_return_if_fail (status == CR_OK); 00253 status = cr_doc_handler_set_result (a_this, at_media); 00254 g_return_if_fail (status == CR_OK); 00255 } 00256 00257 static void 00258 parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this) 00259 { 00260 enum CRStatus status = CR_OK; 00261 CRStatement *stmt = NULL; 00262 CRStatement **stmtptr = NULL; 00263 00264 g_return_if_fail (a_this); 00265 00266 stmtptr = &stmt; 00267 status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr); 00268 if (status != CR_OK) { 00269 cr_utils_trace_info ("Couldn't get parsing context. " 00270 "This may lead to some memory leaks."); 00271 return; 00272 } 00273 if (stmt) { 00274 cr_statement_destroy (stmt); 00275 stmt = NULL; 00276 cr_doc_handler_set_ctxt (a_this, NULL); 00277 cr_doc_handler_set_result (a_this, NULL); 00278 } 00279 } 00280 00281 static void 00282 parse_at_media_start_selector_cb (CRDocHandler * a_this, 00283 CRSelector * a_sellist) 00284 { 00285 enum CRStatus status = CR_OK; 00286 CRStatement *at_media = NULL; 00287 CRStatement **at_media_ptr = NULL; 00288 CRStatement *ruleset = NULL; 00289 00290 g_return_if_fail (a_this && a_this->priv && a_sellist); 00291 00292 at_media_ptr = &at_media; 00293 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr); 00294 g_return_if_fail (status == CR_OK && at_media); 00295 g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT); 00296 ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media); 00297 g_return_if_fail (ruleset); 00298 status = cr_doc_handler_set_ctxt (a_this, ruleset); 00299 g_return_if_fail (status == CR_OK); 00300 } 00301 00302 static void 00303 parse_at_media_property_cb (CRDocHandler * a_this, 00304 CRString * a_name, CRTerm * a_value, 00305 gboolean a_important) 00306 { 00307 enum CRStatus status = CR_OK; 00308 00309 /* 00310 *the current ruleset stmt, child of the 00311 *current at-media being parsed. 00312 */ 00313 CRStatement *stmt = NULL; 00314 CRStatement **stmtptr = NULL; 00315 CRDeclaration *decl = NULL; 00316 CRString *name = NULL; 00317 00318 g_return_if_fail (a_this && a_name); 00319 00320 name = cr_string_dup (a_name) ; 00321 g_return_if_fail (name); 00322 00323 stmtptr = &stmt; 00324 status = cr_doc_handler_get_ctxt (a_this, 00325 (gpointer *) stmtptr); 00326 g_return_if_fail (status == CR_OK && stmt); 00327 g_return_if_fail (stmt->type == RULESET_STMT); 00328 00329 decl = cr_declaration_new (stmt, name, a_value); 00330 g_return_if_fail (decl); 00331 decl->important = a_important; 00332 status = cr_statement_ruleset_append_decl (stmt, decl); 00333 g_return_if_fail (status == CR_OK); 00334 } 00335 00336 static void 00337 parse_at_media_end_selector_cb (CRDocHandler * a_this, 00338 CRSelector * a_sellist) 00339 { 00340 enum CRStatus status = CR_OK; 00341 00342 /* 00343 *the current ruleset stmt, child of the 00344 *current at-media being parsed. 00345 */ 00346 CRStatement *stmt = NULL; 00347 CRStatement **stmtptr = NULL; 00348 00349 g_return_if_fail (a_this && a_sellist); 00350 00351 stmtptr = &stmt; 00352 status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); 00353 g_return_if_fail (status == CR_OK && stmt 00354 && stmt->type == RULESET_STMT); 00355 g_return_if_fail (stmt->kind.ruleset->parent_media_rule); 00356 00357 status = cr_doc_handler_set_ctxt 00358 (a_this, stmt->kind.ruleset->parent_media_rule); 00359 g_return_if_fail (status == CR_OK); 00360 } 00361 00362 static void 00363 parse_at_media_end_media_cb (CRDocHandler * a_this, 00364 GList * a_media_list) 00365 { 00366 enum CRStatus status = CR_OK; 00367 CRStatement *at_media = NULL; 00368 CRStatement **at_media_ptr = NULL; 00369 00370 g_return_if_fail (a_this && a_this->priv); 00371 00372 at_media_ptr = &at_media; 00373 status = cr_doc_handler_get_ctxt (a_this, 00374 (gpointer *) at_media_ptr); 00375 g_return_if_fail (status == CR_OK && at_media); 00376 status = cr_doc_handler_set_result (a_this, at_media); 00377 } 00378 00379 static void 00380 parse_ruleset_start_selector_cb (CRDocHandler * a_this, 00381 CRSelector * a_sellist) 00382 { 00383 CRStatement *ruleset = NULL; 00384 00385 g_return_if_fail (a_this && a_this->priv && a_sellist); 00386 00387 ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL); 00388 g_return_if_fail (ruleset); 00389 00390 cr_doc_handler_set_result (a_this, ruleset); 00391 } 00392 00393 static void 00394 parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this) 00395 { 00396 CRStatement *stmt = NULL; 00397 CRStatement **stmtptr = NULL; 00398 enum CRStatus status = CR_OK; 00399 00400 stmtptr = &stmt; 00401 status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr); 00402 if (status != CR_OK) { 00403 cr_utils_trace_info ("Couldn't get parsing context. " 00404 "This may lead to some memory leaks."); 00405 return; 00406 } 00407 if (stmt) { 00408 cr_statement_destroy (stmt); 00409 stmt = NULL; 00410 cr_doc_handler_set_result (a_this, NULL); 00411 } 00412 } 00413 00414 static void 00415 parse_ruleset_property_cb (CRDocHandler * a_this, 00416 CRString * a_name, 00417 CRTerm * a_value, gboolean a_important) 00418 { 00419 enum CRStatus status = CR_OK; 00420 CRStatement *ruleset = NULL; 00421 CRStatement **rulesetptr = NULL; 00422 CRDeclaration *decl = NULL; 00423 CRString *stringue = NULL; 00424 00425 g_return_if_fail (a_this && a_this->priv && a_name); 00426 00427 stringue = cr_string_dup (a_name); 00428 g_return_if_fail (stringue); 00429 00430 rulesetptr = &ruleset; 00431 status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr); 00432 g_return_if_fail (status == CR_OK 00433 && ruleset 00434 && ruleset->type == RULESET_STMT); 00435 00436 decl = cr_declaration_new (ruleset, stringue, a_value); 00437 g_return_if_fail (decl); 00438 decl->important = a_important; 00439 status = cr_statement_ruleset_append_decl (ruleset, decl); 00440 g_return_if_fail (status == CR_OK); 00441 } 00442 00443 static void 00444 parse_ruleset_end_selector_cb (CRDocHandler * a_this, 00445 CRSelector * a_sellist) 00446 { 00447 CRStatement *result = NULL; 00448 CRStatement **resultptr = NULL; 00449 enum CRStatus status = CR_OK; 00450 00451 g_return_if_fail (a_this && a_sellist); 00452 00453 resultptr = &result; 00454 status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr); 00455 00456 g_return_if_fail (status == CR_OK 00457 && result 00458 && result->type == RULESET_STMT); 00459 } 00460 00461 static void 00462 cr_statement_clear (CRStatement * a_this) 00463 { 00464 g_return_if_fail (a_this); 00465 00466 switch (a_this->type) { 00467 case AT_RULE_STMT: 00468 break; 00469 case RULESET_STMT: 00470 if (!a_this->kind.ruleset) 00471 return; 00472 if (a_this->kind.ruleset->sel_list) { 00473 cr_selector_unref (a_this->kind.ruleset->sel_list); 00474 a_this->kind.ruleset->sel_list = NULL; 00475 } 00476 if (a_this->kind.ruleset->decl_list) { 00477 cr_declaration_destroy 00478 (a_this->kind.ruleset->decl_list); 00479 a_this->kind.ruleset->decl_list = NULL; 00480 } 00481 g_free (a_this->kind.ruleset); 00482 a_this->kind.ruleset = NULL; 00483 break; 00484 00485 case AT_IMPORT_RULE_STMT: 00486 if (!a_this->kind.import_rule) 00487 return; 00488 if (a_this->kind.import_rule->url) { 00489 cr_string_destroy 00490 (a_this->kind.import_rule->url) ; 00491 a_this->kind.import_rule->url = NULL; 00492 } 00493 g_free (a_this->kind.import_rule); 00494 a_this->kind.import_rule = NULL; 00495 break; 00496 00497 case AT_MEDIA_RULE_STMT: 00498 if (!a_this->kind.media_rule) 00499 return; 00500 if (a_this->kind.media_rule->rulesets) { 00501 cr_statement_destroy 00502 (a_this->kind.media_rule->rulesets); 00503 a_this->kind.media_rule->rulesets = NULL; 00504 } 00505 if (a_this->kind.media_rule->media_list) { 00506 GList *cur = NULL; 00507 00508 for (cur = a_this->kind.media_rule->media_list; 00509 cur; cur = cur->next) { 00510 if (cur->data) { 00511 cr_string_destroy ((CRString *) cur->data); 00512 cur->data = NULL; 00513 } 00514 00515 } 00516 g_list_free (a_this->kind.media_rule->media_list); 00517 a_this->kind.media_rule->media_list = NULL; 00518 } 00519 g_free (a_this->kind.media_rule); 00520 a_this->kind.media_rule = NULL; 00521 break; 00522 00523 case AT_PAGE_RULE_STMT: 00524 if (!a_this->kind.page_rule) 00525 return; 00526 00527 if (a_this->kind.page_rule->decl_list) { 00528 cr_declaration_destroy 00529 (a_this->kind.page_rule->decl_list); 00530 a_this->kind.page_rule->decl_list = NULL; 00531 } 00532 if (a_this->kind.page_rule->name) { 00533 cr_string_destroy 00534 (a_this->kind.page_rule->name); 00535 a_this->kind.page_rule->name = NULL; 00536 } 00537 if (a_this->kind.page_rule->pseudo) { 00538 cr_string_destroy 00539 (a_this->kind.page_rule->pseudo); 00540 a_this->kind.page_rule->pseudo = NULL; 00541 } 00542 g_free (a_this->kind.page_rule); 00543 a_this->kind.page_rule = NULL; 00544 break; 00545 00546 case AT_CHARSET_RULE_STMT: 00547 if (!a_this->kind.charset_rule) 00548 return; 00549 00550 if (a_this->kind.charset_rule->charset) { 00551 cr_string_destroy 00552 (a_this->kind.charset_rule->charset); 00553 a_this->kind.charset_rule->charset = NULL; 00554 } 00555 g_free (a_this->kind.charset_rule); 00556 a_this->kind.charset_rule = NULL; 00557 break; 00558 00559 case AT_FONT_FACE_RULE_STMT: 00560 if (!a_this->kind.font_face_rule) 00561 return; 00562 00563 if (a_this->kind.font_face_rule->decl_list) { 00564 cr_declaration_unref 00565 (a_this->kind.font_face_rule->decl_list); 00566 a_this->kind.font_face_rule->decl_list = NULL; 00567 } 00568 g_free (a_this->kind.font_face_rule); 00569 a_this->kind.font_face_rule = NULL; 00570 break; 00571 00572 default: 00573 break; 00574 } 00575 } 00576 00577 /** 00578 * cr_statement_ruleset_to_string: 00579 * 00580 *@a_this: the current instance of #CRStatement 00581 *@a_indent: the number of whitespace to use for indentation 00582 * 00583 *Serializes the ruleset statement into a string 00584 * 00585 *Returns the newly allocated serialised string. Must be freed 00586 *by the caller, using g_free(). 00587 */ 00588 static gchar * 00589 cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent) 00590 { 00591 GString *stringue = NULL; 00592 gchar *tmp_str = NULL, 00593 *result = NULL; 00594 00595 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL); 00596 00597 stringue = g_string_new (NULL); 00598 00599 if (a_this->kind.ruleset->sel_list) { 00600 if (a_indent) 00601 cr_utils_dump_n_chars2 (' ', stringue, a_indent); 00602 00603 tmp_str = 00604 (gchar *) cr_selector_to_string (a_this->kind.ruleset-> 00605 sel_list); 00606 if (tmp_str) { 00607 g_string_append (stringue, tmp_str); 00608 g_free (tmp_str); 00609 tmp_str = NULL; 00610 } 00611 } 00612 g_string_append (stringue, " {\n"); 00613 if (a_this->kind.ruleset->decl_list) { 00614 tmp_str = (gchar *) cr_declaration_list_to_string2 00615 (a_this->kind.ruleset->decl_list, 00616 a_indent + DECLARATION_INDENT_NB, TRUE); 00617 if (tmp_str) { 00618 g_string_append (stringue, tmp_str); 00619 g_free (tmp_str); 00620 tmp_str = NULL; 00621 } 00622 g_string_append (stringue, "\n"); 00623 cr_utils_dump_n_chars2 (' ', stringue, a_indent); 00624 } 00625 g_string_append (stringue, "}"); 00626 result = stringue->str; 00627 00628 if (stringue) { 00629 g_string_free (stringue, FALSE); 00630 stringue = NULL; 00631 } 00632 if (tmp_str) { 00633 g_free (tmp_str); 00634 tmp_str = NULL; 00635 } 00636 return result; 00637 } 00638 00639 00640 /** 00641 * cr_statement_font_face_rule_to_string: 00642 * 00643 *@a_this: the current instance of #CRStatement to consider 00644 *It must be a font face rule statement. 00645 *@a_indent: the number of white spaces of indentation. 00646 * 00647 *Serializes a font face rule statement into a string. 00648 * 00649 *Returns the serialized string. Must be deallocated by the caller 00650 *using g_free(). 00651 */ 00652 static gchar * 00653 cr_statement_font_face_rule_to_string (CRStatement const * a_this, 00654 glong a_indent) 00655 { 00656 gchar *result = NULL, *tmp_str = NULL ; 00657 GString *stringue = NULL ; 00658 00659 g_return_val_if_fail (a_this 00660 && a_this->type == AT_FONT_FACE_RULE_STMT, 00661 NULL); 00662 00663 if (a_this->kind.font_face_rule->decl_list) { 00664 stringue = g_string_new (NULL) ; 00665 g_return_val_if_fail (stringue, NULL) ; 00666 if (a_indent) 00667 cr_utils_dump_n_chars2 (' ', stringue, 00668 a_indent); 00669 g_string_append (stringue, "@font-face {\n"); 00670 tmp_str = (gchar *) cr_declaration_list_to_string2 00671 (a_this->kind.font_face_rule->decl_list, 00672 a_indent + DECLARATION_INDENT_NB, TRUE) ; 00673 if (tmp_str) { 00674 g_string_append (stringue, 00675 tmp_str) ; 00676 g_free (tmp_str) ; 00677 tmp_str = NULL ; 00678 } 00679 g_string_append (stringue, "\n}"); 00680 } 00681 if (stringue) { 00682 result = stringue->str ; 00683 g_string_free (stringue, FALSE) ; 00684 stringue = NULL ; 00685 } 00686 return result ; 00687 } 00688 00689 00690 /** 00691 * cr_statement_charset_to_string: 00692 * 00693 *Serialises an \@charset statement into a string. 00694 *@a_this: the statement to serialize. 00695 *@a_indent: the number of indentation spaces 00696 * 00697 *Returns the serialized charset statement. Must be 00698 *freed by the caller using g_free(). 00699 */ 00700 static gchar * 00701 cr_statement_charset_to_string (CRStatement const *a_this, 00702 gulong a_indent) 00703 { 00704 gchar *str = NULL ; 00705 GString *stringue = NULL ; 00706 00707 g_return_val_if_fail (a_this 00708 && a_this->type == AT_CHARSET_RULE_STMT, 00709 NULL) ; 00710 00711 if (a_this->kind.charset_rule 00712 && a_this->kind.charset_rule->charset 00713 && a_this->kind.charset_rule->charset->stryng 00714 && a_this->kind.charset_rule->charset->stryng->str) { 00715 str = g_strndup (a_this->kind.charset_rule->charset->stryng->str, 00716 a_this->kind.charset_rule->charset->stryng->len); 00717 g_return_val_if_fail (str, NULL); 00718 stringue = g_string_new (NULL) ; 00719 g_return_val_if_fail (stringue, NULL) ; 00720 cr_utils_dump_n_chars2 (' ', stringue, a_indent); 00721 g_string_append_printf (stringue, 00722 "@charset \"%s\" ;", str); 00723 if (str) { 00724 g_free (str); 00725 str = NULL; 00726 } 00727 } 00728 if (stringue) { 00729 str = stringue->str ; 00730 g_string_free (stringue, FALSE) ; 00731 } 00732 return str ; 00733 } 00734 00735 00736 /** 00737 * cr_statement_at_page_rule_to_string: 00738 * 00739 *Serialises the at page rule statement into a string 00740 *@a_this: the current instance of #CRStatement. Must 00741 *be an "\@page" rule statement. 00742 * 00743 *Returns the serialized string. Must be freed by the caller 00744 */ 00745 static gchar * 00746 cr_statement_at_page_rule_to_string (CRStatement const *a_this, 00747 gulong a_indent) 00748 { 00749 GString *stringue = NULL; 00750 gchar *result = NULL ; 00751 00752 stringue = g_string_new (NULL) ; 00753 00754 cr_utils_dump_n_chars2 (' ', stringue, a_indent) ; 00755 g_string_append (stringue, "@page"); 00756 if (a_this->kind.page_rule->name 00757 && a_this->kind.page_rule->name->stryng) { 00758 g_string_append_printf 00759 (stringue, " %s", 00760 a_this->kind.page_rule->name->stryng->str) ; 00761 } else { 00762 g_string_append (stringue, " "); 00763 } 00764 if (a_this->kind.page_rule->pseudo 00765 && a_this->kind.page_rule->pseudo->stryng) { 00766 g_string_append_printf 00767 (stringue, " :%s", 00768 a_this->kind.page_rule->pseudo->stryng->str) ; 00769 } 00770 if (a_this->kind.page_rule->decl_list) { 00771 gchar *str = NULL ; 00772 g_string_append (stringue, " {\n"); 00773 str = (gchar *) cr_declaration_list_to_string2 00774 (a_this->kind.page_rule->decl_list, 00775 a_indent + DECLARATION_INDENT_NB, TRUE) ; 00776 if (str) { 00777 g_string_append (stringue, str) ; 00778 g_free (str) ; 00779 str = NULL ; 00780 } 00781 g_string_append (stringue, "\n}\n"); 00782 } 00783 result = stringue->str ; 00784 g_string_free (stringue, FALSE) ; 00785 stringue = NULL ; 00786 return result ; 00787 } 00788 00789 00790 /** 00791 *Serializes an \@media statement. 00792 *@param a_this the current instance of #CRStatement 00793 *@param a_indent the number of spaces of indentation. 00794 *@return the serialized \@media statement. Must be freed 00795 *by the caller using g_free(). 00796 */ 00797 static gchar * 00798 cr_statement_media_rule_to_string (CRStatement const *a_this, 00799 gulong a_indent) 00800 { 00801 gchar *str = NULL ; 00802 GString *stringue = NULL ; 00803 GList const *cur = NULL; 00804 00805 g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT, 00806 NULL); 00807 00808 if (a_this->kind.media_rule) { 00809 stringue = g_string_new (NULL) ; 00810 cr_utils_dump_n_chars2 (' ', stringue, a_indent); 00811 g_string_append (stringue, "@media"); 00812 00813 for (cur = a_this->kind.media_rule->media_list; cur; 00814 cur = cur->next) { 00815 if (cur->data) { 00816 gchar *str2 = cr_string_dup2 00817 ((CRString const *) cur->data); 00818 00819 if (str2) { 00820 if (cur->prev) { 00821 g_string_append 00822 (stringue, 00823 ","); 00824 } 00825 g_string_append_printf 00826 (stringue, 00827 " %s", str2); 00828 g_free (str2); 00829 str2 = NULL; 00830 } 00831 } 00832 } 00833 g_string_append (stringue, " {\n"); 00834 str = cr_statement_list_to_string 00835 (a_this->kind.media_rule->rulesets, 00836 a_indent + DECLARATION_INDENT_NB) ; 00837 if (str) { 00838 g_string_append (stringue, str) ; 00839 g_free (str) ; 00840 str = NULL ; 00841 } 00842 g_string_append (stringue, "\n}"); 00843 } 00844 if (stringue) { 00845 str = stringue->str ; 00846 g_string_free (stringue, FALSE) ; 00847 } 00848 return str ; 00849 } 00850 00851 00852 static gchar * 00853 cr_statement_import_rule_to_string (CRStatement const *a_this, 00854 gulong a_indent) 00855 { 00856 GString *stringue = NULL ; 00857 gchar *str = NULL; 00858 00859 g_return_val_if_fail (a_this 00860 && a_this->type == AT_IMPORT_RULE_STMT 00861 && a_this->kind.import_rule, 00862 NULL) ; 00863 00864 if (a_this->kind.import_rule->url 00865 && a_this->kind.import_rule->url->stryng) { 00866 stringue = g_string_new (NULL) ; 00867 g_return_val_if_fail (stringue, NULL) ; 00868 str = g_strndup (a_this->kind.import_rule->url->stryng->str, 00869 a_this->kind.import_rule->url->stryng->len); 00870 cr_utils_dump_n_chars2 (' ', stringue, a_indent); 00871 if (str) { 00872 g_string_append_printf (stringue, 00873 "@import url(\"%s\")", 00874 str); 00875 g_free (str); 00876 str = NULL ; 00877 } else /*there is no url, so no import rule, get out! */ 00878 return NULL; 00879 00880 if (a_this->kind.import_rule->media_list) { 00881 GList const *cur = NULL; 00882 00883 for (cur = a_this->kind.import_rule->media_list; 00884 cur; cur = cur->next) { 00885 if (cur->data) { 00886 CRString const *crstr = cur->data; 00887 00888 if (cur->prev) { 00889 g_string_append 00890 (stringue, ", "); 00891 } 00892 if (crstr 00893 && crstr->stryng 00894 && crstr->stryng->str) { 00895 g_string_append_len 00896 (stringue, 00897 crstr->stryng->str, 00898 crstr->stryng->len) ; 00899 } 00900 } 00901 } 00902 } 00903 g_string_append (stringue, " ;"); 00904 } 00905 if (stringue) { 00906 str = stringue->str ; 00907 g_string_free (stringue, FALSE) ; 00908 stringue = NULL ; 00909 } 00910 return str ; 00911 } 00912 00913 00914 /******************* 00915 *public functions 00916 ******************/ 00917 00918 /** 00919 * cr_statement_does_buf_parses_against_core: 00920 * 00921 *@a_buf: the buffer to parse. 00922 *@a_encoding: the character encoding of a_buf. 00923 * 00924 *Tries to parse a buffer and says whether if the content of the buffer 00925 *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the 00926 *css spec) or not. 00927 * 00928 *Returns TRUE if the buffer parses against the core grammar, false otherwise. 00929 */ 00930 gboolean 00931 cr_statement_does_buf_parses_against_core (const guchar * a_buf, 00932 enum CREncoding a_encoding) 00933 { 00934 CRParser *parser = NULL; 00935 enum CRStatus status = CR_OK; 00936 gboolean result = FALSE; 00937 00938 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 00939 a_encoding, FALSE); 00940 g_return_val_if_fail (parser, FALSE); 00941 00942 status = cr_parser_set_use_core_grammar (parser, TRUE); 00943 if (status != CR_OK) { 00944 goto cleanup; 00945 } 00946 00947 status = cr_parser_parse_statement_core (parser); 00948 if (status == CR_OK) { 00949 result = TRUE; 00950 } 00951 00952 cleanup: 00953 if (parser) { 00954 cr_parser_destroy (parser); 00955 } 00956 00957 return result; 00958 } 00959 00960 /** 00961 * cr_statement_parse_from_buf: 00962 * 00963 *@a_buf: the buffer to parse. 00964 *@a_encoding: the character encoding of a_buf. 00965 * 00966 *Parses a buffer that contains a css statement and returns 00967 *an instance of #CRStatement in case of successful parsing. 00968 *TODO: at support of "\@import" rules. 00969 * 00970 *Returns the newly built instance of #CRStatement in case 00971 *of successful parsing, NULL otherwise. 00972 */ 00973 CRStatement * 00974 cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding) 00975 { 00976 CRStatement *result = NULL; 00977 00978 /* 00979 *The strategy of this function is "brute force". 00980 *It tries to parse all the types of CRStatement it knows about. 00981 *I could do this a smarter way but I don't have the time now. 00982 *I think I will revisit this when time of performances and 00983 *pull based incremental parsing comes. 00984 */ 00985 00986 result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding); 00987 if (!result) { 00988 result = cr_statement_at_charset_rule_parse_from_buf 00989 (a_buf, a_encoding); 00990 } else { 00991 goto out; 00992 } 00993 00994 if (!result) { 00995 result = cr_statement_at_media_rule_parse_from_buf 00996 (a_buf, a_encoding); 00997 } else { 00998 goto out; 00999 } 01000 01001 if (!result) { 01002 result = cr_statement_at_charset_rule_parse_from_buf 01003 (a_buf, a_encoding); 01004 } else { 01005 goto out; 01006 } 01007 01008 if (!result) { 01009 result = cr_statement_font_face_rule_parse_from_buf 01010 (a_buf, a_encoding); 01011 01012 } else { 01013 goto out; 01014 } 01015 01016 if (!result) { 01017 result = cr_statement_at_page_rule_parse_from_buf 01018 (a_buf, a_encoding); 01019 } else { 01020 goto out; 01021 } 01022 01023 if (!result) { 01024 result = cr_statement_at_import_rule_parse_from_buf 01025 (a_buf, a_encoding); 01026 } else { 01027 goto out; 01028 } 01029 01030 out: 01031 return result; 01032 } 01033 01034 /** 01035 * cr_statement_ruleset_parse_from_buf: 01036 * 01037 *@a_buf: the buffer to parse. 01038 *@a_enc: the character encoding of a_buf. 01039 * 01040 *Parses a buffer that contains a ruleset statement an instanciates 01041 *a #CRStatement of type RULESET_STMT. 01042 * 01043 *Returns the newly built instance of #CRStatement in case of successful parsing, 01044 *NULL otherwise. 01045 */ 01046 CRStatement * 01047 cr_statement_ruleset_parse_from_buf (const guchar * a_buf, 01048 enum CREncoding a_enc) 01049 { 01050 enum CRStatus status = CR_OK; 01051 CRStatement *result = NULL; 01052 CRStatement **resultptr = NULL; 01053 CRParser *parser = NULL; 01054 CRDocHandler *sac_handler = NULL; 01055 01056 g_return_val_if_fail (a_buf, NULL); 01057 01058 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 01059 a_enc, FALSE); 01060 01061 g_return_val_if_fail (parser, NULL); 01062 01063 sac_handler = cr_doc_handler_new (); 01064 g_return_val_if_fail (parser, NULL); 01065 01066 sac_handler->start_selector = parse_ruleset_start_selector_cb; 01067 sac_handler->end_selector = parse_ruleset_end_selector_cb; 01068 sac_handler->property = parse_ruleset_property_cb; 01069 sac_handler->unrecoverable_error = 01070 parse_ruleset_unrecoverable_error_cb; 01071 01072 cr_parser_set_sac_handler (parser, sac_handler); 01073 cr_parser_try_to_skip_spaces_and_comments (parser); 01074 status = cr_parser_parse_ruleset (parser); 01075 if (status != CR_OK) { 01076 goto cleanup; 01077 } 01078 01079 resultptr = &result; 01080 status = cr_doc_handler_get_result (sac_handler, 01081 (gpointer *) resultptr); 01082 if (!((status == CR_OK) && result)) { 01083 if (result) { 01084 cr_statement_destroy (result); 01085 result = NULL; 01086 } 01087 } 01088 01089 cleanup: 01090 if (parser) { 01091 cr_parser_destroy (parser); 01092 parser = NULL; 01093 sac_handler = NULL ; 01094 } 01095 if (sac_handler) { 01096 cr_doc_handler_unref (sac_handler); 01097 sac_handler = NULL; 01098 } 01099 return result; 01100 } 01101 01102 /** 01103 * cr_statement_new_ruleset: 01104 * 01105 *@a_sel_list: the list of #CRSimpleSel (selectors) 01106 *the rule applies to. 01107 *@a_decl_list: the list of instances of #CRDeclaration 01108 *that composes the ruleset. 01109 *@a_media_types: a list of instances of GString that 01110 *describe the media list this ruleset applies to. 01111 * 01112 *Creates a new instance of #CRStatement of type 01113 *#CRRulSet. 01114 * 01115 *Returns the new instance of #CRStatement or NULL if something 01116 *went wrong. 01117 */ 01118 CRStatement * 01119 cr_statement_new_ruleset (CRStyleSheet * a_sheet, 01120 CRSelector * a_sel_list, 01121 CRDeclaration * a_decl_list, 01122 CRStatement * a_parent_media_rule) 01123 { 01124 CRStatement *result = NULL; 01125 01126 g_return_val_if_fail (a_sel_list, NULL); 01127 01128 if (a_parent_media_rule) { 01129 g_return_val_if_fail 01130 (a_parent_media_rule->type == AT_MEDIA_RULE_STMT, 01131 NULL); 01132 g_return_val_if_fail (a_parent_media_rule->kind.media_rule, 01133 NULL); 01134 } 01135 01136 result = g_try_malloc (sizeof (CRStatement)); 01137 01138 if (!result) { 01139 cr_utils_trace_info ("Out of memory"); 01140 return NULL; 01141 } 01142 01143 memset (result, 0, sizeof (CRStatement)); 01144 result->type = RULESET_STMT; 01145 result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet)); 01146 01147 if (!result->kind.ruleset) { 01148 cr_utils_trace_info ("Out of memory"); 01149 if (result) 01150 g_free (result); 01151 return NULL; 01152 } 01153 01154 memset (result->kind.ruleset, 0, sizeof (CRRuleSet)); 01155 result->kind.ruleset->sel_list = a_sel_list; 01156 if (a_sel_list) 01157 cr_selector_ref (a_sel_list); 01158 result->kind.ruleset->decl_list = a_decl_list; 01159 01160 if (a_parent_media_rule) { 01161 result->kind.ruleset->parent_media_rule = a_parent_media_rule; 01162 a_parent_media_rule->kind.media_rule->rulesets = 01163 cr_statement_append 01164 (a_parent_media_rule->kind.media_rule->rulesets, 01165 result); 01166 } 01167 01168 cr_statement_set_parent_sheet (result, a_sheet); 01169 01170 return result; 01171 } 01172 01173 /** 01174 * cr_statement_at_media_rule_parse_from_buf: 01175 * 01176 *@a_buf: the input to parse. 01177 *@a_enc: the encoding of the buffer. 01178 * 01179 *Parses a buffer that contains an "\@media" declaration 01180 *and builds an \@media css statement. 01181 * 01182 *Returns the \@media statement, or NULL if the buffer could not 01183 *be successfully parsed. 01184 */ 01185 CRStatement * 01186 cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf, 01187 enum CREncoding a_enc) 01188 { 01189 CRParser *parser = NULL; 01190 CRStatement *result = NULL; 01191 CRStatement **resultptr = NULL; 01192 CRDocHandler *sac_handler = NULL; 01193 enum CRStatus status = CR_OK; 01194 01195 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 01196 a_enc, FALSE); 01197 if (!parser) { 01198 cr_utils_trace_info ("Instantiation of the parser failed"); 01199 goto cleanup; 01200 } 01201 01202 sac_handler = cr_doc_handler_new (); 01203 if (!sac_handler) { 01204 cr_utils_trace_info 01205 ("Instantiation of the sac handler failed"); 01206 goto cleanup; 01207 } 01208 01209 sac_handler->start_media = parse_at_media_start_media_cb; 01210 sac_handler->start_selector = parse_at_media_start_selector_cb; 01211 sac_handler->property = parse_at_media_property_cb; 01212 sac_handler->end_selector = parse_at_media_end_selector_cb; 01213 sac_handler->end_media = parse_at_media_end_media_cb; 01214 sac_handler->unrecoverable_error = 01215 parse_at_media_unrecoverable_error_cb; 01216 01217 status = cr_parser_set_sac_handler (parser, sac_handler); 01218 if (status != CR_OK) 01219 goto cleanup; 01220 01221 status = cr_parser_try_to_skip_spaces_and_comments (parser); 01222 if (status != CR_OK) 01223 goto cleanup; 01224 01225 status = cr_parser_parse_media (parser); 01226 if (status != CR_OK) 01227 goto cleanup; 01228 01229 resultptr = &result; 01230 status = cr_doc_handler_get_result (sac_handler, 01231 (gpointer *) resultptr); 01232 if (status != CR_OK) 01233 goto cleanup; 01234 01235 cleanup: 01236 01237 if (parser) { 01238 cr_parser_destroy (parser); 01239 parser = NULL; 01240 sac_handler = NULL ; 01241 } 01242 if (sac_handler) { 01243 cr_doc_handler_unref (sac_handler); 01244 sac_handler = NULL; 01245 } 01246 01247 return result; 01248 } 01249 01250 /** 01251 * cr_statement_new_at_media_rule: 01252 * 01253 *@a_ruleset: the ruleset statements contained 01254 *in the \@media rule. 01255 *@a_media: the media string list. A list of GString pointers. 01256 * 01257 *Instanciates an instance of #CRStatement of type 01258 *AT_MEDIA_RULE_STMT (\@media ruleset). 01259 * 01260 */ 01261 CRStatement * 01262 cr_statement_new_at_media_rule (CRStyleSheet * a_sheet, 01263 CRStatement * a_rulesets, GList * a_media) 01264 { 01265 CRStatement *result = NULL, 01266 *cur = NULL; 01267 01268 if (a_rulesets) 01269 g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL); 01270 01271 result = g_try_malloc (sizeof (CRStatement)); 01272 01273 if (!result) { 01274 cr_utils_trace_info ("Out of memory"); 01275 return NULL; 01276 } 01277 01278 memset (result, 0, sizeof (CRStatement)); 01279 result->type = AT_MEDIA_RULE_STMT; 01280 01281 result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule)); 01282 if (!result->kind.media_rule) { 01283 cr_utils_trace_info ("Out of memory"); 01284 g_free (result); 01285 return NULL; 01286 } 01287 memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule)); 01288 result->kind.media_rule->rulesets = a_rulesets; 01289 for (cur = a_rulesets; cur; cur = cur->next) { 01290 if (cur->type != RULESET_STMT || !cur->kind.ruleset) { 01291 cr_utils_trace_info ("Bad parameter a_rulesets. " 01292 "It should be a list of " 01293 "correct ruleset statement only !"); 01294 goto error; 01295 } 01296 cur->kind.ruleset->parent_media_rule = result; 01297 } 01298 01299 result->kind.media_rule->media_list = a_media; 01300 if (a_sheet) { 01301 cr_statement_set_parent_sheet (result, a_sheet); 01302 } 01303 01304 return result; 01305 01306 error: 01307 return NULL; 01308 } 01309 01310 /** 01311 * cr_statement_new_at_import_rule: 01312 * 01313 *@a_url: the url to connect to the get the file 01314 *to be imported. 01315 *@a_sheet: the imported parsed stylesheet. 01316 * 01317 *Creates a new instance of #CRStatment of type 01318 *#CRAtImportRule. 01319 * 01320 *Returns the newly built instance of #CRStatement. 01321 */ 01322 CRStatement * 01323 cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet, 01324 CRString * a_url, 01325 GList * a_media_list, 01326 CRStyleSheet * a_imported_sheet) 01327 { 01328 CRStatement *result = NULL; 01329 01330 result = g_try_malloc (sizeof (CRStatement)); 01331 01332 if (!result) { 01333 cr_utils_trace_info ("Out of memory"); 01334 return NULL; 01335 } 01336 01337 memset (result, 0, sizeof (CRStatement)); 01338 result->type = AT_IMPORT_RULE_STMT; 01339 01340 result->kind.import_rule = g_try_malloc (sizeof (CRAtImportRule)); 01341 01342 if (!result->kind.import_rule) { 01343 cr_utils_trace_info ("Out of memory"); 01344 g_free (result); 01345 return NULL; 01346 } 01347 01348 memset (result->kind.import_rule, 0, sizeof (CRAtImportRule)); 01349 result->kind.import_rule->url = a_url; 01350 result->kind.import_rule->media_list = a_media_list; 01351 result->kind.import_rule->sheet = a_imported_sheet; 01352 if (a_container_sheet) 01353 cr_statement_set_parent_sheet (result, a_container_sheet); 01354 01355 return result; 01356 } 01357 01358 /** 01359 * cr_statement_at_import_rule_parse_from_buf: 01360 * 01361 *@a_buf: the buffer to parse. 01362 *@a_encoding: the encoding of a_buf. 01363 * 01364 *Parses a buffer that contains an "\@import" rule and 01365 *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT 01366 * 01367 *Returns the newly built instance of #CRStatement in case of 01368 *a successful parsing, NULL otherwise. 01369 */ 01370 CRStatement * 01371 cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf, 01372 enum CREncoding a_encoding) 01373 { 01374 enum CRStatus status = CR_OK; 01375 CRParser *parser = NULL; 01376 CRStatement *result = NULL; 01377 GList *media_list = NULL; 01378 CRString *import_string = NULL; 01379 CRParsingLocation location = {0} ; 01380 01381 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 01382 a_encoding, FALSE); 01383 if (!parser) { 01384 cr_utils_trace_info ("Instantiation of parser failed."); 01385 goto cleanup; 01386 } 01387 01388 status = cr_parser_try_to_skip_spaces_and_comments (parser); 01389 if (status != CR_OK) 01390 goto cleanup; 01391 01392 status = cr_parser_parse_import (parser, 01393 &media_list, 01394 &import_string, 01395 &location); 01396 if (status != CR_OK || !import_string) 01397 goto cleanup; 01398 01399 result = cr_statement_new_at_import_rule (NULL, import_string, 01400 media_list, NULL); 01401 if (result) { 01402 cr_parsing_location_copy (&result->location, 01403 &location) ; 01404 import_string = NULL; 01405 media_list = NULL; 01406 } 01407 01408 cleanup: 01409 if (parser) { 01410 cr_parser_destroy (parser); 01411 parser = NULL; 01412 } 01413 if (media_list) { 01414 for (; media_list; 01415 media_list = g_list_next (media_list)) { 01416 if (media_list->data) { 01417 cr_string_destroy ((CRString*)media_list->data); 01418 media_list->data = NULL; 01419 } 01420 } 01421 g_list_free (media_list); 01422 media_list = NULL; 01423 } 01424 if (import_string) { 01425 cr_string_destroy (import_string); 01426 import_string = NULL; 01427 } 01428 01429 return result; 01430 } 01431 01432 /** 01433 * cr_statement_new_at_page_rule: 01434 * 01435 *@a_decl_list: a list of instances of #CRDeclarations 01436 *which is actually the list of declarations that applies to 01437 *this page rule. 01438 *@a_selector: the page rule selector. 01439 * 01440 *Creates a new instance of #CRStatement of type 01441 *#CRAtPageRule. 01442 * 01443 *Returns the newly built instance of #CRStatement or NULL 01444 *in case of error. 01445 */ 01446 CRStatement * 01447 cr_statement_new_at_page_rule (CRStyleSheet * a_sheet, 01448 CRDeclaration * a_decl_list, 01449 CRString * a_name, CRString * a_pseudo) 01450 { 01451 CRStatement *result = NULL; 01452 01453 result = g_try_malloc (sizeof (CRStatement)); 01454 01455 if (!result) { 01456 cr_utils_trace_info ("Out of memory"); 01457 return NULL; 01458 } 01459 01460 memset (result, 0, sizeof (CRStatement)); 01461 result->type = AT_PAGE_RULE_STMT; 01462 01463 result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule)); 01464 01465 if (!result->kind.page_rule) { 01466 cr_utils_trace_info ("Out of memory"); 01467 g_free (result); 01468 return NULL; 01469 } 01470 01471 memset (result->kind.page_rule, 0, sizeof (CRAtPageRule)); 01472 if (a_decl_list) { 01473 result->kind.page_rule->decl_list = a_decl_list; 01474 cr_declaration_ref (a_decl_list); 01475 } 01476 result->kind.page_rule->name = a_name; 01477 result->kind.page_rule->pseudo = a_pseudo; 01478 if (a_sheet) 01479 cr_statement_set_parent_sheet (result, a_sheet); 01480 01481 return result; 01482 } 01483 01484 /** 01485 * cr_statement_at_page_rule_parse_from_buf: 01486 * 01487 *@a_buf: the character buffer to parse. 01488 *@a_encoding: the character encoding of a_buf. 01489 * 01490 *Parses a buffer that contains an "\@page" production and, 01491 *if the parsing succeeds, builds the page statement. 01492 * 01493 *Returns the newly built at page statement in case of successful parsing, 01494 *NULL otherwise. 01495 */ 01496 CRStatement * 01497 cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf, 01498 enum CREncoding a_encoding) 01499 { 01500 enum CRStatus status = CR_OK; 01501 CRParser *parser = NULL; 01502 CRDocHandler *sac_handler = NULL; 01503 CRStatement *result = NULL; 01504 CRStatement **resultptr = NULL; 01505 01506 g_return_val_if_fail (a_buf, NULL); 01507 01508 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 01509 a_encoding, FALSE); 01510 if (!parser) { 01511 cr_utils_trace_info ("Instantiation of the parser failed."); 01512 goto cleanup; 01513 } 01514 01515 sac_handler = cr_doc_handler_new (); 01516 if (!sac_handler) { 01517 cr_utils_trace_info 01518 ("Instantiation of the sac handler failed."); 01519 goto cleanup; 01520 } 01521 01522 sac_handler->start_page = parse_page_start_page_cb; 01523 sac_handler->property = parse_page_property_cb; 01524 sac_handler->end_page = parse_page_end_page_cb; 01525 sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb; 01526 01527 status = cr_parser_set_sac_handler (parser, sac_handler); 01528 if (status != CR_OK) 01529 goto cleanup; 01530 01531 /*Now, invoke the parser to parse the "@page production" */ 01532 cr_parser_try_to_skip_spaces_and_comments (parser); 01533 if (status != CR_OK) 01534 goto cleanup; 01535 status = cr_parser_parse_page (parser); 01536 if (status != CR_OK) 01537 goto cleanup; 01538 01539 resultptr = &result; 01540 status = cr_doc_handler_get_result (sac_handler, 01541 (gpointer *) resultptr); 01542 01543 cleanup: 01544 01545 if (parser) { 01546 cr_parser_destroy (parser); 01547 parser = NULL; 01548 sac_handler = NULL ; 01549 } 01550 if (sac_handler) { 01551 cr_doc_handler_unref (sac_handler); 01552 sac_handler = NULL; 01553 } 01554 return result; 01555 } 01556 01557 /** 01558 * cr_statement_new_at_charset_rule: 01559 * 01560 *@a_charset: the string representing the charset. 01561 *Note that the newly built instance of #CRStatement becomes 01562 *the owner of a_charset. The caller must not free a_charset !!!. 01563 * 01564 *Creates a new instance of #CRStatement of type 01565 *#CRAtCharsetRule. 01566 * 01567 *Returns the newly built instance of #CRStatement or NULL 01568 *if an error arises. 01569 */ 01570 CRStatement * 01571 cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, 01572 CRString * a_charset) 01573 { 01574 CRStatement *result = NULL; 01575 01576 g_return_val_if_fail (a_charset, NULL); 01577 01578 result = g_try_malloc (sizeof (CRStatement)); 01579 01580 if (!result) { 01581 cr_utils_trace_info ("Out of memory"); 01582 return NULL; 01583 } 01584 01585 memset (result, 0, sizeof (CRStatement)); 01586 result->type = AT_CHARSET_RULE_STMT; 01587 01588 result->kind.charset_rule = g_try_malloc (sizeof (CRAtCharsetRule)); 01589 01590 if (!result->kind.charset_rule) { 01591 cr_utils_trace_info ("Out of memory"); 01592 g_free (result); 01593 return NULL; 01594 } 01595 memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule)); 01596 result->kind.charset_rule->charset = a_charset; 01597 cr_statement_set_parent_sheet (result, a_sheet); 01598 01599 return result; 01600 } 01601 01602 /** 01603 * cr_statement_at_charset_rule_parse_from_buf: 01604 * 01605 *@a_buf: the buffer to parse. 01606 *@a_encoding: the character encoding of the buffer. 01607 * 01608 *Parses a buffer that contains an '\@charset' rule and 01609 *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT. 01610 * 01611 *Returns the newly built instance of #CRStatement. 01612 */ 01613 CRStatement * 01614 cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf, 01615 enum CREncoding a_encoding) 01616 { 01617 enum CRStatus status = CR_OK; 01618 CRParser *parser = NULL; 01619 CRStatement *result = NULL; 01620 CRString *charset = NULL; 01621 01622 g_return_val_if_fail (a_buf, NULL); 01623 01624 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 01625 a_encoding, FALSE); 01626 if (!parser) { 01627 cr_utils_trace_info ("Instantiation of the parser failed."); 01628 goto cleanup; 01629 } 01630 01631 /*Now, invoke the parser to parse the "@charset production" */ 01632 cr_parser_try_to_skip_spaces_and_comments (parser); 01633 if (status != CR_OK) 01634 goto cleanup; 01635 status = cr_parser_parse_charset (parser, &charset, NULL); 01636 if (status != CR_OK || !charset) 01637 goto cleanup; 01638 01639 result = cr_statement_new_at_charset_rule (NULL, charset); 01640 if (result) 01641 charset = NULL; 01642 01643 cleanup: 01644 01645 if (parser) { 01646 cr_parser_destroy (parser); 01647 parser = NULL; 01648 } 01649 if (charset) { 01650 cr_string_destroy (charset); 01651 } 01652 01653 return result; 01654 } 01655 01656 /** 01657 * cr_statement_new_at_font_face_rule: 01658 * 01659 *@a_font_decls: a list of instances of #CRDeclaration. Each declaration 01660 *is actually a font declaration. 01661 * 01662 *Creates an instance of #CRStatement of type #CRAtFontFaceRule. 01663 * 01664 *Returns the newly built instance of #CRStatement. 01665 */ 01666 CRStatement * 01667 cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, 01668 CRDeclaration * a_font_decls) 01669 { 01670 CRStatement *result = NULL; 01671 01672 result = g_try_malloc (sizeof (CRStatement)); 01673 01674 if (!result) { 01675 cr_utils_trace_info ("Out of memory"); 01676 return NULL; 01677 } 01678 memset (result, 0, sizeof (CRStatement)); 01679 result->type = AT_FONT_FACE_RULE_STMT; 01680 01681 result->kind.font_face_rule = g_try_malloc 01682 (sizeof (CRAtFontFaceRule)); 01683 01684 if (!result->kind.font_face_rule) { 01685 cr_utils_trace_info ("Out of memory"); 01686 g_free (result); 01687 return NULL; 01688 } 01689 memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule)); 01690 01691 result->kind.font_face_rule->decl_list = a_font_decls; 01692 if (a_sheet) 01693 cr_statement_set_parent_sheet (result, a_sheet); 01694 01695 return result; 01696 } 01697 01698 /** 01699 * cr_statement_font_face_rule_parse_from_buf: 01700 * 01701 * 01702 *@a_buf: the buffer to parse. 01703 *@a_encoding: the character encoding of a_buf. 01704 * 01705 *Parses a buffer that contains an "\@font-face" rule and builds 01706 *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it. 01707 * 01708 *Returns the newly built instance of #CRStatement in case of successufull 01709 *parsing, NULL otherwise. 01710 */ 01711 CRStatement * 01712 cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf, 01713 enum CREncoding a_encoding) 01714 { 01715 CRStatement *result = NULL; 01716 CRStatement **resultptr = NULL; 01717 CRParser *parser = NULL; 01718 CRDocHandler *sac_handler = NULL; 01719 enum CRStatus status = CR_OK; 01720 01721 parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), 01722 a_encoding, FALSE); 01723 if (!parser) 01724 goto cleanup; 01725 01726 sac_handler = cr_doc_handler_new (); 01727 if (!sac_handler) 01728 goto cleanup; 01729 01730 /* 01731 *set sac callbacks here 01732 */ 01733 sac_handler->start_font_face = parse_font_face_start_font_face_cb; 01734 sac_handler->property = parse_font_face_property_cb; 01735 sac_handler->end_font_face = parse_font_face_end_font_face_cb; 01736 sac_handler->unrecoverable_error = 01737 parse_font_face_unrecoverable_error_cb; 01738 01739 status = cr_parser_set_sac_handler (parser, sac_handler); 01740 if (status != CR_OK) 01741 goto cleanup; 01742 01743 /* 01744 *cleanup spaces of comment that may be there before the real 01745 *"@font-face" thing. 01746 */ 01747 status = cr_parser_try_to_skip_spaces_and_comments (parser); 01748 if (status != CR_OK) 01749 goto cleanup; 01750 01751 status = cr_parser_parse_font_face (parser); 01752 if (status != CR_OK) 01753 goto cleanup; 01754 01755 resultptr = &result; 01756 status = cr_doc_handler_get_result (sac_handler, 01757 (gpointer *) resultptr); 01758 if (status != CR_OK || !result) 01759 goto cleanup; 01760 01761 cleanup: 01762 if (parser) { 01763 cr_parser_destroy (parser); 01764 parser = NULL; 01765 sac_handler = NULL ; 01766 } 01767 if (sac_handler) { 01768 cr_doc_handler_unref (sac_handler); 01769 sac_handler = NULL; 01770 } 01771 return result; 01772 } 01773 01774 /** 01775 * cr_statement_set_parent_sheet: 01776 * 01777 *@a_this: the current instance of #CRStatement. 01778 *@a_sheet: the sheet that contains the current statement. 01779 * 01780 *Sets the container stylesheet. 01781 * 01782 *Returns CR_OK upon successful completion, an error code otherwise. 01783 */ 01784 enum CRStatus 01785 cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet) 01786 { 01787 g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 01788 a_this->parent_sheet = a_sheet; 01789 return CR_OK; 01790 } 01791 01792 /** 01793 * cr_statement_get_parent_sheet: 01794 * 01795 *@a_this: the current #CRStatement. 01796 *@a_sheet: out parameter. A pointer to the sheets that 01797 * 01798 *Gets the sheets that contains the current statement. 01799 * 01800 *Returns CR_OK upon successful completion, an error code otherwise. 01801 */ 01802 enum CRStatus 01803 cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet) 01804 { 01805 g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR); 01806 *a_sheet = a_this->parent_sheet; 01807 return CR_OK; 01808 } 01809 01810 /** 01811 * cr_statement_append: 01812 * 01813 *@a_this: the current instance of the statement list. 01814 *@a_new: a_new the new instance of #CRStatement to append. 01815 * 01816 *Appends a new statement to the statement list. 01817 * 01818 *Returns the new list statement list, or NULL in cas of failure. 01819 */ 01820 CRStatement * 01821 cr_statement_append (CRStatement * a_this, CRStatement * a_new) 01822 { 01823 CRStatement *cur = NULL; 01824 01825 g_return_val_if_fail (a_new, NULL); 01826 01827 if (!a_this) { 01828 return a_new; 01829 } 01830 01831 /*walk forward in the current list to find the tail list element */ 01832 for (cur = a_this; cur && cur->next; cur = cur->next) ; 01833 01834 cur->next = a_new; 01835 a_new->prev = cur; 01836 01837 return a_this; 01838 } 01839 01840 /** 01841 * cr_statement_prepend: 01842 * 01843 *@a_this: the current instance of #CRStatement. 01844 *@a_new: the new statement to prepend. 01845 * 01846 *Prepends the an instance of #CRStatement to 01847 *the current statement list. 01848 * 01849 *Returns the new list with the new statement prepended, 01850 *or NULL in case of an error. 01851 */ 01852 CRStatement * 01853 cr_statement_prepend (CRStatement * a_this, CRStatement * a_new) 01854 { 01855 CRStatement *cur = NULL; 01856 01857 g_return_val_if_fail (a_new, NULL); 01858 01859 if (!a_this) 01860 return a_new; 01861 01862 a_new->next = a_this; 01863 a_this->prev = a_new; 01864 01865 /*walk backward in the prepended list to find the head list element */ 01866 for (cur = a_new; cur && cur->prev; cur = cur->prev) ; 01867 01868 return cur; 01869 } 01870 01871 /** 01872 * cr_statement_unlink: 01873 * 01874 *@a_this: the current statements list. 01875 *@a_to_unlink: the statement to unlink from the list. 01876 * 01877 *Unlinks a statement from the statements list. 01878 * 01879 *Returns the new list where a_to_unlink has been unlinked 01880 *from, or NULL in case of error. 01881 */ 01882 CRStatement * 01883 cr_statement_unlink (CRStatement * a_stmt) 01884 { 01885 CRStatement *result = a_stmt; 01886 01887 g_return_val_if_fail (result, NULL); 01888 01889 /** 01890 *Some sanity checks first 01891 */ 01892 if (a_stmt->next) { 01893 g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL); 01894 } 01895 if (a_stmt->prev) { 01896 g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL); 01897 } 01898 01899 /** 01900 *Now, the real unlinking job. 01901 */ 01902 if (a_stmt->next) { 01903 a_stmt->next->prev = a_stmt->prev; 01904 } 01905 if (a_stmt->prev) { 01906 a_stmt->prev->next = a_stmt->next; 01907 } 01908 01909 if (a_stmt->parent_sheet 01910 && a_stmt->parent_sheet->statements == a_stmt) { 01911 a_stmt->parent_sheet->statements = 01912 a_stmt->parent_sheet->statements->next; 01913 } 01914 01915 a_stmt->next = NULL; 01916 a_stmt->prev = NULL; 01917 a_stmt->parent_sheet = NULL; 01918 01919 return result; 01920 } 01921 01922 /** 01923 * cr_statement_nr_rules: 01924 * 01925 *@a_this: the current instance of #CRStatement. 01926 * 01927 *Gets the number of rules in the statement list; 01928 * 01929 *Returns number of rules in the statement list. 01930 */ 01931 gint 01932 cr_statement_nr_rules (CRStatement const * a_this) 01933 { 01934 CRStatement const *cur = NULL; 01935 int nr = 0; 01936 01937 g_return_val_if_fail (a_this, -1); 01938 01939 for (cur = a_this; cur; cur = cur->next) 01940 nr++; 01941 return nr; 01942 } 01943 01944 /** 01945 * cr_statement_get_from_list: 01946 * 01947 *@a_this: the current instance of #CRStatement. 01948 *@itemnr: the index into the statement list. 01949 * 01950 *Use an index to get a CRStatement from the statement list. 01951 * 01952 *Returns CRStatement at position itemnr, if itemnr > number of statements - 1, 01953 *it will return NULL. 01954 */ 01955 CRStatement * 01956 cr_statement_get_from_list (CRStatement * a_this, int itemnr) 01957 { 01958 CRStatement *cur = NULL; 01959 int nr = 0; 01960 01961 g_return_val_if_fail (a_this, NULL); 01962 01963 for (cur = a_this; cur; cur = cur->next) 01964 if (nr++ == itemnr) 01965 return cur; 01966 return NULL; 01967 } 01968 01969 /** 01970 * cr_statement_ruleset_set_sel_list: 01971 * 01972 *@a_this: the current ruleset statement. 01973 *@a_sel_list: the selector list to set. Note 01974 *that this function increments the ref count of a_sel_list. 01975 *The sel list will be destroyed at the destruction of the 01976 *current instance of #CRStatement. 01977 * 01978 *Sets a selector list to a ruleset statement. 01979 * 01980 *Returns CR_OK upon successful completion, an error code otherwise. 01981 */ 01982 enum CRStatus 01983 cr_statement_ruleset_set_sel_list (CRStatement * a_this, 01984 CRSelector * a_sel_list) 01985 { 01986 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, 01987 CR_BAD_PARAM_ERROR); 01988 01989 if (a_this->kind.ruleset->sel_list) 01990 cr_selector_unref (a_this->kind.ruleset->sel_list); 01991 01992 a_this->kind.ruleset->sel_list = a_sel_list; 01993 01994 if (a_sel_list) 01995 cr_selector_ref (a_sel_list); 01996 01997 return CR_OK; 01998 } 01999 02000 /** 02001 * cr_statement_ruleset_get_declarations: 02002 * 02003 *@a_this: the current instance of #CRStatement. 02004 *@a_decl_list: out parameter. A pointer to the the returned 02005 *list of declaration. Must not be NULL. 02006 * 02007 *Gets a pointer to the list of declaration contained 02008 *in the ruleset statement. 02009 * 02010 *Returns CR_OK upon successful completion, an error code if something 02011 *bad happened. 02012 */ 02013 enum CRStatus 02014 cr_statement_ruleset_get_declarations (CRStatement * a_this, 02015 CRDeclaration ** a_decl_list) 02016 { 02017 g_return_val_if_fail (a_this 02018 && a_this->type == RULESET_STMT 02019 && a_this->kind.ruleset 02020 && a_decl_list, CR_BAD_PARAM_ERROR); 02021 02022 *a_decl_list = a_this->kind.ruleset->decl_list; 02023 02024 return CR_OK; 02025 } 02026 02027 /** 02028 * cr_statement_ruleset_get_sel_list: 02029 * 02030 *@a_this: the current ruleset statement. 02031 *@a_list: out parameter. The returned selector list, 02032 *if and only if the function returned CR_OK. 02033 * 02034 *Gets a pointer to the selector list contained in 02035 *the current ruleset statement. 02036 * 02037 *Returns CR_OK upon successful completion, an error code otherwise. 02038 */ 02039 enum CRStatus 02040 cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list) 02041 { 02042 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02043 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02044 02045 *a_list = a_this->kind.ruleset->sel_list; 02046 02047 return CR_OK; 02048 } 02049 02050 /** 02051 * cr_statement_ruleset_set_decl_list: 02052 * 02053 *@a_this: the current ruleset statement. 02054 *@a_list: the declaration list to be added to the current 02055 *ruleset statement. 02056 * 02057 *Sets a declaration list to the current ruleset statement. 02058 * 02059 *Returns CR_OK upon successful completion, an error code otherwise. 02060 */ 02061 enum CRStatus 02062 cr_statement_ruleset_set_decl_list (CRStatement * a_this, 02063 CRDeclaration * a_list) 02064 { 02065 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02066 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02067 02068 if (a_this->kind.ruleset->decl_list == a_list) 02069 return CR_OK; 02070 02071 if (a_this->kind.ruleset->sel_list) { 02072 cr_declaration_destroy (a_this->kind.ruleset->decl_list); 02073 } 02074 02075 a_this->kind.ruleset->sel_list = NULL; 02076 02077 return CR_OK; 02078 } 02079 02080 /** 02081 * cr_statement_ruleset_append_decl2: 02082 * 02083 *@a_this: the current statement. 02084 *@a_prop: the property of the declaration. 02085 *@a_value: the value of the declaration. 02086 * 02087 *Appends a declaration to the current ruleset statement. 02088 * 02089 *Returns CR_OK upon successful completion, an error code 02090 *otherwise. 02091 */ 02092 enum CRStatus 02093 cr_statement_ruleset_append_decl2 (CRStatement * a_this, 02094 CRString * a_prop, 02095 CRTerm * a_value) 02096 { 02097 CRDeclaration *new_decls = NULL; 02098 02099 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02100 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02101 02102 new_decls = cr_declaration_append2 02103 (a_this->kind.ruleset->decl_list, 02104 a_prop, a_value); 02105 g_return_val_if_fail (new_decls, CR_ERROR); 02106 a_this->kind.ruleset->decl_list = new_decls; 02107 02108 return CR_OK; 02109 } 02110 02111 /** 02112 * cr_statement_ruleset_append_decl: 02113 * 02114 *Appends a declaration to the current statement. 02115 * 02116 *@a_this: the current statement. 02117 *@a_declaration: the declaration to append. 02118 * 02119 *Returns CR_OK upon sucessful completion, an error code 02120 *otherwise. 02121 */ 02122 enum CRStatus 02123 cr_statement_ruleset_append_decl (CRStatement * a_this, 02124 CRDeclaration * a_decl) 02125 { 02126 CRDeclaration *new_decls = NULL; 02127 02128 g_return_val_if_fail (a_this && a_this->type == RULESET_STMT 02129 && a_this->kind.ruleset, CR_BAD_PARAM_ERROR); 02130 02131 new_decls = cr_declaration_append 02132 (a_this->kind.ruleset->decl_list, a_decl); 02133 g_return_val_if_fail (new_decls, CR_ERROR); 02134 a_this->kind.ruleset->decl_list = new_decls; 02135 02136 return CR_OK; 02137 } 02138 02139 /** 02140 * cr_statement_at_import_rule_set_imported_sheet: 02141 * 02142 *Sets a stylesheet to the current \@import rule. 02143 *@a_this: the current \@import rule. 02144 *@a_sheet: the stylesheet. The stylesheet is owned 02145 *by the current instance of #CRStatement, that is, the 02146 *stylesheet will be destroyed when the current instance 02147 *of #CRStatement is destroyed. 02148 * 02149 *Returns CR_OK upon successful completion, an error code otherwise. 02150 */ 02151 enum CRStatus 02152 cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this, 02153 CRStyleSheet * a_sheet) 02154 { 02155 g_return_val_if_fail (a_this 02156 && a_this->type == AT_IMPORT_RULE_STMT 02157 && a_this->kind.import_rule, 02158 CR_BAD_PARAM_ERROR); 02159 02160 a_this->kind.import_rule->sheet = a_sheet; 02161 02162 return CR_OK; 02163 } 02164 02165 /** 02166 * cr_statement_at_import_rule_get_imported_sheet: 02167 * 02168 *@a_this: the current \@import rule statement. 02169 *@a_sheet: out parameter. The returned stylesheet if and 02170 *only if the function returns CR_OK. 02171 * 02172 *Gets the stylesheet contained by the \@import rule statement. 02173 *Returns CR_OK upon sucessful completion, an error code otherwise. 02174 */ 02175 enum CRStatus 02176 cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this, 02177 CRStyleSheet ** a_sheet) 02178 { 02179 g_return_val_if_fail (a_this 02180 && a_this->type == AT_IMPORT_RULE_STMT 02181 && a_this->kind.import_rule, 02182 CR_BAD_PARAM_ERROR); 02183 *a_sheet = a_this->kind.import_rule->sheet; 02184 return CR_OK; 02185 02186 } 02187 02188 /** 02189 * cr_statement_at_import_rule_set_url: 02190 * 02191 *@a_this: the current \@import rule statement. 02192 *@a_url: the url to set. 02193 * 02194 *Sets an url to the current \@import rule statement. 02195 * 02196 *Returns CR_OK upon successful completion, an error code otherwise. 02197 */ 02198 enum CRStatus 02199 cr_statement_at_import_rule_set_url (CRStatement * a_this, 02200 CRString * a_url) 02201 { 02202 g_return_val_if_fail (a_this 02203 && a_this->type == AT_IMPORT_RULE_STMT 02204 && a_this->kind.import_rule, 02205 CR_BAD_PARAM_ERROR); 02206 02207 if (a_this->kind.import_rule->url) { 02208 cr_string_destroy (a_this->kind.import_rule->url); 02209 } 02210 02211 a_this->kind.import_rule->url = a_url; 02212 02213 return CR_OK; 02214 } 02215 02216 /** 02217 * cr_statement_at_import_rule_get_url: 02218 * 02219 *@a_this: the current \@import rule statement. 02220 *@a_url: out parameter. The returned url if 02221 *and only if the function returned CR_OK. 02222 * 02223 *Gets the url of the \@import rule statement. 02224 *Returns CR_OK upon successful completion, an error code otherwise. 02225 */ 02226 enum CRStatus 02227 cr_statement_at_import_rule_get_url (CRStatement const * a_this, 02228 CRString ** a_url) 02229 { 02230 g_return_val_if_fail (a_this 02231 && a_this->type == AT_IMPORT_RULE_STMT 02232 && a_this->kind.import_rule, 02233 CR_BAD_PARAM_ERROR); 02234 02235 *a_url = a_this->kind.import_rule->url; 02236 02237 return CR_OK; 02238 } 02239 02240 /** 02241 * cr_statement_at_media_nr_rules: 02242 * 02243 *@a_this: the current instance of #CRStatement. 02244 * 02245 *Returns the number of rules in the media rule; 02246 */ 02247 int 02248 cr_statement_at_media_nr_rules (CRStatement const * a_this) 02249 { 02250 g_return_val_if_fail (a_this 02251 && a_this->type == AT_MEDIA_RULE_STMT 02252 && a_this->kind.media_rule, CR_BAD_PARAM_ERROR); 02253 02254 return cr_statement_nr_rules (a_this->kind.media_rule->rulesets); 02255 } 02256 02257 /** 02258 * cr_statement_at_media_get_from_list: 02259 * 02260 *@a_this: the current instance of #CRStatement. 02261 *@itemnr: the index into the media rule list of rules. 02262 * 02263 *Use an index to get a CRStatement from the media rule list of rules. 02264 * 02265 *Returns CRStatement at position itemnr, if itemnr > number of rules - 1, 02266 *it will return NULL. 02267 */ 02268 CRStatement * 02269 cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr) 02270 { 02271 g_return_val_if_fail (a_this 02272 && a_this->type == AT_MEDIA_RULE_STMT 02273 && a_this->kind.media_rule, NULL); 02274 02275 return cr_statement_get_from_list (a_this->kind.media_rule->rulesets, 02276 itemnr); 02277 } 02278 02279 /** 02280 * cr_statement_at_page_rule_set_declarations: 02281 * 02282 *@a_this: the current \@page rule statement. 02283 *@a_decl_list: the declaration list to add. Will be freed 02284 *by the current instance of #CRStatement when it is destroyed. 02285 * 02286 *Sets a declaration list to the current \@page rule statement. 02287 * 02288 *Returns CR_OK upon successful completion, an error code otherwise. 02289 */ 02290 enum CRStatus 02291 cr_statement_at_page_rule_set_declarations (CRStatement * a_this, 02292 CRDeclaration * a_decl_list) 02293 { 02294 g_return_val_if_fail (a_this 02295 && a_this->type == AT_PAGE_RULE_STMT 02296 && a_this->kind.page_rule, CR_BAD_PARAM_ERROR); 02297 02298 if (a_this->kind.page_rule->decl_list) { 02299 cr_declaration_unref (a_this->kind.page_rule->decl_list); 02300 } 02301 02302 a_this->kind.page_rule->decl_list = a_decl_list; 02303 02304 if (a_decl_list) { 02305 cr_declaration_ref (a_decl_list); 02306 } 02307 02308 return CR_OK; 02309 } 02310 02311 /** 02312 * cr_statement_at_page_rule_get_declarations: 02313 * 02314 *@a_this: the current \@page rule statement. 02315 *@a_decl_list: out parameter. The returned declaration list. 02316 * 02317 *Gets the declaration list associated to the current \@page rule 02318 *statement. 02319 * 02320 *Returns CR_OK upon successful completion, an error code otherwise. 02321 */ 02322 enum CRStatus 02323 cr_statement_at_page_rule_get_declarations (CRStatement * a_this, 02324 CRDeclaration ** a_decl_list) 02325 { 02326 g_return_val_if_fail (a_this 02327 && a_this->type == AT_PAGE_RULE_STMT 02328 && a_this->kind.page_rule, CR_BAD_PARAM_ERROR); 02329 02330 *a_decl_list = a_this->kind.page_rule->decl_list; 02331 02332 return CR_OK; 02333 } 02334 02335 /** 02336 * cr_statement_at_charset_rule_set_charset: 02337 * 02338 * 02339 *@a_this: the current \@charset rule statement. 02340 *@a_charset: the charset to set. 02341 * 02342 *Sets the charset of the current \@charset rule statement. 02343 * 02344 *Returns CR_OK upon successful completion, an error code otherwise. 02345 */ 02346 enum CRStatus 02347 cr_statement_at_charset_rule_set_charset (CRStatement * a_this, 02348 CRString * a_charset) 02349 { 02350 g_return_val_if_fail (a_this 02351 && a_this->type == AT_CHARSET_RULE_STMT 02352 && a_this->kind.charset_rule, 02353 CR_BAD_PARAM_ERROR); 02354 02355 if (a_this->kind.charset_rule->charset) { 02356 cr_string_destroy (a_this->kind.charset_rule->charset); 02357 } 02358 a_this->kind.charset_rule->charset = a_charset; 02359 return CR_OK; 02360 } 02361 02362 /** 02363 * cr_statement_at_charset_rule_get_charset: 02364 *@a_this: the current \@charset rule statement. 02365 *@a_charset: out parameter. The returned charset string if 02366 *and only if the function returned CR_OK. 02367 * 02368 *Gets the charset string associated to the current 02369 *\@charset rule statement. 02370 * 02371 * Returns CR_OK upon successful completion, an error code otherwise. 02372 */ 02373 enum CRStatus 02374 cr_statement_at_charset_rule_get_charset (CRStatement const * a_this, 02375 CRString ** a_charset) 02376 { 02377 g_return_val_if_fail (a_this 02378 && a_this->type == AT_CHARSET_RULE_STMT 02379 && a_this->kind.charset_rule, 02380 CR_BAD_PARAM_ERROR); 02381 02382 *a_charset = a_this->kind.charset_rule->charset; 02383 02384 return CR_OK; 02385 } 02386 02387 /** 02388 * cr_statement_at_font_face_rule_set_decls: 02389 * 02390 *@a_this: the current \@font-face rule statement. 02391 *@a_decls: the declarations list to set. 02392 * 02393 *Sets a declaration list to the current \@font-face rule statement. 02394 * 02395 *Returns CR_OK upon successful completion, an error code otherwise. 02396 */ 02397 enum CRStatus 02398 cr_statement_at_font_face_rule_set_decls (CRStatement * a_this, 02399 CRDeclaration * a_decls) 02400 { 02401 g_return_val_if_fail (a_this 02402 && a_this->type == AT_FONT_FACE_RULE_STMT 02403 && a_this->kind.font_face_rule, 02404 CR_BAD_PARAM_ERROR); 02405 02406 if (a_this->kind.font_face_rule->decl_list) { 02407 cr_declaration_unref (a_this->kind.font_face_rule->decl_list); 02408 } 02409 02410 a_this->kind.font_face_rule->decl_list = a_decls; 02411 cr_declaration_ref (a_decls); 02412 02413 return CR_OK; 02414 } 02415 02416 /** 02417 * cr_statement_at_font_face_rule_get_decls: 02418 * 02419 *@a_this: the current \@font-face rule statement. 02420 *@a_decls: out parameter. The returned declaration list if 02421 *and only if this function returns CR_OK. 02422 * 02423 *Gets the declaration list associated to the current instance 02424 *of \@font-face rule statement. 02425 * 02426 *Returns CR_OK upon successful completion, an error code otherwise. 02427 */ 02428 enum CRStatus 02429 cr_statement_at_font_face_rule_get_decls (CRStatement * a_this, 02430 CRDeclaration ** a_decls) 02431 { 02432 g_return_val_if_fail (a_this 02433 && a_this->type == AT_FONT_FACE_RULE_STMT 02434 && a_this->kind.font_face_rule, 02435 CR_BAD_PARAM_ERROR); 02436 02437 *a_decls = a_this->kind.font_face_rule->decl_list; 02438 02439 return CR_OK; 02440 } 02441 02442 /** 02443 * cr_statement_at_font_face_rule_add_decl: 02444 * 02445 *@a_this: the current \@font-face rule statement. 02446 *@a_prop: the property of the declaration. 02447 *@a_value: the value of the declaration. 02448 * 02449 *Adds a declaration to the current \@font-face rule 02450 *statement. 02451 * 02452 *Returns CR_OK upon successful completion, an error code otherwise. 02453 */ 02454 enum CRStatus 02455 cr_statement_at_font_face_rule_add_decl (CRStatement * a_this, 02456 CRString * a_prop, CRTerm * a_value) 02457 { 02458 CRDeclaration *decls = NULL; 02459 02460 g_return_val_if_fail (a_this 02461 && a_this->type == AT_FONT_FACE_RULE_STMT 02462 && a_this->kind.font_face_rule, 02463 CR_BAD_PARAM_ERROR); 02464 02465 decls = cr_declaration_append2 02466 (a_this->kind.font_face_rule->decl_list, 02467 a_prop, a_value); 02468 02469 g_return_val_if_fail (decls, CR_ERROR); 02470 02471 if (a_this->kind.font_face_rule->decl_list == NULL) 02472 cr_declaration_ref (decls); 02473 02474 a_this->kind.font_face_rule->decl_list = decls; 02475 02476 return CR_OK; 02477 } 02478 02479 02480 /** 02481 * cr_statement_to_string: 02482 * 02483 *@a_this: the current statement to serialize 02484 *@a_indent: the number of white space of indentation. 02485 * 02486 *Serializes a css statement into a string 02487 * 02488 *Returns the serialized statement. Must be freed by the caller 02489 *using g_free(). 02490 */ 02491 gchar * 02492 cr_statement_to_string (CRStatement const * a_this, gulong a_indent) 02493 { 02494 gchar *str = NULL ; 02495 02496 if (!a_this) 02497 return NULL; 02498 02499 switch (a_this->type) { 02500 case RULESET_STMT: 02501 str = cr_statement_ruleset_to_string 02502 (a_this, a_indent); 02503 break; 02504 02505 case AT_FONT_FACE_RULE_STMT: 02506 str = cr_statement_font_face_rule_to_string 02507 (a_this, a_indent) ; 02508 break; 02509 02510 case AT_CHARSET_RULE_STMT: 02511 str = cr_statement_charset_to_string 02512 (a_this, a_indent); 02513 break; 02514 02515 case AT_PAGE_RULE_STMT: 02516 str = cr_statement_at_page_rule_to_string 02517 (a_this, a_indent); 02518 break; 02519 02520 case AT_MEDIA_RULE_STMT: 02521 str = cr_statement_media_rule_to_string 02522 (a_this, a_indent); 02523 break; 02524 02525 case AT_IMPORT_RULE_STMT: 02526 str = cr_statement_import_rule_to_string 02527 (a_this, a_indent); 02528 break; 02529 02530 default: 02531 cr_utils_trace_info ("Statement unrecognized"); 02532 break; 02533 } 02534 return str ; 02535 } 02536 02537 gchar* 02538 cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) 02539 { 02540 CRStatement const *cur_stmt = NULL ; 02541 GString *stringue = NULL ; 02542 gchar *str = NULL ; 02543 02544 g_return_val_if_fail (a_this, NULL) ; 02545 02546 stringue = g_string_new (NULL) ; 02547 if (!stringue) { 02548 cr_utils_trace_info ("Out of memory") ; 02549 return NULL ; 02550 } 02551 for (cur_stmt = a_this ; cur_stmt; 02552 cur_stmt = cur_stmt->next) { 02553 str = cr_statement_to_string (cur_stmt, a_indent) ; 02554 if (str) { 02555 if (!cur_stmt->prev) { 02556 g_string_append (stringue, str) ; 02557 } else { 02558 g_string_append_printf 02559 (stringue, "\n%s", str) ; 02560 } 02561 g_free (str) ; 02562 str = NULL ; 02563 } 02564 } 02565 str = stringue->str ; 02566 g_string_free (stringue, FALSE) ; 02567 return str ; 02568 } 02569 02570 /** 02571 * cr_statement_dump: 02572 * 02573 *@a_this: the current css2 statement. 02574 *@a_fp: the destination file pointer. 02575 *@a_indent: the number of white space indentation characters. 02576 * 02577 *Dumps the css2 statement to a file. 02578 */ 02579 void 02580 cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent) 02581 { 02582 gchar *str = NULL ; 02583 02584 if (!a_this) 02585 return; 02586 02587 str = cr_statement_to_string (a_this, a_indent) ; 02588 if (str) { 02589 fprintf (a_fp, "%s",str) ; 02590 g_free (str) ; 02591 str = NULL ; 02592 } 02593 } 02594 02595 /** 02596 * cr_statement_dump_ruleset: 02597 * 02598 *@a_this: the current instance of #CRStatement. 02599 *@a_fp: the destination file pointer. 02600 *@a_indent: the number of indentation white spaces to add. 02601 * 02602 *Dumps a ruleset statement to a file. 02603 */ 02604 void 02605 cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent) 02606 { 02607 gchar *str = NULL; 02608 02609 g_return_if_fail (a_fp && a_this); 02610 str = cr_statement_ruleset_to_string (a_this, a_indent); 02611 if (str) { 02612 fprintf (a_fp, "%s", str); 02613 g_free (str); 02614 str = NULL; 02615 } 02616 } 02617 02618 /** 02619 * cr_statement_dump_font_face_rule: 02620 * 02621 *@a_this: the current instance of font face rule statement. 02622 *@a_fp: the destination file pointer. 02623 *@a_indent: the number of white space indentation. 02624 * 02625 *Dumps a font face rule statement to a file. 02626 */ 02627 void 02628 cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp, 02629 glong a_indent) 02630 { 02631 gchar *str = NULL ; 02632 g_return_if_fail (a_this 02633 && a_this->type == AT_FONT_FACE_RULE_STMT); 02634 02635 str = cr_statement_font_face_rule_to_string (a_this, 02636 a_indent) ; 02637 if (str) { 02638 fprintf (a_fp, "%s", str) ; 02639 g_free (str) ; 02640 str = NULL ; 02641 } 02642 } 02643 02644 /** 02645 * cr_statement_dump_charset: 02646 * 02647 *@a_this: the current instance of the \@charset rule statement. 02648 *@a_fp: the destination file pointer. 02649 *@a_indent: the number of indentation white spaces. 02650 * 02651 *Dumps an \@charset rule statement to a file. 02652 */ 02653 void 02654 cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent) 02655 { 02656 gchar *str = NULL; 02657 02658 g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT); 02659 02660 str = cr_statement_charset_to_string (a_this, 02661 a_indent) ; 02662 if (str) { 02663 fprintf (a_fp, "%s", str) ; 02664 g_free (str) ; 02665 str = NULL ; 02666 } 02667 } 02668 02669 02670 /** 02671 * cr_statement_dump_page: 02672 * 02673 *@a_this: the statement to dump on stdout. 02674 *@a_fp: the destination file pointer. 02675 *@a_indent: the number of indentation white spaces. 02676 * 02677 *Dumps an \@page rule statement on stdout. 02678 */ 02679 void 02680 cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent) 02681 { 02682 gchar *str = NULL; 02683 02684 g_return_if_fail (a_this 02685 && a_this->type == AT_PAGE_RULE_STMT 02686 && a_this->kind.page_rule); 02687 02688 str = cr_statement_at_page_rule_to_string (a_this, a_indent) ; 02689 if (str) { 02690 fprintf (a_fp, "%s", str); 02691 g_free (str) ; 02692 str = NULL ; 02693 } 02694 } 02695 02696 02697 /** 02698 * cr_statement_dump_media_rule: 02699 * 02700 *@a_this: the statement to dump. 02701 *@a_fp: the destination file pointer 02702 *@a_indent: the number of white spaces indentation. 02703 * 02704 *Dumps an \@media rule statement to a file. 02705 */ 02706 void 02707 cr_statement_dump_media_rule (CRStatement const * a_this, 02708 FILE * a_fp, 02709 gulong a_indent) 02710 { 02711 gchar *str = NULL ; 02712 g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT); 02713 02714 str = cr_statement_media_rule_to_string (a_this, a_indent) ; 02715 if (str) { 02716 fprintf (a_fp, "%s", str) ; 02717 g_free (str) ; 02718 str = NULL ; 02719 } 02720 } 02721 02722 /** 02723 * cr_statement_dump_import_rule: 02724 * 02725 *@a_fp: the destination file pointer. 02726 *@a_indent: the number of white space indentations. 02727 * 02728 *Dumps an \@import rule statement to a file. 02729 */ 02730 void 02731 cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp, 02732 gulong a_indent) 02733 { 02734 gchar *str = NULL ; 02735 g_return_if_fail (a_this 02736 && a_this->type == AT_IMPORT_RULE_STMT 02737 && a_fp 02738 && a_this->kind.import_rule); 02739 02740 str = cr_statement_import_rule_to_string (a_this, a_indent) ; 02741 if (str) { 02742 fprintf (a_fp, "%s", str) ; 02743 g_free (str) ; 02744 str = NULL ; 02745 } 02746 } 02747 02748 /** 02749 * cr_statement_destroy: 02750 * 02751 * @a_this: the current instance of #CRStatement. 02752 * 02753 *Destructor of #CRStatement. 02754 */ 02755 void 02756 cr_statement_destroy (CRStatement * a_this) 02757 { 02758 CRStatement *cur = NULL; 02759 02760 g_return_if_fail (a_this); 02761 02762 /*go get the tail of the list */ 02763 for (cur = a_this; cur && cur->next; cur = cur->next) { 02764 cr_statement_clear (cur); 02765 } 02766 02767 if (cur) 02768 cr_statement_clear (cur); 02769 02770 if (cur->prev == NULL) { 02771 g_free (a_this); 02772 return; 02773 } 02774 02775 /*walk backward and free next element */ 02776 for (cur = cur->prev; cur && cur->prev; cur = cur->prev) { 02777 if (cur->next) { 02778 g_free (cur->next); 02779 cur->next = NULL; 02780 } 02781 } 02782 02783 if (!cur) 02784 return; 02785 02786 /*free the one remaining list */ 02787 if (cur->next) { 02788 g_free (cur->next); 02789 cur->next = NULL; 02790 } 02791 02792 g_free (cur); 02793 cur = NULL; 02794 }